11import type { FastifyInstance , FastifyReply , FastifyRequest } from 'fastify' ;
2- import { AdminResetPasswordSchema , type AdminResetPasswordInput } from './schemas' ;
2+ import { type AdminResetPasswordInput } from './schemas' ;
33import { PasswordResetService } from '../../services/passwordResetService' ;
44import { requireGlobalAdmin } from '../../middleware/roleMiddleware' ;
5- import { z } from 'zod' ;
6- import { createSchema } from 'zod-openapi' ;
75
8- // Response schemas
9- const adminResetPasswordSuccessResponseSchema = z . object ( {
10- success : z . boolean ( ) . describe ( 'Indicates if the request was processed successfully' ) ,
11- message : z . string ( ) . describe ( 'Success message' )
12- } ) ;
6+ const SUCCESS_RESPONSE_SCHEMA = {
7+ type : 'object' ,
8+ properties : {
9+ success : { type : 'boolean' } ,
10+ message : { type : 'string' }
11+ } ,
12+ required : [ 'success' , 'message' ]
13+ } as const ;
1314
14- const adminResetPasswordErrorResponseSchema = z . object ( {
15- success : z . boolean ( ) . describe ( 'Indicates if the operation was successful (false for errors)' ) . default ( false ) ,
16- error : z . string ( ) . describe ( 'Error message describing what went wrong' )
17- } ) ;
15+ const ERROR_RESPONSE_SCHEMA = {
16+ type : 'object' ,
17+ properties : {
18+ success : { type : 'boolean' , default : false } ,
19+ error : { type : 'string' }
20+ } ,
21+ required : [ 'success' , 'error' ]
22+ } as const ;
1823
1924// Route schema for OpenAPI documentation
2025const adminResetPasswordRouteSchema = {
2126 tags : [ 'Authentication' , 'Admin' ] ,
2227 summary : 'Admin-initiated password reset' ,
2328 description : 'Allows global administrators to initiate password reset for users with email authentication. The admin cannot reset their own password. Requires global_send_mail setting to be enabled. The user will receive an email with a reset link that works the same as self-initiated password resets.' ,
2429 security : [ { cookieAuth : [ ] } ] ,
25- body : createSchema ( AdminResetPasswordSchema ) ,
30+ body : {
31+ type : 'object' ,
32+ properties : {
33+ email : { type : 'string' , format : 'email' }
34+ } ,
35+ required : [ 'email' ] ,
36+ additionalProperties : false
37+ } ,
2638 response : {
27- 200 : createSchema ( adminResetPasswordSuccessResponseSchema . describe ( 'Password reset email sent successfully' ) ) ,
28- 400 : createSchema ( adminResetPasswordErrorResponseSchema . describe ( 'Bad Request - Invalid email, user not found, or user not eligible' ) ) ,
29- 401 : createSchema ( adminResetPasswordErrorResponseSchema . describe ( 'Unauthorized - Authentication required' ) ) ,
30- 403 : createSchema ( adminResetPasswordErrorResponseSchema . describe ( 'Forbidden - Insufficient permissions or self-reset attempt' ) ) ,
31- 503 : createSchema ( adminResetPasswordErrorResponseSchema . describe ( 'Service Unavailable - Email functionality disabled' ) ) ,
32- 500 : createSchema ( adminResetPasswordErrorResponseSchema . describe ( 'Internal Server Error - Password reset failed' ) )
39+ 200 : {
40+ ...SUCCESS_RESPONSE_SCHEMA ,
41+ description : 'Password reset email sent successfully'
42+ } ,
43+ 400 : {
44+ ...ERROR_RESPONSE_SCHEMA ,
45+ description : 'Bad Request - Invalid email, user not found, or user not eligible'
46+ } ,
47+ 401 : {
48+ ...ERROR_RESPONSE_SCHEMA ,
49+ description : 'Unauthorized - Authentication required'
50+ } ,
51+ 403 : {
52+ ...ERROR_RESPONSE_SCHEMA ,
53+ description : 'Forbidden - Insufficient permissions or self-reset attempt'
54+ } ,
55+ 503 : {
56+ ...ERROR_RESPONSE_SCHEMA ,
57+ description : 'Service Unavailable - Email functionality disabled'
58+ } ,
59+ 500 : {
60+ ...ERROR_RESPONSE_SCHEMA ,
61+ description : 'Internal Server Error - Password reset failed'
62+ }
3363 }
3464} ;
3565
36- export default async function adminResetPasswordRoute ( fastify : FastifyInstance ) {
37- fastify . post < { Body : AdminResetPasswordInput } > (
66+ export default async function adminResetPasswordRoute ( server : FastifyInstance ) {
67+ server . post < { Body : AdminResetPasswordInput } > (
3868 '/admin/reset-password' ,
39- {
69+ {
4070 schema : adminResetPasswordRouteSchema ,
4171 preValidation : requireGlobalAdmin ( )
4272 } ,
@@ -45,9 +75,9 @@ export default async function adminResetPasswordRoute(fastify: FastifyInstance)
4575 // Check if password reset is available (email sending enabled)
4676 const isResetAvailable = await PasswordResetService . isPasswordResetAvailable ( ) ;
4777 if ( ! isResetAvailable ) {
48- return reply . status ( 503 ) . send ( {
49- success : false ,
50- error : 'Password reset is currently disabled. Email functionality is not enabled.'
78+ return reply . status ( 503 ) . send ( {
79+ success : false ,
80+ error : 'Password reset is currently disabled. Email functionality is not enabled.'
5181 } ) ;
5282 }
5383
@@ -62,58 +92,58 @@ export default async function adminResetPasswordRoute(fastify: FastifyInstance)
6292 } ) ;
6393 }
6494
65- fastify . log . info ( `Admin-initiated password reset requested by admin ${ adminUserId } for email: ${ email } ` ) ;
95+ server . log . info ( `Admin-initiated password reset requested by admin ${ adminUserId } for email: ${ email } ` ) ;
6696
6797 // Queue admin-initiated reset email as background job
6898 try {
69- const result = await PasswordResetService . prepareAdminResetEmail ( email , adminUserId , fastify . log ) ;
99+ const result = await PasswordResetService . prepareAdminResetEmail ( email , adminUserId , server . log ) ;
70100
71101 if ( ! result . success ) {
72- fastify . log . error ( `Admin password reset preparation failed for ${ email } by admin ${ adminUserId } : ${ result . error } ` ) ;
73-
102+ server . log . error ( `Admin password reset preparation failed for ${ email } by admin ${ adminUserId } : ${ result . error } ` ) ;
103+
74104 // Determine appropriate status code based on error
75105 if ( result . error && result . error . includes ( 'not found' ) || result . error && result . error . includes ( 'not eligible' ) ) {
76- return reply . status ( 400 ) . send ( {
77- success : false ,
78- error : result . error
106+ return reply . status ( 400 ) . send ( {
107+ success : false ,
108+ error : result . error
79109 } ) ;
80110 }
81-
111+
82112 if ( result . error && result . error . includes ( 'cannot reset their own password' ) ) {
83- return reply . status ( 403 ) . send ( {
84- success : false ,
85- error : result . error
113+ return reply . status ( 403 ) . send ( {
114+ success : false ,
115+ error : result . error
86116 } ) ;
87117 }
88-
118+
89119 if ( result . error && result . error . includes ( 'disabled' ) ) {
90- return reply . status ( 503 ) . send ( {
91- success : false ,
92- error : result . error
120+ return reply . status ( 503 ) . send ( {
121+ success : false ,
122+ error : result . error
93123 } ) ;
94124 }
95-
96- return reply . status ( 500 ) . send ( {
97- success : false ,
125+
126+ return reply . status ( 500 ) . send ( {
127+ success : false ,
98128 error : result . error || 'An error occurred during password reset request.'
99129 } ) ;
100130 }
101131
102132 // Queue email as background job if token and emailData were prepared
103133 if ( result . emailData ) {
104134 // eslint-disable-next-line @typescript-eslint/no-explicit-any
105- const jobQueueService = ( fastify as any ) . jobQueueService ;
135+ const jobQueueService = ( server as any ) . jobQueueService ;
106136 if ( jobQueueService ) {
107137 await jobQueueService . createJob ( 'send_email' , result . emailData ) ;
108- fastify . log . info ( `Admin password reset email queued for ${ email } by admin ${ adminUserId } ` ) ;
138+ server . log . info ( `Admin password reset email queued for ${ email } by admin ${ adminUserId } ` ) ;
109139 } else {
110- fastify . log . warn ( 'Job queue service not available, admin password reset email not sent' ) ;
140+ server . log . warn ( 'Job queue service not available, admin password reset email not sent' ) ;
111141 }
112142 }
113143 } catch ( error ) {
114- fastify . log . error ( error , `Error queueing admin password reset email for ${ email } :` ) ;
115- return reply . status ( 500 ) . send ( {
116- success : false ,
144+ server . log . error ( error , `Error queueing admin password reset email for ${ email } :` ) ;
145+ return reply . status ( 500 ) . send ( {
146+ success : false ,
117147 error : 'An unexpected error occurred during password reset request.'
118148 } ) ;
119149 }
@@ -124,10 +154,10 @@ export default async function adminResetPasswordRoute(fastify: FastifyInstance)
124154 } ) ;
125155
126156 } catch ( error ) {
127- fastify . log . error ( error , 'Error during admin-initiated password reset request:' ) ;
128- return reply . status ( 500 ) . send ( {
129- success : false ,
130- error : 'An unexpected error occurred during password reset request.'
157+ server . log . error ( error , 'Error during admin-initiated password reset request:' ) ;
158+ return reply . status ( 500 ) . send ( {
159+ success : false ,
160+ error : 'An unexpected error occurred during password reset request.'
131161 } ) ;
132162 }
133163 }
0 commit comments