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 else
relation = relation.none relation = relation.none
end end
elsif post_query.has_metatag?(:ordfav) elsif post_query.has_metatag?(:ordfav, :ordpool, :ordfavgroup)
# no-op # no-op
else else
relation = search_order(relation, post_query.find_metatag(:order)) relation = search_order(relation, post_query.find_metatag(:order))
@@ -340,135 +340,135 @@ class PostQueryBuilder
def search_order(relation, order) def search_order(relation, order)
case order.to_s.downcase case order.to_s.downcase
when "id", "id_asc" when "id", "id_asc"
relation = relation.order("posts.id ASC") relation = relation.reorder("posts.id ASC")
when "id_desc" when "id_desc"
relation = relation.order("posts.id DESC") relation = relation.reorder("posts.id DESC")
when "md5", "md5_desc" when "md5", "md5_desc"
relation = relation.order("posts.md5 DESC") relation = relation.reorder("posts.md5 DESC")
when "md5_asc" when "md5_asc"
relation = relation.order("posts.md5 ASC") relation = relation.reorder("posts.md5 ASC")
when "score", "score_desc" 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" 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" 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" 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. # XXX down_score is negative so order:downvotes sorts lowest-to-highest so that most downvoted is first.
when "downvotes", "downvotes_desc" 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" 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" 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" 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" when "created_at", "created_at_desc"
relation = relation.order("posts.created_at DESC") relation = relation.reorder("posts.created_at DESC")
when "created_at_asc" when "created_at_asc"
relation = relation.order("posts.created_at ASC") relation = relation.reorder("posts.created_at ASC")
when "change", "change_desc" 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" 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" 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" 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" 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" 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" 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" 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" when "artcomm"
relation = relation.joins("INNER JOIN artist_commentaries ON artist_commentaries.post_id = posts.id") 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" when "artcomm_asc"
relation = relation.joins("INNER JOIN artist_commentaries ON artist_commentaries.post_id = posts.id") 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" when "mpixels", "mpixels_desc"
relation = relation.where(Arel.sql("posts.image_width is not null and posts.image_height is not null")) 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 # Use "w*h/1000000", even though "w*h" would give the same result, so this can use
# the posts_mpixels index. # 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" when "mpixels_asc"
relation = relation.where("posts.image_width is not null and posts.image_height is not null") 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" when "portrait"
relation = relation.where("posts.image_width IS NOT NULL and posts.image_height IS NOT NULL") 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" when "landscape"
relation = relation.where("posts.image_width IS NOT NULL and posts.image_height IS NOT NULL") 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" when "filesize", "filesize_desc"
relation = relation.order("posts.file_size DESC") relation = relation.reorder("posts.file_size DESC")
when "filesize_asc" 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 when /\A(?<column>#{COUNT_METATAGS.join("|")})(_(?<direction>asc|desc))?\z/i
column = $~[:column] column = $~[:column]
direction = $~[:direction] || "desc" direction = $~[:direction] || "desc"
relation = relation.order(column => direction, :id => direction) relation = relation.reorder(column => direction, :id => direction)
when "tagcount", "tagcount_desc" when "tagcount", "tagcount_desc"
relation = relation.order("posts.tag_count DESC") relation = relation.reorder("posts.tag_count DESC")
when "tagcount_asc" when "tagcount_asc"
relation = relation.order("posts.tag_count ASC") relation = relation.reorder("posts.tag_count ASC")
when "duration", "duration_desc" 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" 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 # artags_desc, copytags_desc, chartags_desc, gentags_desc, metatags_desc
when /(#{TagCategory.short_name_list.join("|")})tags(?:\Z|_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 # artags_asc, copytags_asc, chartags_asc, gentags_asc, metatags_asc
when /(#{TagCategory.short_name_list.join("|")})tags_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" when "random"
relation = relation.order("random()") relation = relation.reorder("random()")
when "rank" when "rank"
relation = relation.where("posts.score > 0 and posts.created_at >= ?", 2.days.ago) 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" when "curated"
contributors = User.bit_prefs_match(:can_upload_free, true) contributors = User.bit_prefs_match(:can_upload_free, true)
@@ -478,19 +478,19 @@ class PostQueryBuilder
.where(favorites: { user: contributors }) .where(favorites: { user: contributors })
.group("posts.id") .group("posts.id")
.select("posts.*, COUNT(*) AS contributor_fav_count") .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" 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" 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" when "none"
relation = relation.reorder(nil) relation = relation.reorder(nil)
else else
relation = relation.order("posts.id DESC") relation = relation.reorder("posts.id DESC")
end end
relation relation

View File

@@ -26,6 +26,17 @@ class ModqueueControllerTest < ActionDispatch::IntegrationTest
assert_equal([{ "rating" => @post.rating }], response.parsed_body) assert_equal([{ "rating" => @post.rating }], response.parsed_body)
end 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 should "include appealed posts in the modqueue" do
@appeal = create(:post_appeal) @appeal = create(:post_appeal)
get_auth modqueue_index_path, @admin get_auth modqueue_index_path, @admin