Fix #5057: Modqueue: filtering by tag breaks ordering

Fix the order dropdown box on the modqueue page not working when filtering by tag.

This happened because when you do a tag search, the default order is set to `ORDER BY posts.id DESC`.
When you applied another order with the dropdown box, the new order would be tacked on to the old
ordering as a tiebreaker instead of replacing it, producing e.g. `ORDER BY posts.id DESC, queued_at DESC`
instead of `ORDER BY queued_at DESC`. The default order would always win because `posts.id` is
unique and doesn't have ties.

The fix is to have orders always override the previous order instead of adding to it.

Note that now if you use an `order:`, `ordfav:`, or `ordpool:` metatag in the search box on the
modqueue page, they will always be ignored in favor of the dropdown box.
This commit is contained in:
evazion
2022-09-27 22:51:16 -05:00
parent 91c8038685
commit 59f166a637
2 changed files with 55 additions and 44 deletions

View File

@@ -274,7 +274,7 @@ class PostQueryBuilder
else
relation = relation.none
end
elsif post_query.has_metatag?(:ordfav)
elsif post_query.has_metatag?(:ordfav, :ordpool, :ordfavgroup)
# no-op
else
relation = search_order(relation, post_query.find_metatag(:order))
@@ -340,135 +340,135 @@ class PostQueryBuilder
def search_order(relation, order)
case order.to_s.downcase
when "id", "id_asc"
relation = relation.order("posts.id ASC")
relation = relation.reorder("posts.id ASC")
when "id_desc"
relation = relation.order("posts.id DESC")
relation = relation.reorder("posts.id DESC")
when "md5", "md5_desc"
relation = relation.order("posts.md5 DESC")
relation = relation.reorder("posts.md5 DESC")
when "md5_asc"
relation = relation.order("posts.md5 ASC")
relation = relation.reorder("posts.md5 ASC")
when "score", "score_desc"
relation = relation.order("posts.score DESC, posts.id DESC")
relation = relation.reorder("posts.score DESC, posts.id DESC")
when "score_asc"
relation = relation.order("posts.score ASC, posts.id ASC")
relation = relation.reorder("posts.score ASC, posts.id ASC")
when "upvotes", "upvotes_desc"
relation = relation.order("posts.up_score DESC, posts.id DESC")
relation = relation.reorder("posts.up_score DESC, posts.id DESC")
when "upvotes_asc"
relation = relation.order("posts.up_score ASC, posts.id ASC")
relation = relation.reorder("posts.up_score ASC, posts.id ASC")
# XXX down_score is negative so order:downvotes sorts lowest-to-highest so that most downvoted is first.
when "downvotes", "downvotes_desc"
relation = relation.order("posts.down_score ASC, posts.id ASC")
relation = relation.reorder("posts.down_score ASC, posts.id ASC")
when "downvotes_asc"
relation = relation.order("posts.down_score DESC, posts.id DESC")
relation = relation.reorder("posts.down_score DESC, posts.id DESC")
when "favcount"
relation = relation.order("posts.fav_count DESC, posts.id DESC")
relation = relation.reorder("posts.fav_count DESC, posts.id DESC")
when "favcount_asc"
relation = relation.order("posts.fav_count ASC, posts.id ASC")
relation = relation.reorder("posts.fav_count ASC, posts.id ASC")
when "created_at", "created_at_desc"
relation = relation.order("posts.created_at DESC")
relation = relation.reorder("posts.created_at DESC")
when "created_at_asc"
relation = relation.order("posts.created_at ASC")
relation = relation.reorder("posts.created_at ASC")
when "change", "change_desc"
relation = relation.order("posts.updated_at DESC, posts.id DESC")
relation = relation.reorder("posts.updated_at DESC, posts.id DESC")
when "change_asc"
relation = relation.order("posts.updated_at ASC, posts.id ASC")
relation = relation.reorder("posts.updated_at ASC, posts.id ASC")
when "comment", "comm"
relation = relation.order("posts.last_commented_at DESC NULLS LAST, posts.id DESC")
relation = relation.reorder("posts.last_commented_at DESC NULLS LAST, posts.id DESC")
when "comment_asc", "comm_asc"
relation = relation.order("posts.last_commented_at ASC NULLS LAST, posts.id ASC")
relation = relation.reorder("posts.last_commented_at ASC NULLS LAST, posts.id ASC")
when "comment_bumped"
relation = relation.order("posts.last_comment_bumped_at DESC NULLS LAST")
relation = relation.reorder("posts.last_comment_bumped_at DESC NULLS LAST")
when "comment_bumped_asc"
relation = relation.order("posts.last_comment_bumped_at ASC NULLS FIRST")
relation = relation.reorder("posts.last_comment_bumped_at ASC NULLS FIRST")
when "note"
relation = relation.order("posts.last_noted_at DESC NULLS LAST")
relation = relation.reorder("posts.last_noted_at DESC NULLS LAST")
when "note_asc"
relation = relation.order("posts.last_noted_at ASC NULLS FIRST")
relation = relation.reorder("posts.last_noted_at ASC NULLS FIRST")
when "artcomm"
relation = relation.joins("INNER JOIN artist_commentaries ON artist_commentaries.post_id = posts.id")
relation = relation.order("artist_commentaries.updated_at DESC")
relation = relation.reorder("artist_commentaries.updated_at DESC")
when "artcomm_asc"
relation = relation.joins("INNER JOIN artist_commentaries ON artist_commentaries.post_id = posts.id")
relation = relation.order("artist_commentaries.updated_at ASC")
relation = relation.reorder("artist_commentaries.updated_at ASC")
when "mpixels", "mpixels_desc"
relation = relation.where(Arel.sql("posts.image_width is not null and posts.image_height is not null"))
# Use "w*h/1000000", even though "w*h" would give the same result, so this can use
# the posts_mpixels index.
relation = relation.order(Arel.sql("posts.image_width * posts.image_height / 1000000.0 DESC"))
relation = relation.reorder(Arel.sql("posts.image_width * posts.image_height / 1000000.0 DESC"))
when "mpixels_asc"
relation = relation.where("posts.image_width is not null and posts.image_height is not null")
relation = relation.order(Arel.sql("posts.image_width * posts.image_height / 1000000.0 ASC"))
relation = relation.reorder(Arel.sql("posts.image_width * posts.image_height / 1000000.0 ASC"))
when "portrait"
relation = relation.where("posts.image_width IS NOT NULL and posts.image_height IS NOT NULL")
relation = relation.order(Arel.sql("1.0 * posts.image_width / GREATEST(1, posts.image_height) ASC"))
relation = relation.reorder(Arel.sql("1.0 * posts.image_width / GREATEST(1, posts.image_height) ASC"))
when "landscape"
relation = relation.where("posts.image_width IS NOT NULL and posts.image_height IS NOT NULL")
relation = relation.order(Arel.sql("1.0 * posts.image_width / GREATEST(1, posts.image_height) DESC"))
relation = relation.reorder(Arel.sql("1.0 * posts.image_width / GREATEST(1, posts.image_height) DESC"))
when "filesize", "filesize_desc"
relation = relation.order("posts.file_size DESC")
relation = relation.reorder("posts.file_size DESC")
when "filesize_asc"
relation = relation.order("posts.file_size ASC")
relation = relation.reorder("posts.file_size ASC")
when /\A(?<column>#{COUNT_METATAGS.join("|")})(_(?<direction>asc|desc))?\z/i
column = $~[:column]
direction = $~[:direction] || "desc"
relation = relation.order(column => direction, :id => direction)
relation = relation.reorder(column => direction, :id => direction)
when "tagcount", "tagcount_desc"
relation = relation.order("posts.tag_count DESC")
relation = relation.reorder("posts.tag_count DESC")
when "tagcount_asc"
relation = relation.order("posts.tag_count ASC")
relation = relation.reorder("posts.tag_count ASC")
when "duration", "duration_desc"
relation = relation.joins(:media_asset).order("media_assets.duration DESC NULLS LAST, posts.id DESC")
relation = relation.joins(:media_asset).reorder("media_assets.duration DESC NULLS LAST, posts.id DESC")
when "duration_asc"
relation = relation.joins(:media_asset).order("media_assets.duration ASC NULLS LAST, posts.id ASC")
relation = relation.joins(:media_asset).reorder("media_assets.duration ASC NULLS LAST, posts.id ASC")
# artags_desc, copytags_desc, chartags_desc, gentags_desc, metatags_desc
when /(#{TagCategory.short_name_list.join("|")})tags(?:\Z|_desc)/
relation = relation.order("posts.tag_count_#{TagCategory.short_name_mapping[$1]} DESC")
relation = relation.reorder("posts.tag_count_#{TagCategory.short_name_mapping[$1]} DESC")
# artags_asc, copytags_asc, chartags_asc, gentags_asc, metatags_asc
when /(#{TagCategory.short_name_list.join("|")})tags_asc/
relation = relation.order("posts.tag_count_#{TagCategory.short_name_mapping[$1]} ASC")
relation = relation.reorder("posts.tag_count_#{TagCategory.short_name_mapping[$1]} ASC")
when "random"
relation = relation.order("random()")
relation = relation.reorder("random()")
when "rank"
relation = relation.where("posts.score > 0 and posts.created_at >= ?", 2.days.ago)
relation = relation.order(Arel.sql("log(3, posts.score) + (extract(epoch from posts.created_at) - extract(epoch from timestamp '2005-05-24')) / 35000 DESC"))
relation = relation.reorder(Arel.sql("log(3, posts.score) + (extract(epoch from posts.created_at) - extract(epoch from timestamp '2005-05-24')) / 35000 DESC"))
when "curated"
contributors = User.bit_prefs_match(:can_upload_free, true)
@@ -478,19 +478,19 @@ class PostQueryBuilder
.where(favorites: { user: contributors })
.group("posts.id")
.select("posts.*, COUNT(*) AS contributor_fav_count")
.order("contributor_fav_count DESC, posts.fav_count DESC, posts.id DESC")
.reorder("contributor_fav_count DESC, posts.fav_count DESC, posts.id DESC")
when "modqueue", "modqueue_desc"
relation = relation.with_queued_at.order("queued_at DESC, posts.id DESC")
relation = relation.with_queued_at.reorder("queued_at DESC, posts.id DESC")
when "modqueue_asc"
relation = relation.with_queued_at.order("queued_at ASC, posts.id ASC")
relation = relation.with_queued_at.reorder("queued_at ASC, posts.id ASC")
when "none"
relation = relation.reorder(nil)
else
relation = relation.order("posts.id DESC")
relation = relation.reorder("posts.id DESC")
end
relation

View File

@@ -26,6 +26,17 @@ class ModqueueControllerTest < ActionDispatch::IntegrationTest
assert_equal([{ "rating" => @post.rating }], response.parsed_body)
end
should "order posts correctly when searching for tags" do
post1 = create(:post, tag_string: "touhou", is_pending: true, score: 5)
post2 = create(:post, tag_string: "touhou", is_pending: true, score: 10)
post3 = create(:post, tag_string: "touhou", is_pending: true, score: 15)
get_auth modqueue_index_path(search: { tags: "touhou", order: "score_asc" }), @admin, as: :json
assert_response :success
assert_equal([post1.id, post2.id, post3.id], response.parsed_body.pluck("id"))
end
should "include appealed posts in the modqueue" do
@appeal = create(:post_appeal)
get_auth modqueue_index_path, @admin