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

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