feat: new register flow
This commit is contained in:
		
							parent
							
								
									5598b40d66
								
							
						
					
					
						commit
						cc63e16d9c
					
				
					 4 changed files with 52 additions and 36 deletions
				
			
		|  | @ -31,7 +31,6 @@ export default class AuthController { | ||||||
|     const expiresIn = '15 minutes' |     const expiresIn = '15 minutes' | ||||||
|     const payload = await this.authService.generateCode(email, expiresIn) |     const payload = await this.authService.generateCode(email, expiresIn) | ||||||
| 
 | 
 | ||||||
|     // Send email
 |  | ||||||
|     await mail |     await mail | ||||||
|       .send((message) => { |       .send((message) => { | ||||||
|         message |         message | ||||||
|  | @ -62,7 +61,6 @@ export default class AuthController { | ||||||
|       }) |       }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Find user by id
 |  | ||||||
|     const user = await User.findBy('email', email) |     const user = await User.findBy('email', email) | ||||||
|     if (!user) { |     if (!user) { | ||||||
|       // If the user does not exist, return a token for registration
 |       // If the user does not exist, return a token for registration
 | ||||||
|  | @ -75,59 +73,83 @@ export default class AuthController { | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Perform login
 |  | ||||||
|     await auth.use('web').login(user, true) // true for remember me
 |     await auth.use('web').login(user, true) // true for remember me
 | ||||||
|     return { |     return { | ||||||
|       success: true, |       success: true, | ||||||
|       user, |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // GET /auth/autocomplete
 | ||||||
|  |   async listNames({ request }: HttpContext) { | ||||||
|  |     const { className } = request.qs() | ||||||
|  |     if (!className) { | ||||||
|  |       return { | ||||||
|  |         success: false, | ||||||
|  |         message: 'Veuillez spécifier une classe', | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return User.query() | ||||||
|  |       .select('firstName', 'lastName') | ||||||
|  |       .where('className', className) | ||||||
|  |       .orderBy('lastName', 'asc') | ||||||
|  |       .then((users) => { | ||||||
|  |         return { | ||||||
|  |           success: true, | ||||||
|  |           data: users.map((user) => ({ | ||||||
|  |             value: `${user.firstName}::${user.lastName}`, | ||||||
|  |             label: user.fullName, | ||||||
|  |           })), | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // POST /auth/register
 |   // POST /auth/register
 | ||||||
|   async register({ request, response, auth }: HttpContext) { |   async register({ request, response, auth }: HttpContext) { | ||||||
|     const { firstName, lastName, className, token } = await request.validateUsing(registerValidator) |     const { name, className, token } = await request.validateUsing(registerValidator) | ||||||
| 
 | 
 | ||||||
|     // Validate token
 |     // Validate token
 | ||||||
|     const { success, email } = this.authService.validateToken(token) |     const { success, email } = this.authService.validateToken(token) | ||||||
|     if (!success || !email) { |     const [firstName, lastName] = name.split('::') | ||||||
|  |     if (!success || !email || !firstName || !lastName) { | ||||||
|       return response.badRequest({ |       return response.badRequest({ | ||||||
|         success: false, |         success: false, | ||||||
|         message: 'Votre lien de connexion est invalide ou a expiré.', |         message: 'Votre lien de connexion est invalide ou a expiré.', | ||||||
|       }) |       }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Check if user already exists
 |     const user = await User.query() | ||||||
|     const existingUser = await User.findBy('email', email) |       .where('firstName', firstName) | ||||||
|     if (existingUser) { |       .where('lastName', lastName) | ||||||
|       // If user already exists, perform login
 |       .where('className', className) | ||||||
|       await auth.use('web').login(existingUser, true) // true for remember me
 |       .first() | ||||||
|       return { |     if (!user) { | ||||||
|         success: true, |       return response.badRequest({ | ||||||
|         user: existingUser, |         success: false, | ||||||
|       } |         message: 'Utilisateur non trouvé. Veuillez vérifier vos informations.', | ||||||
|  |       }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // TODO: Check if className is allowed (else redirect for account giving)
 |     if (user.email && user.email.toLowerCase() !== email.toLowerCase()) { | ||||||
|  |       return response.badRequest({ | ||||||
|  |         success: false, | ||||||
|  |         message: | ||||||
|  |           "L'email associé à votre compte ne correspond pas à celui utilisé pour la connexion.", | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     user.email = email.toLowerCase() // Update email if necessary
 | ||||||
|  |     await user.save() | ||||||
| 
 | 
 | ||||||
|     // TODO: Rewrite user creation (NEVER CREATE USER - use string similarity)
 |  | ||||||
|     // Create new user
 |  | ||||||
|     const user = await User.create({ |  | ||||||
|       firstName, |  | ||||||
|       lastName, |  | ||||||
|       className, |  | ||||||
|       email, |  | ||||||
|     }) |  | ||||||
|     // Perform login
 |     // Perform login
 | ||||||
|     await auth.use('web').login(user, true) // true for remember me
 |     await auth.use('web').login(user, true) // true for remember me
 | ||||||
|     return { |     return { | ||||||
|       success: true, |       success: true, | ||||||
|       user, |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // POST /auth/logout
 |   // POST /auth/logout
 | ||||||
|   async logout({ auth }: HttpContext) { |   async logout({ auth }: HttpContext) { | ||||||
|     // Logout user
 |  | ||||||
|     await auth.use('web').logout() |     await auth.use('web').logout() | ||||||
|     return { |     return { | ||||||
|       success: true, |       success: true, | ||||||
|  |  | ||||||
|  | @ -11,10 +11,10 @@ export default class User extends BaseModel { | ||||||
|   @column() |   @column() | ||||||
|   declare className: string |   declare className: string | ||||||
| 
 | 
 | ||||||
|   @column() |   @column({ serializeAs: null}) | ||||||
|   declare firstName: string |   declare firstName: string | ||||||
| 
 | 
 | ||||||
|   @column() |   @column({ serializeAs: null}) | ||||||
|   declare lastName: string |   declare lastName: string | ||||||
| 
 | 
 | ||||||
|   @computed() |   @computed() | ||||||
|  |  | ||||||
|  | @ -19,16 +19,9 @@ export const verifyCodeValidator = vine.compile( | ||||||
|   }) |   }) | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| function toTitleCase(value: string) { |  | ||||||
|   return value.replace(/\w\S*/g, (txt) => { |  | ||||||
|     return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase() |  | ||||||
|   }) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export const registerValidator = vine.compile( | export const registerValidator = vine.compile( | ||||||
|   vine.object({ |   vine.object({ | ||||||
|     firstName: vine.string().minLength(2).maxLength(50).trim().transform(toTitleCase), |     name: vine.string().minLength(2).maxLength(50).trim(), | ||||||
|     lastName: vine.string().minLength(2).maxLength(50).trim().toUpperCase(), |  | ||||||
|     className: vine.string().minLength(2).maxLength(50), |     className: vine.string().minLength(2).maxLength(50), | ||||||
|     token: vine.string(), |     token: vine.string(), | ||||||
|   }) |   }) | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ router.group(() => { | ||||||
|   router.post('/auth/verify', [AuthController, 'verifyCode']).use(throttle) |   router.post('/auth/verify', [AuthController, 'verifyCode']).use(throttle) | ||||||
|   router.post('/auth/register', [AuthController, 'register']).use(throttle) |   router.post('/auth/register', [AuthController, 'register']).use(throttle) | ||||||
|   router.post('/auth/logout', [AuthController, 'logout']) |   router.post('/auth/logout', [AuthController, 'logout']) | ||||||
|  |   router.get('/auth/autocomplete', [AuthController, 'listNames']).use(throttle) | ||||||
|   // TODO: Magic link login
 |   // TODO: Magic link login
 | ||||||
|   // router.get('/auth/magic-link', 'AuthController.magicLink').use(throttle)
 |   // router.get('/auth/magic-link', 'AuthController.magicLink').use(throttle)
 | ||||||
|   // router.get('/auth/listen', 'AuthController.listen')
 |   // router.get('/auth/listen', 'AuthController.listen')
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Nathan Lamy
						Nathan Lamy