From 3cfb42a0f0d349e3595769f4e91c3a29f3cbebb6 Mon Sep 17 00:00:00 2001 From: nanaya Date: Tue, 11 Jul 2023 20:55:45 +0900 Subject: [PATCH 1/5] Support after_id parameter for comment pagination --- app/Http/Controllers/CommentsController.php | 11 ++++++----- app/Libraries/CommentBundle.php | 14 +++++++++++--- app/Libraries/CommentBundleParams.php | 2 ++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/CommentsController.php b/app/Http/Controllers/CommentsController.php index c17d77b199e..6b8bcd23114 100644 --- a/app/Http/Controllers/CommentsController.php +++ b/app/Http/Controllers/CommentsController.php @@ -67,11 +67,12 @@ public function destroy($id) * * `pinned_comments` is only included when `commentable_type` and `commentable_id` are specified. * - * @queryParam commentable_type The type of resource to get comments for. - * @queryParam commentable_id The id of the resource to get comments for. - * @queryParam cursor Pagination option. See [CommentSort](#commentsort) for detail. The format follows [Cursor](#cursor) except it's not currently included in the response. - * @queryParam parent_id Limit to comments which are reply to the specified id. Specify 0 to get top level comments. - * @queryParam sort Sort option as defined in [CommentSort](#commentsort). Defaults to `new` for guests and user-specified default when authenticated. + * @queryParam after_id Return comments which come after the specified comment id as per sort option. No-example + * @queryParam commentable_type The type of resource to get comments for. Example: beatmapset + * @queryParam commentable_id The id of the resource to get comments for. Example: 1 + * @queryParam cursor Pagination option. See [CommentSort](#commentsort) for detail. The format follows [Cursor](#cursor) except it's not currently included in the response. No-example + * @queryParam parent_id Limit to comments which are reply to the specified id. Specify 0 to get top level comments. Example: 1 + * @queryParam sort Sort option as defined in [CommentSort](#commentsort). Defaults to `new` for guests and user-specified default when authenticated. Example: new */ public function index() { diff --git a/app/Libraries/CommentBundle.php b/app/Libraries/CommentBundle.php index 7404eb0f023..764398762dc 100644 --- a/app/Libraries/CommentBundle.php +++ b/app/Libraries/CommentBundle.php @@ -171,7 +171,9 @@ public function countForPaginator() private function getComments($query, $isChildren = true, $pinnedOnly = false) { - $sortOrCursorHelper = $pinnedOnly ? 'new' : $this->params->cursorHelper; + $cursorHelper = $pinnedOnly + ? Comment::makeDbCursorHelper('new') + : $this->params->cursorHelper; $queryLimit = $this->params->limit; if (!$isChildren) { @@ -180,14 +182,20 @@ private function getComments($query, $isChildren = true, $pinnedOnly = false) } $queryLimit++; - $cursor = $this->params->cursor; + + if ($this->params->afterId === null) { + $cursor = $this->params->cursor; + } else { + $lastComment = Comment::findOrFail($this->params->afterId); + $cursor = $cursorHelper->next([$lastComment]); + } if ($cursor === null) { $query->offset(max_offset($this->params->page, $this->params->limit)); } } - $query->cursorSort($sortOrCursorHelper, $cursor ?? null); + $query->cursorSort($cursorHelper, $cursor ?? null); if (!$this->includeDeleted) { $query->whereNull('deleted_at'); diff --git a/app/Libraries/CommentBundleParams.php b/app/Libraries/CommentBundleParams.php index 8b7a0fbab63..b727b17d382 100644 --- a/app/Libraries/CommentBundleParams.php +++ b/app/Libraries/CommentBundleParams.php @@ -13,6 +13,7 @@ class CommentBundleParams const DEFAULT_PAGE = 1; const DEFAULT_LIMIT = 50; + public ?int $afterId = null; public $userId; public $commentableId; public $commentableType; @@ -64,6 +65,7 @@ public function setAll($params) $this->cursorHelper = Comment::makeDbCursorHelper($params['sort'] ?? $this->sort); $this->cursor = get_arr($params['cursor'] ?? null); $this->sort = $this->cursorHelper->getSortName(); + $this->afterId = get_int($params['after_id'] ?? null); } public function filterByParentId() From 7d9bd08e96b25ff8f16b824841ad012a68773142 Mon Sep 17 00:00:00 2001 From: nanaya Date: Tue, 11 Jul 2023 21:17:32 +0900 Subject: [PATCH 2/5] Call it `after` instead to match existing parameter --- app/Http/Controllers/CommentsController.php | 2 +- app/Libraries/CommentBundle.php | 4 ++-- app/Libraries/CommentBundleParams.php | 4 ++-- resources/js/components/comment-show-more.tsx | 7 +------ 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/CommentsController.php b/app/Http/Controllers/CommentsController.php index 6b8bcd23114..b89ce074b41 100644 --- a/app/Http/Controllers/CommentsController.php +++ b/app/Http/Controllers/CommentsController.php @@ -67,7 +67,7 @@ public function destroy($id) * * `pinned_comments` is only included when `commentable_type` and `commentable_id` are specified. * - * @queryParam after_id Return comments which come after the specified comment id as per sort option. No-example + * @queryParam after Return comments which come after the specified comment id as per sort option. No-example * @queryParam commentable_type The type of resource to get comments for. Example: beatmapset * @queryParam commentable_id The id of the resource to get comments for. Example: 1 * @queryParam cursor Pagination option. See [CommentSort](#commentsort) for detail. The format follows [Cursor](#cursor) except it's not currently included in the response. No-example diff --git a/app/Libraries/CommentBundle.php b/app/Libraries/CommentBundle.php index 764398762dc..359d3380cec 100644 --- a/app/Libraries/CommentBundle.php +++ b/app/Libraries/CommentBundle.php @@ -183,10 +183,10 @@ private function getComments($query, $isChildren = true, $pinnedOnly = false) $queryLimit++; - if ($this->params->afterId === null) { + if ($this->params->after === null) { $cursor = $this->params->cursor; } else { - $lastComment = Comment::findOrFail($this->params->afterId); + $lastComment = Comment::findOrFail($this->params->after); $cursor = $cursorHelper->next([$lastComment]); } diff --git a/app/Libraries/CommentBundleParams.php b/app/Libraries/CommentBundleParams.php index b727b17d382..2c84fa2e469 100644 --- a/app/Libraries/CommentBundleParams.php +++ b/app/Libraries/CommentBundleParams.php @@ -13,7 +13,7 @@ class CommentBundleParams const DEFAULT_PAGE = 1; const DEFAULT_LIMIT = 50; - public ?int $afterId = null; + public ?int $after = null; public $userId; public $commentableId; public $commentableType; @@ -65,7 +65,7 @@ public function setAll($params) $this->cursorHelper = Comment::makeDbCursorHelper($params['sort'] ?? $this->sort); $this->cursor = get_arr($params['cursor'] ?? null); $this->sort = $this->cursorHelper->getSortName(); - $this->afterId = get_int($params['after_id'] ?? null); + $this->after = get_int($params['after'] ?? null); } public function filterByParentId() diff --git a/resources/js/components/comment-show-more.tsx b/resources/js/components/comment-show-more.tsx index aa36b60742a..05aa699957c 100644 --- a/resources/js/components/comment-show-more.tsx +++ b/resources/js/components/comment-show-more.tsx @@ -67,12 +67,7 @@ export default class CommentShowMore extends React.Component { const lastComment = last(this.props.comments); if (lastComment != null) { - // TODO: convert to plain after_id params of some sort instead of cursor - params.cursor = { - created_at: lastComment.createdAt, - id: lastComment.id, - votes_count: lastComment.votesCount, - }; + params.after = lastComment.id; } this.xhr = $.ajax(route('comments.index'), { data: params, dataType: 'json' }); From 7fd2bc21409af441ff8a33a7edf0ce36663583fe Mon Sep 17 00:00:00 2001 From: nanaya Date: Thu, 27 Jul 2023 22:15:23 +0900 Subject: [PATCH 3/5] Fix contest rank number when filtered (again) --- resources/js/contest-voting/art-entry-list.coffee | 7 ++++--- resources/js/contest-voting/art-entry.coffee | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/js/contest-voting/art-entry-list.coffee b/resources/js/contest-voting/art-entry-list.coffee index 1856fe25cf2..1cb255a08a5 100644 --- a/resources/js/contest-voting/art-entry-list.coffee +++ b/resources/js/contest-voting/art-entry-list.coffee @@ -14,8 +14,8 @@ export class ArtEntryList extends BaseEntryList selected = new Set(@state.selected) - displayIndex = -1 - entries = @state.contest.entries.map (entry) => + galleryIndex = -1 + entries = @state.contest.entries.map (entry, index) => isSelected = selected.has(entry.id) return null if @state.showVotedOnly && !isSelected @@ -23,7 +23,8 @@ export class ArtEntryList extends BaseEntryList el ArtEntry, key: entry.id, contest: @state.contest, - displayIndex: ++displayIndex, + galleryIndex: ++galleryIndex, + index: index entry: entry, isSelected: isSelected options: @state.options, diff --git a/resources/js/contest-voting/art-entry.coffee b/resources/js/contest-voting/art-entry.coffee index c0ae5e9eb5d..a18cecd9dcd 100644 --- a/resources/js/contest-voting/art-entry.coffee +++ b/resources/js/contest-voting/art-entry.coffee @@ -22,11 +22,11 @@ export class ArtEntry extends React.Component showUserLink = @props.entry.user?.id? thumbnailShape = @props.contest.thumbnail_shape galleryId = "contest-#{@props.contest.id}" - buttonId = "#{galleryId}:#{@props.displayIndex}" + buttonId = "#{galleryId}:#{@props.index}" hideVoteButton = (@props.selected.length >= @props.contest.max_votes || votingOver) && !isSelected if showVotes - place = @props.displayIndex + 1 + place = @props.index + 1 top3 = place <= 3 usersVotedPercentage = _.round((@props.entry.results.votes / @props.contest.users_voted_count)*100, 2) @@ -39,7 +39,7 @@ export class ArtEntry extends React.Component entryLinkProps['data-width'] = @props.entry.artMeta.width entryLinkProps['data-height'] = @props.entry.artMeta.height entryLinkProps['data-gallery-id'] = galleryId - entryLinkProps['data-index'] = @props.displayIndex + entryLinkProps['data-index'] = @props.galleryIndex entryLinkProps['data-button-id'] = buttonId else entryLinkProps.rel = 'nofollow noreferrer' From 9d79208c6c063049693535e62d1b40e03f57ffc8 Mon Sep 17 00:00:00 2001 From: nanaya Date: Thu, 27 Jul 2023 22:22:46 +0900 Subject: [PATCH 4/5] Using consistent id is probably fine...? --- resources/js/contest-voting/art-entry.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/contest-voting/art-entry.coffee b/resources/js/contest-voting/art-entry.coffee index a18cecd9dcd..4df767e8754 100644 --- a/resources/js/contest-voting/art-entry.coffee +++ b/resources/js/contest-voting/art-entry.coffee @@ -22,7 +22,7 @@ export class ArtEntry extends React.Component showUserLink = @props.entry.user?.id? thumbnailShape = @props.contest.thumbnail_shape galleryId = "contest-#{@props.contest.id}" - buttonId = "#{galleryId}:#{@props.index}" + buttonId = "#{galleryId}:#{@props.entry.id}" hideVoteButton = (@props.selected.length >= @props.contest.max_votes || votingOver) && !isSelected if showVotes From fc6034fd30cd6b799e3b6008bcfaeb25c4881c7a Mon Sep 17 00:00:00 2001 From: nanaya Date: Thu, 27 Jul 2023 22:49:56 +0900 Subject: [PATCH 5/5] Use updated index name --- resources/js/contest-voting/art-entry-list.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/contest-voting/art-entry-list.coffee b/resources/js/contest-voting/art-entry-list.coffee index 1cb255a08a5..c1c1f80cb28 100644 --- a/resources/js/contest-voting/art-entry-list.coffee +++ b/resources/js/contest-voting/art-entry-list.coffee @@ -33,7 +33,7 @@ export class ArtEntryList extends BaseEntryList if @state.contest.show_votes partitions = _.partition entries, (i) -> - i != null && i.props.displayIndex < 3 + i != null && i.props.index < 3 div className: 'contest__art-list', div className: 'contest__vote-summary--art',