| Total Complexity | 104 | 
| Total Lines | 918 | 
| Duplicated Lines | 0 % | 
| Changes | 4 | ||
| Bugs | 1 | Features | 0 | 
Complex classes like UsersController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use UsersController, and based on these observations, apply Extract Interface, too.
| 1 | <?php  | 
            ||
| 37 | class UsersController extends AppController  | 
            ||
| 38 | { | 
            ||
| 39 | public $helpers = [  | 
            ||
| 40 | 'SpectrumColorpicker.SpectrumColorpicker',  | 
            ||
| 41 | 'Posting',  | 
            ||
| 42 | 'Siezi/SimpleCaptcha.SimpleCaptcha',  | 
            ||
| 43 | 'Text'  | 
            ||
| 44 | ];  | 
            ||
| 45 | |||
| 46 | /**  | 
            ||
| 47 |      * {@inheritDoc} | 
            ||
| 48 | */  | 
            ||
| 49 | public function initialize()  | 
            ||
| 50 |     { | 
            ||
| 51 | parent::initialize();  | 
            ||
| 52 |         $this->loadComponent('Referer'); | 
            ||
| 53 | }  | 
            ||
| 54 | |||
| 55 | /**  | 
            ||
| 56 | * Login user.  | 
            ||
| 57 | *  | 
            ||
| 58 | * @return void|Response  | 
            ||
| 59 | */  | 
            ||
| 60 | public function login()  | 
            ||
| 61 |     { | 
            ||
| 62 | $data = $this->request->getData();  | 
            ||
| 63 |         if (empty($data['username'])) { | 
            ||
| 64 | $logout = $this->_logoutAndComeHereAgain();  | 
            ||
| 65 |             if ($logout) { | 
            ||
| 66 | return $logout;  | 
            ||
| 67 | }  | 
            ||
| 68 | |||
| 69 | /// Show form to user.  | 
            ||
| 70 |             if ($this->getRequest()->getQuery('redirect', null)) { | 
            ||
| 71 | $this->Flash->set(  | 
            ||
| 72 |                     __('user.authe.required.exp'), | 
            ||
| 73 |                     ['element' => 'warning', 'params' => ['title' => __('user.authe.required.t')]] | 
            ||
| 74 | );  | 
            ||
| 75 | };  | 
            ||
| 76 | |||
| 77 | return;  | 
            ||
| 78 | }  | 
            ||
| 79 | |||
| 80 |         if ($this->AuthUser->login()) { | 
            ||
| 81 | // Redirect query-param in URL.  | 
            ||
| 82 |             $target = $this->getRequest()->getQuery('redirect'); | 
            ||
| 83 | // AuthenticationService puts the full local path into the redirect  | 
            ||
| 84 | // parameter, so we have to strip the base-path off again.  | 
            ||
| 85 | $target = Router::normalize($target);  | 
            ||
| 86 | // Referer from Request  | 
            ||
| 87 | $target = $target ?: $this->referer(null, true);  | 
            ||
| 88 | |||
| 89 |             if (empty($target)) { | 
            ||
| 90 | $target = '/';  | 
            ||
| 91 | }  | 
            ||
| 92 | |||
| 93 | return $this->redirect($target);  | 
            ||
| 94 | }  | 
            ||
| 95 | |||
| 96 | /// error on login  | 
            ||
| 97 |         $username = $this->request->getData('username'); | 
            ||
| 98 | /** @var User */  | 
            ||
| 99 | $User = $this->Users->find()  | 
            ||
| 100 | ->where(['username' => $username])  | 
            ||
| 101 | ->first();  | 
            ||
| 102 | |||
| 103 |         $message = __('user.authe.e.generic'); | 
            ||
| 104 | |||
| 105 |         if (!empty($User)) { | 
            ||
| 106 |             if (!$User->isActivated()) { | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 107 |                 $message = __('user.actv.ny'); | 
            ||
| 108 |             } elseif ($User->isLocked()) { | 
            ||
| 109 | $ends = $this->Users->UserBlocks  | 
            ||
| 110 | ->getBlockEndsForUser($User->getId());  | 
            ||
| 111 |                 if ($ends) { | 
            ||
| 112 | $time = new Time($ends);  | 
            ||
| 113 | $data = [  | 
            ||
| 114 | 'name' => $username,  | 
            ||
| 115 | 'end' => $time->timeAgoInWords(['accuracy' => 'hour'])  | 
            ||
| 116 | ];  | 
            ||
| 117 |                     $message = __('user.block.pubExpEnds', $data); | 
            ||
| 118 |                 } else { | 
            ||
| 119 |                     $message = __('user.block.pubExp', $username); | 
            ||
| 120 | }  | 
            ||
| 121 | }  | 
            ||
| 122 | }  | 
            ||
| 123 | |||
| 124 | // don't autofill password  | 
            ||
| 125 |         $this->setRequest($this->getRequest()->withData('password', '')); | 
            ||
| 126 | |||
| 127 | $Logger = new ForbiddenLogger;  | 
            ||
| 128 | $Logger->write(  | 
            ||
| 129 | "Unsuccessful login for user: $username",  | 
            ||
| 130 | ['msgs' => [$message]]  | 
            ||
| 131 | );  | 
            ||
| 132 | |||
| 133 | $this->Flash->set($message, [  | 
            ||
| 134 |             'element' => 'error', 'params' => ['title' => __('user.authe.e.t')] | 
            ||
| 135 | ]);  | 
            ||
| 136 | }  | 
            ||
| 137 | |||
| 138 | /**  | 
            ||
| 139 | * Logout user.  | 
            ||
| 140 | *  | 
            ||
| 141 | * @return void|Response  | 
            ||
| 142 | */  | 
            ||
| 143 | public function logout()  | 
            ||
| 144 |     { | 
            ||
| 145 | $request = $this->getRequest();  | 
            ||
| 146 | $cookies = $request->getCookieCollection();  | 
            ||
| 147 |         foreach ($cookies as $cookie) { | 
            ||
| 148 |             $cookie = $cookie->withPath($request->getAttribute('webroot')); | 
            ||
| 149 | $this->setResponse($this->getResponse()->withExpiredCookie($cookie));  | 
            ||
| 150 | }  | 
            ||
| 151 | |||
| 152 | $this->AuthUser->logout();  | 
            ||
| 153 |         $this->redirect('/'); | 
            ||
| 154 | }  | 
            ||
| 155 | |||
| 156 | /**  | 
            ||
| 157 | * Register new user.  | 
            ||
| 158 | *  | 
            ||
| 159 | * @return void|Response  | 
            ||
| 160 | */  | 
            ||
| 161 | public function register()  | 
            ||
| 162 |     { | 
            ||
| 163 |         $this->set('status', 'view'); | 
            ||
| 164 | |||
| 165 | $this->AuthUser->logout();  | 
            ||
| 166 | |||
| 167 |         $tosRequired = Configure::read('Saito.Settings.tos_enabled'); | 
            ||
| 168 |         $this->set(compact('tosRequired')); | 
            ||
| 169 | |||
| 170 | $user = $this->Users->newEntity();  | 
            ||
| 171 |         $this->set('user', $user); | 
            ||
| 172 | |||
| 173 |         if (!$this->request->is('post')) { | 
            ||
| 174 | $logout = $this->_logoutAndComeHereAgain();  | 
            ||
| 175 |             if ($logout) { | 
            ||
| 176 | return $logout;  | 
            ||
| 177 | }  | 
            ||
| 178 | |||
| 179 | return;  | 
            ||
| 180 | }  | 
            ||
| 181 | |||
| 182 | $data = $this->request->getData();  | 
            ||
| 183 | |||
| 184 |         if (!$tosRequired) { | 
            ||
| 185 | $data['tos_confirm'] = true;  | 
            ||
| 186 | }  | 
            ||
| 187 | $tosConfirmed = $data['tos_confirm'];  | 
            ||
| 188 |         if (!$tosConfirmed) { | 
            ||
| 189 | return;  | 
            ||
| 190 | }  | 
            ||
| 191 | |||
| 192 | $validator = new SimpleCaptchaValidator();  | 
            ||
| 193 | $errors = $validator->errors($this->request->getData());  | 
            ||
| 194 | |||
| 195 | $user = $this->Users->register($data);  | 
            ||
| 196 | $user->setErrors($errors);  | 
            ||
| 197 | |||
| 198 | $errors = $user->getErrors();  | 
            ||
| 199 |         if (!empty($errors)) { | 
            ||
| 200 | // registering failed, show form again  | 
            ||
| 201 |             if (isset($errors['password'])) { | 
            ||
| 202 | $user->setErrors($errors);  | 
            ||
| 203 | }  | 
            ||
| 204 |             $user->set('tos_confirm', false); | 
            ||
| 205 |             $this->set('user', $user); | 
            ||
| 206 | |||
| 207 | return;  | 
            ||
| 208 | }  | 
            ||
| 209 | |||
| 210 | // registered successfully  | 
            ||
| 211 |         try { | 
            ||
| 212 |             $forumName = Configure::read('Saito.Settings.forum_name'); | 
            ||
| 213 |             $subject = __('register_email_subject', $forumName); | 
            ||
| 214 | $this->SaitoEmail->email(  | 
            ||
| 215 | [  | 
            ||
| 216 | 'recipient' => $user,  | 
            ||
| 217 | 'subject' => $subject,  | 
            ||
| 218 | 'sender' => 'register',  | 
            ||
| 219 | 'template' => 'user_register',  | 
            ||
| 220 | 'viewVars' => ['user' => $user]  | 
            ||
| 221 | ]  | 
            ||
| 222 | );  | 
            ||
| 223 |         } catch (\Exception $e) { | 
            ||
| 224 | $Logger = new ExceptionLogger();  | 
            ||
| 225 | $Logger->write(  | 
            ||
| 226 | 'Registering email confirmation failed',  | 
            ||
| 227 | ['e' => $e]  | 
            ||
| 228 | );  | 
            ||
| 229 |             $this->set('status', 'fail: email'); | 
            ||
| 230 | |||
| 231 | return;  | 
            ||
| 232 | }  | 
            ||
| 233 | |||
| 234 |         $this->set('status', 'success'); | 
            ||
| 235 | }  | 
            ||
| 236 | |||
| 237 | /**  | 
            ||
| 238 | * register success (user clicked link in confirm mail)  | 
            ||
| 239 | *  | 
            ||
| 240 | * @param string $id user-ID  | 
            ||
| 241 | * @return void  | 
            ||
| 242 | * @throws BadRequestException  | 
            ||
| 243 | */  | 
            ||
| 244 | public function rs($id = null)  | 
            ||
| 245 |     { | 
            ||
| 246 |         if (!$id) { | 
            ||
| 247 | throw new BadRequestException();  | 
            ||
| 248 | }  | 
            ||
| 249 |         $code = $this->request->getQuery('c'); | 
            ||
| 250 |         try { | 
            ||
| 251 | $activated = $this->Users->activate((int)$id, $code);  | 
            ||
| 252 |         } catch (\Exception $e) { | 
            ||
| 253 | $activated = false;  | 
            ||
| 254 | }  | 
            ||
| 255 |         if (!$activated) { | 
            ||
| 256 | $activated = ['status' => 'fail'];  | 
            ||
| 257 | }  | 
            ||
| 258 |         $this->set('status', $activated['status']); | 
            ||
| 259 | }  | 
            ||
| 260 | |||
| 261 | /**  | 
            ||
| 262 | * Show list of all users.  | 
            ||
| 263 | *  | 
            ||
| 264 | * @return void  | 
            ||
| 265 | */  | 
            ||
| 266 | public function index()  | 
            ||
| 267 |     { | 
            ||
| 268 | $menuItems = [  | 
            ||
| 269 |             'username' => [__('username_marking'), []], | 
            ||
| 270 |             'user_type' => [__('user_type'), []], | 
            ||
| 271 | 'UserOnline.logged_in' => [  | 
            ||
| 272 |                 __('userlist_online'), | 
            ||
| 273 | ['direction' => 'desc']  | 
            ||
| 274 | ],  | 
            ||
| 275 |             'registered' => [__('registered'), ['direction' => 'desc']] | 
            ||
| 276 | ];  | 
            ||
| 277 |         $showBlocked = $this->CurrentUser->permission('saito.core.user.lock.view'); | 
            ||
| 278 |         if ($showBlocked) { | 
            ||
| 279 | $menuItems['user_lock'] = [  | 
            ||
| 280 |                 __('user.set.lock.t'), | 
            ||
| 281 | ['direction' => 'desc']  | 
            ||
| 282 | ];  | 
            ||
| 283 | }  | 
            ||
| 284 | |||
| 285 | $this->paginate = $options = [  | 
            ||
| 286 | 'contain' => ['UserOnline'],  | 
            ||
| 287 | 'sortWhitelist' => array_keys($menuItems),  | 
            ||
| 288 | 'finder' => 'paginated',  | 
            ||
| 289 | 'limit' => 400,  | 
            ||
| 290 | 'order' => [  | 
            ||
| 291 | 'UserOnline.logged_in' => 'desc',  | 
            ||
| 292 | ]  | 
            ||
| 293 | ];  | 
            ||
| 294 | $users = $this->paginate($this->Users);  | 
            ||
| 295 | |||
| 296 | $showBottomNavigation = true;  | 
            ||
| 297 | |||
| 298 |         $this->set(compact('menuItems', 'showBottomNavigation', 'users')); | 
            ||
| 299 | }  | 
            ||
| 300 | |||
| 301 | /**  | 
            ||
| 302 | * Ignore user.  | 
            ||
| 303 | *  | 
            ||
| 304 | * @return void  | 
            ||
| 305 | */  | 
            ||
| 306 | public function ignore()  | 
            ||
| 307 |     { | 
            ||
| 308 |         $this->request->allowMethod('POST'); | 
            ||
| 309 |         $blockedId = (int)$this->request->getData('id'); | 
            ||
| 310 | $this->_ignore($blockedId, true);  | 
            ||
| 311 | }  | 
            ||
| 312 | |||
| 313 | /**  | 
            ||
| 314 | * Unignore user.  | 
            ||
| 315 | *  | 
            ||
| 316 | * @return void  | 
            ||
| 317 | */  | 
            ||
| 318 | public function unignore()  | 
            ||
| 319 |     { | 
            ||
| 320 |         $this->request->allowMethod('POST'); | 
            ||
| 321 |         $blockedId = (int)$this->request->getData('id'); | 
            ||
| 322 | $this->_ignore($blockedId, false);  | 
            ||
| 323 | }  | 
            ||
| 324 | |||
| 325 | /**  | 
            ||
| 326 | * Mark user as un-/ignored  | 
            ||
| 327 | *  | 
            ||
| 328 | * @param int $blockedId user to ignore  | 
            ||
| 329 | * @param bool $set block or unblock  | 
            ||
| 330 | * @return \Cake\Network\Response  | 
            ||
| 331 | */  | 
            ||
| 332 | protected function _ignore($blockedId, $set)  | 
            ||
| 345 | }  | 
            ||
| 346 | |||
| 347 | /**  | 
            ||
| 348 | * Show user with profile $name  | 
            ||
| 349 | *  | 
            ||
| 350 | * @param string $name username  | 
            ||
| 351 | * @return void  | 
            ||
| 352 | */  | 
            ||
| 353 | public function name($name = null)  | 
            ||
| 354 |     { | 
            ||
| 355 |         if (!empty($name)) { | 
            ||
| 356 | $viewedUser = $this->Users->find()  | 
            ||
| 357 | ->select(['id'])  | 
            ||
| 358 | ->where(['username' => $name])  | 
            ||
| 359 | ->first();  | 
            ||
| 360 |             if (!empty($viewedUser)) { | 
            ||
| 361 | $this->redirect(  | 
            ||
| 362 | [  | 
            ||
| 363 | 'controller' => 'users',  | 
            ||
| 364 | 'action' => 'view',  | 
            ||
| 365 |                         $viewedUser->get('id') | 
            ||
| 366 | ]  | 
            ||
| 367 | );  | 
            ||
| 368 | |||
| 369 | return;  | 
            ||
| 370 | }  | 
            ||
| 371 | }  | 
            ||
| 372 |         $this->Flash->set(__('Invalid user'), ['element' => 'error']); | 
            ||
| 373 |         $this->redirect('/'); | 
            ||
| 374 | }  | 
            ||
| 375 | |||
| 376 | /**  | 
            ||
| 377 | * View user profile.  | 
            ||
| 378 | *  | 
            ||
| 379 | * @param null $id user-ID  | 
            ||
| 380 | * @return \Cake\Network\Response|void  | 
            ||
| 381 | */  | 
            ||
| 382 | public function view($id = null)  | 
            ||
| 383 |     { | 
            ||
| 384 | // redirect view/<username> to name/<username>  | 
            ||
| 385 |         if (!empty($id) && !is_numeric($id)) { | 
            ||
| 386 | $this->redirect(  | 
            ||
| 387 | ['controller' => 'users', 'action' => 'name', $id]  | 
            ||
| 388 | );  | 
            ||
| 389 | |||
| 390 | return;  | 
            ||
| 391 | }  | 
            ||
| 392 | |||
| 393 | $id = (int)$id;  | 
            ||
| 394 | |||
| 395 | /** @var User */  | 
            ||
| 396 | $user = $this->Users->find()  | 
            ||
| 397 | ->contain(  | 
            ||
| 398 | [  | 
            ||
| 399 |                     'UserBlocks' => function ($q) { | 
            ||
| 400 |                         return $q->find('assocUsers'); | 
            ||
| 401 | },  | 
            ||
| 402 | 'UserOnline'  | 
            ||
| 403 | ]  | 
            ||
| 404 | )  | 
            ||
| 405 | ->where(['Users.id' => (int)$id])  | 
            ||
| 406 | ->first();  | 
            ||
| 407 | |||
| 408 |         if (empty($user)) { | 
            ||
| 409 |             $this->Flash->set(__('Invalid user'), ['element' => 'error']); | 
            ||
| 410 | |||
| 411 |             return $this->redirect('/'); | 
            ||
| 412 | }  | 
            ||
| 413 | |||
| 414 | $entriesShownOnPage = 20;  | 
            ||
| 415 | $this->set(  | 
            ||
| 416 | 'lastEntries',  | 
            ||
| 417 | $this->Users->Entries->getRecentPostings(  | 
            ||
| 418 | $this->CurrentUser,  | 
            ||
| 419 | ['user_id' => $id, 'limit' => $entriesShownOnPage]  | 
            ||
| 420 | )  | 
            ||
| 421 | );  | 
            ||
| 422 | |||
| 423 | $this->set(  | 
            ||
| 424 | 'hasMoreEntriesThanShownOnPage',  | 
            ||
| 425 | ($user->numberOfPostings() - $entriesShownOnPage) > 0  | 
            ||
| 426 | );  | 
            ||
| 427 | |||
| 428 |         if ($this->CurrentUser->getId() === $id) { | 
            ||
| 429 | $ignores = $this->Users->UserIgnores->getAllIgnoredBy($id);  | 
            ||
| 430 |             $user->set('ignores', $ignores); | 
            ||
| 431 | }  | 
            ||
| 432 | |||
| 433 | $blockForm = new BlockForm();  | 
            ||
| 434 | $solved = $this->Users->countSolved($id);  | 
            ||
| 435 |         $this->set(compact('blockForm', 'isEditingAllowed', 'solved', 'user')); | 
            ||
| 436 |         $this->set('titleForLayout', $user->get('username')); | 
            ||
| 437 | }  | 
            ||
| 438 | |||
| 439 | /**  | 
            ||
| 440 | * Set user avatar.  | 
            ||
| 441 | *  | 
            ||
| 442 | * @param string $userId user-ID  | 
            ||
| 443 | * @return void|\Cake\Network\Response  | 
            ||
| 444 | */  | 
            ||
| 445 | public function avatar($userId)  | 
            ||
| 446 |     { | 
            ||
| 447 |         if (!$this->Users->exists($userId)) { | 
            ||
| 448 | throw new BadRequestException;  | 
            ||
| 449 | }  | 
            ||
| 450 | |||
| 451 | /** @var User */  | 
            ||
| 452 | $user = $this->Users->get($userId);  | 
            ||
| 453 | |||
| 454 | $permissionEditing = $this->CurrentUser->permission(  | 
            ||
| 455 | 'saito.core.user.edit',  | 
            ||
| 456 | (new ResourceAI())->onRole($user->getRole())->onOwner($user->getId())  | 
            ||
| 457 | );  | 
            ||
| 458 |         if (!$permissionEditing) { | 
            ||
| 459 | throw new \Saito\Exception\SaitoForbiddenException(  | 
            ||
| 460 | "Attempt to edit user $userId.",  | 
            ||
| 461 | ['CurrentUser' => $this->CurrentUser]  | 
            ||
| 462 | );  | 
            ||
| 463 | }  | 
            ||
| 464 | |||
| 465 |         if ($this->request->is('post') || $this->request->is('put')) { | 
            ||
| 466 | $data = [  | 
            ||
| 467 |                 'avatar' => $this->request->getData('avatar'), | 
            ||
| 468 |                 'avatarDelete' => $this->request->getData('avatarDelete') | 
            ||
| 469 | ];  | 
            ||
| 470 |             if (!empty($data['avatarDelete'])) { | 
            ||
| 471 | $data = [  | 
            ||
| 472 | 'avatar' => null,  | 
            ||
| 473 | 'avatar_dir' => null  | 
            ||
| 474 | ];  | 
            ||
| 475 | }  | 
            ||
| 476 | $patched = $this->Users->patchEntity($user, $data);  | 
            ||
| 477 | $errors = $patched->getErrors();  | 
            ||
| 478 |             if (empty($errors) && $this->Users->save($patched)) { | 
            ||
| 479 | return $this->redirect(['action' => 'edit', $userId]);  | 
            ||
| 480 |             } else { | 
            ||
| 481 | $this->Flash->set(  | 
            ||
| 482 |                     __('The user could not be saved. Please, try again.'), | 
            ||
| 483 | ['element' => 'error']  | 
            ||
| 484 | );  | 
            ||
| 485 | }  | 
            ||
| 486 | }  | 
            ||
| 487 | |||
| 488 |         $this->set('user', $user); | 
            ||
| 489 | |||
| 490 | $this->set(  | 
            ||
| 491 | 'titleForPage',  | 
            ||
| 492 |             __('user.avatar.edit.t', [$user->get('username')]) | 
            ||
| 493 | );  | 
            ||
| 494 | }  | 
            ||
| 495 | |||
| 496 | /**  | 
            ||
| 497 | * Edit user.  | 
            ||
| 498 | *  | 
            ||
| 499 | * @param null $id user-ID  | 
            ||
| 500 | *  | 
            ||
| 501 | * @return \Cake\Network\Response|void  | 
            ||
| 502 | */  | 
            ||
| 503 | public function edit($id = null)  | 
            ||
| 504 |     { | 
            ||
| 505 | /** @var User */  | 
            ||
| 506 | $user = $this->Users->get($id);  | 
            ||
| 507 | |||
| 508 | $permissionEditing = $this->CurrentUser->permission(  | 
            ||
| 509 | 'saito.core.user.edit',  | 
            ||
| 510 | (new ResourceAI())->onRole($user->getRole())->onOwner($user->getId())  | 
            ||
| 511 | );  | 
            ||
| 512 |         if (!$permissionEditing) { | 
            ||
| 513 | throw new \Saito\Exception\SaitoForbiddenException(  | 
            ||
| 514 |                 sprintf('Attempt to edit user "%s".', $user->get('id')), | 
            ||
| 515 | ['CurrentUser' => $this->CurrentUser]  | 
            ||
| 516 | );  | 
            ||
| 517 | }  | 
            ||
| 518 | |||
| 519 |         if ($this->request->is('post') || $this->request->is('put')) { | 
            ||
| 520 | $data = $this->request->getData();  | 
            ||
| 521 | $patched = $this->Users->patchEntity($user, $data);  | 
            ||
| 522 | $errors = $patched->getErrors();  | 
            ||
| 523 |             if (empty($errors) && $this->Users->save($patched)) { | 
            ||
| 524 | return $this->redirect(['action' => 'view', $id]);  | 
            ||
| 525 | }  | 
            ||
| 526 | |||
| 527 | $this->Flash->set(  | 
            ||
| 528 |                 __('The user could not be saved. Please, try again.'), | 
            ||
| 529 | ['element' => 'error']  | 
            ||
| 530 | );  | 
            ||
| 531 | }  | 
            ||
| 532 |         $this->set('user', $user); | 
            ||
| 533 | |||
| 534 | $this->set(  | 
            ||
| 535 | 'titleForPage',  | 
            ||
| 536 |             __('user.edit.t', [$user->get('username')]) | 
            ||
| 537 | );  | 
            ||
| 538 | |||
| 539 | $availableThemes = $this->Themes->getAvailable($this->CurrentUser);  | 
            ||
| 540 | $availableThemes = array_combine($availableThemes, $availableThemes);  | 
            ||
| 541 | $currentTheme = $this->Themes->getThemeForUser($this->CurrentUser);  | 
            ||
| 542 |         $this->set(compact('availableThemes', 'currentTheme')); | 
            ||
| 543 | }  | 
            ||
| 544 | |||
| 545 | /**  | 
            ||
| 546 | * delete user  | 
            ||
| 547 | *  | 
            ||
| 548 | * @param string $id user-ID  | 
            ||
| 549 | * @return \Cake\Network\Response|void  | 
            ||
| 550 | */  | 
            ||
| 551 | public function delete($id)  | 
            ||
| 552 |     { | 
            ||
| 553 | $id = (int)$id;  | 
            ||
| 554 | /** @var User */  | 
            ||
| 555 | $readUser = $this->Users->get($id);  | 
            ||
| 556 | |||
| 557 | /// Check permission  | 
            ||
| 558 | $permission = $this->CurrentUser->permission(  | 
            ||
| 559 | 'saito.core.user.delete',  | 
            ||
| 560 | (new ResourceAI())->onRole($readUser->getRole())  | 
            ||
| 561 | );  | 
            ||
| 562 |         if (!$permission) { | 
            ||
| 563 | throw new ForbiddenException(  | 
            ||
| 564 | sprintf(  | 
            ||
| 565 | 'User "%s" is not allowed to delete user "%s".',  | 
            ||
| 566 |                     $this->CurrentUser->get('username'), | 
            ||
| 567 |                     $readUser->get('username') | 
            ||
| 568 | ),  | 
            ||
| 569 | 1571811593  | 
            ||
| 570 | );  | 
            ||
| 571 | }  | 
            ||
| 572 | |||
| 573 |         $this->set('user', $readUser); | 
            ||
| 574 | |||
| 575 | $failure = false;  | 
            ||
| 576 |         if (!$this->request->getData('userdeleteconfirm')) { | 
            ||
| 577 | $failure = true;  | 
            ||
| 578 |             $this->Flash->set(__('user.del.fail.3'), ['element' => 'error']); | 
            ||
| 579 |         } elseif ($this->CurrentUser->isUser($readUser)) { | 
            ||
| 580 | $failure = true;  | 
            ||
| 581 |             $this->Flash->set(__('user.del.fail.1'), ['element' => 'error']); | 
            ||
| 582 | }  | 
            ||
| 583 | |||
| 584 |         if (!$failure) { | 
            ||
| 585 | $result = $this->Users->deleteAllExceptEntries($id);  | 
            ||
| 586 |             if (empty($result)) { | 
            ||
| 587 | $failure = true;  | 
            ||
| 588 |                 $this->Flash->set(__('user.del.fail.2'), ['element' => 'error']); | 
            ||
| 589 | }  | 
            ||
| 590 | }  | 
            ||
| 591 | |||
| 592 |         if ($failure) { | 
            ||
| 593 | return $this->redirect(  | 
            ||
| 594 | [  | 
            ||
| 595 | 'prefix' => false,  | 
            ||
| 596 | 'controller' => 'users',  | 
            ||
| 597 | 'action' => 'view',  | 
            ||
| 598 | $id  | 
            ||
| 599 | ]  | 
            ||
| 600 | );  | 
            ||
| 601 | }  | 
            ||
| 602 | |||
| 603 | $this->Flash->set(  | 
            ||
| 604 |             __('user.del.ok.m', $readUser->get('username')), | 
            ||
| 605 | ['element' => 'success']  | 
            ||
| 606 | );  | 
            ||
| 607 | |||
| 608 |         return $this->redirect('/'); | 
            ||
| 609 | }  | 
            ||
| 610 | |||
| 611 | /**  | 
            ||
| 612 | * Lock user.  | 
            ||
| 613 | *  | 
            ||
| 614 | * @return \Cake\Network\Response|void  | 
            ||
| 615 | * @throws BadRequestException  | 
            ||
| 616 | */  | 
            ||
| 617 | public function lock()  | 
            ||
| 618 |     { | 
            ||
| 619 | $form = new BlockForm();  | 
            ||
| 620 |         if (!$form->validate($this->request->getData())) { | 
            ||
| 621 | throw new BadRequestException;  | 
            ||
| 622 | }  | 
            ||
| 623 | |||
| 624 |         $id = (int)$this->request->getData('lockUserId'); | 
            ||
| 625 | |||
| 626 | /** @var User */  | 
            ||
| 627 | $readUser = $this->Users->get($id);  | 
            ||
| 628 | |||
| 629 | $permission = $this->CurrentUser->permission(  | 
            ||
| 630 | 'saito.core.user.lock.set',  | 
            ||
| 631 | (new ResourceAI())->onRole($readUser->getRole())  | 
            ||
| 632 | );  | 
            ||
| 633 |         if (!$permission) { | 
            ||
| 634 | throw new ForbiddenException(null, 1571316877);  | 
            ||
| 635 | }  | 
            ||
| 636 | |||
| 637 |         if ($this->CurrentUser->isUser($readUser)) { | 
            ||
| 638 |             $message = __('You can\'t lock yourself.'); | 
            ||
| 639 | $this->Flash->set($message, ['element' => 'error']);  | 
            ||
| 640 |         } else { | 
            ||
| 641 |             try { | 
            ||
| 642 |                 $duration = (int)$this->request->getData('lockPeriod'); | 
            ||
| 643 | $blocker = new ManualBlocker($this->CurrentUser->getId(), $duration);  | 
            ||
| 644 | $status = $this->Users->UserBlocks->block($blocker, $id);  | 
            ||
| 645 |                 if (!$status) { | 
            ||
| 646 | throw new \Exception();  | 
            ||
| 647 | }  | 
            ||
| 648 |                 $message = __('User {0} is locked.', $readUser->get('username')); | 
            ||
| 649 | $this->Flash->set($message, ['element' => 'success']);  | 
            ||
| 650 |             } catch (\Exception $e) { | 
            ||
| 651 |                 $message = __('Error while locking.'); | 
            ||
| 652 | $this->Flash->set($message, ['element' => 'error']);  | 
            ||
| 653 | }  | 
            ||
| 654 | }  | 
            ||
| 655 | |||
| 656 | return $this->redirect($this->referer());  | 
            ||
| 657 | }  | 
            ||
| 658 | |||
| 659 | /**  | 
            ||
| 660 | * Unblock user.  | 
            ||
| 661 | *  | 
            ||
| 662 | * @param string $id user-ID  | 
            ||
| 663 | * @return void  | 
            ||
| 664 | */  | 
            ||
| 665 | public function unlock(string $id)  | 
            ||
| 666 |     { | 
            ||
| 667 | $id = (int)$id;  | 
            ||
| 668 | |||
| 669 | /** @var User */  | 
            ||
| 670 | $user = $this->Users  | 
            ||
| 671 | ->find()  | 
            ||
| 672 |             ->matching('UserBlocks', function ($q) use ($id) { | 
            ||
| 673 | return $q->where(['UserBlocks.id' => $id]);  | 
            ||
| 674 | })  | 
            ||
| 675 | ->first();  | 
            ||
| 676 | |||
| 677 | $permission = $this->CurrentUser->permission(  | 
            ||
| 678 | 'saito.core.user.lock.set',  | 
            ||
| 679 | (new ResourceAI())->onRole($user->getRole())  | 
            ||
| 680 | );  | 
            ||
| 681 |         if (!$permission) { | 
            ||
| 682 | throw new ForbiddenException(null, 1571316877);  | 
            ||
| 683 | }  | 
            ||
| 684 | |||
| 685 |         if (!$this->Users->UserBlocks->unblock($id)) { | 
            ||
| 686 | $this->Flash->set(  | 
            ||
| 687 |                 __('Error while unlocking.'), | 
            ||
| 688 | ['element' => 'error']  | 
            ||
| 689 | );  | 
            ||
| 690 | }  | 
            ||
| 691 | |||
| 692 |         $message = __('User {0} is unlocked.', $user->get('username')); | 
            ||
| 693 | $this->Flash->set($message, ['element' => 'success']);  | 
            ||
| 694 | $this->redirect($this->referer());  | 
            ||
| 695 | }  | 
            ||
| 696 | |||
| 697 | /**  | 
            ||
| 698 | * changes user password  | 
            ||
| 699 | *  | 
            ||
| 700 | * @param null $id user-ID  | 
            ||
| 701 | * @return void  | 
            ||
| 702 | * @throws \Saito\Exception\SaitoForbiddenException  | 
            ||
| 703 | * @throws BadRequestException  | 
            ||
| 704 | */  | 
            ||
| 705 | public function changepassword($id = null)  | 
            ||
| 706 |     { | 
            ||
| 707 |         if (empty($id)) { | 
            ||
| 708 | throw new BadRequestException();  | 
            ||
| 709 | }  | 
            ||
| 710 | |||
| 711 | /** @var User */  | 
            ||
| 712 | $user = $this->Users->get($id);  | 
            ||
| 713 | $allowed = $this->CurrentUser->isUser($user);  | 
            ||
| 714 |         if (empty($user) || !$allowed) { | 
            ||
| 715 | throw new SaitoForbiddenException(  | 
            ||
| 716 | "Attempt to change password for user $id.",  | 
            ||
| 717 | ['CurrentUser' => $this->CurrentUser]  | 
            ||
| 718 | );  | 
            ||
| 719 | }  | 
            ||
| 720 |         $this->set('userId', $id); | 
            ||
| 721 |         $this->set('username', $user->get('username')); | 
            ||
| 722 | |||
| 723 | //= just show empty form  | 
            ||
| 724 |         if (empty($this->request->getData())) { | 
            ||
| 725 | return;  | 
            ||
| 726 | }  | 
            ||
| 727 | |||
| 728 | $formFields = ['password', 'password_old', 'password_confirm'];  | 
            ||
| 729 | |||
| 730 | //= process submitted form  | 
            ||
| 731 | $data = [];  | 
            ||
| 732 |         foreach ($formFields as $field) { | 
            ||
| 733 | $data[$field] = $this->request->getData($field);  | 
            ||
| 734 | }  | 
            ||
| 735 | $this->Users->patchEntity($user, $data);  | 
            ||
| 736 | $success = $this->Users->save($user);  | 
            ||
| 737 | |||
| 738 |         if ($success) { | 
            ||
| 739 | $this->Flash->set(  | 
            ||
| 740 |                 __('change_password_success'), | 
            ||
| 741 | ['element' => 'success']  | 
            ||
| 742 | );  | 
            ||
| 743 | $this->redirect(['controller' => 'users', 'action' => 'edit', $id]);  | 
            ||
| 744 | |||
| 745 | return;  | 
            ||
| 746 | }  | 
            ||
| 747 | |||
| 748 | $errors = $user->getErrors();  | 
            ||
| 749 |         if (!empty($errors)) { | 
            ||
| 750 | $this->Flash->set(  | 
            ||
| 751 |                 __d('nondynamic', current(array_pop($errors))), | 
            ||
| 752 | ['element' => 'error']  | 
            ||
| 753 | );  | 
            ||
| 754 | }  | 
            ||
| 755 | |||
| 756 | //= unset all autofill form data  | 
            ||
| 757 |         foreach ($formFields as $field) { | 
            ||
| 758 | $this->request = $this->request->withoutData($field);  | 
            ||
| 759 | }  | 
            ||
| 760 | }  | 
            ||
| 761 | |||
| 762 | /**  | 
            ||
| 763 | * Directly set password for user  | 
            ||
| 764 | *  | 
            ||
| 765 | * @param string $id user-ID  | 
            ||
| 766 | * @return Response|null  | 
            ||
| 767 | */  | 
            ||
| 768 | public function setpassword($id)  | 
            ||
| 769 |     { | 
            ||
| 770 | /** @var User */  | 
            ||
| 771 | $user = $this->Users->get($id);  | 
            ||
| 772 | |||
| 773 |         if (!$this->CurrentUser->permission('saito.core.user.password.set', (new ResourceAI())->onRole($user->getRole()))) { | 
            ||
| 774 | throw new SaitoForbiddenException(  | 
            ||
| 775 | "Attempt to set password for user $id.",  | 
            ||
| 776 | ['CurrentUser' => $this->CurrentUser]  | 
            ||
| 777 | );  | 
            ||
| 778 | }  | 
            ||
| 779 | |||
| 780 |         if ($this->getRequest()->is('post')) { | 
            ||
| 781 | $this->Users->patchEntity($user, $this->getRequest()->getData(), ['fields' => 'password']);  | 
            ||
| 782 | |||
| 783 |             if ($this->Users->save($user)) { | 
            ||
| 784 | $this->Flash->set(  | 
            ||
| 785 |                     __('user.pw.set.s'), | 
            ||
| 786 | ['element' => 'success']  | 
            ||
| 787 | );  | 
            ||
| 788 | |||
| 789 | return $this->redirect(['controller' => 'users', 'action' => 'edit', $id]);  | 
            ||
| 790 | }  | 
            ||
| 791 | $errors = $user->getErrors();  | 
            ||
| 792 |             if (!empty($errors)) { | 
            ||
| 793 | $this->Flash->set(  | 
            ||
| 794 |                     __d('nondynamic', current(array_pop($errors))), | 
            ||
| 795 | ['element' => 'error']  | 
            ||
| 796 | );  | 
            ||
| 797 | }  | 
            ||
| 798 | }  | 
            ||
| 799 | |||
| 800 |         $this->set(compact('user')); | 
            ||
| 801 | }  | 
            ||
| 802 | |||
| 803 | /**  | 
            ||
| 804 | * View and set user role  | 
            ||
| 805 | *  | 
            ||
| 806 | * @param string $id User-ID  | 
            ||
| 807 | * @return void|Response  | 
            ||
| 808 | */  | 
            ||
| 809 | public function role($id)  | 
            ||
| 810 |     { | 
            ||
| 811 | /** @var User */  | 
            ||
| 812 | $user = $this->Users->get($id);  | 
            ||
| 813 | $identifier = (new ResourceAI())->onRole($user->getRole());  | 
            ||
| 814 |         $unrestricted = $this->CurrentUser->permission('saito.core.user.role.set.unrestricted', $identifier); | 
            ||
| 815 |         $restricted = $this->CurrentUser->permission('saito.core.user.role.set.restricted', $identifier); | 
            ||
| 816 |         if (!$restricted && !$unrestricted) { | 
            ||
| 817 | throw new ForbiddenException();  | 
            ||
| 818 | }  | 
            ||
| 819 | |||
| 820 | /** @var Permissions */  | 
            ||
| 821 |         $Permissions = Registry::get('Permissions'); | 
            ||
| 822 | |||
| 823 | $roles = $Permissions->getRoles()->get($this->CurrentUser->getRole(), false, $unrestricted);  | 
            ||
| 824 | |||
| 825 |         if ($this->getRequest()->is('put')) { | 
            ||
| 826 |             $type = $this->getRequest()->getData('user_type'); | 
            ||
| 827 |             if (!in_array($type, $roles)) { | 
            ||
| 828 | throw new \InvalidArgumentException(  | 
            ||
| 829 |                     sprintf('User type "%s" is not available.', $type), | 
            ||
| 830 | 1573376871  | 
            ||
| 831 | );  | 
            ||
| 832 | }  | 
            ||
| 833 | $patched = $this->Users->patchEntity($user, ['user_type' => $type]);  | 
            ||
| 834 | |||
| 835 | $errors = $patched->getErrors();  | 
            ||
| 836 |             if (empty($errors)) { | 
            ||
| 837 | $this->Users->save($patched);  | 
            ||
| 838 | |||
| 839 |                 return $this->redirect(['action' => 'edit', $user->get('id')]); | 
            ||
| 840 | }  | 
            ||
| 841 | |||
| 842 | $msg = current(current($errors));  | 
            ||
| 843 | $this->Flash->set($msg, ['element' => 'error']);  | 
            ||
| 844 | }  | 
            ||
| 845 | |||
| 846 |         $this->set(compact('roles', 'user')); | 
            ||
| 847 | }  | 
            ||
| 848 | |||
| 849 | /**  | 
            ||
| 850 | * Set slidetab-order.  | 
            ||
| 851 | *  | 
            ||
| 852 | * @return \Cake\Network\Response  | 
            ||
| 853 | * @throws BadRequestException  | 
            ||
| 854 | */  | 
            ||
| 855 | public function slidetabOrder()  | 
            ||
| 856 |     { | 
            ||
| 857 |         if (!$this->request->is('ajax')) { | 
            ||
| 858 | throw new BadRequestException;  | 
            ||
| 859 | }  | 
            ||
| 860 | |||
| 861 |         $order = $this->request->getData('slidetabOrder'); | 
            ||
| 862 |         if (!$order) { | 
            ||
| 863 | throw new BadRequestException;  | 
            ||
| 864 | }  | 
            ||
| 865 | |||
| 866 | $allowed = $this->Slidetabs->getAvailable();  | 
            ||
| 867 | $order = array_filter(  | 
            ||
| 868 | $order,  | 
            ||
| 869 |             function ($item) use ($allowed) { | 
            ||
| 870 | return in_array($item, $allowed);  | 
            ||
| 871 | }  | 
            ||
| 872 | );  | 
            ||
| 873 | $order = serialize($order);  | 
            ||
| 874 | |||
| 875 | $userId = $this->CurrentUser->getId();  | 
            ||
| 876 | $user = $this->Users->get($userId);  | 
            ||
| 877 | $this->Users->patchEntity($user, ['slidetab_order' => $order]);  | 
            ||
| 878 | $this->Users->save($user);  | 
            ||
| 879 | |||
| 880 |         $this->CurrentUser->set('slidetab_order', $order); | 
            ||
| 881 | |||
| 882 | $this->response = $this->response->withStringBody(true);  | 
            ||
| 883 | |||
| 884 | return $this->response;  | 
            ||
| 885 | }  | 
            ||
| 886 | |||
| 887 | /**  | 
            ||
| 888 | * Shows user's uploads  | 
            ||
| 889 | *  | 
            ||
| 890 | * @return void  | 
            ||
| 891 | */  | 
            ||
| 892 | public function uploads()  | 
            ||
| 894 | }  | 
            ||
| 895 | |||
| 896 | /**  | 
            ||
| 897 | * Set category for user.  | 
            ||
| 898 | *  | 
            ||
| 899 | * @param string|null $id category-ID  | 
            ||
| 900 | * @return \Cake\Network\Response  | 
            ||
| 901 | */  | 
            ||
| 902 | public function setcategory(?string $id = null)  | 
            ||
| 915 | }  | 
            ||
| 916 | |||
| 917 | /**  | 
            ||
| 918 |      * {@inheritdoc} | 
            ||
| 919 | */  | 
            ||
| 920 | public function beforeFilter(Event $event)  | 
            ||
| 940 | }  | 
            ||
| 941 | |||
| 942 | /**  | 
            ||
| 943 | * Logout user if logged in and create response to revisit logged out  | 
            ||
| 944 | *  | 
            ||
| 945 | * @return Response|null  | 
            ||
| 946 | */  | 
            ||
| 947 | protected function _logoutAndComeHereAgain(): ?Response  | 
            ||
| 955 | }  | 
            ||
| 956 | }  | 
            ||
| 957 |