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

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 

6 

7 

8 

9auth_bp = Blueprint('auth', __name__) 

10 

11 

12@auth_bp.route('/login') 

13def login_page(): 

14 return render_template('login.html') 

15 

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 ) 

68 

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) 

93 

94 

95@auth_bp.route('/auth/complete') 

96def auth_complete_route(): 

97 return render_template('auth_success.html') 

98 

99 

100@auth_bp.route('/auth/callback') 

101def auth(): 

102 code = request.args.get("code") 

103 next_url = session.pop("next_url", "/auth/complete") 

104 

105 if not code: 

106 return error_response( 

107 "Error: Missing authorization code", 

108 None, 

109 StatusCodes.BAD_REQUEST 

110 ) 

111 

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) 

115 

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 ) 

191 

192 

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)