465 lines
19 KiB
Ruby
465 lines
19 KiB
Ruby
|
|
class Collection < ApplicationRecord
|
||
|
|
include Filterable
|
||
|
|
include WorksOwner
|
||
|
|
|
||
|
|
has_one_attached :icon do |attachable|
|
||
|
|
attachable.variant(:standard, resize_to_limit: [100, 100], loader: { n: -1 })
|
||
|
|
end
|
||
|
|
|
||
|
|
# i18n-tasks-use t("errors.attributes.icon.invalid_format")
|
||
|
|
# i18n-tasks-use t("errors.attributes.icon.too_large")
|
||
|
|
validates :icon, attachment: {
|
||
|
|
allowed_formats: %r{image/\S+},
|
||
|
|
maximum_size: ArchiveConfig.ICON_SIZE_KB_MAX.kilobytes
|
||
|
|
}
|
||
|
|
|
||
|
|
belongs_to :parent, class_name: "Collection", inverse_of: :children
|
||
|
|
has_many :children, class_name: "Collection", foreign_key: "parent_id", inverse_of: :parent
|
||
|
|
|
||
|
|
has_one :collection_profile, dependent: :destroy
|
||
|
|
accepts_nested_attributes_for :collection_profile
|
||
|
|
|
||
|
|
has_one :collection_preference, dependent: :destroy
|
||
|
|
accepts_nested_attributes_for :collection_preference
|
||
|
|
|
||
|
|
before_validation :clear_icon
|
||
|
|
before_validation :cleanup_url
|
||
|
|
before_create :ensure_associated
|
||
|
|
def ensure_associated
|
||
|
|
self.collection_preference = CollectionPreference.new unless self.collection_preference
|
||
|
|
self.collection_profile = CollectionProfile.new unless self.collection_profile
|
||
|
|
end
|
||
|
|
|
||
|
|
belongs_to :challenge, dependent: :destroy, polymorphic: true
|
||
|
|
has_many :prompts, dependent: :destroy
|
||
|
|
|
||
|
|
has_many :signups, class_name: "ChallengeSignup", dependent: :destroy
|
||
|
|
has_many :potential_matches, dependent: :destroy
|
||
|
|
has_many :assignments, class_name: "ChallengeAssignment", dependent: :destroy
|
||
|
|
has_many :claims, class_name: "ChallengeClaim", dependent: :destroy
|
||
|
|
|
||
|
|
# We need to get rid of all of these if the challenge is destroyed
|
||
|
|
after_save :clean_up_challenge
|
||
|
|
def clean_up_challenge
|
||
|
|
return if self.challenge_id
|
||
|
|
|
||
|
|
assignments.each(&:destroy)
|
||
|
|
potential_matches.each(&:destroy)
|
||
|
|
signups.each(&:destroy)
|
||
|
|
prompts.each(&:destroy)
|
||
|
|
end
|
||
|
|
|
||
|
|
has_many :collection_items, dependent: :destroy
|
||
|
|
accepts_nested_attributes_for :collection_items, allow_destroy: true
|
||
|
|
has_many :approved_collection_items, -> { approved_by_both }, class_name: "CollectionItem"
|
||
|
|
|
||
|
|
has_many :works, through: :collection_items, source: :item, source_type: "Work"
|
||
|
|
has_many :approved_works, -> { posted }, through: :approved_collection_items, source: :item, source_type: "Work"
|
||
|
|
|
||
|
|
has_many :bookmarks, through: :collection_items, source: :item, source_type: "Bookmark"
|
||
|
|
has_many :approved_bookmarks, through: :approved_collection_items, source: :item, source_type: "Bookmark"
|
||
|
|
|
||
|
|
has_many :collection_participants, dependent: :destroy
|
||
|
|
accepts_nested_attributes_for :collection_participants, allow_destroy: true
|
||
|
|
|
||
|
|
has_many :participants, through: :collection_participants, source: :pseud
|
||
|
|
has_many :users, through: :participants, source: :user
|
||
|
|
has_many :invited, -> { where(collection_participants: { participant_role: CollectionParticipant::INVITED }) }, through: :collection_participants, source: :pseud
|
||
|
|
has_many :owners, -> { where(collection_participants: { participant_role: CollectionParticipant::OWNER }) }, through: :collection_participants, source: :pseud
|
||
|
|
has_many :moderators, -> { where(collection_participants: { participant_role: CollectionParticipant::MODERATOR }) }, through: :collection_participants, source: :pseud
|
||
|
|
has_many :members, -> { where(collection_participants: { participant_role: CollectionParticipant::MEMBER }) }, through: :collection_participants, source: :pseud
|
||
|
|
has_many :posting_participants, -> { where(collection_participants: { participant_role: [CollectionParticipant::MEMBER, CollectionParticipant::MODERATOR, CollectionParticipant::OWNER] }) }, through: :collection_participants, source: :pseud
|
||
|
|
|
||
|
|
CHALLENGE_TYPE_OPTIONS = [
|
||
|
|
["", ""],
|
||
|
|
[ts("Gift Exchange"), "GiftExchange"],
|
||
|
|
[ts("Prompt Meme"), "PromptMeme"]
|
||
|
|
].freeze
|
||
|
|
|
||
|
|
validate :must_have_owners
|
||
|
|
def must_have_owners
|
||
|
|
# we have to use collection participants because the association may not exist until after
|
||
|
|
# the collection is saved
|
||
|
|
errors.add(:base, ts("Collection has no valid owners.")) if (self.collection_participants + (self.parent ? self.parent.collection_participants : [])).select(&:is_owner?)
|
||
|
|
.empty?
|
||
|
|
end
|
||
|
|
|
||
|
|
validate :collection_depth
|
||
|
|
def collection_depth
|
||
|
|
errors.add(:base, ts("Sorry, but %{name} is a subcollection, so it can't also be a parent collection.", name: parent.name)) if self.parent&.parent || (self.parent && !self.children.empty?) || (!self.children.empty? && !self.children.collect(&:children).flatten.empty?)
|
||
|
|
end
|
||
|
|
|
||
|
|
validate :parent_exists
|
||
|
|
def parent_exists
|
||
|
|
errors.add(:base, ts("We couldn't find a collection with name %{name}.", name: parent_name)) unless parent_name.blank? || Collection.find_by(name: parent_name)
|
||
|
|
end
|
||
|
|
|
||
|
|
validate :parent_is_allowed
|
||
|
|
def parent_is_allowed
|
||
|
|
if parent
|
||
|
|
if parent == self
|
||
|
|
errors.add(:base, ts("You can't make a collection its own parent."))
|
||
|
|
elsif parent_id_changed? && !parent.user_is_maintainer?(User.current_user)
|
||
|
|
errors.add(:base, ts("You have to be a maintainer of %{name} to make a subcollection.", name: parent.name))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
validates :name, presence: { message: ts("Please enter a name for your collection.") }
|
||
|
|
validates :name, uniqueness: { message: ts("Sorry, that name is already taken. Try again, please!") }
|
||
|
|
validates :name,
|
||
|
|
length: { minimum: ArchiveConfig.TITLE_MIN,
|
||
|
|
too_short: ts("must be at least %{min} characters long.", min: ArchiveConfig.TITLE_MIN) }
|
||
|
|
validates :name,
|
||
|
|
length: { maximum: ArchiveConfig.TITLE_MAX,
|
||
|
|
too_long: ts("must be less than %{max} characters long.", max: ArchiveConfig.TITLE_MAX) }
|
||
|
|
validates :name,
|
||
|
|
format: { message: ts("must begin and end with a letter or number; it may also contain underscores. It may not contain any other characters, including spaces."),
|
||
|
|
with: /\A[A-Za-z0-9]\w*[A-Za-z0-9]\Z/ }
|
||
|
|
validates :icon_alt_text, length: { allow_blank: true, maximum: ArchiveConfig.ICON_ALT_MAX,
|
||
|
|
too_long: ts("must be less than %{max} characters long.", max: ArchiveConfig.ICON_ALT_MAX) }
|
||
|
|
validates :icon_comment_text, length: { allow_blank: true, maximum: ArchiveConfig.ICON_COMMENT_MAX,
|
||
|
|
too_long: ts("must be less than %{max} characters long.", max: ArchiveConfig.ICON_COMMENT_MAX) }
|
||
|
|
|
||
|
|
validates :email, email_format: { allow_blank: true }
|
||
|
|
|
||
|
|
validates :title, presence: { message: ts("Please enter a title to be displayed for your collection.") }
|
||
|
|
validates :title,
|
||
|
|
length: { minimum: ArchiveConfig.TITLE_MIN,
|
||
|
|
too_short: ts("must be at least %{min} characters long.", min: ArchiveConfig.TITLE_MIN) }
|
||
|
|
validates :title,
|
||
|
|
length: { maximum: ArchiveConfig.TITLE_MAX,
|
||
|
|
too_long: ts("must be less than %{max} characters long.", max: ArchiveConfig.TITLE_MAX) }
|
||
|
|
validate :no_reserved_strings
|
||
|
|
def no_reserved_strings
|
||
|
|
errors.add(:title, ts("^Sorry, the ',' character cannot be in a collection Display Title.")) if
|
||
|
|
title.match(/,/)
|
||
|
|
end
|
||
|
|
|
||
|
|
# return title.html_safe to overcome escaping done by sanitiser
|
||
|
|
def title
|
||
|
|
self[:title].try(:html_safe)
|
||
|
|
end
|
||
|
|
|
||
|
|
validates :description,
|
||
|
|
length: { allow_blank: true,
|
||
|
|
maximum: ArchiveConfig.SUMMARY_MAX,
|
||
|
|
too_long: ts("must be less than %{max} characters long.", max: ArchiveConfig.SUMMARY_MAX) }
|
||
|
|
|
||
|
|
validates :header_image_url, format: { allow_blank: true, with: URI::DEFAULT_PARSER.make_regexp(%w[http https]), message: ts("is not a valid URL.") }
|
||
|
|
validates :header_image_url, format: { allow_blank: true, with: /\A\S+\.(png|gif|jpg)\z/, message: ts("can only point to a gif, jpg, or png file.") }
|
||
|
|
|
||
|
|
validates :tags_after_saving,
|
||
|
|
length: { maximum: ArchiveConfig.COLLECTION_TAGS_MAX,
|
||
|
|
message: "^Sorry, a collection can only have %{count} tags." }
|
||
|
|
|
||
|
|
scope :top_level, -> { where(parent_id: nil) }
|
||
|
|
scope :closed, -> { joins(:collection_preference).where(collection_preferences: { closed: true }) }
|
||
|
|
scope :not_closed, -> { joins(:collection_preference).where(collection_preferences: { closed: false }) }
|
||
|
|
scope :moderated, -> { joins(:collection_preference).where(collection_preferences: { moderated: true }) }
|
||
|
|
scope :unmoderated, -> { joins(:collection_preference).where(collection_preferences: { moderated: false }) }
|
||
|
|
scope :unrevealed, -> { joins(:collection_preference).where(collection_preferences: { unrevealed: true }) }
|
||
|
|
scope :anonymous, -> { joins(:collection_preference).where(collection_preferences: { anonymous: true }) }
|
||
|
|
scope :no_challenge, -> { where(challenge_type: nil) }
|
||
|
|
scope :gift_exchange, -> { where(challenge_type: "GiftExchange") }
|
||
|
|
scope :prompt_meme, -> { where(challenge_type: "PromptMeme") }
|
||
|
|
scope :name_only, -> { select("collections.name") }
|
||
|
|
scope :by_title, -> { order(:title) }
|
||
|
|
scope :for_blurb, -> { includes(:parent, :moderators, :children, :collection_preference, owners: [:user]).with_attached_icon }
|
||
|
|
|
||
|
|
def cleanup_url
|
||
|
|
self.header_image_url = Addressable::URI.heuristic_parse(self.header_image_url) if self.header_image_url
|
||
|
|
end
|
||
|
|
|
||
|
|
# Get only collections with running challenges
|
||
|
|
def self.signup_open(challenge_type)
|
||
|
|
case challenge_type
|
||
|
|
when "PromptMeme"
|
||
|
|
not_closed.where(challenge_type: challenge_type)
|
||
|
|
.joins("INNER JOIN prompt_memes on prompt_memes.id = challenge_id").where("prompt_memes.signup_open = 1")
|
||
|
|
.where("prompt_memes.signups_close_at > ?", Time.zone.now).order("prompt_memes.signups_close_at DESC")
|
||
|
|
when "GiftExchange"
|
||
|
|
not_closed.where(challenge_type: challenge_type)
|
||
|
|
.joins("INNER JOIN gift_exchanges on gift_exchanges.id = challenge_id").where("gift_exchanges.signup_open = 1")
|
||
|
|
.where("gift_exchanges.signups_close_at > ?", Time.zone.now).order("gift_exchanges.signups_close_at DESC")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
scope :with_name_like, lambda { |name|
|
||
|
|
where("collections.name LIKE ?", "%#{name}%")
|
||
|
|
.limit(10)
|
||
|
|
}
|
||
|
|
|
||
|
|
scope :with_title_like, lambda { |title|
|
||
|
|
where("collections.title LIKE ?", "%#{title}%")
|
||
|
|
}
|
||
|
|
|
||
|
|
scope :with_item_count, lambda {
|
||
|
|
select("collections.*, count(distinct collection_items.id) as item_count")
|
||
|
|
.joins("left join collections child_collections on child_collections.parent_id = collections.id
|
||
|
|
left join collection_items on ( (collection_items.collection_id = child_collections.id OR collection_items.collection_id = collections.id)
|
||
|
|
AND collection_items.user_approval_status = 1
|
||
|
|
AND collection_items.collection_approval_status = 1)")
|
||
|
|
.group("collections.id")
|
||
|
|
}
|
||
|
|
|
||
|
|
def to_param
|
||
|
|
name_was
|
||
|
|
end
|
||
|
|
|
||
|
|
# Change membership of collection(s) from a particular pseud to the orphan account
|
||
|
|
def self.orphan(pseuds, collections, default: true)
|
||
|
|
pseuds.each do |pseud|
|
||
|
|
collections.each do |collection|
|
||
|
|
if pseud && collection && collection.owners.include?(pseud)
|
||
|
|
orphan_pseud = default ? User.orphan_account.default_pseud : User.orphan_account.pseuds.find_or_create_by(name: pseud.name)
|
||
|
|
pseud.change_membership(collection, orphan_pseud)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
## AUTOCOMPLETE
|
||
|
|
# set up autocomplete and override some methods
|
||
|
|
include AutocompleteSource
|
||
|
|
|
||
|
|
def autocomplete_search_string
|
||
|
|
"#{name} #{title}"
|
||
|
|
end
|
||
|
|
|
||
|
|
def autocomplete_search_string_before_last_save
|
||
|
|
"#{name_before_last_save} #{title_before_last_save}"
|
||
|
|
end
|
||
|
|
|
||
|
|
def autocomplete_prefixes
|
||
|
|
["autocomplete_collection_all",
|
||
|
|
"autocomplete_collection_#{closed? ? 'closed' : 'open'}"]
|
||
|
|
end
|
||
|
|
|
||
|
|
def autocomplete_score
|
||
|
|
all_items.approved_by_collection.approved_by_user.count
|
||
|
|
end
|
||
|
|
## END AUTOCOMPLETE
|
||
|
|
|
||
|
|
def parent_name=(name)
|
||
|
|
@parent_name = name
|
||
|
|
self.parent = Collection.find_by(name: name)
|
||
|
|
end
|
||
|
|
|
||
|
|
def parent_name
|
||
|
|
@parent_name || (self.parent ? self.parent.name : "")
|
||
|
|
end
|
||
|
|
|
||
|
|
def all_owners
|
||
|
|
(self.owners + (self.parent ? self.parent.owners : [])).uniq
|
||
|
|
end
|
||
|
|
|
||
|
|
def all_moderators
|
||
|
|
(self.moderators + (self.parent ? self.parent.moderators : [])).uniq
|
||
|
|
end
|
||
|
|
|
||
|
|
def all_members
|
||
|
|
(self.members + (self.parent ? self.parent.members : [])).uniq
|
||
|
|
end
|
||
|
|
|
||
|
|
def all_posting_participants
|
||
|
|
(self.posting_participants + (self.parent ? self.parent.posting_participants : [])).uniq
|
||
|
|
end
|
||
|
|
|
||
|
|
def all_participants
|
||
|
|
(self.participants + (self.parent ? self.parent.participants : [])).uniq
|
||
|
|
end
|
||
|
|
|
||
|
|
def all_items
|
||
|
|
CollectionItem.where(collection_id: ([self.id] + self.children.pluck(:id)))
|
||
|
|
end
|
||
|
|
|
||
|
|
def maintainers
|
||
|
|
self.all_owners + self.all_moderators
|
||
|
|
end
|
||
|
|
|
||
|
|
def user_is_owner?(user)
|
||
|
|
user && user != false && !(user.pseuds & self.all_owners).empty?
|
||
|
|
end
|
||
|
|
|
||
|
|
def user_is_moderator?(user)
|
||
|
|
user && user != false && !(user.pseuds & self.all_moderators).empty?
|
||
|
|
end
|
||
|
|
|
||
|
|
def user_is_maintainer?(user)
|
||
|
|
user && user != false && !(user.pseuds & (self.all_moderators + self.all_owners)).empty?
|
||
|
|
end
|
||
|
|
|
||
|
|
def user_is_participant?(user)
|
||
|
|
user && user != false && !get_participating_pseuds_for_user(user).empty?
|
||
|
|
end
|
||
|
|
|
||
|
|
def user_is_posting_participant?(user)
|
||
|
|
user && user != false && !(user.pseuds & self.all_posting_participants).empty?
|
||
|
|
end
|
||
|
|
|
||
|
|
def get_participating_pseuds_for_user(user)
|
||
|
|
(user && user != false) ? user.pseuds & self.all_participants : []
|
||
|
|
end
|
||
|
|
|
||
|
|
def get_participants_for_user(user)
|
||
|
|
return [] unless user
|
||
|
|
|
||
|
|
CollectionParticipant.in_collection(self).for_user(user)
|
||
|
|
end
|
||
|
|
|
||
|
|
def assignment_notification
|
||
|
|
self.collection_profile.assignment_notification || (parent ? parent.collection_profile.assignment_notification : "")
|
||
|
|
end
|
||
|
|
|
||
|
|
def gift_notification
|
||
|
|
self.collection_profile.gift_notification || (parent ? parent.collection_profile.gift_notification : "")
|
||
|
|
end
|
||
|
|
|
||
|
|
def moderated?() = self.collection_preference.moderated
|
||
|
|
|
||
|
|
def closed?() = self.collection_preference.closed
|
||
|
|
|
||
|
|
def unrevealed?() = self.collection_preference.unrevealed
|
||
|
|
|
||
|
|
def anonymous?() = self.collection_preference.anonymous
|
||
|
|
|
||
|
|
def challenge?() = !self.challenge.nil?
|
||
|
|
|
||
|
|
def gift_exchange?
|
||
|
|
self.challenge_type == "GiftExchange"
|
||
|
|
end
|
||
|
|
|
||
|
|
def prompt_meme?
|
||
|
|
self.challenge_type == "PromptMeme"
|
||
|
|
end
|
||
|
|
|
||
|
|
def maintainers_list
|
||
|
|
self.maintainers.collect(&:user).flatten.uniq
|
||
|
|
end
|
||
|
|
|
||
|
|
def collection_email
|
||
|
|
return self.email if self.email.present?
|
||
|
|
return parent.email if parent && parent.email.present?
|
||
|
|
end
|
||
|
|
|
||
|
|
def notify_maintainers_assignments_sent
|
||
|
|
subject = I18n.t("user_mailer.collection_notification.assignments_sent.subject")
|
||
|
|
message = I18n.t("user_mailer.collection_notification.assignments_sent.complete")
|
||
|
|
if self.collection_email.present?
|
||
|
|
UserMailer.collection_notification(self.id, subject, message, self.collection_email).deliver_later
|
||
|
|
else
|
||
|
|
# if collection email is not set and collection parent email is not set, loop through maintainers and send each a notice via email
|
||
|
|
self.maintainers_list.each do |user|
|
||
|
|
I18n.with_locale(user.preference.locale_for_mails) do
|
||
|
|
translated_subject = I18n.t("user_mailer.collection_notification.assignments_sent.subject")
|
||
|
|
translated_message = I18n.t("user_mailer.collection_notification.assignments_sent.complete")
|
||
|
|
UserMailer.collection_notification(self.id, translated_subject, translated_message, user.email).deliver_later
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def notify_maintainers_challenge_default(challenge_assignment, assignments_page_url)
|
||
|
|
if self.collection_email.present?
|
||
|
|
subject = I18n.t("user_mailer.collection_notification.challenge_default.subject", offer_byline: challenge_assignment.offer_byline)
|
||
|
|
message = I18n.t("user_mailer.collection_notification.challenge_default.complete", offer_byline: challenge_assignment.offer_byline, request_byline: challenge_assignment.request_byline, assignments_page_url: assignments_page_url)
|
||
|
|
UserMailer.collection_notification(self.id, subject, message, self.collection_email).deliver_later
|
||
|
|
else
|
||
|
|
# if collection email is not set and collection parent email is not set, loop through maintainers and send each a notice via email
|
||
|
|
self.maintainers_list.each do |user|
|
||
|
|
I18n.with_locale(user.preference.locale_for_mails) do
|
||
|
|
translated_subject = I18n.t("user_mailer.collection_notification.challenge_default.subject", offer_byline: challenge_assignment.offer_byline)
|
||
|
|
translated_message = I18n.t("user_mailer.collection_notification.challenge_default.complete", offer_byline: challenge_assignment.offer_byline, request_byline: challenge_assignment.request_byline, assignments_page_url: assignments_page_url)
|
||
|
|
UserMailer.collection_notification(self.id, translated_subject, translated_message, user.email).deliver_later
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
include AsyncWithResque
|
||
|
|
@queue = :collection
|
||
|
|
|
||
|
|
def reveal!
|
||
|
|
async(:reveal_collection_items)
|
||
|
|
end
|
||
|
|
|
||
|
|
def reveal_authors!
|
||
|
|
async(:reveal_collection_item_authors)
|
||
|
|
end
|
||
|
|
|
||
|
|
def reveal_collection_items
|
||
|
|
approved_collection_items.each { |collection_item| collection_item.update_attribute(:unrevealed, false) }
|
||
|
|
send_reveal_notifications
|
||
|
|
end
|
||
|
|
|
||
|
|
def reveal_collection_item_authors
|
||
|
|
approved_collection_items.each { |collection_item| collection_item.update_attribute(:anonymous, false) }
|
||
|
|
end
|
||
|
|
|
||
|
|
def send_reveal_notifications
|
||
|
|
approved_collection_items.each(&:notify_of_reveal)
|
||
|
|
end
|
||
|
|
|
||
|
|
def self.sorted_and_filtered(sort, filters, page)
|
||
|
|
pagination_args = { page: page }
|
||
|
|
|
||
|
|
# build up the query with scopes based on the options the user specifies
|
||
|
|
query = Collection.top_level
|
||
|
|
|
||
|
|
if filters[:title].present?
|
||
|
|
# we get the matching collections out of autocomplete and use their ids
|
||
|
|
ids = Collection.autocomplete_lookup(search_param: filters[:title],
|
||
|
|
autocomplete_prefix: (if filters[:closed].blank?
|
||
|
|
"autocomplete_collection_all"
|
||
|
|
else
|
||
|
|
(filters[:closed] ? "autocomplete_collection_closed" : "autocomplete_collection_open")
|
||
|
|
end)).map { |result| Collection.id_from_autocomplete(result) }
|
||
|
|
query = query.where(collections: { id: ids })
|
||
|
|
elsif filters[:closed].present?
|
||
|
|
query = (filters[:closed] == "true" ? query.closed : query.not_closed)
|
||
|
|
end
|
||
|
|
query = (filters[:moderated] == "true" ? query.moderated : query.unmoderated) if filters[:moderated].present?
|
||
|
|
if filters[:challenge_type].present?
|
||
|
|
case filters[:challenge_type]
|
||
|
|
when "gift_exchange"
|
||
|
|
query = query.gift_exchange
|
||
|
|
when "prompt_meme"
|
||
|
|
query = query.prompt_meme
|
||
|
|
when "no_challenge"
|
||
|
|
query = query.no_challenge
|
||
|
|
end
|
||
|
|
end
|
||
|
|
query = query.order(sort).for_blurb
|
||
|
|
|
||
|
|
if filters[:fandom].blank?
|
||
|
|
query.paginate(pagination_args)
|
||
|
|
else
|
||
|
|
fandom = Fandom.find_by_name(filters[:fandom])
|
||
|
|
if fandom
|
||
|
|
(fandom.approved_collections & query).paginate(pagination_args)
|
||
|
|
else
|
||
|
|
[]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
# Delete current icon (thus reverting to archive default icon)
|
||
|
|
def delete_icon=(value)
|
||
|
|
@delete_icon = !value.to_i.zero?
|
||
|
|
end
|
||
|
|
|
||
|
|
def delete_icon
|
||
|
|
!!@delete_icon
|
||
|
|
end
|
||
|
|
alias delete_icon? delete_icon
|
||
|
|
|
||
|
|
def clear_icon
|
||
|
|
return unless delete_icon?
|
||
|
|
|
||
|
|
self.icon.purge
|
||
|
|
self.icon_alt_text = nil
|
||
|
|
self.icon_comment_text = nil
|
||
|
|
end
|
||
|
|
end
|