from flask import request, render_template, Blueprint, redirect, session
from app.services.auth_service import login_with_email, login_with_provider, callback, signout, signup_with_email
from app.models.response import *
from app.models.status_codes import StatusCodes
from flasgger import swag_from
auth_bp = Blueprint('auth', __name__)
[docs]
@auth_bp.route('/login')
def login_page():
return render_template('login.html')
[docs]
@auth_bp.route('/auth/login', methods=['GET', 'POST'])
@swag_from({
'tags': ['Auth'],
'summary': 'Login route',
'description': 'Handles login with email or provider.',
'parameters': [
{
'name': 'provider',
'in': 'query',
'type': 'string',
'enum': ['email', 'github'],
'required': True,
'description': 'Provider for authentication'
},
{
'name': 'next',
'in': 'query',
'type': 'string',
'description': 'Next URL after successful login'
},
{
'name': 'body',
'in': 'body',
'required': False,
'schema': {
'type': 'object',
'properties': {
'email': {'type': 'string', 'example': 'jaime@example.com'},
'password': {'type': 'string', 'example': 'password123'}
},
'required': ['email', 'password']
}
}
],
'responses': {
'200': {
"description": "Login successful."
},
'400': {
"description": "Bad request (missing provider or email/password)."
}
}
})
def login_route():
provider = request.args.get("provider", "")
next_url = request.args.get("next", "/auth/complete")
if not provider:
return error_response(
"Provider not provided. Ex github",
None,
StatusCodes.BAD_REQUEST
)
if provider == "email":
data = request.json
email = data.get("email", "")
password = data.get("password", "")
if not email or not password:
return error_response(
"Email or password not provided",
None,
StatusCodes.BAD_REQUEST
)
res = login_with_email(email, password)
return success_response(
"Login successful",
{
"token": res.user.id,
"access_token": res.session.access_token,
"refresh_token": res.session.refresh_token,
},
StatusCodes.OK
)
else:
res = login_with_provider(provider)
session["next_url"] = next_url
return redirect(res.url)
[docs]
@auth_bp.route('/auth/complete')
def auth_complete_route():
return render_template('auth_success.html')
[docs]
@auth_bp.route('/auth/callback')
def auth():
code = request.args.get("code")
next_url = session.pop("next_url", "/auth/complete")
if not code:
return error_response(
"Error: Missing authorization code",
None,
StatusCodes.BAD_REQUEST
)
res = callback(code)
redirect_url = f"{next_url}?id={res.user.id}&access_token={res.session.access_token}&refresh_token={res.session.refresh_token}"
return redirect(redirect_url)
[docs]
@auth_bp.route('/auth/signup', methods=['POST'])
@swag_from({
'tags': ['Auth'],
'summary': 'Create a new user',
'description': 'Registers a new user with first name, last name, email, and password.',
'parameters': [
{
'name': 'body',
'in': 'body',
'required': True,
'schema': {
'type': 'object',
'properties': {
'first_name': {'type': 'string', 'example': 'Jaime'},
'last_name': {'type': 'string', 'example': 'Nguyen'},
'email': {'type': 'string', 'example': 'jaime@example.com'},
'password': {'type': 'string', 'example': 'password123'}
},
'required': ['first_name', 'last_name', 'email', 'password']
}
}
],
'responses': {
'201': {
'description': 'User created successfully',
'schema': {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'first_name': {'type': 'string'},
'last_name': {'type': 'string'},
'email': {'type': 'string'}
}
}
},
'400': {
'description': 'Bad request (missing fields or email already exists)',
'schema': {
'type': 'object',
'properties': {
'error': {'type': 'string'}
}
}
},
'500': {
'description': 'Internal server error',
'schema': {
'type': 'object',
'properties': {
'error': {'type': 'string'}
}
}
}
}
})
def signup_route():
data = request.json
email = data.get("email", "")
password = data.get("password", "")
first_name = data.get("first_name", "")
last_name = data.get("last_name", "")
if not email or not password or not first_name or not last_name:
return error_response(
"Email or password not provided",
None,
StatusCodes.BAD_REQUEST
)
res = signup_with_email(email, password, first_name, last_name)
return success_response(
"Signup successful",
{
"token": res.user.id,
},
StatusCodes.OK
)
[docs]
@auth_bp.route('/auth/signout', methods=['POST'])
@swag_from({
'tags': ['Auth'],
'summary': 'Sign out route',
'description': 'Handles sign out of a user.',
'parameters': [
{
'name': 'body',
'in': 'body',
'required': True,
'schema': {
'type': 'object',
'properties': {
'user_id': {'type': 'string', 'example': '12345'}
},
'required': ['user_id']
}
}
],
'responses': {
200: {
"description": "User signed out successfully."
},
400: {
"description": "Bad request (missing user ID)."
}
}
})
def signout_route():
data = request.json
user_id = data.get("user_id", "")
if not user_id:
return error_response(
"User ID not provided",
None,
StatusCodes.BAD_REQUEST
)
return signout(user_id)