77use App \Core \Auth ;
88use App \Core \Controller ;
99use App \Core \Csrf ;
10+ use App \Core \Session ;
1011use App \Models \Admin ;
1112use App \Models \InquiryLog ;
1213
@@ -29,6 +30,29 @@ public function index(): void
2930 ]);
3031 }
3132
33+ public function edit (): void
34+ {
35+ if (!Auth::can ('tools.view ' )) {
36+ flash ('error ' , 'You do not have permission to access user management. ' );
37+ redirect ('dashboard ' );
38+ }
39+
40+ $ id = (int ) ($ _GET ['id ' ] ?? 0 );
41+ $ adminModel = new Admin ();
42+ $ admin = $ adminModel ->findById ($ id );
43+
44+ if (!$ admin ) {
45+ flash ('error ' , 'Admin user not found. ' );
46+ redirect ('admins ' );
47+ }
48+
49+ $ this ->view ('dashboard/admin-user-edit ' , [
50+ 'pageTitle ' => 'Edit Admin User ' ,
51+ 'adminUser ' => $ admin ,
52+ 'csrfToken ' => Csrf::token (),
53+ ]);
54+ }
55+
3256 public function create (): void
3357 {
3458 if (!Auth::can ('tools.view ' ) || !Csrf::verify ($ _POST ['_csrf ' ] ?? null )) {
@@ -39,8 +63,8 @@ public function create(): void
3963 $ username = trim ((string ) ($ _POST ['username ' ] ?? '' ));
4064 $ nickname = trim ((string ) ($ _POST ['nickname ' ] ?? '' ));
4165 $ email = trim ((string ) ($ _POST ['email ' ] ?? '' ));
42- $ role = trim ((string ) ($ _POST ['role ' ] ?? 'agent ' ));
43- $ status = trim ((string ) ($ _POST ['status ' ] ?? 'active ' ));
66+ $ role = $ this -> sanitizeRole ((string ) ($ _POST ['role ' ] ?? 'agent ' ));
67+ $ status = $ this -> sanitizeStatus ((string ) ($ _POST ['status ' ] ?? 'active ' ));
4468 $ password = (string ) ($ _POST ['password ' ] ?? '' );
4569
4670 if ($ username === '' || $ email === '' || $ password === '' ) {
@@ -51,11 +75,9 @@ public function create(): void
5175 flash ('error ' , 'Please enter a valid email address. ' );
5276 redirect ('admins ' );
5377 }
54- if (!in_array ($ role , ['admin ' , 'manager ' , 'agent ' , 'viewer ' ], true )) {
55- $ role = 'agent ' ;
56- }
57- if (!in_array ($ status , ['active ' , 'disabled ' ], true )) {
58- $ status = 'active ' ;
78+ if (strlen ($ password ) < 8 ) {
79+ flash ('error ' , 'Password must be at least 8 characters long. ' );
80+ redirect ('admins ' );
5981 }
6082
6183 $ created = (new Admin ())->create ([
@@ -88,27 +110,194 @@ public function updateMeta(): void
88110 }
89111
90112 $ id = (int ) ($ _POST ['id ' ] ?? 0 );
91- $ role = trim ((string ) ($ _POST ['role ' ] ?? 'agent ' ));
92- $ status = trim ((string ) ($ _POST ['status ' ] ?? 'active ' ));
113+ $ role = $ this -> sanitizeRole ((string ) ($ _POST ['role ' ] ?? 'agent ' ));
114+ $ status = $ this -> sanitizeStatus ((string ) ($ _POST ['status ' ] ?? 'active ' ));
93115
94116 if ($ id <= 0 ) {
95117 flash ('error ' , 'Invalid admin id. ' );
96118 redirect ('admins ' );
97119 }
98- if (!in_array ($ role , ['admin ' , 'manager ' , 'agent ' , 'viewer ' ], true )) {
99- $ role = 'agent ' ;
120+
121+ $ adminModel = new Admin ();
122+ $ target = $ adminModel ->findById ($ id );
123+ if (!$ target ) {
124+ flash ('error ' , 'Admin user not found. ' );
125+ redirect ('admins ' );
100126 }
101- if (!in_array ($ status , ['active ' , 'disabled ' ], true )) {
102- $ status = 'active ' ;
127+
128+ $ guardMessage = $ this ->guardAdminChange ($ target , $ role , $ status );
129+ if ($ guardMessage !== null ) {
130+ flash ('error ' , $ guardMessage );
131+ redirect ('admins ' );
103132 }
104133
105- $ updated = ( new Admin ()) ->updateRoleAndStatus ($ id , $ role , $ status );
134+ $ updated = $ adminModel ->updateRoleAndStatus ($ id , $ role , $ status );
106135 if ($ updated ) {
136+ $ this ->refreshAuthUserIfCurrent ($ id );
107137 (new InquiryLog ())->create (null , Auth::id (), 'admin_user_updated ' , 'Updated admin # ' . $ id . ' to ' . $ role . '/ ' . $ status );
108138 flash ('success ' , 'Admin user updated successfully. ' );
109139 } else {
110140 flash ('error ' , 'Unable to update admin user. ' );
111141 }
112142 redirect ('admins ' );
113143 }
144+
145+ public function update (): void
146+ {
147+ if (!Auth::can ('tools.view ' ) || !Csrf::verify ($ _POST ['_csrf ' ] ?? null )) {
148+ flash ('error ' , 'Invalid request. ' );
149+ redirect ('admins ' );
150+ }
151+
152+ $ id = (int ) ($ _POST ['id ' ] ?? 0 );
153+ $ nickname = trim ((string ) ($ _POST ['nickname ' ] ?? '' ));
154+ $ email = trim ((string ) ($ _POST ['email ' ] ?? '' ));
155+ $ role = $ this ->sanitizeRole ((string ) ($ _POST ['role ' ] ?? 'agent ' ));
156+ $ status = $ this ->sanitizeStatus ((string ) ($ _POST ['status ' ] ?? 'active ' ));
157+ $ password = (string ) ($ _POST ['password ' ] ?? '' );
158+ $ passwordConfirm = (string ) ($ _POST ['password_confirm ' ] ?? '' );
159+
160+ if ($ id <= 0 ) {
161+ flash ('error ' , 'Invalid admin id. ' );
162+ redirect ('admins ' );
163+ }
164+ if ($ nickname === '' || $ email === '' ) {
165+ flash ('error ' , 'Nickname and email are required. ' );
166+ redirect ('admins/edit?id= ' . $ id );
167+ }
168+ if (!filter_var ($ email , FILTER_VALIDATE_EMAIL )) {
169+ flash ('error ' , 'Please enter a valid email address. ' );
170+ redirect ('admins/edit?id= ' . $ id );
171+ }
172+
173+ $ adminModel = new Admin ();
174+ $ target = $ adminModel ->findById ($ id );
175+ if (!$ target ) {
176+ flash ('error ' , 'Admin user not found. ' );
177+ redirect ('admins ' );
178+ }
179+
180+ $ guardMessage = $ this ->guardAdminChange ($ target , $ role , $ status );
181+ if ($ guardMessage !== null ) {
182+ flash ('error ' , $ guardMessage );
183+ redirect ('admins/edit?id= ' . $ id );
184+ }
185+
186+ $ adminModel ->updateManagedUser ($ id , [
187+ 'nickname ' => $ nickname ,
188+ 'email ' => $ email ,
189+ 'role ' => $ role ,
190+ 'status ' => $ status ,
191+ ]);
192+
193+ if ($ password !== '' || $ passwordConfirm !== '' ) {
194+ if ($ password !== $ passwordConfirm ) {
195+ flash ('error ' , 'The two passwords do not match. ' );
196+ redirect ('admins/edit?id= ' . $ id );
197+ }
198+ if (strlen ($ password ) < 8 ) {
199+ flash ('error ' , 'Password must be at least 8 characters long. ' );
200+ redirect ('admins/edit?id= ' . $ id );
201+ }
202+ $ adminModel ->updatePassword ($ id , password_hash ($ password , PASSWORD_DEFAULT ));
203+ }
204+
205+ $ this ->refreshAuthUserIfCurrent ($ id );
206+ (new InquiryLog ())->create (null , Auth::id (), 'admin_user_profile_updated ' , 'Updated admin profile # ' . $ id );
207+ flash ('success ' , 'Admin user saved successfully. ' );
208+ redirect ('admins/edit?id= ' . $ id );
209+ }
210+
211+ public function toggleStatus (): void
212+ {
213+ if (!Auth::can ('tools.view ' ) || !Csrf::verify ($ _POST ['_csrf ' ] ?? null )) {
214+ flash ('error ' , 'Invalid request. ' );
215+ redirect ('admins ' );
216+ }
217+
218+ $ id = (int ) ($ _POST ['id ' ] ?? 0 );
219+ $ targetStatus = $ this ->sanitizeStatus ((string ) ($ _POST ['target_status ' ] ?? 'disabled ' ));
220+
221+ $ adminModel = new Admin ();
222+ $ target = $ adminModel ->findById ($ id );
223+ if (!$ target ) {
224+ flash ('error ' , 'Admin user not found. ' );
225+ redirect ('admins ' );
226+ }
227+
228+ $ guardMessage = $ this ->guardAdminChange ($ target , (string ) ($ target ['role ' ] ?? 'agent ' ), $ targetStatus );
229+ if ($ guardMessage !== null ) {
230+ flash ('error ' , $ guardMessage );
231+ redirect ('admins ' );
232+ }
233+
234+ $ updated = $ adminModel ->updateStatus ($ id , $ targetStatus );
235+ if ($ updated ) {
236+ $ this ->refreshAuthUserIfCurrent ($ id );
237+ $ action = $ targetStatus === 'disabled ' ? 'admin_user_disabled ' : 'admin_user_enabled ' ;
238+ (new InquiryLog ())->create (null , Auth::id (), $ action , ucfirst ($ targetStatus ) . ' admin # ' . $ id );
239+ flash ('success ' , 'Admin user status updated successfully. ' );
240+ } else {
241+ flash ('error ' , 'Unable to update admin status. ' );
242+ }
243+ redirect ('admins ' );
244+ }
245+
246+ private function sanitizeRole (string $ role ): string
247+ {
248+ return in_array ($ role , ['admin ' , 'manager ' , 'agent ' , 'viewer ' ], true ) ? $ role : 'agent ' ;
249+ }
250+
251+ private function sanitizeStatus (string $ status ): string
252+ {
253+ return in_array ($ status , ['active ' , 'disabled ' ], true ) ? $ status : 'active ' ;
254+ }
255+
256+ private function guardAdminChange (array $ target , string $ newRole , string $ newStatus ): ?string
257+ {
258+ $ id = (int ) ($ target ['id ' ] ?? 0 );
259+ $ currentRole = (string ) ($ target ['role ' ] ?? 'agent ' );
260+ $ currentStatus = (string ) ($ target ['status ' ] ?? 'active ' );
261+ $ adminModel = new Admin ();
262+
263+ if ($ id === (int ) Auth::id () && $ newStatus === 'disabled ' ) {
264+ return 'You cannot disable your own account. ' ;
265+ }
266+
267+ if ($ currentStatus === 'active ' && $ newStatus === 'disabled ' && $ adminModel ->countActiveAdmins (null , $ id ) < 1 ) {
268+ return 'At least one active administrator account must remain. ' ;
269+ }
270+
271+ $ isRemovingLastActiveAdmin = $ currentRole === 'admin ' && $ currentStatus === 'active '
272+ && ($ newRole !== 'admin ' || $ newStatus !== 'active ' )
273+ && $ adminModel ->countActiveAdmins ('admin ' , $ id ) < 1 ;
274+
275+ if ($ isRemovingLastActiveAdmin ) {
276+ return 'At least one active admin role account must remain. ' ;
277+ }
278+
279+ return null ;
280+ }
281+
282+ private function refreshAuthUserIfCurrent (int $ id ): void
283+ {
284+ if ($ id !== (int ) Auth::id ()) {
285+ return ;
286+ }
287+
288+ $ updated = (new Admin ())->findById ($ id );
289+ if (!$ updated ) {
290+ return ;
291+ }
292+
293+ Session::set ('auth_user ' , [
294+ 'id ' => (int ) $ updated ['id ' ],
295+ 'username ' => $ updated ['username ' ],
296+ 'nickname ' => $ updated ['nickname ' ] ?: $ updated ['username ' ],
297+ 'email ' => $ updated ['email ' ],
298+ 'role ' => $ updated ['role ' ] ?? 'admin ' ,
299+ 'status ' => $ updated ['status ' ] ?? 'active ' ,
300+ 'page_size ' => (int ) ($ updated ['page_size ' ] ?? 20 ),
301+ ]);
302+ }
114303}
0 commit comments