UserController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <?php
  2. namespace App\Controllers;
  3. use App\Exceptions\UnauthorizedException;
  4. use App\Web\Session;
  5. use Slim\Exception\NotFoundException;
  6. use Slim\Http\Request;
  7. use Slim\Http\Response;
  8. class UserController extends Controller
  9. {
  10. const PER_PAGE = 15;
  11. /**
  12. * @param Request $request
  13. * @param Response $response
  14. * @param $args
  15. * @return Response
  16. */
  17. public function index(Request $request, Response $response, $args): Response
  18. {
  19. $page = isset($args['page']) ? (int)$args['page'] : 0;
  20. $page = max(0, --$page);
  21. $users = $this->database->query('SELECT * FROM `users` LIMIT ? OFFSET ?', [self::PER_PAGE, $page * self::PER_PAGE])->fetchAll();
  22. $pages = $this->database->query('SELECT COUNT(*) AS `count` FROM `users`')->fetch()->count / self::PER_PAGE;
  23. return $this->view->render($response,
  24. 'user/index.twig',
  25. [
  26. 'users' => $users,
  27. 'next' => $page < floor($pages),
  28. 'previous' => $page >= 1,
  29. 'current_page' => ++$page,
  30. ]
  31. );
  32. }
  33. /**
  34. * @param Request $request
  35. * @param Response $response
  36. * @return Response
  37. */
  38. public function create(Request $request, Response $response): Response
  39. {
  40. return $this->view->render($response, 'user/create.twig');
  41. }
  42. /**
  43. * @param Request $request
  44. * @param Response $response
  45. * @return Response
  46. */
  47. public function store(Request $request, Response $response): Response
  48. {
  49. if ($request->getParam('email') === null) {
  50. Session::alert('The email is required.', 'danger');
  51. return $this->redirectTo($response,'/user/create');
  52. }
  53. if ($request->getParam('username') === null) {
  54. Session::alert('The username is required.', 'danger');
  55. return $this->redirectTo($response,'/user/create');
  56. }
  57. if ($request->getParam('password') === null) {
  58. Session::alert('The password is required.', 'danger');
  59. return $this->redirectTo($response,'/user/create');
  60. }
  61. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ?', $request->getParam('username'))->fetch()->count > 0) {
  62. Session::alert('The username already taken.', 'danger');
  63. return $this->redirectTo($response,'/user/create');
  64. }
  65. do {
  66. $userCode = substr(md5(microtime()), rand(0, 26), 5);
  67. } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `user_code` = ?', $userCode)->fetch()->count > 0);
  68. $token = $this->generateNewToken();
  69. $this->database->query('INSERT INTO `users`(`email`, `username`, `password`, `is_admin`, `active`, `user_code`, `token`) VALUES (?, ?, ?, ?, ?, ?, ?)', [
  70. $request->getParam('email'),
  71. $request->getParam('username'),
  72. password_hash($request->getParam('password'), PASSWORD_DEFAULT),
  73. $request->getParam('is_admin') !== null,
  74. $request->getParam('is_active') !== null,
  75. $userCode,
  76. $token
  77. ]);
  78. Session::alert("User '{$request->getParam('username')}' created!", 'success');
  79. $this->logger->info('User ' . Session::get('username') . ' created a new user.', [array_diff($request->getParams(), ['password'])]);
  80. return $this->redirectTo($response,'/users');
  81. }
  82. /**
  83. * @param Request $request
  84. * @param Response $response
  85. * @param $args
  86. * @return Response
  87. * @throws NotFoundException
  88. */
  89. public function edit(Request $request, Response $response, $args): Response
  90. {
  91. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  92. if (!$user) {
  93. throw new NotFoundException($request, $response);
  94. }
  95. return $this->view->render($response, 'user/edit.twig', [
  96. 'profile' => false,
  97. 'user' => $user
  98. ]);
  99. }
  100. /**
  101. * @param Request $request
  102. * @param Response $response
  103. * @param $args
  104. * @return Response
  105. * @throws NotFoundException
  106. */
  107. public function update(Request $request, Response $response, $args): Response
  108. {
  109. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  110. if (!$user) {
  111. throw new NotFoundException($request, $response);
  112. }
  113. if ($request->getParam('email') === null) {
  114. Session::alert('The email is required.', 'danger');
  115. return $this->redirectTo($response,'/user/' . $args['id'] . '/edit');
  116. }
  117. if ($request->getParam('username') === null) {
  118. Session::alert('The username is required.', 'danger');
  119. return $this->redirectTo($response,'/user/' . $args['id'] . '/edit');
  120. }
  121. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ? AND `username` <> ?', [$request->getParam('username'), $user->username])->fetch()->count > 0) {
  122. Session::alert('The username already taken.', 'danger');
  123. return $this->redirectTo($response,'/user/' . $args['id'] . '/edit');
  124. }
  125. if ($user->id === Session::get('user_id') && $request->getParam('is_admin') === null) {
  126. Session::alert('You cannot demote yourself.', 'danger');
  127. return $this->redirectTo($response,'/user/' . $args['id'] . '/edit');
  128. }
  129. if ($request->getParam('password') !== null && !empty($request->getParam('password'))) {
  130. $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `password`=?, `is_admin`=?, `active`=? WHERE `id` = ?', [
  131. $request->getParam('email'),
  132. $request->getParam('username'),
  133. password_hash($request->getParam('password'), PASSWORD_DEFAULT),
  134. $request->getParam('is_admin') !== null,
  135. $request->getParam('is_active') !== null,
  136. $user->id
  137. ]);
  138. } else {
  139. $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `is_admin`=?, `active`=? WHERE `id` = ?', [
  140. $request->getParam('email'),
  141. $request->getParam('username'),
  142. $request->getParam('is_admin') !== null,
  143. $request->getParam('is_active') !== null,
  144. $user->id
  145. ]);
  146. }
  147. Session::alert("User '{$request->getParam('username')}' updated!", 'success');
  148. $this->logger->info('User ' . Session::get('username') . " updated $user->id.", [$user, array_diff($request->getParams(), ['password'])]);
  149. return $this->redirectTo($response,'/users');
  150. }
  151. /**
  152. * @param Request $request
  153. * @param Response $response
  154. * @param $args
  155. * @return Response
  156. * @throws NotFoundException
  157. */
  158. public function delete(Request $request, Response $response, $args): Response
  159. {
  160. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  161. if (!$user) {
  162. throw new NotFoundException($request, $response);
  163. }
  164. if ($user->id === Session::get('user_id')) {
  165. Session::alert('You cannot delete yourself.', 'danger');
  166. return $this->redirectTo($response,'/users');
  167. }
  168. $this->database->query('DELETE FROM `users` WHERE `id` = ?', $user->id);
  169. Session::alert('User deleted.', 'success');
  170. $this->logger->info('User ' . Session::get('username') . " deleted $user->id.");
  171. return $this->redirectTo($response,'/users');
  172. }
  173. /**
  174. * @param Request $request
  175. * @param Response $response
  176. * @return Response
  177. * @throws NotFoundException
  178. * @throws UnauthorizedException
  179. */
  180. public function profile(Request $request, Response $response): Response
  181. {
  182. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', Session::get('user_id'))->fetch();
  183. if (!$user) {
  184. throw new NotFoundException($request, $response);
  185. }
  186. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  187. throw new UnauthorizedException();
  188. }
  189. return $this->view->render($response, 'user/edit.twig', [
  190. 'profile' => true,
  191. 'user' => $user
  192. ]);
  193. }
  194. /**
  195. * @param Request $request
  196. * @param Response $response
  197. * @param $args
  198. * @return Response
  199. * @throws NotFoundException
  200. * @throws UnauthorizedException
  201. */
  202. public function profileEdit(Request $request, Response $response, $args): Response
  203. {
  204. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  205. if (!$user) {
  206. throw new NotFoundException($request, $response);
  207. }
  208. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  209. throw new UnauthorizedException();
  210. }
  211. if ($request->getParam('email') === null) {
  212. Session::alert('The email is required.', 'danger');
  213. return $this->redirectTo($response,'/profile');
  214. }
  215. if ($request->getParam('password') !== null && !empty($request->getParam('password'))) {
  216. $this->database->query('UPDATE `users` SET `email`=?, `password`=? WHERE `id` = ?', [
  217. $request->getParam('email'),
  218. password_hash($request->getParam('password'), PASSWORD_DEFAULT),
  219. $user->id
  220. ]);
  221. } else {
  222. $this->database->query('UPDATE `users` SET `email`=? WHERE `id` = ?', [
  223. $request->getParam('email'),
  224. $user->id
  225. ]);
  226. }
  227. Session::alert('Profile updated successfully!', 'success');
  228. $this->logger->info('User ' . Session::get('username') . " updated profile of $user->id.");
  229. return $this->redirectTo($response,'/profile');
  230. }
  231. /**
  232. * @param Request $request
  233. * @param Response $response
  234. * @param $args
  235. * @return Response
  236. * @throws NotFoundException
  237. * @throws UnauthorizedException
  238. */
  239. public function refreshToken(Request $request, Response $response, $args): Response
  240. {
  241. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  242. if (!$user) {
  243. throw new NotFoundException($request, $response);
  244. }
  245. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  246. throw new UnauthorizedException();
  247. }
  248. $token = $this->generateNewToken();
  249. $this->database->query('UPDATE `users` SET `token`=? WHERE `id` = ?', [
  250. $token,
  251. $user->id
  252. ]);
  253. $this->logger->info('User ' . Session::get('username') . " refreshed token of user $user->id.");
  254. $response->getBody()->write($token);
  255. return $response;
  256. }
  257. /**
  258. * @param Request $request
  259. * @param Response $response
  260. * @param $args
  261. * @return Response
  262. * @throws NotFoundException
  263. * @throws UnauthorizedException
  264. */
  265. public function getShareXconfigFile(Request $request, Response $response, $args): Response
  266. {
  267. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  268. if (!$user) {
  269. throw new NotFoundException($request, $response);
  270. }
  271. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  272. throw new UnauthorizedException();
  273. }
  274. $base_url = $this->settings['base_url'];
  275. $json = [
  276. 'DestinationType' => 'ImageUploader, TextUploader, FileUploader',
  277. 'RequestURL' => "$base_url/upload",
  278. 'FileFormName' => 'upload',
  279. 'Arguments' => [
  280. 'file' => '$filename$',
  281. 'text' => '$input$',
  282. 'token' => $user->token,
  283. ],
  284. 'URL' => '$json:url$',
  285. 'ThumbnailURL' => '$json:url$/raw',
  286. ];
  287. return $response
  288. ->withHeader('Content-Disposition', 'attachment;filename="' . $user->username . '-ShareX.sxcu"')
  289. ->withJson($json, 200, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
  290. }
  291. /**
  292. * @return string
  293. */
  294. protected function generateNewToken(): string
  295. {
  296. do {
  297. $token = 'token_' . md5(uniqid('', true));
  298. } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `token` = ?', $token)->fetch()->count > 0);
  299. return $token;
  300. }
  301. }