UserController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <?php
  2. namespace App\Controllers;
  3. use Psr\Http\Message\ResponseInterface as Response;
  4. use Psr\Http\Message\ServerRequestInterface as Request;
  5. use Slim\Exception\HttpNotFoundException;
  6. use Slim\Exception\HttpUnauthorizedException;
  7. class UserController extends Controller
  8. {
  9. const PER_PAGE = 15;
  10. /**
  11. * @param Response $response
  12. * @param int|null $page
  13. *
  14. * @return Response
  15. * @throws \Twig\Error\RuntimeError
  16. * @throws \Twig\Error\SyntaxError
  17. *
  18. * @throws \Twig\Error\LoaderError
  19. */
  20. public function index(Response $response, int $page = 0): Response
  21. {
  22. $page = max(0, --$page);
  23. $users = $this->database->query('SELECT * FROM `users` LIMIT ? OFFSET ?', [self::PER_PAGE, $page * self::PER_PAGE])->fetchAll();
  24. $pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `users`')->fetch()->count / self::PER_PAGE;
  25. return view()->render($response,
  26. 'user/index.twig',
  27. [
  28. 'users' => $users,
  29. 'next' => $page < floor($pages),
  30. 'previous' => $page >= 1,
  31. 'current_page' => ++$page,
  32. 'quota_enabled' => $this->getSetting('quota_enabled'),
  33. ]
  34. );
  35. }
  36. /**
  37. * @param Response $response
  38. *
  39. * @return Response
  40. * @throws \Twig\Error\RuntimeError
  41. * @throws \Twig\Error\SyntaxError
  42. *
  43. * @throws \Twig\Error\LoaderError
  44. */
  45. public function create(Response $response): Response
  46. {
  47. return view()->render($response, 'user/create.twig', [
  48. 'default_user_quota' => humanFileSize($this->getSetting('default_user_quota'), 0, true),
  49. 'quota_enabled' => $this->getSetting('quota_enabled', 'off'),
  50. ]);
  51. }
  52. /**
  53. * @param Request $request
  54. * @param Response $response
  55. *
  56. * @return Response
  57. */
  58. public function store(Request $request, Response $response): Response
  59. {
  60. if (param($request, 'email') === null && !filter_var(param($request, 'email'), FILTER_VALIDATE_EMAIL)) {
  61. $this->session->alert(lang('email_required'), 'danger');
  62. return redirect($response, route('user.create'));
  63. }
  64. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ?', param($request, 'email'))->fetch()->count > 0) {
  65. $this->session->alert(lang('email_taken'), 'danger');
  66. return redirect($response, route('user.create'));
  67. }
  68. if (param($request, 'username') === null) {
  69. $this->session->alert(lang('username_required'), 'danger');
  70. return redirect($response, route('user.create'));
  71. }
  72. if (param($request, 'password') === null) {
  73. $this->session->alert(lang('password_required'), 'danger');
  74. return redirect($response, route('user.create'));
  75. }
  76. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ?', param($request, 'username'))->fetch()->count > 0) {
  77. $this->session->alert(lang('username_taken'), 'danger');
  78. return redirect($response, route('user.create'));
  79. }
  80. $maxUserQuota = -1;
  81. if ($this->getSetting('quota_enabled') === 'on') {
  82. $maxUserQuotaStr = param($request, 'max_user_quota', humanFileSize($this->getSetting('default_user_quota'), 0, true));
  83. if (!preg_match('/([0-9]+[K|M|G|T])|(\-1)/i', $maxUserQuotaStr)) {
  84. $this->session->alert(lang('invalid_quota', 'danger'));
  85. return redirect($response, route('user.create'));
  86. }
  87. if ($maxUserQuotaStr !== '-1') {
  88. $maxUserQuota = stringToBytes($maxUserQuotaStr);
  89. }
  90. }
  91. do {
  92. $userCode = humanRandomString(5);
  93. } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `user_code` = ?', $userCode)->fetch()->count > 0);
  94. $token = $this->generateUserUploadToken();
  95. $this->database->query('INSERT INTO `users`(`email`, `username`, `password`, `is_admin`, `active`, `user_code`, `token`, `max_disk_quota`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [
  96. param($request, 'email'),
  97. param($request, 'username'),
  98. password_hash(param($request, 'password'), PASSWORD_DEFAULT),
  99. param($request, 'is_admin') !== null ? 1 : 0,
  100. param($request, 'is_active') !== null ? 1 : 0,
  101. $userCode,
  102. $token,
  103. $maxUserQuota,
  104. ]);
  105. $this->session->alert(lang('user_created', [param($request, 'username')]), 'success');
  106. $this->logger->info('User '.$this->session->get('username').' created a new user.', [array_diff_key($request->getParsedBody(), array_flip(['password']))]);
  107. return redirect($response, route('user.index'));
  108. }
  109. /**
  110. * @param Request $request
  111. * @param Response $response
  112. * @param $id
  113. *
  114. * @return Response
  115. * @throws \Twig\Error\LoaderError
  116. * @throws \Twig\Error\RuntimeError
  117. * @throws \Twig\Error\SyntaxError
  118. * @throws HttpUnauthorizedException
  119. *
  120. * @throws HttpNotFoundException
  121. */
  122. public function edit(Request $request, Response $response, int $id): Response
  123. {
  124. $user = $this->getUser($request, $id, false);
  125. return view()->render($response, 'user/edit.twig', [
  126. 'profile' => false,
  127. 'user' => $user,
  128. 'quota_enabled' => $this->getSetting('quota_enabled', 'off'),
  129. 'max_disk_quota' => $user->max_disk_quota > 0 ? humanFileSize($user->max_disk_quota, 0, true) : -1,
  130. ]);
  131. }
  132. /**
  133. * @param Request $request
  134. * @param Response $response
  135. * @param int $id
  136. *
  137. * @return Response
  138. * @throws HttpUnauthorizedException
  139. *
  140. * @throws HttpNotFoundException
  141. */
  142. public function update(Request $request, Response $response, int $id): Response
  143. {
  144. $user = $this->getUser($request, $id, false);
  145. if (param($request, 'email') === null && !filter_var(param($request, 'email'), FILTER_VALIDATE_EMAIL)) {
  146. $this->session->alert(lang('email_required'), 'danger');
  147. return redirect($response, route('user.edit', ['id' => $id]));
  148. }
  149. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [param($request, 'email'), $user->email])->fetch()->count > 0) {
  150. $this->session->alert(lang('email_taken'), 'danger');
  151. return redirect($response, route('user.edit', ['id' => $id]));
  152. }
  153. if (param($request, 'username') === null) {
  154. $this->session->alert(lang('username_required'), 'danger');
  155. return redirect($response, route('user.edit', ['id' => $id]));
  156. }
  157. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ? AND `username` <> ?', [param($request, 'username'), $user->username])->fetch()->count > 0) {
  158. $this->session->alert(lang('username_taken'), 'danger');
  159. return redirect($response, route('user.edit', ['id' => $id]));
  160. }
  161. if ($user->id === $this->session->get('user_id') && param($request, 'is_admin') === null) {
  162. $this->session->alert(lang('cannot_demote'), 'danger');
  163. return redirect($response, route('user.edit', ['id' => $id]));
  164. }
  165. $user->max_disk_quota = -1;
  166. if ($this->getSetting('quota_enabled') === 'on') {
  167. $maxUserQuota = param($request, 'max_user_quota', humanFileSize($this->getSetting('default_user_quota'), 0, true));
  168. if (!preg_match('/([0-9]+[K|M|G|T])|(\-1)/i', $maxUserQuota)) {
  169. $this->session->alert(lang('invalid_quota', 'danger'));
  170. return redirect($response, route('user.create'));
  171. }
  172. if ($maxUserQuota !== '-1') {
  173. $user->max_disk_quota = stringToBytes($maxUserQuota);
  174. }
  175. }
  176. if (param($request, 'password') !== null && !empty(param($request, 'password'))) {
  177. $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `password`=?, `is_admin`=?, `active`=?, `max_disk_quota`=? WHERE `id` = ?', [
  178. param($request, 'email'),
  179. param($request, 'username'),
  180. password_hash(param($request, 'password'), PASSWORD_DEFAULT),
  181. param($request, 'is_admin') !== null ? 1 : 0,
  182. param($request, 'is_active') !== null ? 1 : 0,
  183. $user->max_disk_quota,
  184. $user->id,
  185. ]);
  186. } else {
  187. $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `is_admin`=?, `active`=?, `max_disk_quota`=? WHERE `id` = ?', [
  188. param($request, 'email'),
  189. param($request, 'username'),
  190. param($request, 'is_admin') !== null ? 1 : 0,
  191. param($request, 'is_active') !== null ? 1 : 0,
  192. $user->max_disk_quota,
  193. $user->id,
  194. ]);
  195. }
  196. if ($user->id === $this->session->get('user_id')) {
  197. $this->setSessionQuotaInfo($user->current_disk_quota, $user->max_disk_quota);
  198. }
  199. $this->session->alert(lang('user_updated', [param($request, 'username')]), 'success');
  200. $this->logger->info('User '.$this->session->get('username')." updated $user->id.", [
  201. array_diff_key((array) $user, array_flip(['password'])),
  202. array_diff_key($request->getParsedBody(), array_flip(['password'])),
  203. ]);
  204. return redirect($response, route('user.index'));
  205. }
  206. /**
  207. * @param Request $request
  208. * @param Response $response
  209. * @param int $id
  210. *
  211. * @return Response
  212. * @throws HttpUnauthorizedException
  213. *
  214. * @throws HttpNotFoundException
  215. */
  216. public function delete(Request $request, Response $response, int $id): Response
  217. {
  218. $user = $this->getUser($request, $id, false);
  219. if ($user->id === $this->session->get('user_id')) {
  220. $this->session->alert(lang('cannot_delete'), 'danger');
  221. return redirect($response, route('user.index'));
  222. }
  223. $this->database->query('DELETE FROM `users` WHERE `id` = ?', $user->id);
  224. $this->session->alert(lang('user_deleted'), 'success');
  225. $this->logger->info('User '.$this->session->get('username')." deleted $user->id.");
  226. return redirect($response, route('user.index'));
  227. }
  228. /**
  229. * @param Request $request
  230. * @param Response $response
  231. * @param int $id
  232. *
  233. * @return Response
  234. * @throws HttpUnauthorizedException
  235. *
  236. * @throws HttpNotFoundException
  237. */
  238. public function refreshToken(Request $request, Response $response, int $id): Response
  239. {
  240. $user = $this->getUser($request, $id, true);
  241. $token = $this->generateUserUploadToken();
  242. $this->database->query('UPDATE `users` SET `token`=? WHERE `id` = ?', [
  243. $token,
  244. $user->id,
  245. ]);
  246. $this->logger->info('User '.$this->session->get('username')." refreshed token of user $user->id.");
  247. $response->getBody()->write($token);
  248. return $response;
  249. }
  250. }