<commit_before><?php

/**
 *    Copyright (c) ppy Pty Ltd <<EMAIL>>.
 *
 *    This file is part of osu!web. osu!web is distributed with the hope of
 *    attracting more community contributions to the core ecosystem of osu!.
 *
 *    osu!web is free software: you can redistribute it and/or modify
 *    it under the terms of the Affero GNU General Public License version 3
 *    as published by the Free Software Foundation.
 *
 *    osu!web is distributed WITHOUT ANY WARRANTY; without even the implied
 *    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *    See the GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with osu!web.  If not, see <http://www.gnu.org/licenses/>.
 */

namespace App\Http\Controllers;

use App\Exceptions\ModelNotSavedException;
use App\Libraries\CommentBundle;
use App\Libraries\CommentBundleParams;
use App\Libraries\MorphMap;
use App\Models\Comment;
use App\Models\Log;
use App\Models\Notification;
use Carbon\Carbon;
use Exception;
use Illuminate\Pagination\LengthAwarePaginator;

/**
 * @group Comments
 */
class CommentsController extends Controller
{
    protected $section = 'community';
    protected $actionPrefix = 'comments-';

    public function __construct()
    {
        parent::__construct();

        $this->middleware('auth', ['except' => ['index', 'show']]);
    }

    /**
     * Delete Comment
     *
     * Deletes the specified comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function destroy($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentDestroy', $comment)->ensureCan();

        $comment->softDelete(auth()->user());

        if ($comment->user_id !== auth()->user()->getKey()) {
            $this->logModerate('LOG_COMMENT_DELETE', $comment);
        }

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Get Comments
     *
     * Returns a list comments and their replies up to 2 levels deep.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     *
     * @queryParam commentable_type The type of resource to get comments for.
     * @queryParam commentable_id The id of the resource to get comments for.
     */
    public function index()
    {
        $type = request('commentable_type');
        $id = request('commentable_id');

        if (isset($type) && isset($id)) {
            if (!Comment::isValidType($type)) {
                abort(422);
            }

            $class = MorphMap::getClass($type);
            $commentable = $class::findOrFail($id);
        }

        $params = request()->all();
        $params['sort'] = $params['sort'] ?? CommentBundleParams::DEFAULT_SORT;
        $commentBundle = new CommentBundle(
            $commentable ?? null,
            ['params' => $params]
        );

        if (is_json_request()) {
            return $commentBundle->toArray();
        } else {
            $commentBundle->depth = 0;
            $commentBundle->includeCommentableMeta = true;
            $commentBundle->includeDeleted = isset($commentable);
            $commentBundle->includePinned = false;

            $countQuery = isset($commentable) ? $commentable->comments() : Comment::query();
            $count = $commentBundle->includeDeleted ? $countQuery->count() : $countQuery->withoutTrashed()->count();

            $commentPagination = new LengthAwarePaginator(
                [],
                $count,
                $commentBundle->params->limit,
                $commentBundle->params->page,
                [
                    'path' => LengthAwarePaginator::resolveCurrentPath(),
                    'query' => $commentBundle->params->forUrl(),
                ]
            );

            return view('comments.index', compact('commentBundle', 'commentPagination'));
        }
    }

    public function restore($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentRestore', $comment)->ensureCan();

        $comment->restore();

        $this->logModerate('LOG_COMMENT_RESTORE', $comment);

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Get a Comment
     *
     * Gets a comment and its replies up to 2 levels deep.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function show($id)
    {
        $comment = Comment::findOrFail($id);

        $commentBundle = CommentBundle::forComment($comment, true);

        if (is_json_request()) {
            return $commentBundle->toArray();
        }

        return view('comments.show', compact('commentBundle'));
    }

    /**
     * Post a new comment
     *
     * Posts a new comment to a comment thread.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     *
     * @queryParam comment.commentable_id Resource ID the comment thread is attached to
     * @queryParam comment.commentable_type Resource type the comment thread is attached to
     * @queryParam comment.message Text of the comment
     * @queryParam comment.parent_id The id of the comment to reply to, null if not a reply
     */
    public function store()
    {
        $user = auth()->user();

        $params = get_params(request(), 'comment', [
            'commentable_id:int',
            'commentable_type',
            'message',
            'parent_id:int',
        ]);
        $params['user_id'] = optional($user)->getKey();

        $comment = new Comment($params);

        priv_check('CommentStore', $comment)->ensureCan();

        try {
            $comment->saveOrExplode();
        } catch (ModelNotSavedException $e) {
            return error_popup($e->getMessage());
        }

        broadcast_notification(Notification::COMMENT_NEW, $comment, $user);

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Edit Comment
     *
     * Edit an existing comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     *
     * @queryParam comment.message New text of the comment
     */
    public function update($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentUpdate', $comment)->ensureCan();

        $params = get_params(request(), 'comment', ['message']);
        $params['edited_by_id'] = auth()->user()->getKey();
        $params['edited_at'] = Carbon::now();
        $comment->update($params);

        if ($comment->user_id !== auth()->user()->getKey()) {
            $this->logModerate('LOG_COMMENT_UPDATE', $comment);
        }

        return CommentBundle::forComment($comment)->toArray();
    }

    public function pinDestroy($id)
    {
        priv_check('CommentPin')->ensureCan();

        $comment = Comment::findOrFail($id);
        $comment->update(['pinned' => false]);

        return CommentBundle::forComment($comment)->toArray();
    }

    public function pinStore($id)
    {
        priv_check('CommentPin')->ensureCan();

        $comment = Comment::findOrFail($id);
        $comment->update(['pinned' => true]);

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Remove Comment vote
     *
     * Un-upvotes a comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function voteDestroy($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentVote', $comment)->ensureCan();

        $vote = $comment->votes()->where([
            'user_id' => auth()->user()->getKey(),
        ])->first();

        optional($vote)->delete();

        return CommentBundle::forComment($comment->fresh(), false)->toArray();
    }

    /**
     * Add Comment vote
     *
     * Upvotes a comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function voteStore($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentVote', $comment)->ensureCan();

        try {
            $comment->votes()->create([
                'user_id' => auth()->user()->getKey(),
            ]);
        } catch (Exception $e) {
            if (!is_sql_unique_exception($e)) {
                throw $e;
            }
        }

        return CommentBundle::forComment($comment->fresh(), false)->toArray();
    }

    private function logModerate($operation, $comment)
    {
        $this->log([
            'log_type' => Log::LOG_COMMENT_MOD,
            'log_operation' => $operation,
            'log_data' => [
                'commentable_type' => $comment->commentable_type,
                'commentable_id' => $comment->commentable_id,
                'id' => $comment->getKey(),
            ],
        ]);
    }
}
<commit_msg>correct query params for paginator<commit_after><?php

/**
 *    Copyright (c) ppy Pty Ltd <<EMAIL>>.
 *
 *    This file is part of osu!web. osu!web is distributed with the hope of
 *    attracting more community contributions to the core ecosystem of osu!.
 *
 *    osu!web is free software: you can redistribute it and/or modify
 *    it under the terms of the Affero GNU General Public License version 3
 *    as published by the Free Software Foundation.
 *
 *    osu!web is distributed WITHOUT ANY WARRANTY; without even the implied
 *    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *    See the GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with osu!web.  If not, see <http://www.gnu.org/licenses/>.
 */

namespace App\Http\Controllers;

use App\Exceptions\ModelNotSavedException;
use App\Libraries\CommentBundle;
use App\Libraries\CommentBundleParams;
use App\Libraries\MorphMap;
use App\Models\Comment;
use App\Models\Log;
use App\Models\Notification;
use Carbon\Carbon;
use Exception;
use Illuminate\Pagination\LengthAwarePaginator;

/**
 * @group Comments
 */
class CommentsController extends Controller
{
    protected $section = 'community';
    protected $actionPrefix = 'comments-';

    public function __construct()
    {
        parent::__construct();

        $this->middleware('auth', ['except' => ['index', 'show']]);
    }

    /**
     * Delete Comment
     *
     * Deletes the specified comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function destroy($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentDestroy', $comment)->ensureCan();

        $comment->softDelete(auth()->user());

        if ($comment->user_id !== auth()->user()->getKey()) {
            $this->logModerate('LOG_COMMENT_DELETE', $comment);
        }

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Get Comments
     *
     * Returns a list comments and their replies up to 2 levels deep.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     *
     * @queryParam commentable_type The type of resource to get comments for.
     * @queryParam commentable_id The id of the resource to get comments for.
     */
    public function index()
    {
        $requestParams = get_params(request(), null, [
            'commentable_id:int',
            'commentable_type',
        ]);

        $id = $requestParams['commentable_id'] ?? null;
        $type = $requestParams['commentable_type'] ?? null;

        if (isset($type) && isset($id)) {
            if (!Comment::isValidType($type)) {
                abort(422);
            }

            $class = MorphMap::getClass($type);
            $commentable = $class::findOrFail($id);
        }

        $params = request()->all();
        $params['sort'] = $params['sort'] ?? CommentBundleParams::DEFAULT_SORT;
        $commentBundle = new CommentBundle(
            $commentable ?? null,
            ['params' => $params]
        );

        if (is_json_request()) {
            return $commentBundle->toArray();
        } else {
            $commentBundle->depth = 0;
            $commentBundle->includeCommentableMeta = true;
            $commentBundle->includeDeleted = isset($commentable);
            $commentBundle->includePinned = false;

            $countQuery = isset($commentable) ? $commentable->comments() : Comment::query();
            $count = $commentBundle->includeDeleted ? $countQuery->count() : $countQuery->withoutTrashed()->count();

            $commentPagination = new LengthAwarePaginator(
                [],
                $count,
                $commentBundle->params->limit,
                $commentBundle->params->page,
                [
                    'path' => LengthAwarePaginator::resolveCurrentPath(),
                    'query' => array_merge($commentBundle->params->forUrl(), $requestParams),
                ]
            );

            return view('comments.index', compact('commentBundle', 'commentPagination'));
        }
    }

    public function restore($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentRestore', $comment)->ensureCan();

        $comment->restore();

        $this->logModerate('LOG_COMMENT_RESTORE', $comment);

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Get a Comment
     *
     * Gets a comment and its replies up to 2 levels deep.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function show($id)
    {
        $comment = Comment::findOrFail($id);

        $commentBundle = CommentBundle::forComment($comment, true);

        if (is_json_request()) {
            return $commentBundle->toArray();
        }

        return view('comments.show', compact('commentBundle'));
    }

    /**
     * Post a new comment
     *
     * Posts a new comment to a comment thread.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     *
     * @queryParam comment.commentable_id Resource ID the comment thread is attached to
     * @queryParam comment.commentable_type Resource type the comment thread is attached to
     * @queryParam comment.message Text of the comment
     * @queryParam comment.parent_id The id of the comment to reply to, null if not a reply
     */
    public function store()
    {
        $user = auth()->user();

        $params = get_params(request(), 'comment', [
            'commentable_id:int',
            'commentable_type',
            'message',
            'parent_id:int',
        ]);
        $params['user_id'] = optional($user)->getKey();

        $comment = new Comment($params);

        priv_check('CommentStore', $comment)->ensureCan();

        try {
            $comment->saveOrExplode();
        } catch (ModelNotSavedException $e) {
            return error_popup($e->getMessage());
        }

        broadcast_notification(Notification::COMMENT_NEW, $comment, $user);

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Edit Comment
     *
     * Edit an existing comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     *
     * @queryParam comment.message New text of the comment
     */
    public function update($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentUpdate', $comment)->ensureCan();

        $params = get_params(request(), 'comment', ['message']);
        $params['edited_by_id'] = auth()->user()->getKey();
        $params['edited_at'] = Carbon::now();
        $comment->update($params);

        if ($comment->user_id !== auth()->user()->getKey()) {
            $this->logModerate('LOG_COMMENT_UPDATE', $comment);
        }

        return CommentBundle::forComment($comment)->toArray();
    }

    public function pinDestroy($id)
    {
        priv_check('CommentPin')->ensureCan();

        $comment = Comment::findOrFail($id);
        $comment->update(['pinned' => false]);

        return CommentBundle::forComment($comment)->toArray();
    }

    public function pinStore($id)
    {
        priv_check('CommentPin')->ensureCan();

        $comment = Comment::findOrFail($id);
        $comment->update(['pinned' => true]);

        return CommentBundle::forComment($comment)->toArray();
    }

    /**
     * Remove Comment vote
     *
     * Un-upvotes a comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function voteDestroy($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentVote', $comment)->ensureCan();

        $vote = $comment->votes()->where([
            'user_id' => auth()->user()->getKey(),
        ])->first();

        optional($vote)->delete();

        return CommentBundle::forComment($comment->fresh(), false)->toArray();
    }

    /**
     * Add Comment vote
     *
     * Upvotes a comment.
     *
     * ---
     *
     * ### Response Format
     *
     * Returns [CommentBundle](#commentbundle)
     *
     * @authenticated
     */
    public function voteStore($id)
    {
        $comment = Comment::findOrFail($id);

        priv_check('CommentVote', $comment)->ensureCan();

        try {
            $comment->votes()->create([
                'user_id' => auth()->user()->getKey(),
            ]);
        } catch (Exception $e) {
            if (!is_sql_unique_exception($e)) {
                throw $e;
            }
        }

        return CommentBundle::forComment($comment->fresh(), false)->toArray();
    }

    private function logModerate($operation, $comment)
    {
        $this->log([
            'log_type' => Log::LOG_COMMENT_MOD,
            'log_operation' => $operation,
            'log_data' => [
                'commentable_type' => $comment->commentable_type,
                'commentable_id' => $comment->commentable_id,
                'id' => $comment->getKey(),
            ],
        ]);
    }
}

{'fraction_non_alphanumeric': 0.1412140575079872, 'fraction_numerical': 0.0007454739084132055, 'mean_word_length': 2.169789029535865, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 181, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3302413', 'n_tokens_mistral': 5236, 'n_tokens_neox': 5096, 'n_words': 1116}