View file app/Controllers/Admin/ForumController.php

File size: 21.81Kb
<?php

namespace App\Controllers\Admin;

use App\Classes\Validator;
use App\Models\File;
use App\Models\Forum;
use App\Models\Post;
use App\Models\Topic;
use App\Models\User;
use App\Models\Vote;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Http\Request;

class ForumController extends AdminController
{
    /**
     * Главная страница
     */
    public function index()
    {
        $forums = Forum::query()
            ->where('parent_id', 0)
            ->with('lastTopic.lastPost.user')
            ->with('children')
            ->orderBy('sort')
            ->get();

        return view('admin/forums/index', compact('forums'));
    }

    /**
     * Создание раздела
     *
     * @param Request   $request
     * @param Validator $validator
     */
    public function create(Request $request, Validator $validator): void
    {
        if (! isAdmin(User::BOSS)) {
            abort(403, 'Доступ запрещен!');
        }

        $token = check($request->input('token'));
        $title = check($request->input('title'));

        $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!')
            ->length($title, 5, 50, ['title' => 'Слишком длинное или короткое название раздела!']);

        if ($validator->isValid()) {

            $max = Forum::query()->max('sort') + 1;

            /** @var Forum $forum */
            $forum = Forum::query()->create([
                'title' => $title,
                'sort'  => $max,
            ]);

            setFlash('success', 'Новый раздел успешно создан!');
            redirect('/admin/forums/edit/' . $forum->id);
        } else {
            setInput($request->all());
            setFlash('danger', $validator->getErrors());
        }

        redirect('/admin/forums');
    }

    /**
     * Редактирование форума
     *
     * @param int       $id
     * @param Request   $request
     * @param Validator $validator
     * @return string
     */
    public function edit(int $id, Request $request, Validator $validator): string
    {
        if (! isAdmin(User::BOSS)) {
            abort(403, 'Доступ запрещен!');
        }

        /** @var Forum $forum */
        $forum = Forum::query()->with('children')->find($id);

        if (! $forum) {
            abort(404, 'Данного раздела не существует!');
        }

        $forums = Forum::query()
            ->where('parent_id', 0)
            ->orderBy('sort')
            ->get();

        if ($request->isMethod('post')) {
            $token       = check($request->input('token'));
            $parent      = int($request->input('parent'));
            $title       = check($request->input('title'));
            $description = check($request->input('description'));
            $sort        = check($request->input('sort'));
            $closed      = empty($request->input('closed')) ? 0 : 1;

            $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!')
                ->length($title, 5, 50, ['title' => 'Слишком длинное или короткое название раздела!'])
                ->length($description, 0, 100, ['description' => 'Слишком длинное описания раздела!'])
                ->notEqual($parent, $forum->id, ['parent' => 'Недопустимый выбор родительского раздела!']);

            if (! empty($parent) && $forum->children->isNotEmpty()) {
                $validator->addError(['parent' => 'Текущий раздел имеет подфорумы!']);
            }

            if ($validator->isValid()) {

                $forum->update([
                    'parent_id'   => $parent,
                    'title'       => $title,
                    'description' => $description,
                    'sort'        => $sort,
                    'closed'      => $closed,
                ]);

                setFlash('success', 'Раздел успешно отредактирован!');
                redirect('/admin/forums');
            } else {
                setInput($request->all());
                setFlash('danger', $validator->getErrors());
            }
        }

        return view('admin/forums/edit', compact('forums', 'forum'));
    }

    /**
     * Удаление раздела
     *
     * @param int       $id
     * @param Request   $request
     * @param Validator $validator
     * @return void
     * @throws \Exception
     */
    public function delete(int $id, Request $request, Validator $validator): void
    {
        if (! isAdmin(User::BOSS)) {
            abort(403, 'Доступ запрещен!');
        }

        /** @var Forum $forum */
        $forum = Forum::query()->with('children')->find($id);

        if (! $forum) {
            abort(404, 'Данного раздела не существует!');
        }

        $token = check($request->input('token'));

        $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!')
            ->true($forum->children->isEmpty(), 'Удаление невозможно! Данный раздел имеет подфорумы!');

        $topic = Topic::query()->where('forum_id', $forum->id)->first();
        if ($topic) {
            $validator->addError('Удаление невозможно! В данном разделе имеются темы!');
        }

        if ($validator->isValid()) {

            $forum->delete();

            setFlash('success', 'Раздел успешно удален!');
        } else {
            setFlash('danger', $validator->getErrors());
        }

        redirect('/admin/forums');
    }

    /**
     * Пересчет данных
     *
     * @param Request $request
     */
    public function restatement(Request $request): void
    {
        if (! isAdmin(User::BOSS)) {
            abort(403, 'Доступ запрещен!');
        }

        $token = check($request->input('token'));

        if ($token === $_SESSION['token']) {

            restatement('forums');

            setFlash('success', 'Данные успешно пересчитаны!');
        } else {
            setFlash('danger', 'Ошибка! Неверный идентификатор сессии, повторите действие!');
        }

        redirect('/admin/forums');
    }

    /**
     * Просмотр тем раздела
     *
     * @param int $id
     * @return string
     */
    public function forum(int $id): string
    {
        /** @var Forum $forum */
        $forum = Forum::query()->with('parent', 'children.lastTopic.lastPost.user')->find($id);

        if (! $forum) {
            abort(404, 'Данного раздела не существует!');
        }

        $total = Topic::query()->where('forum_id', $forum->id)->count();

        $page = paginate(setting('forumtem'), $total);

        $topics = Topic::query()
            ->where('forum_id', $forum->id)
            ->orderBy('locked', 'desc')
            ->orderBy('updated_at', 'desc')
            ->offset($page->offset)
            ->limit($page->limit)
            ->with('lastPost.user')
            ->get();

        return view('admin/forums/forum', compact('forum', 'topics', 'page'));
    }

    /**
     * Редактирование темы
     *
     * @param int       $id
     * @param Request   $request
     * @param Validator $validator
     * @return string
     */
    public function editTopic(int $id, Request $request, Validator $validator): string
    {
        /** @var Topic $topic */
        $topic = Topic::query()->find($id);

        if (! $topic) {
            abort(404, 'Данной темы не существует!');
        }

        if ($request->isMethod('post')) {

            $token      = check($request->input('token'));
            $title      = check($request->input('title'));
            $note       = check($request->input('note'));
            $moderators = check($request->input('moderators'));
            $locked     = empty($request->input('locked')) ? 0 : 1;
            $closed     = empty($request->input('closed')) ? 0 : 1;

            $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!')
                ->length($title, 5, 50, ['title' => 'Слишком длинное или короткое название темы!'])
                ->length($note, 0, 250, ['note' => 'Слишком длинное объявление!']);

            if ($validator->isValid()) {

                $moderators = implode(',', preg_split('/[\s]*[,][\s]*/', $moderators));

                $topic->update([
                    'title'      => $title,
                    'note'       => $note,
                    'moderators' => $moderators,
                    'locked'     => $locked,
                    'closed'     => $closed,
                ]);

                setFlash('success', 'Тема успешно отредактирована!');
                redirect('/admin/forums/' . $topic->forum_id);
            } else {
                setInput($request->all());
                setFlash('danger', $validator->getErrors());
            }
        }

        return view('admin/forums/edit_topic', compact('topic'));
    }

    /**
     * Перенос темы
     *
     * @param int       $id
     * @param Request   $request
     * @param Validator $validator
     * @return string
     */
    public function moveTopic(int $id, Request $request, Validator $validator): string
    {
        /** @var Topic $topic */
        $topic = Topic::query()->find($id);

        if (! $topic) {
            abort(404, 'Данной темы не существует!');
        }

        if ($request->isMethod('post')) {
            $token = check($request->input('token'));
            $fid   = int($request->input('fid'));

            /** @var Forum $forum */
            $forum = Forum::query()->find($fid);

            $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!')
                ->notEmpty($forum, ['forum' => 'Выбранного раздела не существует!']);

            if ($forum) {
                $validator->empty($forum->closed, ['forum' => 'В закрытый раздел запрещено перемещать темы!']);
                $validator->notEqual($topic->forum_id, $forum->id, ['forum' => 'Нельзя переносить тему в этот же раздел!']);
            }

            if ($validator->isValid()) {

                $oldTopic = $topic->replicate();

                $topic->update([
                    'forum_id' => $forum->id,
                ]);

                // Обновление счетчиков
                $topic->forum->restatement();
                $oldTopic->forum->restatement();

                setFlash('success', 'Тема успешно перенесена!');
                redirect('/admin/forums/' . $topic->forum_id);
            } else {
                setInput($request->all());
                setFlash('danger', $validator->getErrors());
            }
        }

        $forums = Forum::query()
            ->where('parent_id', 0)
            ->with('children')
            ->orderBy('sort')
            ->get();

        return view('admin/forums/move_topic', compact('forums', 'topic'));
    }

    /**
     * Закрытие и закрепление тем
     *
     * @param int     $id
     * @param Request $request
     * @return void
     */
    public function actionTopic(int $id, Request $request): void
    {
        $page  = int($request->input('page', 1));
        $token = check($request->input('token'));
        $type  = check($request->input('type'));

        /** @var Topic $topic */
        $topic = Topic::query()->find($id);

        if (! $topic) {
            abort(404, 'Данной темы не существует!');
        }

        if ($token === $_SESSION['token']) {

            switch ($type):
                case 'closed':
                    $topic->update(['closed' => 1]);

                    $vote = Vote::query()->where('topic_id', $topic->id)->first();
                    if ($vote) {
                        $vote->update(['closed' => 1]);
                        $vote->pollings()->delete();
                    }

                    setFlash('success', 'Тема успешно закрыта!');
                    break;

                case 'open':
                    $topic->update(['closed' => 0]);

                    $vote = Vote::query()->where('topic_id', $topic->id)->first();
                    if ($vote) {
                        $vote->update(['closed' => 0]);
                    }

                    setFlash('success', 'Тема успешно открыта!');
                    break;

                case 'locked':
                    $topic->update(['locked' => 1]);
                    setFlash('success', 'Тема успешно закреплена!');
                    break;

                case 'unlocked':
                    $topic->update(['locked' => 0]);
                    setFlash('success', 'Тема успешно откреплена!');
                    break;

                default:
                    setFlash('danger', 'Не выбрано действие для темы!');
            endswitch;

        } else {
            setFlash('danger', 'Ошибка! Неверный идентификатор сессии, повторите действие!');
        }

        redirect('/admin/topics/' . $topic->id . '?page=' . $page);
    }

    /**
     * Удаление тем
     *
     * @param int       $id
     * @param Request   $request
     * @param Validator $validator
     * @return void
     * @throws \Exception
     */
    public function deleteTopic(int $id, Request $request, Validator $validator): void
    {
        $page  = int($request->input('page', 1));
        $token = check($request->input('token'));

        /** @var Topic $topic */
        $topic = Topic::query()->find($id);

        if (! $topic) {
            abort(404, 'Данной темы не существует!');
        }

        $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!');

        if ($validator->isValid()) {

            // Удаление загруженных файлов
            $filtered = $topic->posts->load('files')->filter(function ($post) {
                return $post->files->isNotEmpty();
            });

            $filtered->each(function(Post $post) {
                $post->delete();
            });

            // Удаление голосований
            $topic->vote->answers()->delete();
            $topic->vote->pollings()->delete();
            $topic->vote->delete();

            // Удаление закладок
            $topic->bookmarks()->delete();

            $topic->posts()->delete();
            $topic->delete();

            // Обновление счетчиков
            $topic->forum->restatement();

            setFlash('success', 'Тема успешно удалена!');
        } else {
            setFlash('danger', $validator->getErrors());
        }

        redirect('/admin/forums/' . $topic->forum->id . '?page=' . $page);
    }

    /**
     * Просмотр темы
     *
     * @param int $id
     * @return string
     */
    public function topic(int $id): string
    {
        $topic = Topic::query()->where('id', $id)->with('forum.parent')->first();

        if (! $topic) {
            abort(404, 'Данной темы не существует!');
        }

        $total = Post::query()->where('topic_id', $topic->id)->count();
        $page = paginate(setting('forumpost'), $total);

        $posts = Post::query()
            ->select('posts.*', 'pollings.vote')
            ->where('topic_id', $topic->id)
            ->leftJoin('pollings', function (JoinClause $join) {
                $join->on('posts.id', 'pollings.relate_id')
                    ->where('pollings.relate_type', Post::class)
                    ->where('pollings.user_id', getUser('id'));
            })
            ->with('files', 'user', 'editUser')
            ->offset($page->offset)
            ->limit($page->limit)
            ->orderBy('created_at')
            ->get();

        // Кураторы
        if ($topic->moderators) {
            $topic->curators = User::query()->whereIn('id', explode(',', $topic->moderators))->get();
        }

        // Голосование
        $vote = Vote::query()->where('topic_id', $topic->id)->first();

        if ($vote) {
            $vote->poll = $vote->pollings()
                ->where('user_id', getUser('id'))
                ->first();

            if ($vote->answers->isNotEmpty()) {

                $results = array_pluck($vote->answers, 'result', 'answer');
                $max = max($results);

                arsort($results);

                $vote->voted = $results;

                $vote->sum = ($vote->count > 0) ? $vote->count : 1;
                $vote->max = ($max > 0) ? $max : 1;
            }
        }

        return view('admin/forums/topic', compact('topic', 'posts', 'page', 'vote'));
    }

    /**
     * Редактирование сообщения
     *
     * @param int       $id
     * @param Request   $request
     * @param Validator $validator
     * @return string
     */
    public function editPost(int $id, Request $request, Validator $validator): string
    {
        $page = int($request->input('page', 1));

        /** @var Post $post */
        $post = Post::query()->find($id);

        if (! $post) {
            abort(404, 'Данного сообщения не существует!');
        }

        if ($request->isMethod('post')) {

            $token   = check($request->input('token'));
            $msg     = check($request->input('msg'));
            $delfile = intar($request->input('delfile'));

            $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!')
                ->length($msg, 5, setting('forumtextlength'), ['msg' => 'Слишком длинное или короткое сообщение!']);

            if ($validator->isValid()) {

                $msg = antimat($msg);

                $post->update([
                    'text'         => $msg,
                    'edit_user_id' => getUser('id'),
                    'updated_at'   => SITETIME,
                ]);

                // ------ Удаление загруженных файлов -------//
                if ($delfile) {
                    $files = File::query()
                        ->where('relate_type', Post::class)
                        ->where('relate_id', $post->id)
                        ->whereIn('id', $delfile)
                        ->get();

                    if ($files->isNotEmpty()) {
                        foreach ($files as $file) {
                            deleteFile(HOME . $file->hash);
                            $file->delete();
                        }
                    }
                }

                setFlash('success', 'Сообщение успешно отредактировано!');
                redirect('/admin/topics/' . $post->topic_id . '?page=' . $page);
            } else {
                setInput($request->all());
                setFlash('danger', $validator->getErrors());
            }
        }

        return view('admin/forums/edit_post', compact('post', 'page'));
    }

    /**
     * Удаление тем
     *
     * @param Request   $request
     * @param Validator $validator
     * @return void
     */
    public function deletePosts(Request $request, Validator $validator): void
    {
        $tid   = int($request->input('tid'));
        $page  = int($request->input('page', 1));
        $token = check($request->input('token'));
        $del   = intar($request->input('del'));

        $topic = Topic::query()->where('id', $tid)->first();

        if (! $topic) {
            abort(404, 'Данной темы не существует!');
        }

        $validator->equal($token, $_SESSION['token'], 'Неверный идентификатор сессии, повторите действие!')
            ->true($del, 'Отсутствуют выбранные сообщения для удаления!');

        if ($validator->isValid()) {

            $posts = Post::query()
                ->whereIn('id', $del)
                ->get();

            $posts->each(function(Post $post) {
                $post->delete();
            });

            // Обновление счетчиков
            $topic->restatement();

            setFlash('success', 'Выбранные сообщения успешно удалены!');
        } else {
            setFlash('danger', $validator->getErrors());
        }

        redirect('/admin/topics/' . $topic->id . '?page=' . $page);
    }

    /**
     * Переадресация к последнему сообщению
     *
     * @return void
     * @param $id
     */
    public function end(int $id): void
    {
        /** @var Topic $topic */
        $topic = Topic::query()->find($id);

        if (! $topic) {
            abort(404, 'Выбранная вами тема не существует, возможно она была удалена!');
        }

        $end = ceil($topic->count_posts / setting('forumpost'));
        redirect('/admin/topics/' . $topic->id . '?page=' . $end);
    }
}