Coverage for app/routes/auth.py: 100%
59 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-05-02 02:49 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-05-02 02:49 +0000
1from flask import request, render_template, Blueprint, redirect, session
2from app.services.auth_service import login_with_email, login_with_provider, callback, signout, signup_with_email
3from app.models.response import *
4from app.models.status_codes import StatusCodes
5from flasgger import swag_from
9auth_bp = Blueprint('auth', __name__)
12@auth_bp.route('/login')
13def login_page():
14 return render_template('login.html')
16@auth_bp.route('/auth/login', methods=['GET', 'POST'])
17@swag_from({
18 'tags': ['Auth'],
19 'summary': 'Login route',
20 'description': 'Handles login with email or provider.',
21 'parameters': [
22 {
23 'name': 'provider',
24 'in': 'query',
25 'type': 'string',
26 'enum': ['email', 'github'],
27 'required': True,
28 'description': 'Provider for authentication'
29 },
30 {
31 'name': 'next',
32 'in': 'query',
33 'type': 'string',
34 'description': 'Next URL after successful login'
35 },
36 {
37 'name': 'body',
38 'in': 'body',
39 'required': False,
40 'schema': {
41 'type': 'object',
42 'properties': {
43 'email': {'type': 'string', 'example': 'jaime@example.com'},
44 'password': {'type': 'string', 'example': 'password123'}
45 },
46 'required': ['email', 'password']
47 }
48 }
49 ],
50 'responses': {
51 '200': {
52 "description": "Login successful."
53 },
54 '400': {
55 "description": "Bad request (missing provider or email/password)."
56 }
57 }
58})
59def login_route():
60 provider = request.args.get("provider", "")
61 next_url = request.args.get("next", "/auth/complete")
62 if not provider:
63 return error_response(
64 "Provider not provided. Ex github",
65 None,
66 StatusCodes.BAD_REQUEST
67 )
69 if provider == "email":
70 data = request.json
71 email = data.get("email", "")
72 password = data.get("password", "")
73 if not email or not password:
74 return error_response(
75 "Email or password not provided",
76 None,
77 StatusCodes.BAD_REQUEST
78 )
79 res = login_with_email(email, password)
80 return success_response(
81 "Login successful",
82 {
83 "token": res.user.id,
84 "access_token": res.session.access_token,
85 "refresh_token": res.session.refresh_token,
86 },
87 StatusCodes.OK
88 )
89 else:
90 res = login_with_provider(provider)
91 session["next_url"] = next_url
92 return redirect(res.url)
95@auth_bp.route('/auth/complete')
96def auth_complete_route():
97 return render_template('auth_success.html')
100@auth_bp.route('/auth/callback')
101def auth():
102 code = request.args.get("code")
103 next_url = session.pop("next_url", "/auth/complete")
105 if not code:
106 return error_response(
107 "Error: Missing authorization code",
108 None,
109 StatusCodes.BAD_REQUEST
110 )
112 res = callback(code)
113 redirect_url = f"{next_url}?id={res.user.id}&access_token={res.session.access_token}&refresh_token={res.session.refresh_token}"
114 return redirect(redirect_url)
116@auth_bp.route('/auth/signup', methods=['POST'])
117@swag_from({
118 'tags': ['Auth'],
119 'summary': 'Create a new user',
120 'description': 'Registers a new user with first name, last name, email, and password.',
121 'parameters': [
122 {
123 'name': 'body',
124 'in': 'body',
125 'required': True,
126 'schema': {
127 'type': 'object',
128 'properties': {
129 'first_name': {'type': 'string', 'example': 'Jaime'},
130 'last_name': {'type': 'string', 'example': 'Nguyen'},
131 'email': {'type': 'string', 'example': 'jaime@example.com'},
132 'password': {'type': 'string', 'example': 'password123'}
133 },
134 'required': ['first_name', 'last_name', 'email', 'password']
135 }
136 }
137 ],
138 'responses': {
139 '201': {
140 'description': 'User created successfully',
141 'schema': {
142 'type': 'object',
143 'properties': {
144 'id': {'type': 'string'},
145 'first_name': {'type': 'string'},
146 'last_name': {'type': 'string'},
147 'email': {'type': 'string'}
148 }
149 }
150 },
151 '400': {
152 'description': 'Bad request (missing fields or email already exists)',
153 'schema': {
154 'type': 'object',
155 'properties': {
156 'error': {'type': 'string'}
157 }
158 }
159 },
160 '500': {
161 'description': 'Internal server error',
162 'schema': {
163 'type': 'object',
164 'properties': {
165 'error': {'type': 'string'}
166 }
167 }
168 }
169 }
170})
171def signup_route():
172 data = request.json
173 email = data.get("email", "")
174 password = data.get("password", "")
175 first_name = data.get("first_name", "")
176 last_name = data.get("last_name", "")
177 if not email or not password or not first_name or not last_name:
178 return error_response(
179 "Email or password not provided",
180 None,
181 StatusCodes.BAD_REQUEST
182 )
183 res = signup_with_email(email, password, first_name, last_name)
184 return success_response(
185 "Signup successful",
186 {
187 "token": res.user.id,
188 },
189 StatusCodes.OK
190 )
193@auth_bp.route('/auth/signout', methods=['POST'])
194@swag_from({
195 'tags': ['Auth'],
196 'summary': 'Sign out route',
197 'description': 'Handles sign out of a user.',
198 'parameters': [
199 {
200 'name': 'body',
201 'in': 'body',
202 'required': True,
203 'schema': {
204 'type': 'object',
205 'properties': {
206 'user_id': {'type': 'string', 'example': '12345'}
207 },
208 'required': ['user_id']
209 }
210 }
211 ],
212 'responses': {
213 200: {
214 "description": "User signed out successfully."
215 },
216 400: {
217 "description": "Bad request (missing user ID)."
218 }
219 }
220})
221def signout_route():
222 data = request.json
223 user_id = data.get("user_id", "")
224 if not user_id:
225 return error_response(
226 "User ID not provided",
227 None,
228 StatusCodes.BAD_REQUEST
229 )
230 return signout(user_id)