Просмотр файла app/Http/Controllers/Admin/ForumController.php

Размер файла: 19.99Kb
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace App\Http\Controllers\Admin;
  6.  
  7. use App\Classes\Validator;
  8. use App\Models\Forum;
  9. use App\Models\Post;
  10. use App\Models\Topic;
  11. use App\Models\User;
  12. use App\Models\Vote;
  13. use Exception;
  14. use Illuminate\Database\Query\JoinClause;
  15. use Illuminate\Http\RedirectResponse;
  16. use Illuminate\Http\Request;
  17. use Illuminate\Support\Arr;
  18. use Illuminate\View\View;
  19.  
  20. class ForumController extends AdminController
  21. {
  22. /**
  23. * Главная страница
  24. */
  25. public function index(): View
  26. {
  27. $forums = Forum::query()
  28. ->where('parent_id', 0)
  29. ->with('lastTopic.lastPost.user')
  30. ->with('children')
  31. ->orderBy('sort')
  32. ->get();
  33.  
  34. return view('admin/forums/index', compact('forums'));
  35. }
  36.  
  37. /**
  38. * Создание раздела
  39. *
  40. * @param Request $request
  41. * @param Validator $validator
  42. *
  43. * @return RedirectResponse
  44. */
  45. public function create(Request $request, Validator $validator): RedirectResponse
  46. {
  47. if (! isAdmin(User::BOSS)) {
  48. abort(403, __('errors.forbidden'));
  49. }
  50.  
  51. $title = $request->input('title');
  52.  
  53. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
  54. ->length($title, 3, 50, ['title' => __('validator.text')]);
  55.  
  56. if ($validator->isValid()) {
  57. $max = Forum::query()->max('sort') + 1;
  58.  
  59. /** @var Forum $forum */
  60. $forum = Forum::query()->create([
  61. 'title' => $title,
  62. 'sort' => $max,
  63. ]);
  64.  
  65. setFlash('success', __('forums.forum_success_created'));
  66.  
  67. return redirect('admin/forums/edit/' . $forum->id);
  68. }
  69.  
  70. setInput($request->all());
  71. setFlash('danger', $validator->getErrors());
  72.  
  73. return redirect('admin/forums');
  74. }
  75.  
  76. /**
  77. * Редактирование форума
  78. *
  79. * @param int $id
  80. * @param Request $request
  81. * @param Validator $validator
  82. *
  83. * @return View|RedirectResponse
  84. */
  85. public function edit(int $id, Request $request, Validator $validator)
  86. {
  87. if (! isAdmin(User::BOSS)) {
  88. abort(403, __('errors.forbidden'));
  89. }
  90.  
  91. /** @var Forum $forum */
  92. $forum = Forum::query()->with('children')->find($id);
  93.  
  94. if (! $forum) {
  95. abort(404, __('forums.forum_not_exist'));
  96. }
  97.  
  98. $forums = Forum::query()
  99. ->where('parent_id', 0)
  100. ->orderBy('sort')
  101. ->get();
  102.  
  103. if ($request->isMethod('post')) {
  104. $parent = int($request->input('parent'));
  105. $title = $request->input('title');
  106. $description = $request->input('description');
  107. $sort = int($request->input('sort'));
  108. $closed = empty($request->input('closed')) ? 0 : 1;
  109.  
  110. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
  111. ->length($title, 3, 50, ['title' => __('validator.text')])
  112. ->length($description, 0, 100, ['description' => __('validator.text')])
  113. ->notEqual($parent, $forum->id, ['parent' => __('forums.forum_invalid')]);
  114.  
  115. if (! empty($parent) && $forum->children->isNotEmpty()) {
  116. $validator->addError(['parent' => __('forums.forum_has_subforums')]);
  117. }
  118.  
  119. if ($validator->isValid()) {
  120. $forum->update([
  121. 'parent_id' => $parent,
  122. 'title' => $title,
  123. 'description' => $description,
  124. 'sort' => $sort,
  125. 'closed' => $closed,
  126. ]);
  127.  
  128. setFlash('success', __('forums.forum_success_edited'));
  129.  
  130. return redirect('admin/forums');
  131. }
  132.  
  133. setInput($request->all());
  134. setFlash('danger', $validator->getErrors());
  135. }
  136.  
  137. return view('admin/forums/edit', compact('forums', 'forum'));
  138. }
  139.  
  140. /**
  141. * Удаление раздела
  142. *
  143. * @param int $id
  144. * @param Request $request
  145. * @param Validator $validator
  146. *
  147. * @return RedirectResponse
  148. */
  149. public function delete(int $id, Request $request, Validator $validator): RedirectResponse
  150. {
  151. if (! isAdmin(User::BOSS)) {
  152. abort(403, __('errors.forbidden'));
  153. }
  154.  
  155. /** @var Forum $forum */
  156. $forum = Forum::query()->with('children')->find($id);
  157.  
  158. if (! $forum) {
  159. abort(404, __('forums.forum_not_exist'));
  160. }
  161.  
  162. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
  163. ->true($forum->children->isEmpty(), __('forums.forum_has_subforums'));
  164.  
  165. $topic = Topic::query()->where('forum_id', $forum->id)->first();
  166. if ($topic) {
  167. $validator->addError(__('forums.forum_has_topics'));
  168. }
  169.  
  170. if ($validator->isValid()) {
  171. $forum->delete();
  172.  
  173. setFlash('success', __('forums.forum_success_deleted'));
  174. } else {
  175. setFlash('danger', $validator->getErrors());
  176. }
  177.  
  178. return redirect('admin/forums');
  179. }
  180.  
  181. /**
  182. * Пересчет данных
  183. *
  184. * @param Request $request
  185. *
  186. * @return RedirectResponse
  187. */
  188. public function restatement(Request $request): RedirectResponse
  189. {
  190. if (! isAdmin(User::BOSS)) {
  191. abort(403, __('errors.forbidden'));
  192. }
  193.  
  194. if ($request->input('_token') === csrf_token()) {
  195. restatement('forums');
  196.  
  197. setFlash('success', __('main.success_recounted'));
  198. } else {
  199. setFlash('danger', __('validator.token'));
  200. }
  201.  
  202. return redirect('admin/forums');
  203. }
  204.  
  205. /**
  206. * Просмотр тем раздела
  207. *
  208. * @param int $id
  209. *
  210. * @return View
  211. */
  212. public function forum(int $id): View
  213. {
  214. /** @var Forum $forum */
  215. $forum = Forum::query()->with('parent', 'children.lastTopic.lastPost.user')->find($id);
  216.  
  217. if (! $forum) {
  218. abort(404, __('forums.forum_not_exist'));
  219. }
  220.  
  221. $topics = Topic::query()
  222. ->select('topics.*', 'bookmarks.count_posts as bookmark_posts')
  223. ->where('forum_id', $forum->id)
  224. ->leftJoin('bookmarks', static function (JoinClause $join) {
  225. $join->on('topics.id', 'bookmarks.topic_id')
  226. ->where('bookmarks.user_id', getUser('id'));
  227. })
  228. ->orderByDesc('locked')
  229. ->orderByDesc('updated_at')
  230. ->with('lastPost.user')
  231. ->paginate(setting('forumtem'));
  232.  
  233. return view('admin/forums/forum', compact('forum', 'topics'));
  234. }
  235.  
  236. /**
  237. * Редактирование темы
  238. *
  239. * @param int $id
  240. * @param Request $request
  241. * @param Validator $validator
  242. *
  243. * @return View|RedirectResponse
  244. */
  245. public function editTopic(int $id, Request $request, Validator $validator)
  246. {
  247. /** @var Topic $topic */
  248. $topic = Topic::query()->find($id);
  249.  
  250. if (! $topic) {
  251. abort(404, __('forums.topic_not_exist'));
  252. }
  253.  
  254. if ($request->isMethod('post')) {
  255. $title = $request->input('title');
  256. $note = $request->input('note');
  257. $moderators = (string) $request->input('moderators');
  258. $locked = empty($request->input('locked')) ? 0 : 1;
  259. $closed = empty($request->input('closed')) ? 0 : 1;
  260. $closeUserId = $closed ? getUser('id') : null;
  261.  
  262. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
  263. ->length($title, 3, 50, ['title' => __('validator.text')])
  264. ->length($note, 0, 250, ['note' => __('validator.text_long')]);
  265.  
  266. $moderators = preg_split('/[\s]*[,][\s]*/', trim($moderators, ','), -1, PREG_SPLIT_NO_EMPTY);
  267.  
  268. foreach ($moderators as $moderator) {
  269. if (! getUserByLogin($moderator)) {
  270. $validator->addError(['moderator' => __('validator.user_login', ['login' => $moderator])]);
  271. break;
  272. }
  273. }
  274.  
  275. if ($validator->isValid()) {
  276. $topic->update([
  277. 'title' => $title,
  278. 'note' => $note,
  279. 'moderators' => implode(',', $moderators),
  280. 'locked' => $locked,
  281. 'closed' => $closed,
  282. 'close_user_id' => $closeUserId,
  283. ]);
  284.  
  285. clearCache(['statForums', 'recentTopics']);
  286. setFlash('success', __('forums.topic_success_edited'));
  287.  
  288. return redirect('admin/forums/' . $topic->forum_id);
  289. }
  290.  
  291. setInput($request->all());
  292. setFlash('danger', $validator->getErrors());
  293. }
  294.  
  295. return view('admin/forums/edit_topic', compact('topic'));
  296. }
  297.  
  298. /**
  299. * Перенос темы
  300. *
  301. * @param int $id
  302. * @param Request $request
  303. * @param Validator $validator
  304. *
  305. * @return View|RedirectResponse
  306. */
  307. public function moveTopic(int $id, Request $request, Validator $validator)
  308. {
  309. /** @var Topic $topic */
  310. $topic = Topic::query()->find($id);
  311.  
  312. if (! $topic) {
  313. abort(404, __('forums.topic_not_exist'));
  314. }
  315.  
  316. if ($request->isMethod('post')) {
  317. $fid = int($request->input('fid'));
  318.  
  319. /** @var Forum $forum */
  320. $forum = Forum::query()->find($fid);
  321.  
  322. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
  323. ->notEmpty($forum, ['forum' => __('forums.forum_not_exist')]);
  324.  
  325. if ($forum) {
  326. $validator->empty($forum->closed, ['forum' => __('forums.forum_closed')]);
  327. $validator->notEqual($topic->forum_id, $forum->id, ['forum' => __('forums.forum_invalid')]);
  328. }
  329.  
  330. if ($validator->isValid()) {
  331. $oldTopic = $topic->replicate();
  332.  
  333. $topic->update([
  334. 'forum_id' => $forum->id,
  335. ]);
  336.  
  337. // Обновление счетчиков
  338. $topic->forum->restatement();
  339. $oldTopic->forum->restatement();
  340.  
  341. setFlash('success', __('forums.topic_success_moved'));
  342.  
  343. return redirect('admin/forums/' . $topic->forum_id);
  344. }
  345.  
  346. setInput($request->all());
  347. setFlash('danger', $validator->getErrors());
  348. }
  349.  
  350. $forums = Forum::query()
  351. ->where('parent_id', 0)
  352. ->with('children')
  353. ->orderBy('sort')
  354. ->get();
  355.  
  356. return view('admin/forums/move_topic', compact('forums', 'topic'));
  357. }
  358.  
  359. /**
  360. * Закрытие и закрепление тем
  361. *
  362. * @param int $id
  363. * @param Request $request
  364. *
  365. * @return RedirectResponse
  366. */
  367. public function actionTopic(int $id, Request $request): RedirectResponse
  368. {
  369. $page = int($request->input('page', 1));
  370.  
  371. /** @var Topic $topic */
  372. $topic = Topic::query()->find($id);
  373.  
  374. if (! $topic) {
  375. abort(404, __('forums.topic_not_exist'));
  376. }
  377.  
  378. if ($request->input('_token') === csrf_token()) {
  379. switch ($request->input('type')) :
  380. case 'closed':
  381. $topic->update([
  382. 'closed' => 1,
  383. 'close_user_id' => getUser('id'),
  384. ]);
  385.  
  386. if ($topic->vote) {
  387. $topic->vote->update(['closed' => 1]);
  388. $topic->vote->pollings()->delete();
  389. }
  390.  
  391. setFlash('success', __('forums.topic_success_closed'));
  392. break;
  393.  
  394. case 'open':
  395. $topic->update([
  396. 'closed' => 0,
  397. 'close_user_id' => null,
  398. ]);
  399.  
  400. if ($topic->vote) {
  401. $topic->vote->update(['closed' => 0]);
  402. }
  403.  
  404. setFlash('success', __('forums.topic_success_opened'));
  405. break;
  406.  
  407. case 'locked':
  408. $topic->update(['locked' => 1]);
  409. setFlash('success', __('forums.topic_success_pinned'));
  410. break;
  411.  
  412. case 'unlocked':
  413. $topic->update(['locked' => 0]);
  414. setFlash('success', __('forums.topic_success_unpinned'));
  415. break;
  416.  
  417. default:
  418. setFlash('danger', __('main.action_not_selected'));
  419. endswitch;
  420. } else {
  421. setFlash('danger', __('validator.token'));
  422. }
  423.  
  424. return redirect('admin/topics/' . $topic->id . '?page=' . $page);
  425. }
  426.  
  427. /**
  428. * Удаление тем
  429. *
  430. * @param int $id
  431. * @param Request $request
  432. * @param Validator $validator
  433. *
  434. * @return RedirectResponse
  435. * @throws Exception
  436. */
  437. public function deleteTopic(int $id, Request $request, Validator $validator): RedirectResponse
  438. {
  439. $page = int($request->input('page', 1));
  440.  
  441. /** @var Topic $topic */
  442. $topic = Topic::query()->find($id);
  443.  
  444. if (! $topic) {
  445. abort(404, __('forums.topic_not_exist'));
  446. }
  447.  
  448. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'));
  449.  
  450. if ($validator->isValid()) {
  451. // Удаление загруженных файлов
  452. $filtered = $topic->posts->load('files')->filter(static function ($post) {
  453. return $post->files->isNotEmpty();
  454. });
  455.  
  456. $filtered->each(static function (Post $post) {
  457. $post->delete();
  458. });
  459.  
  460. // Удаление голосований
  461. $topic->vote->answers()->delete();
  462. $topic->vote->pollings()->delete();
  463. $topic->vote->delete();
  464.  
  465. // Удаление закладок
  466. $topic->bookmarks()->delete();
  467.  
  468. $topic->posts()->delete();
  469. $topic->delete();
  470.  
  471. // Обновление счетчиков
  472. $topic->forum->restatement();
  473.  
  474. clearCache(['statForums', 'recentTopics']);
  475. setFlash('success', __('forums.topic_success_deleted'));
  476. } else {
  477. setFlash('danger', $validator->getErrors());
  478. }
  479.  
  480. return redirect('admin/forums/' . $topic->forum->id . '?page=' . $page);
  481. }
  482.  
  483. /**
  484. * Просмотр темы
  485. *
  486. * @param int $id
  487. *
  488. * @return View
  489. */
  490. public function topic(int $id): View
  491. {
  492. $topic = Topic::query()->where('id', $id)->with('forum.parent')->first();
  493.  
  494. if (! $topic) {
  495. abort(404, __('forums.topic_not_exist'));
  496. }
  497.  
  498. $posts = Post::query()
  499. ->select('posts.*', 'pollings.vote')
  500. ->where('topic_id', $topic->id)
  501. ->leftJoin('pollings', static function (JoinClause $join) {
  502. $join->on('posts.id', 'pollings.relate_id')
  503. ->where('pollings.relate_type', Post::$morphName)
  504. ->where('pollings.user_id', getUser('id'));
  505. })
  506. ->with('files', 'user', 'editUser')
  507. ->orderBy('created_at')
  508. ->paginate(setting('forumpost'));
  509.  
  510. // Кураторы
  511. if ($topic->moderators) {
  512. $topic->curators = User::query()->whereIn('login', explode(',', (string) $topic->moderators))->get();
  513. }
  514.  
  515. // Голосование
  516. $vote = Vote::query()->where('topic_id', $topic->id)->first();
  517.  
  518. if ($vote) {
  519. $vote->poll = $vote->pollings()
  520. ->where('user_id', getUser('id'))
  521. ->first();
  522.  
  523. if ($vote->answers->isNotEmpty()) {
  524. $results = Arr::pluck($vote->answers, 'result', 'answer');
  525. $max = max($results);
  526.  
  527. arsort($results);
  528.  
  529. $vote->voted = $results;
  530.  
  531. $vote->sum = ($vote->count > 0) ? $vote->count : 1;
  532. $vote->max = ($max > 0) ? $max : 1;
  533. }
  534. }
  535.  
  536. return view('admin/forums/topic', compact('topic', 'posts', 'vote'));
  537. }
  538.  
  539. /**
  540. * Редактирование сообщения
  541. *
  542. * @param int $id
  543. * @param Request $request
  544. * @param Validator $validator
  545. *
  546. * @return View|RedirectResponse
  547. */
  548. public function editPost(int $id, Request $request, Validator $validator)
  549. {
  550. $page = int($request->input('page', 1));
  551.  
  552. /** @var Post $post */
  553. $post = Post::query()->find($id);
  554.  
  555. if (! $post) {
  556. abort(404, __('forums.post_not_exist'));
  557. }
  558.  
  559. if ($request->isMethod('post')) {
  560. $msg = $request->input('msg');
  561. $delfile = intar($request->input('delfile'));
  562.  
  563. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
  564. ->length($msg, 5, setting('forumtextlength'), ['msg' => __('validator.text')]);
  565.  
  566. if ($validator->isValid()) {
  567. $msg = antimat($msg);
  568.  
  569. $post->update([
  570. 'text' => $msg,
  571. 'edit_user_id' => getUser('id'),
  572. 'updated_at' => SITETIME,
  573. ]);
  574.  
  575. // ------ Удаление загруженных файлов -------//
  576. if ($delfile) {
  577. $files = $post->files()
  578. ->whereIn('id', $delfile)
  579. ->get();
  580.  
  581. if ($files->isNotEmpty()) {
  582. foreach ($files as $file) {
  583. $file->delete();
  584. }
  585. }
  586. }
  587.  
  588. setFlash('success', __('main.message_edited_success'));
  589.  
  590. return redirect('admin/topics/' . $post->topic_id . '?page=' . $page);
  591. }
  592.  
  593. setInput($request->all());
  594. setFlash('danger', $validator->getErrors());
  595. }
  596.  
  597. return view('admin/forums/edit_post', compact('post', 'page'));
  598. }
  599.  
  600. /**
  601. * Удаление тем
  602. *
  603. * @param Request $request
  604. * @param Validator $validator
  605. *
  606. * @return RedirectResponse
  607. * @throws Exception
  608. */
  609. public function deletePosts(Request $request, Validator $validator): RedirectResponse
  610. {
  611. $tid = int($request->input('tid'));
  612. $page = int($request->input('page', 1));
  613. $del = intar($request->input('del'));
  614.  
  615. $topic = Topic::query()->where('id', $tid)->first();
  616.  
  617. if (! $topic) {
  618. abort(404, __('forums.topic_not_exist'));
  619. }
  620.  
  621. $validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
  622. ->true($del, __('validator.deletion'));
  623.  
  624. if ($validator->isValid()) {
  625. $posts = Post::query()
  626. ->whereIn('id', $del)
  627. ->get();
  628.  
  629. $posts->each(static function (Post $post) {
  630. $post->delete();
  631. });
  632.  
  633. // Обновление счетчиков
  634. $topic->restatement();
  635.  
  636. setFlash('success', __('main.messages_deleted_success'));
  637. } else {
  638. setFlash('danger', $validator->getErrors());
  639. }
  640.  
  641. return redirect('admin/topics/' . $topic->id . '?page=' . $page);
  642. }
  643.  
  644. /**
  645. * Переадресация к последнему сообщению
  646. *
  647. * @param int $id
  648. *
  649. * @return RedirectResponse
  650. */
  651. public function end(int $id): RedirectResponse
  652. {
  653. /** @var Topic $topic */
  654. $topic = Topic::query()->find($id);
  655.  
  656. if (! $topic) {
  657. abort(404, __('forums.topic_not_exist'));
  658. }
  659.  
  660. $end = ceil($topic->count_posts / setting('forumpost'));
  661.  
  662. return redirect('admin/topics/' . $topic->id . '?page=' . $end);
  663. }
  664. }