diff --git a/app/logical/concerns/searchable.rb b/app/logical/concerns/searchable.rb index 37813e40f..1740cce95 100644 --- a/app/logical/concerns/searchable.rb +++ b/app/logical/concerns/searchable.rb @@ -1,6 +1,15 @@ module Searchable extend ActiveSupport::Concern + def parameter_hash?(params) + params.present? && params.respond_to?(:each) + end + + def parameter_depth(params) + return 0 if params.values.empty? + 1 + params.values.map { |v| parameter_hash?(v) ? parameter_depth(v) : 1 }.max + end + def negate(kind = :nand) unscoped.where(all.where_clause.invert(kind).ast) end @@ -139,8 +148,13 @@ module Searchable end def search_attributes(params, *attributes) + raise ArgumentError, "max parameter depth of 10 exceeded" if parameter_depth(params) > 10 + + # This allows the hash keys to be either strings or symbols + indifferent_params = params.try(:with_indifferent_access) || params.try(:to_unsafe_h) + raise ArgumentError, "unable to process params" if indifferent_params.nil? attributes.reduce(all) do |relation, attribute| - relation.search_attribute(attribute, params) + relation.search_attribute(attribute, indifferent_params) end end @@ -159,7 +173,9 @@ module Searchable when "User" search_user_attribute(name, params) when "Post" - search_post_id_attribute(params) + search_post_attribute(name, params) + when "Model" + search_polymorphic_attribute(name, params) when :string, :text search_text_attribute(name, params) when :boolean @@ -173,7 +189,8 @@ module Searchable when :array search_array_attribute(name, subtype, params) else - raise NotImplementedError, "unhandled attribute type: #{name}" + raise NotImplementedError, "unhandled attribute type: #{name}" if type.blank? + search_includes(name, params, type) end end @@ -214,26 +231,56 @@ module Searchable end def search_user_attribute(attr, params) - if params["#{attr}_id"] - search_attribute("#{attr}_id", params) - elsif params["#{attr}_name"] + if params["#{attr}_name"].present? where(attr => User.search(name_matches: params["#{attr}_name"]).reorder(nil)) - elsif params[attr] - where(attr => User.search(params[attr]).reorder(nil)) + else + search_includes(attr, params, "User") + end + end + + def search_post_attribute(attr, params) + if params["#{attr}_tags_match"] + where(attr => Post.user_tag_match(params["#{attr}_tags_match"]).reorder(nil)) + else + search_includes(attr, params, "Post") + end + end + + def search_includes(attr, params, type) + model = Kernel.const_get(type) + if params["#{attr}_id"].present? + search_attribute("#{attr}_id", params) + elsif params["has_#{attr}"].to_s.truthy? || params["has_#{attr}"].to_s.falsy? + search_has_include(attr, params["has_#{attr}"].to_s.truthy?, model) + elsif parameter_hash?(params[attr]) + where(attr => model.search(params[attr]).reorder(nil)) else all end end - def search_post_id_attribute(params) - relation = all + def search_polymorphic_attribute(attr, params) + model_keys = ((model_types || []) & params.keys) + # The user can only logically specify one model at a time, so more than that should return no results + return none if model_keys.length > 1 - if params[:post_id].present? - relation = relation.search_attribute(:post_id, params) + relation = all + model_specified = false + model_key = model_keys[0] + if model_keys.length == 1 && parameter_hash?(params[model_key]) + # Returning none here for the same reason specified above + return none if params["#{attr}_type"].present? && params["#{attr}_type"] != model_key + model_specified = true + model = Kernel.const_get(model_key) + relation = relation.where(attr => model.search(params[model_key])) end - if params[:post_tags_match].present? - relation = relation.where(post_id: Post.user_tag_match(params[:post_tags_match]).reorder(nil)) + if params["#{attr}_id"].present? + relation = relation.search_attribute("#{attr}_id", params) + end + + if params["#{attr}_type"].present? && !model_specified + relation = relation.search_attribute("#{attr}_type", params) end relation @@ -292,6 +339,28 @@ module Searchable relation end + def search_has_include(name, exists, model) + if column_names.include?("#{name}_id") + return exists ? where.not("#{name}_id" => nil) : where("#{name}_id" => nil) + end + + association = reflect_on_association(name) + primary_key = association.active_record_primary_key + foreign_key = association.foreign_key + # The belongs_to macro has its primary and foreign keys reversed + primary_key, foreign_key = foreign_key, primary_key if association.macro == :belongs_to + return all if primary_key.nil? || foreign_key.nil? + + self_table = arel_table + model_table = model.arel_table + model_exists = model.model_restriction(model_table).where(model_table[foreign_key].eq(self_table[primary_key])).exists + if exists + attribute_restriction(name).where(model_exists) + else + attribute_restriction(name).where.not(model_exists) + end + end + def apply_default_order(params) if params[:order] == "custom" parse_ids = PostQueryBuilder.new(nil).parse_range(params[:id], :integer) @@ -319,7 +388,8 @@ module Searchable params ||= {} default_attributes = (attribute_names.map(&:to_sym) & %i[id created_at updated_at]) - search_attributes(params, *default_attributes) + all_attributes = default_attributes + searchable_includes + search_attributes(params, *all_attributes) end private diff --git a/app/models/application_record.rb b/app/models/application_record.rb index bd366d214..ec5af12fe 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -93,6 +93,22 @@ class ApplicationRecord < ActiveRecord::Base end end + concerning :SearchMethods do + class_methods do + def searchable_includes + [] + end + + def model_restriction(table) + table.project(1) + end + + def attribute_restriction(*) + all + end + end + end + concerning :ActiveRecordExtensions do class_methods do def without_timeout diff --git a/app/models/artist.rb b/app/models/artist.rb index e40820fef..dccde5f68 100644 --- a/app/models/artist.rb +++ b/app/models/artist.rb @@ -266,12 +266,6 @@ class Artist < ApplicationRecord q = q.url_matches(params[:url_matches]) end - if params[:has_tag].to_s.truthy? - q = q.where(name: Tag.nonempty.select(:name)) - elsif params[:has_tag].to_s.falsy? - q = q.where.not(name: Tag.nonempty.select(:name)) - end - case params[:order] when "name" q = q.order("artists.name") @@ -295,6 +289,14 @@ class Artist < ApplicationRecord include BanMethods extend SearchMethods + def self.model_restriction(table) + super.where(table[:is_deleted].eq(false)) + end + + def self.searchable_includes + [:urls, :wiki_page, :tag_alias, :tag] + end + def self.available_includes [:members, :urls, :wiki_page, :tag_alias, :tag] end diff --git a/app/models/artist_commentary.rb b/app/models/artist_commentary.rb index 64cf215a9..d94939d22 100644 --- a/app/models/artist_commentary.rb +++ b/app/models/artist_commentary.rb @@ -33,7 +33,7 @@ class ArtistCommentary < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :post, :original_title, :original_description, :translated_title, :translated_description) + q = q.search_attributes(params, :original_title, :original_description, :translated_title, :translated_description) if params[:text_matches].present? q = q.text_matches(params[:text_matches]) @@ -146,6 +146,10 @@ class ArtistCommentary < ApplicationRecord extend SearchMethods include VersionMethods + def self.searchable_includes + [:post] + end + def self.available_includes [:post] end diff --git a/app/models/artist_commentary_version.rb b/app/models/artist_commentary_version.rb index d052810e8..1bf34aa02 100644 --- a/app/models/artist_commentary_version.rb +++ b/app/models/artist_commentary_version.rb @@ -2,9 +2,23 @@ class ArtistCommentaryVersion < ApplicationRecord belongs_to :post belongs_to_updater + def self.text_matches(query) + query = "*#{query}*" unless query =~ /\*/ + + where_ilike(:original_title, query) + .or(where_ilike(:original_description, query)) + .or(where_ilike(:translated_title, query)) + .or(where_ilike(:translated_description, query)) + end + def self.search(params) q = super - q = q.search_attributes(params, :post, :updater, :original_title, :original_description, :translated_title, :translated_description) + q = q.search_attributes(params, :original_title, :original_description, :translated_title, :translated_description) + + if params[:text_matches].present? + q = q.text_matches(params[:text_matches]) + end + q.apply_default_order(params) end @@ -42,6 +56,10 @@ class ArtistCommentaryVersion < ApplicationRecord self[field].strip.empty? && (previous.nil? || previous[field].strip.empty?) end + def self.searchable_includes + [:post, :updater] + end + def self.available_includes [:post, :updater] end diff --git a/app/models/artist_url.rb b/app/models/artist_url.rb index b4e4d9af5..1119305a5 100644 --- a/app/models/artist_url.rb +++ b/app/models/artist_url.rb @@ -42,9 +42,8 @@ class ArtistUrl < ApplicationRecord def self.search(params = {}) q = super - q = q.search_attributes(params, :url, :normalized_url, :artist_id, :is_active) + q = q.search_attributes(params, :url, :normalized_url, :is_active) - q = q.artist_matches(params[:artist]) q = q.url_matches(params[:url_matches]) q = q.normalized_url_matches(params[:normalized_url_matches]) @@ -59,11 +58,6 @@ class ArtistUrl < ApplicationRecord q end - def self.artist_matches(params = {}) - return all if params.blank? - where(artist_id: Artist.search(params).reorder(nil)) - end - def self.url_attribute_matches(attr, url) if url.blank? all @@ -134,6 +128,10 @@ class ArtistUrl < ApplicationRecord errors[:url] << "'#{uri}' is malformed: #{error}" end + def self.searchable_includes + [:artist] + end + def self.available_includes [:artist] end diff --git a/app/models/artist_version.rb b/app/models/artist_version.rb index bcd08fa2b..19d608e6b 100644 --- a/app/models/artist_version.rb +++ b/app/models/artist_version.rb @@ -9,7 +9,9 @@ class ArtistVersion < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :updater, :is_deleted, :is_banned, :artist_id, :name, :group_name) + q = q.search_attributes(params, :is_deleted, :is_banned, :name, :group_name, :urls, :other_names) + q = q.text_attribute_matches(:name, params[:name_matches]) + q = q.text_attribute_matches(:group_name, params[:group_name_matches]) if params[:order] == "name" q = q.order("artist_versions.name").default_order @@ -103,6 +105,10 @@ class ArtistVersion < ApplicationRecord end end + def self.searchable_includes + [:updater, :artist] + end + def self.available_includes [:updater, :artist] end diff --git a/app/models/ban.rb b/app/models/ban.rb index 7b2ece40d..4af738b30 100644 --- a/app/models/ban.rb +++ b/app/models/ban.rb @@ -22,7 +22,7 @@ class Ban < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :banner, :user, :expires_at, :reason) + q = q.search_attributes(params, :expires_at, :reason) q = q.text_attribute_matches(:reason, params[:reason_matches]) q = q.expired if params[:expired].to_s.truthy? @@ -97,6 +97,10 @@ class Ban < ApplicationRecord ModAction.log(%{Unbanned <@#{user_name}>}, :user_unban) end + def self.searchable_includes + [:user, :banner] + end + def self.available_includes [:user, :banner] end diff --git a/app/models/bulk_update_request.rb b/app/models/bulk_update_request.rb index 6909728a6..2070dc1db 100644 --- a/app/models/bulk_update_request.rb +++ b/app/models/bulk_update_request.rb @@ -35,7 +35,7 @@ class BulkUpdateRequest < ApplicationRecord def search(params = {}) q = super - q = q.search_attributes(params, :user, :approver, :forum_topic_id, :forum_post_id, :script, :tags) + q = q.search_attributes(params, :script, :tags) q = q.text_attribute_matches(:script, params[:script_matches]) if params[:status].present? @@ -152,6 +152,10 @@ class BulkUpdateRequest < ApplicationRecord status == "rejected" end + def self.searchable_includes + [:user, :forum_topic, :forum_post, :approver] + end + def self.available_includes [:user, :forum_topic, :forum_post, :approver] end diff --git a/app/models/comment.rb b/app/models/comment.rb index a402fcbc2..ade9a8073 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -28,7 +28,7 @@ class Comment < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :post, :creator, :updater, :is_deleted, :is_sticky, :do_not_bump_post, :body, :score) + q = q.search_attributes(params, :is_deleted, :is_sticky, :do_not_bump_post, :body, :score) q = q.text_attribute_matches(:body, params[:body_matches], index_column: :body_index) case params[:order] @@ -140,6 +140,10 @@ class Comment < ApplicationRecord DText.quote(body, creator.name) end + def self.searchable_includes + [:post, :creator, :updater] + end + def self.available_includes [:post, :creator, :updater] end diff --git a/app/models/comment_vote.rb b/app/models/comment_vote.rb index 0cfea7c16..ec1a5ce11 100644 --- a/app/models/comment_vote.rb +++ b/app/models/comment_vote.rb @@ -18,15 +18,9 @@ class CommentVote < ApplicationRecord end end - def self.comment_matches(params) - return all if params.blank? - where(comment_id: Comment.search(params).reorder(nil).select(:id)) - end - def self.search(params) q = super - q = q.search_attributes(params, :comment_id, :user, :score) - q = q.comment_matches(params[:comment]) + q = q.search_attributes(params, :score) q.apply_default_order(params) end @@ -44,6 +38,10 @@ class CommentVote < ApplicationRecord score == -1 end + def self.searchable_includes + [:comment, :user] + end + def self.available_includes [:comment, :user] end diff --git a/app/models/dmail.rb b/app/models/dmail.rb index 25c053213..54b167242 100644 --- a/app/models/dmail.rb +++ b/app/models/dmail.rb @@ -98,7 +98,7 @@ class Dmail < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :to, :from, :is_read, :is_deleted, :title, :body) + q = q.search_attributes(params, :is_read, :is_deleted, :title, :body) q = q.text_attribute_matches(:title, params[:title_matches]) q = q.text_attribute_matches(:body, params[:message_matches], index_column: :message_index) @@ -172,6 +172,10 @@ class Dmail < ApplicationRecord key ? "dmail ##{id}/#{self.key}" : "dmail ##{id}" end + def self.searchable_includes + [:to, :from] + end + def self.available_includes [:owner, :to, :from] end diff --git a/app/models/dtext_link.rb b/app/models/dtext_link.rb index 08df3bc23..ea4902d53 100644 --- a/app/models/dtext_link.rb +++ b/app/models/dtext_link.rb @@ -1,6 +1,7 @@ class DtextLink < ApplicationRecord belongs_to :model, polymorphic: true belongs_to :linked_wiki, primary_key: :title, foreign_key: :link_target, class_name: "WikiPage", optional: true + belongs_to :linked_tag, primary_key: :name, foreign_key: :link_target, class_name: "Tag", optional: true enum link_type: [:wiki_link, :external_link] @@ -28,43 +29,9 @@ class DtextLink < ApplicationRecord links end - def self.model_matches(params) - return all if params.blank? - where(model_type: "WikiPage", model_id: WikiPage.search(params).reorder(nil)) - end - - def self.linked_wiki_exists(exists = true) - dtext_links = DtextLink.arel_table - wiki_pages = WikiPage.arel_table - wiki_exists = wiki_pages.project(1).where(wiki_pages[:is_deleted].eq(false)).where(wiki_pages[:title].eq(dtext_links[:link_target])).exists - - if exists - where(link_type: :wiki_link).where(wiki_exists) - else - where(link_type: :wiki_link).where.not(wiki_exists) - end - end - - def self.linked_tag_exists(exists = true) - dtext_links = DtextLink.arel_table - tags = Tag.arel_table - tag_exists = tags.project(1).where(tags[:post_count].gt(0)).where(tags[:name].eq(dtext_links[:link_target])).exists - - if exists - where(link_type: :wiki_link).where(tag_exists) - else - where(link_type: :wiki_link).where.not(tag_exists) - end - end - def self.search(params) q = super - q = q.search_attributes(params, :model_type, :model_id, :link_type, :link_target) - - q = q.model_matches(params[:model]) - q = q.linked_wiki_exists(params[:linked_wiki_exists].truthy?) if params[:linked_wiki_exists].present? - q = q.linked_tag_exists(params[:linked_tag_exists].truthy?) if params[:linked_tag_exists].present? - + q = q.search_attributes(params, :link_type, :link_target) q.apply_default_order(params) end @@ -78,7 +45,15 @@ class DtextLink < ApplicationRecord self.link_target = self.link_target.truncate(2048, omission: "") end + def self.attribute_restriction(*) + where(link_type: :wiki_link) + end + + def self.searchable_includes + [:model, :linked_wiki, :linked_tag] + end + def self.available_includes - [:model] + [:model, :linked_wiki, :linked_tag] end end diff --git a/app/models/favorite_group.rb b/app/models/favorite_group.rb index d90e0e04a..edd4d0dfe 100644 --- a/app/models/favorite_group.rb +++ b/app/models/favorite_group.rb @@ -27,7 +27,7 @@ class FavoriteGroup < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :name, :is_public, :post_ids, :creator) + q = q.search_attributes(params, :name, :is_public, :post_ids) if params[:name_matches].present? q = q.name_matches(params[:name_matches]) @@ -164,6 +164,10 @@ class FavoriteGroup < ApplicationRecord post_ids.include?(post_id) end + def self.searchable_includes + [:creator] + end + def self.available_includes [:creator] end diff --git a/app/models/forum_post.rb b/app/models/forum_post.rb index fde386242..d82c7b15f 100644 --- a/app/models/forum_post.rb +++ b/app/models/forum_post.rb @@ -32,31 +32,19 @@ class ForumPost < ApplicationRecord ) module SearchMethods - def topic_title_matches(title) - where(topic_id: ForumTopic.search(title_matches: title).select(:id)) - end - def visible(user) where(topic_id: ForumTopic.visible(user)) end def search(params) q = super - q = q.search_attributes(params, :creator, :updater, :topic_id, :is_deleted, :body) + q = q.search_attributes(params, :is_deleted, :body) q = q.text_attribute_matches(:body, params[:body_matches], index_column: :text_index) if params[:linked_to].present? q = q.where(id: DtextLink.forum_post.wiki_link.where(link_target: params[:linked_to]).select(:model_id)) end - if params[:topic_title_matches].present? - q = q.topic_title_matches(params[:topic_title_matches]) - end - - if params[:topic_category_id].present? - q = q.where(topic_id: ForumTopic.where(category_id: params[:topic_category_id])) - end - q.apply_default_order(params) end end @@ -179,6 +167,10 @@ class ForumPost < ApplicationRecord "forum ##{id}" end + def self.searchable_includes + [:creator, :updater, :topic, :dtext_links, :votes, :tag_alias, :tag_implication, :bulk_update_request] + end + def self.available_includes [:creator, :updater, :topic, :dtext_links, :votes, :tag_alias, :tag_implication, :bulk_update_request] end diff --git a/app/models/forum_post_vote.rb b/app/models/forum_post_vote.rb index fe2bcd77c..3ea592389 100644 --- a/app/models/forum_post_vote.rb +++ b/app/models/forum_post_vote.rb @@ -20,7 +20,7 @@ class ForumPostVote < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :creator, :forum_post_id, :score) + q = q.search_attributes(params, :score) q = q.forum_post_matches(params[:forum_post]) q.apply_default_order(params) end @@ -59,7 +59,11 @@ class ForumPostVote < ApplicationRecord end end + def self.searchable_includes + [:creator, :forum_post] + end + def self.available_includes - [:creator] + [:creator, :forum_post] end end diff --git a/app/models/forum_topic.rb b/app/models/forum_topic.rb index 22858c7f8..7daef04c4 100644 --- a/app/models/forum_topic.rb +++ b/app/models/forum_topic.rb @@ -19,6 +19,8 @@ class ForumTopic < ApplicationRecord has_many :moderation_reports, through: :forum_posts has_one :original_post, -> { order(id: :asc) }, class_name: "ForumPost", foreign_key: "topic_id", inverse_of: :topic has_many :bulk_update_requests, :foreign_key => "forum_topic_id" + has_many :tag_aliases, :foreign_key => "forum_topic_id" + has_many :tag_implications, :foreign_key => "forum_topic_id" validates_presence_of :title validates_associated :original_post @@ -85,7 +87,7 @@ class ForumTopic < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :creator, :updater, :is_sticky, :is_locked, :is_deleted, :category_id, :title, :response_count) + q = q.search_attributes(params, :is_sticky, :is_locked, :is_deleted, :category_id, :title, :response_count) q = q.text_attribute_matches(:title, params[:title_matches], index_column: :text_index) if params[:is_private].to_s.truthy? @@ -111,6 +113,8 @@ class ForumTopic < ApplicationRecord case params[:order] when "sticky" q = q.sticky_first + when "id" + q = q.order(id: :desc) else q = q.apply_default_order(params) end @@ -190,6 +194,10 @@ class ForumTopic < ApplicationRecord super + [:is_read?] end + def self.searchable_includes + [:creator, :updater, :forum_posts, :bulk_update_requests, :tag_aliases, :tag_implications] + end + def self.available_includes [:creator, :updater, :original_post] end diff --git a/app/models/ip_address.rb b/app/models/ip_address.rb index 0fcf5a8fb..00920ced7 100644 --- a/app/models/ip_address.rb +++ b/app/models/ip_address.rb @@ -13,7 +13,7 @@ class IpAddress < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :user, :model_type, :model_id, :ip_addr) + q = q.search_attributes(params, :ip_addr) q.order(created_at: :desc) end @@ -54,6 +54,10 @@ class IpAddress < ApplicationRecord super & attributes.keys.map(&:to_sym) end + def self.searchable_includes + [:user, :model] + end + def self.available_includes [:user, :model] end diff --git a/app/models/ip_ban.rb b/app/models/ip_ban.rb index 7772250fa..266ff0ea0 100644 --- a/app/models/ip_ban.rb +++ b/app/models/ip_ban.rb @@ -26,7 +26,8 @@ class IpBan < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :creator, :reason) + q = q.search_attributes(params, :reason) + q = q.text_attribute_matches(:reason, params[:reason_matches]) if params[:ip_addr].present? q = q.where("ip_addr = ?", params[:ip_addr]) @@ -77,6 +78,10 @@ class IpBan < ApplicationRecord super(ip_addr.strip) end + def self.searchable_includes + [:creator] + end + def self.available_includes [:creator] end diff --git a/app/models/mod_action.rb b/app/models/mod_action.rb index 73b3f58f9..430948648 100644 --- a/app/models/mod_action.rb +++ b/app/models/mod_action.rb @@ -63,7 +63,7 @@ class ModAction < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :creator, :category, :description) + q = q.search_attributes(params, :category, :description) q = q.text_attribute_matches(:description, params[:description_matches]) q.apply_default_order(params) @@ -77,6 +77,10 @@ class ModAction < ApplicationRecord create(creator: user, description: desc, category: categories[cat]) end + def self.searchable_includes + [:creator] + end + def self.available_includes [:creator] end diff --git a/app/models/moderation_report.rb b/app/models/moderation_report.rb index b45a6d86c..4fa1f77de 100644 --- a/app/models/moderation_report.rb +++ b/app/models/moderation_report.rb @@ -83,11 +83,16 @@ class ModerationReport < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :model_type, :model_id, :creator_id) + q = q.search_attributes(params, :reason) + q = q.text_attribute_matches(:reason, params[:reason_matches]) q.apply_default_order(params) end + def self.searchable_includes + [:creator, :model] + end + def self.available_includes [:creator, :model] end diff --git a/app/models/note.rb b/app/models/note.rb index 9dd89362e..4facb2028 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -16,7 +16,7 @@ class Note < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :post, :is_active, :x, :y, :width, :height, :body, :version) + q = q.search_attributes(params, :is_active, :x, :y, :width, :height, :body, :version) q = q.text_attribute_matches(:body, params[:body_matches], index_column: :body_index) q.apply_default_order(params) @@ -129,6 +129,10 @@ class Note < ApplicationRecord new_note.save end + def self.searchable_includes + [:post] + end + def self.available_includes [:post] end diff --git a/app/models/note_version.rb b/app/models/note_version.rb index d8655f995..d8c3aed07 100644 --- a/app/models/note_version.rb +++ b/app/models/note_version.rb @@ -6,7 +6,7 @@ class NoteVersion < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :updater, :is_active, :post, :note_id, :x, :y, :width, :height, :body, :version) + q = q.search_attributes(params, :is_active, :x, :y, :width, :height, :body, :version) q = q.text_attribute_matches(:body, params[:body_matches]) q.apply_default_order(params) @@ -71,6 +71,10 @@ class NoteVersion < ApplicationRecord end end + def self.searchable_includes + [:updater, :note, :post] + end + def self.available_includes [:updater, :note, :post] end diff --git a/app/models/pixiv_ugoira_frame_data.rb b/app/models/pixiv_ugoira_frame_data.rb index 2bfe5af3d..92c1eba2b 100644 --- a/app/models/pixiv_ugoira_frame_data.rb +++ b/app/models/pixiv_ugoira_frame_data.rb @@ -4,13 +4,17 @@ class PixivUgoiraFrameData < ApplicationRecord serialize :data before_validation :normalize_data, on: :create + def self.searchable_includes + [:post] + end + def self.available_includes [:post] end def self.search(params) q = super - q = q.search_attributes(params, :post, :data, :content_type) + q = q.search_attributes(params, :data, :content_type) q.apply_default_order(params) end diff --git a/app/models/post.rb b/app/models/post.rb index 93cbfa75c..b01b4979a 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1291,12 +1291,12 @@ class Post < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, - :approver, :uploader, :rating, :source, :pixiv_id, :fav_count, :score, :up_score, - :down_score, :md5, :file_ext, :file_size, :image_width, :image_height, :tag_count, - :parent, :has_children, :has_active_children, :is_note_locked, :is_rating_locked, - :is_status_locked, :is_pending, :is_flagged, :is_deleted, :is_banned, - :last_comment_bumped_at, :last_commented_at, :last_noted_at + q = q.search_attributes( + params, + :rating, :source, :pixiv_id, :fav_count, :score, :up_score, :down_score, :md5, :file_ext, + :file_size, :image_width, :image_height, :tag_count, :has_children, :has_active_children, + :is_note_locked, :is_rating_locked, :is_status_locked, :is_pending, :is_flagged, :is_deleted, + :is_banned, :last_comment_bumped_at, :last_commented_at, :last_noted_at ) if params[:tags].present? @@ -1508,6 +1508,14 @@ class Post < ApplicationRecord super + [:has_large?, :current_image_size] end + def self.model_restriction(table) + super.where(table[:is_pending].eq(false)).where(table[:is_flagged].eq(false)).where(table[:is_deleted].eq(false)) + end + + def self.searchable_includes + [:uploader, :updater, :approver, :parent, :upload, :artist_commentary, :flags, :appeals, :notes, :comments, :children, :approvals, :replacements, :pixiv_ugoira_frame_data] + end + def self.available_includes [:uploader, :updater, :approver, :parent, :upload, :artist_commentary, :flags, :appeals, :notes, :comments, :children, :approvals, :replacements, :pixiv_ugoira_frame_data] end diff --git a/app/models/post_appeal.rb b/app/models/post_appeal.rb index 84fc143aa..8c8be655a 100644 --- a/app/models/post_appeal.rb +++ b/app/models/post_appeal.rb @@ -18,7 +18,7 @@ class PostAppeal < ApplicationRecord module SearchMethods def search(params) q = super - q = q.search_attributes(params, :creator, :post, :reason, :status) + q = q.search_attributes(params, :reason, :status) q = q.text_attribute_matches(:reason, params[:reason_matches]) q.apply_default_order(params) @@ -35,6 +35,10 @@ class PostAppeal < ApplicationRecord errors[:post] << "cannot be appealed" if post.is_status_locked? || !post.is_appealable? end + def self.searchable_includes + [:creator, :post] + end + def self.available_includes [:creator, :post] end diff --git a/app/models/post_approval.rb b/app/models/post_approval.rb index b2efa6437..599cd1ba9 100644 --- a/app/models/post_approval.rb +++ b/app/models/post_approval.rb @@ -39,10 +39,13 @@ class PostApproval < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :user, :post) q.apply_default_order(params) end + def self.searchable_includes + [:user, :post] + end + def self.available_includes [:user, :post] end diff --git a/app/models/post_disapproval.rb b/app/models/post_disapproval.rb index fc1076d6b..0c6af91d8 100644 --- a/app/models/post_disapproval.rb +++ b/app/models/post_disapproval.rb @@ -23,7 +23,7 @@ class PostDisapproval < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :post, :user, :message, :reason) + q = q.search_attributes(params, :message, :reason) q = q.text_attribute_matches(:message, params[:message_matches]) q = q.with_message if params[:has_message].to_s.truthy? @@ -41,6 +41,10 @@ class PostDisapproval < ApplicationRecord end end + def self.searchable_includes + [:user, :post] + end + def self.available_includes [:user, :post] end diff --git a/app/models/post_flag.rb b/app/models/post_flag.rb index 852de1809..80f5b07f1 100644 --- a/app/models/post_flag.rb +++ b/app/models/post_flag.rb @@ -58,7 +58,7 @@ class PostFlag < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :post, :reason, :status) + q = q.search_attributes(params, :reason, :status) q = q.text_attribute_matches(:reason, params[:reason_matches]) if params[:creator_id].present? @@ -113,6 +113,10 @@ class PostFlag < ApplicationRecord post.uploader_id end + def self.searchable_includes + [:post] + end + def self.available_includes [:post] end diff --git a/app/models/post_replacement.rb b/app/models/post_replacement.rb index 40cbaed2d..35dd266a6 100644 --- a/app/models/post_replacement.rb +++ b/app/models/post_replacement.rb @@ -22,7 +22,7 @@ class PostReplacement < ApplicationRecord class_methods do def search(params = {}) q = super - q = q.search_attributes(params, :post, :creator, :md5, :md5_was, :file_ext, :file_ext_was, :original_url, :replacement_url) + q = q.search_attributes(params, :md5, :md5_was, :file_ext, :file_ext_was, :original_url, :replacement_url) q.apply_default_order(params) end end @@ -39,6 +39,10 @@ class PostReplacement < ApplicationRecord tags.join(" ") end + def self.searchable_includes + [:creator, :post] + end + def self.available_includes [:creator, :post] end diff --git a/app/models/post_vote.rb b/app/models/post_vote.rb index bcbcc74a2..fdc9aa896 100644 --- a/app/models/post_vote.rb +++ b/app/models/post_vote.rb @@ -20,12 +20,12 @@ class PostVote < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :post, :user, :score) + q = q.search_attributes(params, :score) q.apply_default_order(params) end def initialize_attributes - self.user_id ||= CurrentUser.user.id + self.user_id ||= CurrentUser.id if vote == "up" self.score = 1 @@ -50,6 +50,10 @@ class PostVote < ApplicationRecord end end + def self.searchable_includes + [:user, :post] + end + def self.available_includes [:user, :post] end diff --git a/app/models/tag.rb b/app/models/tag.rb index 731f2aee7..f018c2dbf 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -5,6 +5,7 @@ class Tag < ApplicationRecord has_many :consequent_aliases, -> {active}, :class_name => "TagAlias", :foreign_key => "consequent_name", :primary_key => "name" has_many :antecedent_implications, -> {active}, :class_name => "TagImplication", :foreign_key => "antecedent_name", :primary_key => "name" has_many :consequent_implications, -> {active}, :class_name => "TagImplication", :foreign_key => "consequent_name", :primary_key => "name" + has_many :dtext_links, foreign_key: :link_target, primary_key: :name validates :name, tag_name: true, uniqueness: true, on: :create validates :name, tag_name: true, on: :name @@ -284,18 +285,6 @@ class Tag < ApplicationRecord q = q.nonempty end - if params[:has_wiki].to_s.truthy? - q = q.joins(:wiki_page).merge(WikiPage.undeleted) - elsif params[:has_wiki].to_s.falsy? - q = q.left_outer_joins(:wiki_page).where("wiki_pages.title IS NULL OR wiki_pages.is_deleted = TRUE") - end - - if params[:has_artist].to_s.truthy? - q = q.joins(:artist).merge(Artist.undeleted) - elsif params[:has_artist].to_s.falsy? - q = q.left_outer_joins(:artist).where("artists.name IS NULL OR artists.is_deleted = TRUE") - end - case params[:order] when "name" q = q.order("name") @@ -355,8 +344,16 @@ class Tag < ApplicationRecord Post.system_tag_match(name) end + def self.model_restriction(table) + super.where(table[:post_count].gt(0)) + end + + def self.searchable_includes + [:wiki_page, :artist, :antecedent_alias, :consequent_aliases, :antecedent_implications, :consequent_implications, :dtext_links] + end + def self.available_includes - [:wiki_page, :artist, :antecedent_alias, :consequent_aliases, :antecedent_implications, :consequent_implications] + [:wiki_page, :artist, :antecedent_alias, :consequent_aliases, :antecedent_implications, :consequent_implications, :dtext_links] end include ApiMethods diff --git a/app/models/tag_relationship.rb b/app/models/tag_relationship.rb index 1ed46ad98..75d37571a 100644 --- a/app/models/tag_relationship.rb +++ b/app/models/tag_relationship.rb @@ -12,8 +12,8 @@ class TagRelationship < ApplicationRecord belongs_to :forum_topic, optional: true belongs_to :antecedent_tag, class_name: "Tag", foreign_key: "antecedent_name", primary_key: "name", default: -> { Tag.find_or_create_by_name(antecedent_name) } belongs_to :consequent_tag, class_name: "Tag", foreign_key: "consequent_name", primary_key: "name", default: -> { Tag.find_or_create_by_name(consequent_name) } - has_one :antecedent_wiki, through: :antecedent_tag, source: :wiki_page - has_one :consequent_wiki, through: :consequent_tag, source: :wiki_page + belongs_to :antecedent_wiki, class_name: "WikiPage", foreign_key: "antecedent_name", primary_key: "title", optional: true + belongs_to :consequent_wiki, class_name: "WikiPage", foreign_key: "antecedent_name", primary_key: "title", optional: true scope :active, -> {approved} scope :approved, -> {where(status: %w[active processing queued])} @@ -94,7 +94,7 @@ class TagRelationship < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :creator, :approver, :forum_topic_id, :forum_post_id, :antecedent_name, :consequent_name) + q = q.search_attributes(params, :antecedent_name, :consequent_name) if params[:name_matches].present? q = q.name_matches(params[:name_matches]) @@ -157,6 +157,14 @@ class TagRelationship < ApplicationRecord end end + def self.model_restriction(table) + super.where(table[:status].eq("active")) + end + + def self.searchable_includes + [:creator, :approver, :forum_post, :forum_topic, :antecedent_tag, :consequent_tag, :antecedent_wiki, :consequent_wiki] + end + def self.available_includes [:creator, :approver, :forum_post, :forum_topic, :antecedent_tag, :consequent_tag, :antecedent_wiki, :consequent_wiki] end diff --git a/app/models/upload.rb b/app/models/upload.rb index 3d46380b7..e3e8cda1a 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -184,7 +184,7 @@ class Upload < ApplicationRecord def self.search(params) q = super - q = q.search_attributes(params, :uploader, :post, :source, :rating, :parent_id, :server, :md5, :server, :file_ext, :file_size, :image_width, :image_height, :referer_url) + q = q.search_attributes(params, :source, :rating, :parent_id, :server, :md5, :server, :file_ext, :file_size, :image_width, :image_height, :referer_url) if params[:source_matches].present? q = q.where_like(:source, params[:source_matches]) @@ -225,6 +225,10 @@ class Upload < ApplicationRecord artist_commentary_title.present? || artist_commentary_desc.present? || translated_commentary_title.present? || translated_commentary_desc.present? end + def self.searchable_includes + [:uploader, :post] + end + def self.available_includes [:uploader, :post] end diff --git a/app/models/user.rb b/app/models/user.rb index afee4db2d..835e08894 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -80,7 +80,6 @@ class User < ApplicationRecord validates_presence_of :comment_threshold before_validation :normalize_blacklisted_tags before_create :promote_to_admin_if_first_user - has_many :artists, foreign_key: :creator_id has_many :artist_versions, foreign_key: :updater_id has_many :artist_commentary_versions, foreign_key: :updater_id has_many :comments, foreign_key: :creator_id @@ -91,7 +90,6 @@ class User < ApplicationRecord has_many :forum_topic_visits, dependent: :destroy has_many :visited_forum_topics, through: :forum_topic_visits, source: :forum_topic has_many :moderation_reports, as: :model - has_many :pools, foreign_key: :creator_id has_many :posts, :foreign_key => "uploader_id" has_many :post_appeals, foreign_key: :creator_id has_many :post_approvals, :dependent => :destroy @@ -105,10 +103,10 @@ class User < ApplicationRecord has_one :api_key has_one :token_bucket has_one :email_address, dependent: :destroy - has_many :notes, foreign_key: :creator_id has_many :note_versions, :foreign_key => "updater_id" has_many :dmails, -> {order("dmails.id desc")}, :foreign_key => "owner_id" has_many :saved_searches + has_many :forum_topics, :foreign_key => "creator_id" has_many :forum_posts, -> {order("forum_posts.created_at, forum_posts.id")}, :foreign_key => "creator_id" has_many :user_name_change_requests, -> {order("user_name_change_requests.created_at desc")} has_many :favorite_groups, -> {order(name: :asc)}, foreign_key: :creator_id @@ -537,7 +535,7 @@ class User < ApplicationRecord params = params.dup params[:name_matches] = params.delete(:name) if params[:name].present? - q = q.search_attributes(params, :name, :level, :inviter, :post_upload_count, :post_update_count, :note_update_count, :favorite_count) + q = q.search_attributes(params, :name, :level, :post_upload_count, :post_update_count, :note_update_count, :favorite_count) if params[:name_matches].present? q = q.where_ilike(:name, normalize_name(params[:name_matches])) @@ -606,6 +604,10 @@ class User < ApplicationRecord "<@#{name}>" end + def self.searchable_includes + [:posts, :note_versions, :artist_commentary_versions, :post_appeals, :post_approvals, :artist_versions, :comments, :wiki_page_versions, :feedback, :forum_topics, :forum_posts, :forum_post_votes, :tag_aliases, :tag_implications, :bans, :inviter] + end + def self.available_includes [:inviter] end diff --git a/app/models/user_feedback.rb b/app/models/user_feedback.rb index 90690d56a..e7ffbcb45 100644 --- a/app/models/user_feedback.rb +++ b/app/models/user_feedback.rb @@ -32,7 +32,7 @@ class UserFeedback < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :user, :creator, :category, :body, :is_deleted) + q = q.search_attributes(params, :category, :body, :is_deleted) q = q.text_attribute_matches(:body, params[:body_matches]) q.apply_default_order(params) @@ -65,6 +65,10 @@ class UserFeedback < ApplicationRecord Dmail.create_automated(:to_id => user_id, :title => "Your user record has been updated", :body => body) end + def self.searchable_includes + [:creator, :user] + end + def self.available_includes [:creator, :user] end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 73f7f8ced..f2651be56 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -48,10 +48,6 @@ class WikiPage < ApplicationRecord end end - def tag_matches(params) - where(title: Tag.search(params).select(:name).reorder(nil)) - end - def linked_to(title) where(dtext_links: DtextLink.wiki_page.wiki_link.where(link_target: normalize_title(title))) end @@ -78,10 +74,6 @@ class WikiPage < ApplicationRecord q = q.other_names_match(params[:other_names_match]) end - if params[:tag].present? - q = q.tag_matches(params[:tag]) - end - if params[:linked_to].present? q = q.linked_to(params[:linked_to]) end @@ -197,12 +189,12 @@ class WikiPage < ApplicationRecord def merge_version? prev = versions.last - prev && prev.updater_id == CurrentUser.user.id && prev.updated_at > 1.hour.ago + prev && prev.updater_id == CurrentUser.id && prev.updated_at > 1.hour.ago end def create_new_version versions.create( - :updater_id => CurrentUser.user.id, + :updater_id => CurrentUser.id, :updater_ip_addr => CurrentUser.ip_addr, :title => title, :body => body, @@ -245,6 +237,14 @@ class WikiPage < ApplicationRecord end end + def self.model_restriction(table) + super.where(table[:is_deleted].eq(false)) + end + + def self.searchable_includes + [:tag, :artist, :dtext_links] + end + def self.available_includes [:tag, :artist, :dtext_links] end diff --git a/app/models/wiki_page_version.rb b/app/models/wiki_page_version.rb index 4830b83fd..b0687b191 100644 --- a/app/models/wiki_page_version.rb +++ b/app/models/wiki_page_version.rb @@ -9,9 +9,9 @@ class WikiPageVersion < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :updater, :is_locked, :is_deleted, :wiki_page_id) - q = q.text_attribute_matches(:title, params[:title]) - q = q.text_attribute_matches(:body, params[:body]) + q = q.search_attributes(params, :title, :body, :other_names, :is_locked, :is_deleted) + q = q.text_attribute_matches(:title, params[:title_matches]) + q = q.text_attribute_matches(:body, params[:body_matches]) q.apply_default_order(params) end @@ -77,7 +77,11 @@ class WikiPageVersion < ApplicationRecord end end + def self.searchable_includes + [:updater, :wiki_page, :artist, :tag] + end + def self.available_includes - [:updater, :wiki_page, :artist] + [:updater, :wiki_page, :artist, :tag] end end diff --git a/app/views/dtext_links/index.html.erb b/app/views/dtext_links/index.html.erb index 8cc2957fd..8ec40e974 100644 --- a/app/views/dtext_links/index.html.erb +++ b/app/views/dtext_links/index.html.erb @@ -4,8 +4,8 @@ <%= f.input :link_target_ilike, label: "Link", hint: "Use * for wildcard", input_html: { value: params[:search][:link_target_ilike], data: { autocomplete: "wiki-page" } } %> <%= f.input :model_type, label: "Page Type", collection: [["Wiki Page", "WikiPage"], ["Forum Post", "ForumPost"]], include_blank: true, selected: params[:search][:model_type] %> <%= f.input :link_type, label: "Link Type", collection: [["Wiki", "0"], ["External", "1"]], include_blank: true, selected: params[:search][:link_type] %> - <%= f.input :linked_wiki_exists, label: "Wiki Exists?", collection: ["Yes", "No"], include_blank: true, selected: params[:search][:linked_wiki_exists] %> - <%= f.input :linked_tag_exists, label: "Tag Exists?", collection: ["Yes", "No"], include_blank: true, selected: params[:search][:linked_tag_exists] %> + <%= f.input :has_linked_wiki, label: "Wiki Exists?", collection: ["Yes", "No"], include_blank: true, selected: params[:search][:has_linked_wiki] %> + <%= f.input :has_linked_tag, label: "Tag Exists?", collection: ["Yes", "No"], include_blank: true, selected: params[:search][:has_linked_tag] %> <%= f.submit "Search" %> <% end %> diff --git a/app/views/forum_posts/search.html.erb b/app/views/forum_posts/search.html.erb index decceebfe..f889cd3a3 100644 --- a/app/views/forum_posts/search.html.erb +++ b/app/views/forum_posts/search.html.erb @@ -3,11 +3,15 @@

Search Forum

<%= search_form_for(forum_posts_path) do |f| %> - <%= f.input :topic_title_matches, label: "Title" %> + <%= f.simple_fields_for :topic do |pf| %> + <%= pf.input :title_matches, label: "Title" %> + <% end %> <%= f.input :body_matches, label: "Body" %> <%= f.input :creator_name, label: "Creator", input_html: { "data-autocomplete": "user" } %> <%= f.input :linked_to, label: "Tag", hint: "Find posts mentioning a tag", input_html: { "data-autocomplete": "tag" } %> - <%= f.input :topic_category_id, label: "Category", collection: ForumTopic::CATEGORIES.invert.to_a, include_blank: true %> + <%= f.simple_fields_for :topic do |pf| %> + <%= pf.input :category_id, label: "Category", collection: ForumTopic::CATEGORIES.invert.to_a, include_blank: true %> + <% end %> <%= f.submit "Search" %> <% end %> diff --git a/app/views/tags/_search.html.erb b/app/views/tags/_search.html.erb index a4fb623b6..a6a2bfbe1 100644 --- a/app/views/tags/_search.html.erb +++ b/app/views/tags/_search.html.erb @@ -3,7 +3,7 @@ <%= f.input :category, label: "Category", collection: TagCategory.canonical_mapping.to_a, include_blank: true,selected: params[:search][:category] %> <%= f.input :order, collection: [%w[Newest date], %w[Count count], %w[Name name]], include_blank: false, selected: params[:search][:order] %> <%= f.input :hide_empty, label: "Hide empty?", collection: %w[yes no], selected: params[:search][:hide_empty] %> - <%= f.input :has_wiki, label: "Has wiki?", collection: %w[yes no], include_blank: true, selected: params[:search][:has_wiki] %> + <%= f.input :has_wiki_page, label: "Has wiki?", collection: %w[yes no], include_blank: true, selected: params[:search][:has_wiki_page] %> <%= f.input :has_artist, label: "Has artist?", collection: %w[yes no], include_blank: true, selected: params[:search][:has_artist] %> <%= f.submit "Search" %> <% end %> diff --git a/test/factories/forum_post.rb b/test/factories/forum_post.rb index acc151a70..09e65918a 100644 --- a/test/factories/forum_post.rb +++ b/test/factories/forum_post.rb @@ -1,6 +1,7 @@ FactoryBot.define do factory(:forum_post) do creator + topic factory: :forum_topic body {FFaker::Lorem.sentences.join(" ")} end end diff --git a/test/factories/mod_action.rb b/test/factories/mod_action.rb index 4be3425e2..18ae08903 100644 --- a/test/factories/mod_action.rb +++ b/test/factories/mod_action.rb @@ -2,5 +2,6 @@ FactoryBot.define do factory(:mod_action) do creator :factory => :user description {"1234"} + category {"other"} end end diff --git a/test/factories/post_disapproval.rb b/test/factories/post_disapproval.rb index 55052a2b5..89f5717ef 100644 --- a/test/factories/post_disapproval.rb +++ b/test/factories/post_disapproval.rb @@ -1,7 +1,7 @@ FactoryBot.define do factory(:post_disapproval) do - user - post + user factory: :moderator_user + post factory: :post, is_pending: true reason { PostDisapproval::REASONS.sample } message { FFaker::Lorem.sentence } end diff --git a/test/factories/post_replacement.rb b/test/factories/post_replacement.rb index 119242c0a..43108423a 100644 --- a/test/factories/post_replacement.rb +++ b/test/factories/post_replacement.rb @@ -1,5 +1,6 @@ FactoryBot.define do factory(:post_replacement) do + post factory: :post, source: FFaker::Internet.http_url original_url { FFaker::Internet.http_url } replacement_url { FFaker::Internet.http_url } end diff --git a/test/factories/post_vote.rb b/test/factories/post_vote.rb index 8a360bd39..4d1e6b3b9 100644 --- a/test/factories/post_vote.rb +++ b/test/factories/post_vote.rb @@ -1,6 +1,6 @@ FactoryBot.define do factory(:post_vote) do - user + user factory: :gold_user post score { [-1, 1].sample } end diff --git a/test/factories/tag_alias.rb b/test/factories/tag_alias.rb index 3ab1efb46..c280d7dab 100644 --- a/test/factories/tag_alias.rb +++ b/test/factories/tag_alias.rb @@ -1,8 +1,8 @@ FactoryBot.define do factory :tag_alias do creator - antecedent_name {"aaa"} - consequent_name {"bbb"} + antecedent_name {"#{FFaker::Name.first_name.downcase}#{rand(1000)}"} + consequent_name {"#{FFaker::Name.first_name.downcase}#{rand(1000)}"} status {"active"} skip_secondary_validations {true} end diff --git a/test/factories/tag_implication.rb b/test/factories/tag_implication.rb index c1f0d7fd5..08677a9d2 100644 --- a/test/factories/tag_implication.rb +++ b/test/factories/tag_implication.rb @@ -1,8 +1,8 @@ FactoryBot.define do factory :tag_implication do creator - antecedent_name {"aaa"} - consequent_name {"bbb"} + antecedent_name {"#{FFaker::Name.first_name.downcase}#{rand(1000)}"} + consequent_name {"#{FFaker::Name.first_name.downcase}#{rand(1000)}"} status {"active"} skip_secondary_validations {true} end diff --git a/test/functional/artist_commentaries_controller_test.rb b/test/functional/artist_commentaries_controller_test.rb index beea52479..9698a00bd 100644 --- a/test/functional/artist_commentaries_controller_test.rb +++ b/test/functional/artist_commentaries_controller_test.rb @@ -3,43 +3,43 @@ require 'test_helper' class ArtistCommentariesControllerTest < ActionDispatch::IntegrationTest context "The artist commentaries controller" do setup do - @user = create(:user) - + @user = create(:user, id: 1000, name: "danbo", created_at: 2.weeks.ago) as(@user) do - @commentary1 = create(:artist_commentary) - @commentary2 = create(:artist_commentary) + @commentary = create(:artist_commentary, post: build(:post, id: 999, tag_string: "hakurei_reimu", uploader: @user), original_title: "ot1", translated_title: "tt1") + @other_commentary = create(:artist_commentary, translated_title: "", translated_description: "") end end context "index action" do + setup do + @deleted_commentary = create(:artist_commentary, original_title: "", original_description: "", translated_title: "", translated_description: "") + end + should "render" do get artist_commentaries_path assert_response :success end - should "render with search params" do - params = { - search: { - text_matches: @commentary1.original_title, - post_id: @commentary1.post_id, - original_present: "yes", - translated_present: "yes", - post_tags_match: @commentary1.post.tag_array.first - } - } + should respond_to_search({}).with { [@deleted_commentary, @other_commentary, @commentary] } + should respond_to_search(text_matches: "ot1").with { @commentary } + should respond_to_search(original_present: "true").with { [@other_commentary, @commentary] } + should respond_to_search(translated_present: "true").with { @commentary } + should respond_to_search(is_deleted: "yes").with { @deleted_commentary } - get artist_commentaries_path(params) - assert_response :success + context "using includes" do + should respond_to_search(post_id: 999).with { @commentary } + should respond_to_search(post_tags_match: "hakurei_reimu").with { @commentary } + should respond_to_search(post: {uploader_name: "danbo"}).with { @commentary } end end context "show action" do should "render" do - get artist_commentary_path(@commentary1.id) - assert_redirected_to(@commentary1.post) + get artist_commentary_path(@commentary.id) + assert_redirected_to(@commentary.post) - get artist_commentary_path(post_id: @commentary1.post_id) - assert_redirected_to(@commentary1.post) + get artist_commentary_path(post_id: @commentary.post_id) + assert_redirected_to(@commentary.post) end end @@ -62,27 +62,27 @@ class ArtistCommentariesControllerTest < ActionDispatch::IntegrationTest should "render for update" do params = { artist_commentary: { - post_id: @commentary1.post_id, + post_id: @commentary.post_id, original_title: "foo" }, format: "js" } put_auth create_or_update_artist_commentaries_path(params), @user - @commentary1.reload + @commentary.reload assert_response :success - assert_equal("foo", @commentary1.reload.original_title) + assert_equal("foo", @commentary.reload.original_title) end end context "revert action" do should "work" do - original_title = @commentary1.original_title - @commentary1.update(original_title: "foo") - @commentary1.reload - put_auth revert_artist_commentary_path(@commentary1.post_id, version_id: @commentary1.versions.first.id, format: "js"), @user + original_title = @commentary.original_title + @commentary.update(original_title: "foo") + @commentary.reload + put_auth revert_artist_commentary_path(@commentary.post_id, version_id: @commentary.versions.first.id, format: "js"), @user assert_response :success - assert_equal(original_title, @commentary1.reload.original_title) + assert_equal(original_title, @commentary.reload.original_title) end should "return 404 when trying to revert a nonexistent commentary" do @@ -91,9 +91,9 @@ class ArtistCommentariesControllerTest < ActionDispatch::IntegrationTest end should "not allow reverting to a previous version of another artist commentary" do - put_auth revert_artist_commentary_path(@commentary1.post_id, version_id: @commentary2.versions.first.id, format: "js"), @user - @commentary1.reload - assert_not_equal(@commentary1.original_title, @commentary2.original_title) + put_auth revert_artist_commentary_path(@commentary.post_id, version_id: @other_commentary.versions.first.id, format: "js"), @user + @commentary.reload + assert_not_equal(@commentary.original_title, @other_commentary.original_title) assert_response :missing end end diff --git a/test/functional/artist_commentary_versions_controller_test.rb b/test/functional/artist_commentary_versions_controller_test.rb index 246fda590..9c5f79f2d 100644 --- a/test/functional/artist_commentary_versions_controller_test.rb +++ b/test/functional/artist_commentary_versions_controller_test.rb @@ -3,24 +3,48 @@ require 'test_helper' class ArtistCommentaryVersionsControllerTest < ActionDispatch::IntegrationTest context "The artist commentary versions controller" do setup do - @user = create(:user) - @commentary1 = as(@user) { create(:artist_commentary) } - @commentary2 = as(@user) { create(:artist_commentary) } + @user = create(:member_user, id: 1000, created_at: 2.weeks.ago) + @builder = create(:builder_user, created_at: 2.weeks.ago) + as(@user) do + @commentary = create(:artist_commentary, post: build(:post, id: 999, tag_string: "hakurei_reimu", uploader: @user)) + end + as (@builder) { @commentary.update(original_title: "traslated") } + as (@user) { @commentary.update(original_title: "translated") } end context "index action" do + setup do + @versions = @commentary.versions + as(@builder) do + @other_commentary = create(:artist_commentary, post: build(:post, uploader: @builder)) + end + @other_versions = @other_commentary.versions + end + should "render" do get artist_commentary_versions_path assert_response :success end + + should respond_to_search({}).with { @other_versions + @versions.reverse } + should respond_to_search(original_title: "translated").with { @versions[2] } + should respond_to_search(text_matches: "traslated").with { @versions[1] } + + context "using includes" do + should respond_to_search(post_id: 999).with { @versions.reverse } + should respond_to_search(post_tags_match: "hakurei_reimu").with { @versions.reverse } + should respond_to_search(post: {uploader: {level: User::Levels::BUILDER}}).with { @other_commentary.versions } + should respond_to_search(updater_id: 1000).with { [@versions[2], @versions[0]] } + should respond_to_search(updater: {level: User::Levels::BUILDER}).with { [@other_versions[0], @versions[1]] } + end end context "show action" do should "work" do - get artist_commentary_version_path(@commentary1.versions.first) - assert_redirected_to artist_commentary_versions_path(search: { post_id: @commentary1.post_id }) + get artist_commentary_version_path(@commentary.versions.first) + assert_redirected_to artist_commentary_versions_path(search: { post_id: @commentary.post_id }) - get artist_commentary_version_path(@commentary1.versions.first), as: :json + get artist_commentary_version_path(@commentary.versions.first), as: :json assert_response :success end end diff --git a/test/functional/artist_urls_controller_test.rb b/test/functional/artist_urls_controller_test.rb index 8a0f15707..1cbe927db 100644 --- a/test/functional/artist_urls_controller_test.rb +++ b/test/functional/artist_urls_controller_test.rb @@ -2,28 +2,24 @@ require 'test_helper' class ArtistUrlsControllerTest < ActionDispatch::IntegrationTest context "The artist urls controller" do + setup do + @artist = create(:artist, name: "bkub", url_string: "-http://bkub.com") + @banned = create(:artist, name: "danbo", is_banned: true, url_string: "https://danbooru.donmai.us") + end + context "index page" do should "render" do get artist_urls_path assert_response :success end - should "render for a json request" do - get artist_urls_path, as: :json - assert_response :success - end + should respond_to_search({}).with { @banned.urls + @artist.urls } + should respond_to_search(url_matches: "*bkub*").with { @artist.urls } + should respond_to_search(is_active: "false").with { @artist.urls } - should "render for a complex search" do - @artist = FactoryBot.create(:artist, name: "bkub", url_string: "-http://bkub.com") - - get artist_urls_path(search: { - artist: { name: "bkub" }, - url_matches: "*bkub*", - is_active: "false", - order: "created_at" - }) - - assert_response :success + context "using includes" do + should respond_to_search(artist: {name: "bkub"}).with { @artist.urls } + should respond_to_search(artist: {is_banned: "true"}).with { @banned.urls } end end end diff --git a/test/functional/artist_versions_controller_test.rb b/test/functional/artist_versions_controller_test.rb index 143b8d196..d04ba86b8 100644 --- a/test/functional/artist_versions_controller_test.rb +++ b/test/functional/artist_versions_controller_test.rb @@ -3,18 +3,37 @@ require 'test_helper' class ArtistVersionsControllerTest < ActionDispatch::IntegrationTest context "An artist versions controller" do setup do - @user = create(:gold_user) - @artist = as(@user) { create(:artist) } + @user = create(:gold_user, id: 100) + @builder = create(:builder_user, name: "danbo") + as(@builder) { @artist = create(:artist, name: "masao", url_string: "https://masao.deviantart.com") } + as(@user) { @artist.update(name: "masao_(deleted)", is_deleted: true) } + as(@builder) { @artist.update(name: "masao", is_deleted: false, group_name: "the_best", url_string: "https://www.deviantart.com/masao") } end - should "get the index page" do - get_auth artist_versions_path, @user - assert_response :success - end + context "index action" do + setup do + @versions = @artist.versions + end - should "get the index page when searching for something" do - get_auth artist_versions_path(search: {name: @artist.name}), @user - assert_response :success + should "render" do + get artist_versions_path + assert_response :success + end + + should respond_to_search({}).with { @versions.reverse } + should respond_to_search(name: "masao").with { [@versions[2], @versions[0]] } + should respond_to_search(name_matches: "(deleted)").with { @versions[1] } + should respond_to_search(group_name_matches: "the_best").with { @versions[2] } + should respond_to_search(urls_include_any: "https://www.deviantart.com/masao").with { @versions[2] } + should respond_to_search(is_deleted: "true").with { @versions[1] } + + context "using includes" do + should respond_to_search(updater_id: 100).with { @versions[1] } + should respond_to_search(updater_name: "danbo").with { [@versions[2], @versions[0]] } + should respond_to_search(updater: {level: User::Levels::BUILDER}).with { [@versions[2], @versions[0]] } + should respond_to_search(artist: {name: "masao"}).with { @versions.reverse } + should respond_to_search(artist: {name: "doesntexist"}).with { [] } + end end context "show action" do diff --git a/test/functional/artists_controller_test.rb b/test/functional/artists_controller_test.rb index 076d8fd41..11ebae670 100644 --- a/test/functional/artists_controller_test.rb +++ b/test/functional/artists_controller_test.rb @@ -28,6 +28,8 @@ class ArtistsControllerTest < ActionDispatch::IntegrationTest @artist = create(:artist) @masao = create(:artist, name: "masao", url_string: "http://www.pixiv.net/member.php?id=32777") @artgerm = create(:artist, name: "artgerm", url_string: "http://artgerm.deviantart.com/") + @wiki = create(:wiki_page, title: "artgerm") + @post = create(:post, tag_string: "masao") end end @@ -130,7 +132,7 @@ class ArtistsControllerTest < ActionDispatch::IntegrationTest end context "index action" do - should "get the index page" do + should "render" do get artists_path assert_response :success end @@ -142,26 +144,36 @@ class ArtistsControllerTest < ActionDispatch::IntegrationTest end context "when searching the index page" do + setup do + @deleted = create(:artist, is_deleted: true) + @banned = create(:artist, is_banned: true) + end + should "find artists by name" do get artists_path(name: "masao", format: "json") assert_artist_found("masao") end - should "find artists by image URL" do - get artists_path(search: { url_matches: "http://i2.pixiv.net/img04/img/syounen_no_uta/46170939_m.jpg" }, format: "json") - assert_artist_found("masao") + should respond_to_search({}).with { [@banned, @deleted, @artgerm, @masao, @artist] } + should respond_to_search(name: "masao").with { @masao } + should respond_to_search(is_banned: "true").with { @banned } + should respond_to_search(is_deleted: "true").with { @deleted } + should respond_to_search(url_matches: "http://i2.pixiv.net/img04/img/syounen_no_uta/46170939_m.jpg").with { @masao } + should respond_to_search(url_matches: "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=46170939").with { @masao } + + context "ignoring whitespace" do + should respond_to_search(url_matches: " http://www.pixiv.net/member_illust.php?mode=medium&illust_id=46170939 ").with { @masao } end - should "find artists by page URL" do - url = "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=46170939" - get artists_path(search: { url_matches: url }, format: "json") - assert_artist_found("masao") - end - - should "ignore whitespace when searching by URL" do - url = " http://www.pixiv.net/member_illust.php?mode=medium&illust_id=46170939 " - get artists_path(search: { url_matches: url }, format: "json") - assert_artist_found("masao") + context "using includes" do + should respond_to_search(has_wiki_page: "true").with { @artgerm } + should respond_to_search(has_wiki_page: "false").with { [@banned, @deleted, @masao, @artist] } + should respond_to_search(has_tag: "true").with { @masao } + should respond_to_search(has_tag: "false").with { [@banned, @deleted, @artgerm, @artist] } + should respond_to_search(has_urls: "true").with { [@artgerm, @masao] } + should respond_to_search(has_urls: "false").with { [@banned, @deleted, @artist] } + should respond_to_search(urls: {url: "http://www.pixiv.net/member.php?id=32777"}).with { @masao } + should respond_to_search(urls: {normalized_url: "http://www.deviantart.com/artgerm/"}).with { @artgerm } end end end diff --git a/test/functional/bans_controller_test.rb b/test/functional/bans_controller_test.rb index 629ae922a..f2168b420 100644 --- a/test/functional/bans_controller_test.rb +++ b/test/functional/bans_controller_test.rb @@ -3,8 +3,11 @@ require 'test_helper' class BansControllerTest < ActionDispatch::IntegrationTest context "A bans controller" do setup do - @mod = create(:moderator_user) - @ban = create(:ban) + @mod = create(:moderator_user, name: "danbo") + @admin = create(:admin_user) + @user = create(:member_user, id: 999, name: "cirno") + + as(@mod) { @ban = create(:ban, reason: "blah", user: @user, banner: @mod) } end context "new action" do @@ -29,16 +32,25 @@ class BansControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + as(@admin) { @admin_ban = create(:ban, user: build(:builder_user), banner: @admin, expires_at: 1.day.ago ) } + end + should "render" do - get_auth bans_path, @mod + get bans_path assert_response :success end - end - context "search action" do - should "render" do - get_auth bans_path(search: { user_name: @ban.user.name }), @mod - assert_response :success + should respond_to_search({}).with { [@admin_ban, @ban] } + should respond_to_search(reason_matches: "blah").with { @ban } + should respond_to_search(expired: "true").with { @admin_ban } + + context "using includes" do + should respond_to_search(banner_name: "danbo").with { @ban } + should respond_to_search(banner: {level: User::Levels::ADMIN}).with { @admin_ban } + should respond_to_search(user_id: 999).with { @ban } + should respond_to_search(user: {name: "cirno"}).with { @ban } + should respond_to_search(user: {level: User::Levels::BUILDER}).with { @admin_ban } end end @@ -55,7 +67,6 @@ class BansControllerTest < ActionDispatch::IntegrationTest should "not allow mods to ban admins" do assert_difference("Ban.count", 0) do - @admin = create(:admin_user) post_auth bans_path, @mod, params: { ban: { duration: 60, reason: "xxx", user_id: @admin.id }} assert_response 403 diff --git a/test/functional/bulk_update_requests_controller_test.rb b/test/functional/bulk_update_requests_controller_test.rb index b91a8e04c..5b91dd92f 100644 --- a/test/functional/bulk_update_requests_controller_test.rb +++ b/test/functional/bulk_update_requests_controller_test.rb @@ -3,10 +3,11 @@ require 'test_helper' class BulkUpdateRequestsControllerTest < ActionDispatch::IntegrationTest context "BulkUpdateRequestsController" do setup do - @user = create(:user) + @user = create(:user, id: 999) @builder = create(:builder_user) @admin = create(:admin_user) - @bulk_update_request = create(:bulk_update_request, user: @user) + as(@admin) { @forum_topic = create(:forum_topic, id: 100, category_id: 0) } + as(@user) { @bulk_update_request = create(:bulk_update_request, user: @user, forum_topic: @forum_topic) } end context "#new" do @@ -73,10 +74,31 @@ class BulkUpdateRequestsControllerTest < ActionDispatch::IntegrationTest end context "#index" do + setup do + @other_BUR = create(:bulk_update_request, user: @builder, script: "create alias cirno -> 9") + @rejected_BUR = create(:bulk_update_request, status: "rejected") + @approved_BUR = create(:bulk_update_request, status: "approved", approver: @admin) + end + should "render" do get bulk_update_requests_path assert_response :success end + + should respond_to_search({}).with { [@other_BUR, @bulk_update_request, @approved_BUR, @rejected_BUR] } + should respond_to_search(order: "id_desc").with { [@approved_BUR, @rejected_BUR, @other_BUR, @bulk_update_request] } + should respond_to_search(status: "pending").with { [@other_BUR, @bulk_update_request] } + should respond_to_search(script_matches: "cirno -> 9").with { @other_BUR } + should respond_to_search(tags_include_any: "cirno").with { @other_BUR } + + context "using includes" do + should respond_to_search(forum_topic_id: 100).with { @bulk_update_request } + should respond_to_search(forum_topic: {category_id: 0}).with { @bulk_update_request } + should respond_to_search(user_id: 999).with { @bulk_update_request } + should respond_to_search(user: {level: User::Levels::BUILDER}).with { @other_BUR } + should respond_to_search(has_approver: "true").with { @approved_BUR } + should respond_to_search(has_approver: "false").with { [@other_BUR, @bulk_update_request, @rejected_BUR] } + end end context "#show" do diff --git a/test/functional/comment_votes_controller_test.rb b/test/functional/comment_votes_controller_test.rb index 5d2b713d8..20cf11ce3 100644 --- a/test/functional/comment_votes_controller_test.rb +++ b/test/functional/comment_votes_controller_test.rb @@ -3,9 +3,9 @@ require 'test_helper' class CommentVotesControllerTest < ActionDispatch::IntegrationTest context "A comment votes controller" do setup do - CurrentUser.user = @user = create(:user) + CurrentUser.user = @user = create(:user, name: "cirno") CurrentUser.ip_addr = "127.0.0.1" - @comment = create(:comment) + @comment = create(:comment, creator: @user) end teardown do @@ -13,12 +13,36 @@ class CommentVotesControllerTest < ActionDispatch::IntegrationTest CurrentUser.ip_addr = nil end - context "#index" do - should "work" do - create(:comment_vote, user: @user) - get_auth comment_votes_path, @user + context "index action" do + setup do + @voter = create(:gold_user, name: "rumia") + @vote = as (@voter) { create(:comment_vote, comment: @comment, user: @voter) } + @negative_vote = create(:comment_vote, comment: @comment, score: -1) + @unrelated_vote = create(:comment_vote) + end - assert_response :success + context "as a user" do + should "render" do + get_auth comment_votes_path, @user + assert_response :success + end + + should respond_to_search({}).with { [] } + end + + context "as a moderator" do + setup do + CurrentUser.user = create(:mod_user) + end + + should respond_to_search({}).with { [@unrelated_vote, @negative_vote, @vote] } + should respond_to_search(score: -1).with { @negative_vote } + + context "using includes" do + should respond_to_search(comment: {creator_name: "cirno"}).with { [@negative_vote, @vote] } + should respond_to_search(user_name: "rumia").with { @vote } + should respond_to_search(user: {level: User::Levels::GOLD}).with { @vote } + end end end diff --git a/test/functional/comments_controller_test.rb b/test/functional/comments_controller_test.rb index b0c74dbe5..048726ed0 100644 --- a/test/functional/comments_controller_test.rb +++ b/test/functional/comments_controller_test.rb @@ -4,8 +4,8 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest context "A comments controller" do setup do @mod = FactoryBot.create(:moderator_user) - @user = FactoryBot.create(:member_user) - @post = create(:post) + @user = FactoryBot.create(:member_user, name: "cirno") + @post = create(:post, id: 100) CurrentUser.user = @user CurrentUser.ip_addr = "127.0.0.1" @@ -87,10 +87,31 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest end end - should "render by comment" do - @comment = as(@user) { create(:comment, post: @post) } - get comments_path(group_by: "comment") - assert_response :success + context "grouped by comment" do + setup do + @user_comment = create(:comment, post: @post, score: 10, do_not_bump_post: true, creator: @user) + @mod_comment = create(:comment, post: build(:post, tag_string: "touhou"), body: "blah", is_sticky: true, creator: @mod) + @deleted_comment = create(:comment, is_deleted: true) + end + + should "render" do + get comments_path(group_by: "comment") + assert_response :success + end + + should respond_to_search({}, other_params: {group_by: "comment"}).with { [@deleted_comment, @mod_comment, @user_comment] } + should respond_to_search(body_matches: "blah").with { @mod_comment } + should respond_to_search(score: 10).with { @user_comment } + should respond_to_search(is_sticky: "true").with { @mod_comment } + should respond_to_search(do_not_bump_post: "true").with { @user_comment } + should respond_to_search(is_deleted: "true").with { @deleted_comment } + + context "using includes" do + should respond_to_search(post_id: 100).with { @user_comment } + should respond_to_search(post_tags_match: "touhou").with { @mod_comment } + should respond_to_search(creator_name: "cirno").with { @user_comment } + should respond_to_search(creator: {level: User::Levels::MODERATOR}).with { @mod_comment } + end end context "for atom feeds" do diff --git a/test/functional/dmails_controller_test.rb b/test/functional/dmails_controller_test.rb index 5c27628a7..963868a64 100644 --- a/test/functional/dmails_controller_test.rb +++ b/test/functional/dmails_controller_test.rb @@ -3,9 +3,9 @@ require 'test_helper' class DmailsControllerTest < ActionDispatch::IntegrationTest context "The dmails controller" do setup do - @user = create(:user, unread_dmail_count: 1) - @unrelated_user = create(:user) - @dmail = create(:dmail, owner: @user) + @user = create(:user, id: 999, unread_dmail_count: 1) + @unrelated_user = create(:moderator_user, id: 1000, name: "reimu") + @dmail = create(:dmail, owner: @user, from: @user) end teardown do @@ -40,28 +40,41 @@ class DmailsControllerTest < ActionDispatch::IntegrationTest end context "index action" do - should "show dmails owned by the current user by sent" do - get_auth dmails_path, @user, params: {:search => {:owner_id => @dmail.owner_id, :folder => "sent"}} + setup do + CurrentUser.user = @user + @received_dmail = create(:dmail, owner: @user, body: "blah", to: @user, from: @unrelated_user, is_read: true) + @deleted_dmail = create(:dmail, owner: @user, title: "UMAD", to: @unrelated_user, from: @user, is_deleted: true) + @unrelated_dmail = create(:dmail, owner: @unrelated_user, from: @unrelated_user) + end + + should "render" do + get_auth dmails_path, @user assert_response :success end - should "show dmails owned by the current user by received" do - get_auth dmails_path, @user, params: {:search => {:owner_id => @dmail.owner_id, :folder => "received"}} - assert_response :success + should respond_to_search({}).with { [@deleted_dmail, @received_dmail, @dmail] } + should respond_to_search(folder: "sent").with { @dmail } + should respond_to_search(folder: "received").with { @received_dmail } + should respond_to_search(title_matches: "UMAD").with { @deleted_dmail } + should respond_to_search(message_matches: "blah").with { @received_dmail } + should respond_to_search(is_read: "true").with { @received_dmail } + should respond_to_search(is_deleted: "true").with { @deleted_dmail } + + context "using includes" do + should respond_to_search(to_id: 1000).with { @deleted_dmail } + should respond_to_search(from_id: 999).with { [@deleted_dmail, @dmail] } + should respond_to_search(from_name: "reimu").with { @received_dmail } + should respond_to_search(from: {level: User::Levels::MODERATOR}).with { @received_dmail } end - should "not show dmails not owned by the current user" do - get_auth dmails_path, @user, params: {:search => {:owner_id => @dmail.owner_id}} - assert_response :success - end + context "as a banned user" do + setup do + as(create(:admin_user)) do + create(:ban, user: @user) + end - should "work for banned users" do - as(create(:admin_user)) do - create(:ban, :user => @user) + should respond_to_search({}).with { [@received_dmail, @dmail] } end - get_auth dmails_path, @dmail.owner, params: {:search => {:owner_id => @dmail.owner_id, :folder => "sent"}} - - assert_response :success end end diff --git a/test/functional/dtext_links_controller_test.rb b/test/functional/dtext_links_controller_test.rb index 17f6f274a..366a1b510 100644 --- a/test/functional/dtext_links_controller_test.rb +++ b/test/functional/dtext_links_controller_test.rb @@ -1,12 +1,30 @@ require "test_helper" class DtextLinksControllerTest < ActionDispatch::IntegrationTest + setup do + @user = create(:user) + as(@user) do + @wiki = create(:wiki_page, title: "case", body: "[[test]]") + @forum = create(:forum_post, topic: build(:forum_topic, title: "blah"), body: "[[case]]") + create(:tag, name: "test") + end + end + context "index action" do - should "work" do - @user = create(:user) - @wiki = as(@user) { create(:wiki_page, body: "[[test]]") } + should "render" do get dtext_links_path assert_response :success end + + should respond_to_search({}).with { @forum.dtext_links + @wiki.dtext_links } + + context "using includes" do + should respond_to_search(model_type: "WikiPage").with { @wiki.dtext_links } + should respond_to_search(model_type: "ForumPost").with { @forum.dtext_links } + should respond_to_search(has_linked_tag: "true").with { @wiki.dtext_links } + should respond_to_search(has_linked_wiki: "true").with { @forum.dtext_links } + should respond_to_search(ForumPost: {topic: {title_matches: "blah"}}).with { @forum.dtext_links } + should respond_to_search(ForumPost: {topic: {title_matches: "nah"}}).with { [] } + end end end diff --git a/test/functional/favorite_groups_controller_test.rb b/test/functional/favorite_groups_controller_test.rb index 1b853dd0e..f9d0d32bb 100644 --- a/test/functional/favorite_groups_controller_test.rb +++ b/test/functional/favorite_groups_controller_test.rb @@ -8,10 +8,31 @@ class FavoriteGroupsControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + @mod_favgroup = create(:favorite_group, name: "monochrome", creator: build(:moderator_user, name: "fumimi")) + @private_favgroup = create(:favorite_group, creator: @user, is_public: false) + end + should "render" do get favorite_groups_path assert_response :success end + + should respond_to_search({}).with { [@mod_favgroup, @favgroup] } + should respond_to_search(name: "monochrome").with { @mod_favgroup } + + context "using includes" do + should respond_to_search(creator_name: "fumimi").with { @mod_favgroup } + should respond_to_search(creator: {level: User::Levels::MEMBER}).with { @favgroup } + end + + context "for private favorite groups as the creator" do + setup do + CurrentUser.user = @user + end + + should respond_to_search(is_public: "false").with { @private_favgroup } + end end context "show action" do diff --git a/test/functional/forum_post_votes_controller_test.rb b/test/functional/forum_post_votes_controller_test.rb index 5d693d26b..952551cb4 100644 --- a/test/functional/forum_post_votes_controller_test.rb +++ b/test/functional/forum_post_votes_controller_test.rb @@ -3,22 +3,35 @@ require 'test_helper' class ForumPostVotesControllerTest < ActionDispatch::IntegrationTest context "The forum post votes controller" do setup do - @user = create(:user) + @user = create(:user, name: "cirno") @other_user = create(:user) as(@user) do - @forum_topic = create(:forum_topic) - @forum_post = create(:forum_post, topic: @forum_topic) + @forum_post = create(:forum_post, body: "blah", creator: @user) @bulk_update_request = create(:bulk_update_request, forum_post: @forum_post) end end context "index action" do + setup do + @vote = create(:forum_post_vote, forum_post: @forum_post, creator: build(:user, name: "rumia"), score: 1) + @negative_vote = create(:forum_post_vote, forum_post: @forum_post, score: -1) + @unrelated_vote = as (@user) { create(:forum_post_vote, score: 0) } + end + should "render" do - @forum_post_vote = create(:forum_post_vote, creator: @user, forum_post: @forum_post) get forum_post_votes_path assert_response :success end + + should respond_to_search({}).with { [@unrelated_vote, @negative_vote, @vote] } + should respond_to_search(score: -1).with { @negative_vote } + + context "using includes" do + should respond_to_search(creator_name: "rumia").with { @vote } + should respond_to_search(forum_post: {creator_name: "cirno"}).with { [@negative_vote, @vote] } + should respond_to_search(forum_post: {body_matches: "blah"}).with { [@negative_vote, @vote] } + end end context "create action" do diff --git a/test/functional/forum_posts_controller_test.rb b/test/functional/forum_posts_controller_test.rb index d6c643e52..41cde00d0 100644 --- a/test/functional/forum_posts_controller_test.rb +++ b/test/functional/forum_posts_controller_test.rb @@ -3,9 +3,9 @@ require 'test_helper' class ForumPostsControllerTest < ActionDispatch::IntegrationTest context "The forum posts controller" do setup do - @user = create(:user) + @user = create(:user, id: 999) @other_user = create(:user) - @mod = create(:moderator_user) + @mod = create(:moderator_user, name: "okuu") @forum_topic = as(@user) { create(:forum_topic, title: "my forum topic", creator: @user) } @forum_post = as(@user) { create(:forum_post, creator: @user, topic: @forum_topic, body: "alias xxx -> yyy") } end @@ -52,65 +52,61 @@ class ForumPostsControllerTest < ActionDispatch::IntegrationTest end context "index action" do - should "list all forum posts" do - get forum_posts_path - assert_response :success + setup do + @admin = create(:admin_user) + @other_forum = as(@user) { create(:forum_post, body: "[[test]]", topic: build(:forum_topic, title: "my topic", category_id: 1)) } + @mod_forum = as(@mod) { create(:forum_post, creator: @mod, topic: build(:forum_topic, min_level: User::Levels::MODERATOR)) } + @admin_forum = as(@admin) { create(:forum_post, creator: @admin, topic: build(:forum_topic, min_level: User::Levels::ADMIN)) } + @unrelated_forum = as (@user) { create(:forum_post, is_deleted: true) } + as (@user) { create(:forum_post_vote, forum_post: @forum_post) } + create(:bulk_update_request, forum_post: @other_forum) end - context "with search conditions" do - should "list all matching forum posts" do - get forum_posts_path, params: { search: { body_matches: "xxx", topic_title_matches: "my forum topic" }} - assert_response :success - assert_select "#forum-post-#{@forum_post.id}" - end - - should "list nothing for when the search matches nothing" do - get forum_posts_path, params: {:search => {:body_matches => "bababa"}} - assert_response :success - assert_select "#forum-post-#{@forum_post.id}", false - end - - should "list by creator id" do - get forum_posts_path, params: {:search => {:creator_id => @user.id}} - assert_response :success - assert_select "#forum-post-#{@forum_post.id}" - end - end - - context "for posts in private topics" do + context "as a user" do setup do - @admin = create(:admin_user) - @mod_post = as(@mod) { create(:forum_post, creator: @mod, topic: build(:forum_topic, min_level: User::Levels::MODERATOR)) } - @admin_post = as(@admin) { create(:forum_post, creator: @admin, topic: build(:forum_topic, min_level: User::Levels::ADMIN)) } + CurrentUser.user = @user end - should "list only permitted posts for anons" do - get forum_posts_path - + should "render" do + get_auth comment_votes_path, @user assert_response :success - assert_select "#forum-post-#{@forum_post.id}" - assert_select "#forum-post-#{@mod_post.id}", false - assert_select "#forum-post-#{@admin_post.id}", false end - should "list only permitted posts for mods" do - get_auth forum_posts_path, @mod + should respond_to_search({}).with { [@unrelated_forum, @other_forum, @forum_post] } + should respond_to_search(body_matches: "xxx").with { @forum_post } + should respond_to_search(body_matches: "bababa").with { [] } + should respond_to_search(is_deleted: "true").with { @unrelated_forum } - assert_response :success - assert_select "#forum-post-#{@forum_post.id}" - assert_select "#forum-post-#{@mod_post.id}" - assert_select "#forum-post-#{@admin_post.id}", false + context "using includes" do + should respond_to_search(topic: {title_matches: "my forum topic"}).with { @forum_post } + should respond_to_search(topic: {category_id: 1}).with { @other_forum } + should respond_to_search(has_bulk_update_request: "true").with { @other_forum } + should respond_to_search(has_votes: "true").with { @forum_post } + should respond_to_search(has_dtext_links: "true").with { @other_forum } + should respond_to_search(creator_id: 999).with { @forum_post } + should respond_to_search(creator: {name: "okuu"}).with { [] } + end + end + + context "as a moderator" do + setup do + CurrentUser.user = @mod end - should "list only permitted posts for admins" do - get_auth forum_posts_path, @admin + should respond_to_search({}).with { [@unrelated_forum, @mod_forum, @other_forum, @forum_post] } - assert_response :success - assert_select "#forum-post-#{@forum_post.id}" - assert_select "#forum-post-#{@mod_post.id}" - assert_select "#forum-post-#{@admin_post.id}" + context "using includes" do + should respond_to_search(creator: {name: "okuu"}).with { @mod_forum } end end + + context "as an admin" do + setup do + CurrentUser.user = @admin + end + + should respond_to_search({}).with { [@unrelated_forum, @admin_forum, @mod_forum, @other_forum, @forum_post] } + end end context "show action" do diff --git a/test/functional/forum_topics_controller_test.rb b/test/functional/forum_topics_controller_test.rb index 4b3a0e2e4..06e7d0807 100644 --- a/test/functional/forum_topics_controller_test.rb +++ b/test/functional/forum_topics_controller_test.rb @@ -1,15 +1,18 @@ require 'test_helper' class ForumTopicsControllerTest < ActionDispatch::IntegrationTest + def default_search_order(items) + ->{ items.each { |val| val.reload }.sort_by(&:updated_at).reverse } + end + context "The forum topics controller" do setup do @user = create(:user) @other_user = create(:user) - @mod = create(:moderator_user) + @mod = create(:moderator_user, name: "okuu") as(@user) do - @forum_topic = create(:forum_topic, creator: @user, title: "my forum topic") - @forum_post = create(:forum_post, creator: @user, topic: @forum_topic, body: "xxx") + @forum_topic = create(:forum_topic, creator: @user, title: "my forum topic", original_post: build(:forum_post, creator: @user, topic: @forum_topic, body: "xxx")) end end @@ -88,25 +91,26 @@ class ForumTopicsControllerTest < ActionDispatch::IntegrationTest context "index action" do setup do as(@user) do - @topic1 = create(:forum_topic, is_sticky: true, creator: @user) - @topic2 = create(:forum_topic, creator: @user) - @post1 = create(:forum_post, topic: @topic1, creator: @user, body: "xxx") - @post2 = create(:forum_post, topic: @topic2, creator: @user, body: "xxx") + @sticky_topic = create(:forum_topic, is_sticky: true, creator: @user, original_post: build(:forum_post)) + @other_topic = create(:forum_topic, creator: @user, original_post: build(:forum_post)) end + @mod_topic = as(@mod) { create(:forum_topic, creator: @mod, min_level: User::Levels::MODERATOR, original_post: build(:forum_post)) } + create(:bulk_update_request, forum_topic: @forum_topic) + create(:tag_alias, forum_topic: @other_topic) end should "list public forum topics for members" do get forum_topics_path assert_response :success - assert_select "a.forum-post-link", count: 1, text: @topic1.title - assert_select "a.forum-post-link", count: 1, text: @topic2.title + assert_select "a.forum-post-link", count: 1, text: @sticky_topic.title + assert_select "a.forum-post-link", count: 1, text: @other_topic.title end should "not list stickied topics first for JSON responses" do get forum_topics_path, params: {format: :json} forum_topics = JSON.parse(response.body) - assert_equal([@topic2.id, @topic1.id, @forum_topic.id], forum_topics.map {|t| t["id"]}) + assert_equal(default_search_order([@other_topic, @sticky_topic, @forum_topic]).call.map(&:id), forum_topics.map {|t| t["id"]}) end should "render for atom feed" do @@ -117,44 +121,59 @@ class ForumTopicsControllerTest < ActionDispatch::IntegrationTest should "render for a sitemap" do get forum_topics_path(format: :sitemap) assert_response :success - assert_equal(ForumTopic.count, response.parsed_body.css("urlset url loc").size) + assert_equal(ForumTopic.visible(User.anonymous).count, response.parsed_body.css("urlset url loc").size) end context "with private topics" do should "not show private topics to unprivileged users" do - as(@user) { @topic2.update!(min_level: User::Levels::MODERATOR) } + as(@user) { @other_topic.update!(min_level: User::Levels::MODERATOR) } get forum_topics_path assert_response :success - assert_select "a.forum-post-link", count: 1, text: @topic1.title - assert_select "a.forum-post-link", count: 0, text: @topic2.title + assert_select "a.forum-post-link", count: 1, text: @sticky_topic.title + assert_select "a.forum-post-link", count: 0, text: @other_topic.title end should "show private topics to privileged users" do - as(@user) { @topic2.update!(min_level: User::Levels::MODERATOR) } + as(@user) { @other_topic.update!(min_level: User::Levels::MODERATOR) } get_auth forum_topics_path, @mod assert_response :success - assert_select "a.forum-post-link", count: 1, text: @topic1.title - assert_select "a.forum-post-link", count: 1, text: @topic2.title + assert_select "a.forum-post-link", count: 1, text: @sticky_topic.title + assert_select "a.forum-post-link", count: 1, text: @other_topic.title end end context "with search conditions" do - should "list all matching forum topics" do - get forum_topics_path, params: {:search => {:title_matches => "forum"}} - assert_response :success - assert_select "a.forum-post-link", @forum_topic.title - assert_select "a.forum-post-link", count: 0, text: @topic1.title - assert_select "a.forum-post-link", count: 0, text: @topic2.title + context "as a user" do + setup do + CurrentUser.user = @user + end + + should respond_to_search({}).with { default_search_order([@sticky_topic, @other_topic, @forum_topic]) } + should respond_to_search(order: "id").with { [@other_topic, @sticky_topic, @forum_topic] } + should respond_to_search(title_matches: "forum").with { @forum_topic } + should respond_to_search(title_matches: "bababa").with { [] } + should respond_to_search(is_sticky: "true").with { @sticky_topic } + + context "using includes" do + should respond_to_search(forum_posts: {body_matches: "xxx"}).with { @forum_topic } + should respond_to_search(has_bulk_update_requests: "true").with { @forum_topic } + should respond_to_search(has_tag_aliases: "true").with { @other_topic } + should respond_to_search(creator_name: "okuu").with { [] } + end end - should "list nothing for when the search matches nothing" do - get forum_topics_path, params: {:search => {:title_matches => "bababa"}} - assert_response :success - assert_select "a.forum-post-link", count: 0, text: @forum_topic.title - assert_select "a.forum-post-link", count: 0, text: @topic1.title - assert_select "a.forum-post-link", count: 0, text: @topic2.title + context "as a moderator" do + setup do + CurrentUser.user = @mod + end + + should respond_to_search({}).with { default_search_order([@sticky_topic, @other_topic, @mod_topic, @forum_topic]) } + + context "using includes" do + should respond_to_search(creator_name: "okuu").with { @mod_topic } + end end end diff --git a/test/functional/ip_bans_controller_test.rb b/test/functional/ip_bans_controller_test.rb index bd6465afc..2ac8f3075 100644 --- a/test/functional/ip_bans_controller_test.rb +++ b/test/functional/ip_bans_controller_test.rb @@ -3,8 +3,8 @@ require 'test_helper' class IpBansControllerTest < ActionDispatch::IntegrationTest context "The ip bans controller" do setup do - @admin = create(:admin_user) - @ip_ban = create(:ip_ban) + @admin = create(:admin_user, name: "yukari") + @ip_ban = create(:ip_ban, ip_addr: "6.7.8.9") end context "new action" do @@ -24,21 +24,34 @@ class IpBansControllerTest < ActionDispatch::IntegrationTest should "log a mod action" do post_auth ip_bans_path, @admin, params: { ip_ban: { ip_addr: "1.2.3.4", reason: "xyz" }} - assert_equal("ip_ban_create", ModAction.last.category) + assert_equal("ip_ban_create", ModAction.last&.category) end end context "index action" do + setup do + CurrentUser.user = @admin + @subnet_ban = create(:ip_ban, ip_addr: "2.0.0.0/24", creator: @admin) + @other_ban = create(:ip_ban, reason: "malware") + end + + should "render access denied for anonymous users" do + get ip_bans_path + assert_response 403 + end + should "render" do get_auth ip_bans_path, @admin assert_response :success end - context "with search parameters" do - should "render" do - get_auth ip_bans_path, @admin, params: {:search => {:ip_addr => "1.2.3.4"}} - assert_response :success - end + should respond_to_search({}).with { [@other_ban, @subnet_ban, @ip_ban] } + should respond_to_search(ip_addr: "6.7.8.9").with { @ip_ban } + should respond_to_search(reason_matches: "malware").with { @other_ban } + + context "using includes" do + should respond_to_search(creator_name: "yukari").with { @subnet_ban } + should respond_to_search(creator: {level: User::Levels::ADMIN}).with { @subnet_ban } end end diff --git a/test/functional/mod_actions_controller_test.rb b/test/functional/mod_actions_controller_test.rb index 9052cdf36..eb97ca25c 100644 --- a/test/functional/mod_actions_controller_test.rb +++ b/test/functional/mod_actions_controller_test.rb @@ -2,6 +2,10 @@ require 'test_helper' class ModActionsControllerTest < ActionDispatch::IntegrationTest context "The mod actions controller" do + setup do + @mod_action = create(:mod_action, description: "blah", category: "post_delete") + end + context "index action" do setup do @ban = create(:mod_action, category: :post_ban) @@ -13,6 +17,15 @@ class ModActionsControllerTest < ActionDispatch::IntegrationTest assert_response :success end + should respond_to_search({}).with { [@unrelated_action, @promote_action, @mod_action] } + should respond_to_search(category: ModAction.categories["user_level_change"]).with { @promote_action } + should respond_to_search(description_matches: "blah").with { @mod_action } + + context "using includes" do + should respond_to_search(creator_name: "rumia").with { @promote_action } + should respond_to_search(creator: {level: User::Levels::BUILDER}).with { @promote_action } + end + context "category enum searches" do should respond_to_search(category: "post_ban").with { [@ban] } should respond_to_search(category: "post_unban").with { [@unban] } @@ -23,6 +36,7 @@ class ModActionsControllerTest < ActionDispatch::IntegrationTest should respond_to_search(category_id: "44").with { [@ban] } should respond_to_search(category_id: "44,45").with { [@unban, @ban] } should respond_to_search(category_id: ">=44").with { [@unban, @ban] } + end end diff --git a/test/functional/moderation_reports_controller_test.rb b/test/functional/moderation_reports_controller_test.rb index 568e6e81b..ff9af203c 100644 --- a/test/functional/moderation_reports_controller_test.rb +++ b/test/functional/moderation_reports_controller_test.rb @@ -9,9 +9,8 @@ class ModerationReportsControllerTest < ActionDispatch::IntegrationTest as(@spammer) do @dmail = create(:dmail, from: @spammer, owner: @user, to: @user) - @comment = create(:comment, creator: @spammer) - @forum_topic = create(:forum_topic, creator: @spammer) - @forum_post = create(:forum_post, topic: @forum_topic, creator: @spammer) + @comment = create(:comment, id: 1234, creator: @spammer) + @forum_post = create(:forum_post, topic: build(:forum_topic), body: "xxx", creator: @spammer) end end @@ -29,24 +28,37 @@ class ModerationReportsControllerTest < ActionDispatch::IntegrationTest context "index action" do setup do - create(:moderation_report, model: @comment, creator: @user) + @comment_report = create(:moderation_report, model: @comment, creator: @user) + @forum_report = create(:moderation_report, model: @forum_post, creator: @user) + @dmail_report = create(:moderation_report, reason: "spam", model: @dmail, creator: build(:builder_user, name: "daiyousei", created_at: 2.weeks.ago)) end - should "render the access denied page for members" do - get_auth moderation_reports_path, @user - assert_response 403 + context "as a user" do + should "render the access denied page" do + get_auth moderation_reports_path, @user + assert_response 403 + end end - should "render for mods" do - get_auth moderation_reports_path, @mod - assert_response :success - end + context "as a moderator" do + setup do + CurrentUser.user = @mod + end - context "with search parameters" do should "render" do - get_auth moderation_reports_path, @mod, params: {:search => {:model_id => @comment.id}} + get_auth moderation_reports_path, @mod assert_response :success end + + should respond_to_search({}).with { [@dmail_report, @forum_report, @comment_report] } + should respond_to_search(reason_matches: "spam").with { @dmail_report } + + context "using includes" do + should respond_to_search(model_id: 1234).with { @comment_report } + should respond_to_search(model_type: "ForumPost").with { @forum_report } + should respond_to_search(ForumPost: {body_matches: "xxx"}).with { @forum_report } + should respond_to_search(creator_name: "daiyousei").with { @dmail_report } + end end end diff --git a/test/functional/note_versions_controller_test.rb b/test/functional/note_versions_controller_test.rb index cbc100c99..22b5da38d 100644 --- a/test/functional/note_versions_controller_test.rb +++ b/test/functional/note_versions_controller_test.rb @@ -3,23 +3,34 @@ require 'test_helper' class NoteVersionsControllerTest < ActionDispatch::IntegrationTest context "The note versions controller" do setup do - @user = create(:user) - @user_2 = create(:user) + @user = create(:user, id: 100) + @user_2 = create(:user, name: "cirno") - as(@user) { @note = create(:note) } - as(@user_2) { @note.update(body: "1 2") } - as(@user) { @note.update(body: "1 2 3") } + as(@user) { @note = create(:note, id: 101) } + as(@user_2) { @note.update(body: "blah", is_active: false) } + as(@user) { @note.update(body: "1 2 3", is_active: true) } end context "index action" do - should "list all versions" do + setup do + @versions = @note.versions + end + + should "render" do get note_versions_path assert_response :success end - should "list all versions that match the search criteria" do - get note_versions_path, params: {:search => {:updater_id => @user_2.id}} - assert_response :success + should respond_to_search({}).with { @versions.reverse } + should respond_to_search(body_matches: "blah").with { @versions[1] } + should respond_to_search(version: 1).with { @versions[0] } + should respond_to_search(is_active: "false").with { @versions[1] } + + context "using includes" do + should respond_to_search(note_id: 101).with { @versions.reverse } + should respond_to_search(note_id: 102).with { [] } + should respond_to_search(updater_id: 100).with { [@versions[2], @versions[0]] } + should respond_to_search(updater: {name: "cirno"}).with { @versions[1] } end end diff --git a/test/functional/notes_controller_test.rb b/test/functional/notes_controller_test.rb index 8bae95026..1acb91d36 100644 --- a/test/functional/notes_controller_test.rb +++ b/test/functional/notes_controller_test.rb @@ -8,24 +8,25 @@ class NotesControllerTest < ActionDispatch::IntegrationTest end context "index action" do - should "list all notes" do + setup do + as(@user) do + @post_note = create(:note, post: build(:post, id: 2001, tag_string: "touhou")) + @deleted_note = create(:note, is_active: false) + end + end + + should "render" do get notes_path assert_response :success end - should "list all notes (with search)" do - params = { - group_by: "note", - search: { - body_matches: "000", - is_active: true, - post_id: @note.post_id, - post_tags_match: @note.post.tag_array.first - } - } + should respond_to_search({}).with { [@deleted_note, @post_note, @note] } + should respond_to_search(body_matches: "000").with { @note } + should respond_to_search(is_active: "true").with { [@post_note, @note] } - get notes_path, params: params - assert_response :success + context "using includes" do + should respond_to_search(post_id: 2001).with { @post_note } + should respond_to_search(post_tags_match: "touhou").with { @post_note } end end diff --git a/test/functional/post_appeals_controller_test.rb b/test/functional/post_appeals_controller_test.rb index a8dcc1607..9c1795f1f 100644 --- a/test/functional/post_appeals_controller_test.rb +++ b/test/functional/post_appeals_controller_test.rb @@ -3,7 +3,8 @@ require 'test_helper' class PostAppealsControllerTest < ActionDispatch::IntegrationTest context "The post appeals controller" do setup do - @user = create(:user) + @user = create(:user, name: "orin") + @post = create(:post, id: 101, is_deleted: true) end context "new action" do @@ -24,8 +25,10 @@ class PostAppealsControllerTest < ActionDispatch::IntegrationTest context "index action" do setup do as(@user) do - @post = create(:post, :is_deleted => true) - @post_appeal = create(:post_appeal, :post => @post) + @post_appeal = create(:post_appeal, post: @post, creator: @user) + @unrelated_appeal = create(:post_appeal, reason: "Good.") + @resolved_appeal = create(:post_appeal) + @resolved_appeal.post.update(is_deleted: false) end end @@ -34,16 +37,14 @@ class PostAppealsControllerTest < ActionDispatch::IntegrationTest assert_response :success end - should "render for json" do - get post_appeals_path, as: :json - assert_response :success - end + should respond_to_search({}).with { [@resolved_appeal, @unrelated_appeal, @post_appeal] } + should respond_to_search(reason_matches: "Good.").with { @unrelated_appeal } + should respond_to_search(is_resolved: "true").with { @resolved_appeal } - context "with search parameters" do - should "render" do - get_auth post_appeals_path, @user, params: {:search => {:post_id => @post_appeal.post_id}} - assert_response :success - end + context "using includes" do + should respond_to_search(post_id: 101).with { @post_appeal } + should respond_to_search(post: {is_deleted: "true"}).with { [@unrelated_appeal, @post_appeal] } + should respond_to_search(creator_name: "orin").with { @post_appeal } end end diff --git a/test/functional/post_approvals_controller_test.rb b/test/functional/post_approvals_controller_test.rb index 813cf62ef..9655733c5 100644 --- a/test/functional/post_approvals_controller_test.rb +++ b/test/functional/post_approvals_controller_test.rb @@ -3,7 +3,7 @@ require 'test_helper' class PostApprovalsControllerTest < ActionDispatch::IntegrationTest context "The post approvals controller" do setup do - @approver = create(:approver) + @approver = create(:approver, name: "eiki") end context "create action" do @@ -60,11 +60,25 @@ class PostApprovalsControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + @post = create(:post, tag_string: "touhou", is_pending: true, uploader: build(:user, name: "komachi", created_at: 2.weeks.ago)) + @post_approval = create(:post_approval, post: @post) + @user_approval = create(:post_approval, user: @approver) + @unrelated_approval = create(:post_approval) + end + should "render" do - @approval = create(:post_approval) get post_approvals_path assert_response :success end + + should respond_to_search({}).with { [@unrelated_approval, @user_approval, @post_approval] } + + context "using includes" do + should respond_to_search(user_name: "eiki").with { @user_approval } + should respond_to_search(post_tags_match: "touhou").with { @post_approval } + should respond_to_search(post: {uploader_name: "komachi"}).with { @post_approval } + end end end end diff --git a/test/functional/post_disapprovals_controller_test.rb b/test/functional/post_disapprovals_controller_test.rb index 9260dda0f..513b16c67 100644 --- a/test/functional/post_disapprovals_controller_test.rb +++ b/test/functional/post_disapprovals_controller_test.rb @@ -3,9 +3,8 @@ require 'test_helper' class PostDisapprovalsControllerTest < ActionDispatch::IntegrationTest context "The post disapprovals controller" do setup do - @approver = create(:approver) - @post = create(:post, is_pending: true) - @post_disapproval = create(:post_disapproval, post: @post) + @approver = create(:approver, name: "eiki") + @post = create(:post, tag_string: "touhou", is_pending: true, uploader: build(:user, name: "marisa", created_at: 2.weeks.ago)) end context "create action" do @@ -40,16 +39,36 @@ class PostDisapprovalsControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + @post_disapproval = create(:post_disapproval, post: @post) + @user_disapproval = create(:post_disapproval, user: @approver) + @unrelated_disapproval = create(:post_disapproval, message: "bad") + end + + should "render" do + get post_disapprovals_path + assert_response :success + end + + should respond_to_search({}).with { [@unrelated_disapproval, @user_disapproval, @post_disapproval] } + should respond_to_search(message: "bad").with { @unrelated_disapproval } + + context "using includes" do + should respond_to_search(post_tags_match: "touhou").with { @post_disapproval } + should respond_to_search(post: {uploader_name: "marisa"}).with { @post_disapproval } + should respond_to_search(user_name: "eiki").with { @user_disapproval } + end + should "allow mods to see disapprover names" do get_auth post_disapprovals_path, create(:mod_user) assert_response :success - assert_select "tr#post-disapproval-#{@post_disapproval.id} .created-column a.user-member", true + assert_select "tr#post-disapproval-#{@post_disapproval.id} .created-column a.user-post-approver", true end should "not allow non-mods to see disapprover names" do get post_disapprovals_path assert_response :success - assert_select "tr#post-disapproval-#{@post_disapproval.id} .created-column a.user-member", false + assert_select "tr#post-disapproval-#{@post_disapproval.id} .created-column a.user-post-approver", false end end end diff --git a/test/functional/post_flags_controller_test.rb b/test/functional/post_flags_controller_test.rb index a4766c54f..fe74264ea 100644 --- a/test/functional/post_flags_controller_test.rb +++ b/test/functional/post_flags_controller_test.rb @@ -4,10 +4,10 @@ class PostFlagsControllerTest < ActionDispatch::IntegrationTest context "The post flags controller" do setup do @user = create(:user) - @flagger = create(:gold_user, created_at: 2.weeks.ago) - @uploader = create(:mod_user, created_at: 2.weeks.ago) + @flagger = create(:gold_user, id: 999, created_at: 2.weeks.ago) + @uploader = create(:mod_user, name: "chen", created_at: 2.weeks.ago) @mod = create(:mod_user) - @post = create(:post, is_flagged: true, uploader: @uploader) + @post = create(:post, id: 101, is_flagged: true, uploader: @uploader) @post_flag = create(:post_flag, post: @post, creator: @flagger) end @@ -26,6 +26,11 @@ class PostFlagsControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + @other_flag = create(:post_flag, post: build(:post, is_flagged: true, tag_string: "touhou")) + @unrelated_flag = create(:post_flag, reason: "poor quality") + end + should "render" do get post_flags_path assert_response :success @@ -60,23 +65,46 @@ class PostFlagsControllerTest < ActionDispatch::IntegrationTest assert_select "tr#post-flag-#{@post_flag.id} .flagged-column a.user-gold", true end - context "with search parameters" do - should "render" do - get_auth post_flags_path(search: { post_id: @post_flag.post_id }), @user - assert_response :success + context "as a normal user" do + setup do + CurrentUser.user = @user end - should "hide flagged posts when the searcher is the uploader" do - get_auth post_flags_path(search: { creator_id: @flagger.id }), @uploader - assert_response :success - assert_select "tr#post-flag-#{@post_flag.id}", false + should respond_to_search({}).with { [@unrelated_flag, @other_flag, @post_flag] } + should respond_to_search(reason_matches: "poor quality").with { @unrelated_flag } + should respond_to_search(category: "normal").with { [@unrelated_flag, @other_flag, @post_flag] } + should respond_to_search(category: "deleted").with { [] } + + context "using includes" do + should respond_to_search(post_id: 101).with { @post_flag } + should respond_to_search(post_tags_match: "touhou").with { @other_flag } + should respond_to_search(post: {uploader_name: "chen"}).with { @post_flag } + should respond_to_search(creator_id: 999).with { [] } + end + end + + context "when the user is the uploader" do + setup do + CurrentUser.user = @uploader end - should "show flagged posts when the searcher is not the uploader" do - get_auth post_flags_path(search: { creator_id: @flagger.id }), @mod - assert_response :success - assert_select "tr#post-flag-#{@post_flag.id}", true + should respond_to_search(creator_id: 999).with { [] } + end + + context "when the user is a mod and not the uploader" do + setup do + CurrentUser.user = @mod end + + should respond_to_search(creator_id: 999).with { @post_flag } + end + + context "when the user is the flagger" do + setup do + CurrentUser.user = @flagger + end + + should respond_to_search(creator_id: 999).with { @post_flag } end end diff --git a/test/functional/post_replacements_controller_test.rb b/test/functional/post_replacements_controller_test.rb index 26f41ccf5..e9021d1de 100644 --- a/test/functional/post_replacements_controller_test.rb +++ b/test/functional/post_replacements_controller_test.rb @@ -3,9 +3,9 @@ require 'test_helper' class PostReplacementsControllerTest < ActionDispatch::IntegrationTest context "The post replacements controller" do setup do - @mod = create(:moderator_user, can_approve_posts: true, created_at: 1.month.ago) + @mod = create(:moderator_user, name: "yukari", can_approve_posts: true, created_at: 1.month.ago) as(@mod) do - @post = create(:post, source: "https://google.com") + @post = create(:post, source: "https://google.com", tag_string: "touhou") @post_replacement = create(:post_replacement, post: @post) end end @@ -60,10 +60,23 @@ class PostReplacementsControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + as(create(:admin_user)) { @admin_replacement = create(:post_replacement, replacement_url: "https://danbooru.donmai.us") } + end + should "render" do - get post_replacements_path, params: {format: "json"} + get post_replacements_path assert_response :success end + + should respond_to_search({}).with { [@admin_replacement, @post_replacement] } + should respond_to_search(replacement_url_like: "*danbooru*").with { @admin_replacement } + + context "using includes" do + should respond_to_search(post_tags_match: "touhou").with { @post_replacement } + should respond_to_search(creator: {level: User::Levels::ADMIN}).with { @admin_replacement } + should respond_to_search(creator_name: "yukari").with { @post_replacement } + end end end end diff --git a/test/functional/post_votes_controller_test.rb b/test/functional/post_votes_controller_test.rb index 4024010d7..65313b022 100644 --- a/test/functional/post_votes_controller_test.rb +++ b/test/functional/post_votes_controller_test.rb @@ -3,17 +3,45 @@ require 'test_helper' class PostVotesControllerTest < ActionDispatch::IntegrationTest context "The post vote controller" do setup do - @user = create(:gold_user) - @post = create(:post) + @user = create(:gold_user, name: "meiling") + @post = create(:post, tag_string: "dragon") end context "index action" do - should "work" do - as(@user) { create(:post_vote, post_id: @post.id, user_id: @user.id) } - get_auth post_votes_path, @user + setup do + @admin = create(:admin_user) + as(@user) { @post_vote = create(:post_vote, post: @post, user: @user) } + as(@admin) { @admin_vote = create(:post_vote, post: @post, user: @admin) } + @unrelated_vote = create(:post_vote) + end + should "render" do + get_auth post_votes_path, @user assert_response :success end + + context "as a user" do + setup do + CurrentUser.user = @user + end + + should respond_to_search({}).with { @post_vote } + end + + context "as a moderator" do + setup do + CurrentUser.user = @admin + end + + should respond_to_search({}).with { [@unrelated_vote, @admin_vote, @post_vote] } + should respond_to_search(score: 1).with { [@unrelated_vote, @admin_vote, @post_vote].select{ |v| v.score == 1 } } + + context "using includes" do + should respond_to_search(post_tags_match: "dragon").with { [@admin_vote, @post_vote] } + should respond_to_search(user_name: "meiling").with { @post_vote } + should respond_to_search(user: {level: User::Levels::ADMIN}).with { @admin_vote } + end + end end context "create action" do diff --git a/test/functional/tag_aliases_controller_test.rb b/test/functional/tag_aliases_controller_test.rb index f987f4580..4e6111d83 100644 --- a/test/functional/tag_aliases_controller_test.rb +++ b/test/functional/tag_aliases_controller_test.rb @@ -7,14 +7,42 @@ class TagAliasesControllerTest < ActionDispatch::IntegrationTest end context "index action" do - should "list all tag alias" do + setup do + @user = create(:builder_user, name: "sakuya") + as (@user) do + @forum_topic = create(:forum_topic, title: "Touhou BUR") + @forum_post = create(:forum_post, topic: @forum_topic, body: "because") + end + @antecedent_tag = create(:copyright_tag, name: "touhou", post_count: 1000) + @consequent_tag = create(:copyright_tag, name: "touhou_project", post_count: 10) + @antecedent_wiki = create(:wiki_page, title: "touhou", body: "zun project") + @consequent_wiki = create(:wiki_page, title: "touhou_project") + + @other_alias = create(:tag_alias, antecedent_name: "touhou", consequent_name: "touhou_project", creator: @user, status: "pending", forum_topic: @forum_topic, forum_post: @forum_post) + @unrelated_alias = create(:tag_alias) + end + + should "render" do get tag_aliases_path assert_response :success end - should "list all tag_alias (with search)" do - get tag_aliases_path, params: {:search => {:antecedent_name => "aaa"}} - assert_response :success + should respond_to_search({}).with { [@unrelated_alias, @other_alias, @tag_alias] } + should respond_to_search(antecedent_name: "aaa").with { @tag_alias } + should respond_to_search(consequent_name: "bbb").with { @tag_alias } + should respond_to_search(status: "pending").with { @other_alias } + + context "using includes" do + should respond_to_search(antecedent_tag: {post_count: 1000}).with { @other_alias } + should respond_to_search(consequent_tag: {category: Tag.categories.copyright}).with { @other_alias } + should respond_to_search(has_antecedent_tag: "true").with { @other_alias } + should respond_to_search(has_consequent_tag: "false").with { [@unrelated_alias, @tag_alias] } + should respond_to_search(antecedent_wiki: {body_matches: "zun project"}).with { @other_alias } + should respond_to_search(has_consequent_wiki: "true").with { @other_alias } + should respond_to_search(forum_topic: {title_matches: "Touhou BUR"}).with { @other_alias } + should respond_to_search(forum_post: {body: "because"}).with { @other_alias } + should respond_to_search(creator_name: "sakuya").with { @other_alias } + should respond_to_search(creator: {level: User::Levels::BUILDER}).with { @other_alias } end end diff --git a/test/functional/tag_implications_controller_test.rb b/test/functional/tag_implications_controller_test.rb index c43858be3..f7f9b4187 100644 --- a/test/functional/tag_implications_controller_test.rb +++ b/test/functional/tag_implications_controller_test.rb @@ -7,6 +7,44 @@ class TagImplicationsControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + @user = create(:builder_user, name: "sakuya") + as (@user) do + @forum_topic = create(:forum_topic, title: "Weapon BUR") + @forum_post = create(:forum_post, topic: @forum_topic, body: "because") + end + @antecedent_tag = create(:copyright_tag, name: "cannon", post_count: 10) + @consequent_tag = create(:copyright_tag, name: "weapon", post_count: 1000) + @antecedent_wiki = create(:wiki_page, title: "cannon", body: "made of fun") + @consequent_wiki = create(:wiki_page, title: "weapon") + + @other_implication = create(:tag_implication, antecedent_name: "cannon", consequent_name: "weapon", creator: @user, status: "pending", forum_topic: @forum_topic, forum_post: @forum_post) + @unrelated_implication = create(:tag_implication) + end + + should "render" do + get tag_implications_path + assert_response :success + end + + should respond_to_search({}).with { [@unrelated_implication, @other_implication, @tag_implication] } + should respond_to_search(antecedent_name: "aaa").with { @tag_implication } + should respond_to_search(consequent_name: "bbb").with { @tag_implication } + should respond_to_search(status: "pending").with { @other_implication } + + context "using includes" do + should respond_to_search(antecedent_tag: {post_count: 10}).with { @other_implication } + should respond_to_search(consequent_tag: {category: Tag.categories.copyright}).with { @other_implication } + should respond_to_search(has_antecedent_tag: "true").with { @other_implication } + should respond_to_search(has_consequent_tag: "false").with { [@unrelated_implication, @tag_implication] } + should respond_to_search(antecedent_wiki: {body_matches: "made of fun"}).with { @other_implication } + should respond_to_search(has_consequent_wiki: "true").with { @other_implication } + should respond_to_search(forum_topic: {title_matches: "Weapon BUR"}).with { @other_implication } + should respond_to_search(forum_post: {body: "because"}).with { @other_implication } + should respond_to_search(creator_name: "sakuya").with { @other_implication } + should respond_to_search(creator: {level: User::Levels::BUILDER}).with { @other_implication } + end + should "list all tag implications" do get tag_implications_path assert_response :success diff --git a/test/functional/tags_controller_test.rb b/test/functional/tags_controller_test.rb index 91eea376d..56dead38c 100644 --- a/test/functional/tags_controller_test.rb +++ b/test/functional/tags_controller_test.rb @@ -36,27 +36,43 @@ class TagsControllerTest < ActionDispatch::IntegrationTest context "searching" do setup do as(@user) do - @miku = create(:tag, name: "hatsune_miku", category: Tag.categories.character) - @wokada = create(:tag, name: "wokada", category: Tag.categories.artist) - @vocaloid = create(:tag, name: "vocaloid", category: Tag.categories.copyright) + @miku = create(:character_tag, name: "hatsune_miku") + @wokada = create(:artist_tag, name: "wokada") + @vocaloid = create(:copyright_tag, name: "vocaloid") + @weapon = create(:tag, name: "weapon") @empty = create(:tag, name: "empty", post_count: 0) create(:tag_alias, antecedent_name: "miku", consequent_name: "hatsune_miku") - create(:wiki_page, title: "hatsune_miku") + create(:tag_implication, antecedent_name: "axe", consequent_name: "weapon") + create(:wiki_page, title: "hatsune_miku", body: "[[vocaloid]]") create(:artist, name: "wokada") end end + should "render" do + get tags_path + assert_response :success + end + + should respond_to_search({}).with { [@weapon, @vocaloid, @wokada, @miku, @tag] } should respond_to_search(name_matches: "hatsune_miku").with { @miku } should respond_to_search(name_normalize: "HATSUNE_MIKU ").with { @miku } should respond_to_search(name_or_alias_matches: "miku").with { @miku } should respond_to_search(fuzzy_name_matches: "miku_hatsune", order: "similarity").with { @miku } should respond_to_search(name: "empty", hide_empty: "true").with { [] } should respond_to_search(name: "empty", hide_empty: "false").with { [@empty] } - should respond_to_search(name: "wokada", has_artist: "true").with { @wokada } - should respond_to_search(name: "hatsune_miku", has_artist: "false").with { @miku } - should respond_to_search(name: "hatsune_miku", has_wiki: "true").with { @miku } - should respond_to_search(name: "vocaloid", has_wiki: "false").with { @vocaloid } + + context "using includes" do + should respond_to_search(name: "wokada", has_artist: "true").with { @wokada } + should respond_to_search(name: "hatsune_miku", has_artist: "false").with { @miku } + should respond_to_search(name: "hatsune_miku", has_wiki_page: "true").with { @miku } + should respond_to_search(name: "vocaloid", has_wiki_page: "false").with { @vocaloid } + should respond_to_search(consequent_aliases: {antecedent_name: "miku"}).with { @miku } + should respond_to_search(consequent_implications: {antecedent_name: "axe"}).with { @weapon } + should respond_to_search(wiki_page: {body_matches: "*vocaloid*"}).with { @miku } + should respond_to_search(artist: {is_banned: "false"}).with { @wokada } + should respond_to_search(has_dtext_links: "true").with { @vocaloid } + end end end diff --git a/test/functional/uploads_controller_test.rb b/test/functional/uploads_controller_test.rb index e5fcc445c..17bbb071d 100644 --- a/test/functional/uploads_controller_test.rb +++ b/test/functional/uploads_controller_test.rb @@ -30,7 +30,7 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest context "The uploads controller" do setup do - @user = create(:contributor_user) + @user = create(:contributor_user, name: "marisa") mock_iqdb_service! end @@ -173,8 +173,11 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest context "index action" do setup do as(@user) do - @upload = create(:source_upload, tag_string: "foo bar") - @upload2 = create(:source_upload, tag_string: "tagme", rating: "e") + @upload = create(:upload, tag_string: "foo bar", source: "http://example.com/foobar") + @post_upload = create(:source_upload, status: "completed", post: build(:post, tag_string: "touhou"), rating: "e") + end + as(create(:user)) do + @upload3 = create(:upload) end end @@ -183,23 +186,28 @@ class UploadsControllerTest < ActionDispatch::IntegrationTest assert_response :success end - context "with search parameters" do - should "render" do - search_params = { - uploader_name: @upload.uploader.name, - source_matches: @upload.source, - rating: @upload.rating, - status: @upload.status, - server: @upload.server - } - - get_auth uploads_path, @user, params: { search: search_params } - assert_response :success - - get_auth uploads_path(format: :json), @user, params: { search: search_params } - assert_response :success - assert_equal(@upload.id, response.parsed_body.first["id"]) + context "as an uploader" do + setup do + CurrentUser.user = @user end + + should respond_to_search({}).with { [@post_upload, @upload] } + should respond_to_search(source: "http://example.com/foobar").with { @upload } + should respond_to_search(rating: "e").with { @post_upload } + should respond_to_search(tag_string: "*foo*").with { @upload } + + context "using includes" do + should respond_to_search(post_tags_match: "touhou").with { @post_upload } + should respond_to_search(uploader: {name: "marisa"}).with { [@post_upload, @upload] } + end + end + + context "as an admin" do + setup do + CurrentUser.user = create(:admin_user) + end + + should respond_to_search({}).with { [@upload3, @post_upload, @upload] } end end diff --git a/test/functional/user_feedbacks_controller_test.rb b/test/functional/user_feedbacks_controller_test.rb index 4c88f6f24..012f2be58 100644 --- a/test/functional/user_feedbacks_controller_test.rb +++ b/test/functional/user_feedbacks_controller_test.rb @@ -3,9 +3,9 @@ require 'test_helper' class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest context "The user feedbacks controller" do setup do - @user = create(:user) - @critic = create(:gold_user) - @mod = create(:moderator_user) + @user = create(:user, name: "cirno") + @critic = create(:gold_user, name: "eiki") + @mod = create(:moderator_user, id: 1000) @user_feedback = create(:user_feedback, user: @user, creator: @critic) end @@ -37,23 +37,43 @@ class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest end context "index action" do + setup do + @other_feedback = create(:user_feedback, user: @user, creator: @mod, body: "blah", category: "neutral") + @unrelated_feedback = create(:user_feedback, is_deleted: true) + end + should "render" do get_auth user_feedbacks_path, @user assert_response :success end - should "not allow members to see deleted feedbacks" do - as(@user) { @user_feedback.update!(is_deleted: true) } - get_auth user_feedbacks_path, @user + context "as a user" do + setup do + CurrentUser.user = @user + end - assert_response :success - assert_select "tr#user-feedback-#{@user_feedback.id}", false + should respond_to_search({}).with { [@other_feedback, @user_feedback] } + should respond_to_search(body_matches: "blah").with { @other_feedback } + should respond_to_search(category: "positive").with { @user_feedback } + should respond_to_search(is_deleted: "true").with { [] } + + context "using includes" do + should respond_to_search(creator_name: "eiki").with { @user_feedback } + should respond_to_search(creator_id: 1000).with { @other_feedback } + should respond_to_search(creator: {level: User::Levels::GOLD}).with { @user_feedback } + end end - context "with search parameters" do - should "render" do - get_auth user_feedbacks_path, @critic, params: {:search => {:user_id => @user.id}} - assert_response :success + context "as a moderator" do + setup do + CurrentUser.user = @mod + end + + should respond_to_search({}).with { [@unrelated_feedback, @other_feedback, @user_feedback] } + should respond_to_search(is_deleted: "true").with { @unrelated_feedback } + + context "using includes" do + should respond_to_search(user_name: "cirno").with { [@other_feedback, @user_feedback] } end end end diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index c342a98a0..694c38fe7 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -7,7 +7,14 @@ class UsersControllerTest < ActionDispatch::IntegrationTest end context "index action" do - should "list all users" do + setup do + @first_user = User.find(1) + @mod_user = create(:moderator_user, name: "yukari") + @other_user = create(:builder_user, can_upload_free: true, inviter: @mod_user, created_at: 2.weeks.ago) + @uploader = create(:user, created_at: 2.weeks.ago) + end + + should "render" do get users_path assert_response :success end @@ -28,14 +35,54 @@ class UsersControllerTest < ActionDispatch::IntegrationTest assert_response 404 end - should "list all users (with search)" do - get users_path, params: {:search => {:name_matches => @user.name}} - assert_response :success - end + should respond_to_search({}).with { [@uploader, @other_user, @mod_user, @user, @first_user] } + should respond_to_search(min_level: User::Levels::BUILDER).with { [@other_user, @mod_user, @first_user] } + should respond_to_search(can_upload_free: "true").with { @other_user } + should respond_to_search(name_matches: "yukari").with { @mod_user } - should "list all users (with blank search parameters)" do - get users_path, params: { search: { inviter: { name_matches: "" }, level: "", name: "test" } } - assert_redirected_to users_path(search: { name: "test" }) + context "using includes" do + setup do + as (@uploader) { @post = create(:post, tag_string: "touhou", uploader: @uploader, is_flagged: true) } + as (@user) do + create(:note, post: @post) + create(:artist_commentary, post: @post) + create(:artist) + create(:wiki_page) + @forum = create(:forum_post, creator: @user, topic: build(:forum_topic, creator: @user)) + end + as (@other_user) do + @other_post = create(:post, rating: "e", uploader: @other_user) + create(:post_appeal, creator: @other_user, post: @post) + create(:comment, creator: @other_user, post: @other_post) + create(:forum_post_vote, creator: @other_user, forum_post: @forum) + create(:tag_alias, creator: @other_user) + create(:tag_implication, creator: @other_user) + end + as (@mod_user) do + create(:post_approval, user: @mod_user, post: @post) + create(:user_feedback, user: @other_user, creator: @mod_user) + create(:ban, user: @other_user, banner: @mod_user) + end + end + + should respond_to_search(has_artist_versions: "true").with { @user } + should respond_to_search(has_wiki_page_versions: "true").with { @user } + should respond_to_search(has_forum_topics: "true").with { @user } + should respond_to_search(has_forum_posts: "true").with { @user } + should respond_to_search(has_forum_post_votes: "true").with { @other_user } + should respond_to_search(has_feedback: "true").with { @other_user } + should respond_to_search(has_tag_aliases: "true").with { @other_user } + should respond_to_search(has_tag_implications: "true").with { @other_user } + should respond_to_search(has_bans: "true").with { @other_user } + should respond_to_search(has_artist_commentary_versions: "true").with { @user } + should respond_to_search(has_comments: "true").with { @other_user } + should respond_to_search(has_note_versions: "true").with { @user } + should respond_to_search(has_post_appeals: "true").with { @other_user } + should respond_to_search(has_post_approvals: "true").with { @mod_user } + should respond_to_search(has_posts: "true").with { [@uploader, @other_user] } + should respond_to_search(posts_tags_match: "touhou").with { @uploader } + should respond_to_search(posts: {rating: "e"}).with { @other_user } + should respond_to_search(inviter: {name: "yukari"}).with { @other_user } end end diff --git a/test/functional/wiki_page_versions_controller_test.rb b/test/functional/wiki_page_versions_controller_test.rb index 110021e59..ad897b10c 100644 --- a/test/functional/wiki_page_versions_controller_test.rb +++ b/test/functional/wiki_page_versions_controller_test.rb @@ -3,23 +3,34 @@ require 'test_helper' class WikiPageVersionsControllerTest < ActionDispatch::IntegrationTest context "The wiki page versions controller" do setup do - @user = create(:user) - as(@user) do - @wiki_page = create(:wiki_page) - @wiki_page.update(:body => "1 2") - @wiki_page.update(:body => "2 3") - end + @user = create(:user, id: 100) + @builder = create(:builder_user, name: "nitori") + as(@user) { @wiki_page = create(:wiki_page, id: 101) } + as(@builder) { @wiki_page.update(title: "supreme", body: "blah", other_names: ["not_this"]) } + as(@user) { @wiki_page.update(body: "blah blah") } end context "index action" do - should "list all versions" do + setup do + @versions = @wiki_page.versions + end + + should "render" do get wiki_page_versions_path assert_response :success end - should "list all versions that match the search criteria" do - get wiki_page_versions_path, params: {:search => {:wiki_page_id => @wiki_page.id}} - assert_response :success + should respond_to_search({}).with { @versions.reverse } + should respond_to_search(title_matches: "supreme").with { [@versions[2], @versions[1]] } + should respond_to_search(body_matches: "blah").with { [@versions[2], @versions[1]] } + should respond_to_search(other_names_include_any: "not_this").with { [@versions[2], @versions[1]] } + + context "using includes" do + should respond_to_search(wiki_page_id: 101).with { @versions.reverse } + should respond_to_search(wiki_page_id: 102).with { [] } + should respond_to_search(updater_id: 100).with { [@versions[2], @versions[0]] } + should respond_to_search(updater_name: "nitori").with { @versions[1] } + should respond_to_search(updater: {level: User::Levels::BUILDER}).with { @versions[1] } end end diff --git a/test/functional/wiki_pages_controller_test.rb b/test/functional/wiki_pages_controller_test.rb index 713b28e1e..5a4ad9c2b 100644 --- a/test/functional/wiki_pages_controller_test.rb +++ b/test/functional/wiki_pages_controller_test.rb @@ -14,11 +14,13 @@ class WikiPagesControllerTest < ActionDispatch::IntegrationTest @deleted = create(:wiki_page, title: "deleted", is_deleted: true) @vocaloid = create(:wiki_page, title: "vocaloid") @miku = create(:wiki_page, title: "hatsune_miku", other_names: ["初音ミク"], body: "miku is a [[vocaloid]]") - create(:tag, name: "hatsune_miku", category: Tag.categories.character) + @picasso = create(:wiki_page, title: "picasso") + create(:artist, name: "picasso", is_banned: true) + create(:character_tag, name: "hatsune_miku") end end - should "list all wiki_pages" do + should "render" do get wiki_pages_path assert_response :success end @@ -34,19 +36,27 @@ class WikiPagesControllerTest < ActionDispatch::IntegrationTest assert_redirected_to wiki_pages_path(search: { title_normalize: "tagme" }, redirect: true) end + should respond_to_search({}).with { [@picasso, @miku, @vocaloid, @deleted, @tagme] } should respond_to_search(title: "tagme").with { @tagme } should respond_to_search(title: "tagme", order: "post_count").with { @tagme } should respond_to_search(title_normalize: "TAGME ").with { @tagme } - should respond_to_search(tag: { category: Tag.categories.character }).with { @miku } - should respond_to_search(hide_deleted: "true").with { [@miku, @vocaloid, @tagme] } + should respond_to_search(hide_deleted: "true").with { [@picasso, @miku, @vocaloid, @tagme] } should respond_to_search(linked_to: "vocaloid").with { @miku } - should respond_to_search(not_linked_to: "vocaloid").with { [@vocaloid, @deleted, @tagme] } + should respond_to_search(not_linked_to: "vocaloid").with { [@picasso, @vocaloid, @deleted, @tagme] } should respond_to_search(other_names_match: "初音ミク").with { @miku } should respond_to_search(other_names_match: "初*").with { @miku } should respond_to_search(other_names_present: "true").with { @miku } - should respond_to_search(other_names_present: "false").with { [@vocaloid, @deleted, @tagme] } + should respond_to_search(other_names_present: "false").with { [@picasso, @vocaloid, @deleted, @tagme] } + + context "using includes" do + should respond_to_search(has_tag: "true").with { @miku } + should respond_to_search(tag: { category: Tag.categories.character }).with { @miku } + should respond_to_search(has_dtext_links: "true").with { @miku } + should respond_to_search(has_artist: "true").with { @picasso } + should respond_to_search(artist: {is_banned: "true"}).with { @picasso } + end end context "search action" do diff --git a/test/test_helpers/controller_helper.rb b/test/test_helpers/controller_helper.rb index 716bfaa97..35796d6de 100644 --- a/test/test_helpers/controller_helper.rb +++ b/test/test_helpers/controller_helper.rb @@ -9,28 +9,37 @@ module ControllerHelper # setup { @touhou = create(:tag, name: "touhou") } # should respond_to_search(name: "touhou").with { @touhou } # - def respond_to_search(search_params) - RespondToSearchMatcher.new(search_params) + def respond_to_search(search_params, other_params: {}) + RespondToSearchMatcher.new(search_params, other_params) end - class RespondToSearchMatcher < Struct.new(:params) + class RespondToSearchMatcher < Struct.new(:params, :other_params) def description "should respond to a search for #{params}" end def matches?(subject, &block) - search_params = { search: params } + search_params = other_params.merge({ search: params }) expected_items = @test_case.instance_eval(&@expected) @test_case.instance_eval do # calls e.g. "wiki_pages_path" if we're in WikiPagesControllerTest. index_url = send("#{subject.controller_path}_path") - get index_url, as: :json, params: search_params + # Allows for different authorization levels to be used, instead of just anonymous + if CurrentUser.user.present? + get_auth index_url, CurrentUser.user, as: :json, params: search_params + else + get index_url, as: :json, params: search_params + end + # Don't continue processing if there was an error + assert_response :success + + # Some fields like :updated_at do not get finalized until later, so allow lambda functions + # to evaluate expressions like a sort after the network call has completed + expected_items = expected_items.call if expected_items.respond_to?(:call) expected_ids = Array(expected_items).map(&:id) responded_ids = response.parsed_body.map { |item| item["id"] } - - assert_response :success assert_equal(expected_ids, responded_ids) end end diff --git a/test/unit/bulk_update_request_test.rb b/test/unit/bulk_update_request_test.rb index eb95c7418..c4763e8e1 100644 --- a/test/unit/bulk_update_request_test.rb +++ b/test/unit/bulk_update_request_test.rb @@ -83,7 +83,7 @@ class BulkUpdateRequestTest < ActiveSupport::TestCase context "that has an invalid alias" do setup do - @alias1 = create(:tag_alias, creator: @admin) + @alias1 = create(:tag_alias, antecedent_name: "aaa", consequent_name: "bbb", creator: @admin) @req = FactoryBot.build(:bulk_update_request, :script => "create alias bbb -> aaa") end