UserController.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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(lang('email_required'), 'danger');
  51. return redirect($response, 'user.create');
  52. }
  53. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ?', $request->getParam('email'))->fetch()->count > 0) {
  54. Session::alert(lang('email_taken'), 'danger');
  55. return redirect($response, 'user.create');
  56. }
  57. if ($request->getParam('username') === null) {
  58. Session::alert(lang('username_required'), 'danger');
  59. return redirect($response, 'user.create');
  60. }
  61. if ($request->getParam('password') === null) {
  62. Session::alert(lang('password_required'), 'danger');
  63. return redirect($response, 'user.create');
  64. }
  65. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ?', $request->getParam('username'))->fetch()->count > 0) {
  66. Session::alert(lang('username_taken'), 'danger');
  67. return redirect($response, 'user.create');
  68. }
  69. do {
  70. $userCode = substr(md5(microtime()), rand(0, 26), 5);
  71. } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `user_code` = ?', $userCode)->fetch()->count > 0);
  72. $token = $this->generateNewToken();
  73. $this->database->query('INSERT INTO `users`(`email`, `username`, `password`, `is_admin`, `active`, `user_code`, `token`) VALUES (?, ?, ?, ?, ?, ?, ?)', [
  74. $request->getParam('email'),
  75. $request->getParam('username'),
  76. password_hash($request->getParam('password'), PASSWORD_DEFAULT),
  77. $request->getParam('is_admin') !== null ? 1 : 0,
  78. $request->getParam('is_active') !== null ? 1 : 0,
  79. $userCode,
  80. $token,
  81. ]);
  82. Session::alert(lang('user_created', [$request->getParam('username')]), 'success');
  83. $this->logger->info('User ' . Session::get('username') . ' created a new user.', [array_diff($request->getParams(), ['password'])]);
  84. return redirect($response, 'user.index');
  85. }
  86. /**
  87. * @param Request $request
  88. * @param Response $response
  89. * @param $args
  90. * @return Response
  91. * @throws NotFoundException
  92. */
  93. public function edit(Request $request, Response $response, $args): Response
  94. {
  95. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  96. if (!$user) {
  97. throw new NotFoundException($request, $response);
  98. }
  99. return $this->view->render($response, 'user/edit.twig', [
  100. 'profile' => false,
  101. 'user' => $user,
  102. ]);
  103. }
  104. /**
  105. * @param Request $request
  106. * @param Response $response
  107. * @param $args
  108. * @return Response
  109. * @throws NotFoundException
  110. */
  111. public function update(Request $request, Response $response, $args): Response
  112. {
  113. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  114. if (!$user) {
  115. throw new NotFoundException($request, $response);
  116. }
  117. if ($request->getParam('email') === null) {
  118. Session::alert(lang('email_required'), 'danger');
  119. return redirect($response, 'user.edit', ['id' => $args['id']]);
  120. }
  121. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [$request->getParam('email'), $user->email])->fetch()->count > 0) {
  122. Session::alert(lang('email_taken'), 'danger');
  123. return redirect($response, 'user.edit', ['id' => $args['id']]);
  124. }
  125. if ($request->getParam('username') === null) {
  126. Session::alert(lang('username_required'), 'danger');
  127. return redirect($response, 'user.edit', ['id' => $args['id']]);
  128. }
  129. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `username` = ? AND `username` <> ?', [$request->getParam('username'), $user->username])->fetch()->count > 0) {
  130. Session::alert(lang('username_taken'), 'danger');
  131. return redirect($response, 'user.edit', ['id' => $args['id']]);
  132. }
  133. if ($user->id === Session::get('user_id') && $request->getParam('is_admin') === null) {
  134. Session::alert(lang('cannot_demote'), 'danger');
  135. return redirect($response, 'user.edit', ['id' => $args['id']]);
  136. }
  137. if ($request->getParam('password') !== null && !empty($request->getParam('password'))) {
  138. $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `password`=?, `is_admin`=?, `active`=? WHERE `id` = ?', [
  139. $request->getParam('email'),
  140. $request->getParam('username'),
  141. password_hash($request->getParam('password'), PASSWORD_DEFAULT),
  142. $request->getParam('is_admin') !== null ? 1 : 0,
  143. $request->getParam('is_active') !== null ? 1 : 0,
  144. $user->id,
  145. ]);
  146. } else {
  147. $this->database->query('UPDATE `users` SET `email`=?, `username`=?, `is_admin`=?, `active`=? WHERE `id` = ?', [
  148. $request->getParam('email'),
  149. $request->getParam('username'),
  150. $request->getParam('is_admin') !== null ? 1 : 0,
  151. $request->getParam('is_active') !== null ? 1 : 0,
  152. $user->id,
  153. ]);
  154. }
  155. Session::alert(lang('user_updated', [$request->getParam('username')]), 'success');
  156. $this->logger->info('User ' . Session::get('username') . " updated $user->id.", [$user, array_diff($request->getParams(), ['password'])]);
  157. return redirect($response, 'user.index');
  158. }
  159. /**
  160. * @param Request $request
  161. * @param Response $response
  162. * @param $args
  163. * @return Response
  164. * @throws NotFoundException
  165. */
  166. public function delete(Request $request, Response $response, $args): Response
  167. {
  168. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  169. if (!$user) {
  170. throw new NotFoundException($request, $response);
  171. }
  172. if ($user->id === Session::get('user_id')) {
  173. Session::alert(lang('cannot_delete'), 'danger');
  174. return redirect($response, 'user.index');
  175. }
  176. $this->database->query('DELETE FROM `users` WHERE `id` = ?', $user->id);
  177. Session::alert(lang('user_deleted'), 'success');
  178. $this->logger->info('User ' . Session::get('username') . " deleted $user->id.");
  179. return redirect($response, 'user.index');
  180. }
  181. /**
  182. * @param Request $request
  183. * @param Response $response
  184. * @return Response
  185. * @throws NotFoundException
  186. * @throws UnauthorizedException
  187. */
  188. public function profile(Request $request, Response $response): Response
  189. {
  190. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', Session::get('user_id'))->fetch();
  191. if (!$user) {
  192. throw new NotFoundException($request, $response);
  193. }
  194. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  195. throw new UnauthorizedException();
  196. }
  197. return $this->view->render($response, 'user/edit.twig', [
  198. 'profile' => true,
  199. 'user' => $user,
  200. ]);
  201. }
  202. /**
  203. * @param Request $request
  204. * @param Response $response
  205. * @param $args
  206. * @return Response
  207. * @throws NotFoundException
  208. * @throws UnauthorizedException
  209. */
  210. public function profileEdit(Request $request, Response $response, $args): Response
  211. {
  212. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  213. if (!$user) {
  214. throw new NotFoundException($request, $response);
  215. }
  216. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  217. throw new UnauthorizedException();
  218. }
  219. if ($request->getParam('email') === null) {
  220. Session::alert(lang('email_required'), 'danger');
  221. return redirect($response, 'profile');
  222. }
  223. if ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `email` = ? AND `email` <> ?', [$request->getParam('email'), $user->email])->fetch()->count > 0) {
  224. Session::alert(lang('email_taken'), 'danger');
  225. return redirect($response, 'profile');
  226. }
  227. if ($request->getParam('password') !== null && !empty($request->getParam('password'))) {
  228. $this->database->query('UPDATE `users` SET `email`=?, `password`=? WHERE `id` = ?', [
  229. $request->getParam('email'),
  230. password_hash($request->getParam('password'), PASSWORD_DEFAULT),
  231. $user->id,
  232. ]);
  233. } else {
  234. $this->database->query('UPDATE `users` SET `email`=? WHERE `id` = ?', [
  235. $request->getParam('email'),
  236. $user->id,
  237. ]);
  238. }
  239. Session::alert(lang('profile_updated'), 'success');
  240. $this->logger->info('User ' . Session::get('username') . " updated profile of $user->id.");
  241. return redirect($response, 'profile');
  242. }
  243. /**
  244. * @param Request $request
  245. * @param Response $response
  246. * @param $args
  247. * @return Response
  248. * @throws NotFoundException
  249. * @throws UnauthorizedException
  250. */
  251. public function refreshToken(Request $request, Response $response, $args): Response
  252. {
  253. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  254. if (!$user) {
  255. throw new NotFoundException($request, $response);
  256. }
  257. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  258. throw new UnauthorizedException();
  259. }
  260. $token = $this->generateNewToken();
  261. $this->database->query('UPDATE `users` SET `token`=? WHERE `id` = ?', [
  262. $token,
  263. $user->id,
  264. ]);
  265. $this->logger->info('User ' . Session::get('username') . " refreshed token of user $user->id.");
  266. $response->getBody()->write($token);
  267. return $response;
  268. }
  269. /**
  270. * @param Request $request
  271. * @param Response $response
  272. * @param $args
  273. * @return Response
  274. * @throws NotFoundException
  275. * @throws UnauthorizedException
  276. */
  277. public function getShareXconfigFile(Request $request, Response $response, $args): Response
  278. {
  279. $user = $this->database->query('SELECT * FROM `users` WHERE `id` = ? LIMIT 1', $args['id'])->fetch();
  280. if (!$user) {
  281. throw new NotFoundException($request, $response);
  282. }
  283. if ($user->id !== Session::get('user_id') && !Session::get('admin', false)) {
  284. throw new UnauthorizedException();
  285. }
  286. if ($user->token === null || $user->token === '') {
  287. Session::alert('You don\'t have a personal upload token. (Click the update token button and try again)', 'danger');
  288. return $response->withRedirect($request->getHeaderLine('HTTP_REFERER'));
  289. }
  290. $base_url = $this->settings['base_url'];
  291. $json = [
  292. 'DestinationType' => 'ImageUploader, TextUploader, FileUploader',
  293. 'RequestURL' => "$base_url/upload",
  294. 'FileFormName' => 'upload',
  295. 'Arguments' => [
  296. 'file' => '$filename$',
  297. 'text' => '$input$',
  298. 'token' => $user->token,
  299. ],
  300. 'URL' => '$json:url$',
  301. 'ThumbnailURL' => '$json:url$/raw',
  302. 'DeletionURL' => '$json:url$/delete/' . $user->token,
  303. ];
  304. return $response
  305. ->withHeader('Content-Disposition', 'attachment;filename="' . $user->username . '-ShareX.sxcu"')
  306. ->withJson($json, 200, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
  307. }
  308. /**
  309. * @return string
  310. */
  311. protected function generateNewToken(): string
  312. {
  313. do {
  314. $token = 'token_' . md5(uniqid('', true));
  315. } while ($this->database->query('SELECT COUNT(*) AS `count` FROM `users` WHERE `token` = ?', $token)->fetch()->count > 0);
  316. return $token;
  317. }
  318. }