otwarchive-symphonyarchive/app/models/external_work.rb

127 lines
4.4 KiB
Ruby
Raw Normal View History

2026-03-11 22:22:11 +00:00
class ExternalWork < ApplicationRecord
include Bookmarkable
include Filterable
include Searchable
has_many :related_works, as: :parent
belongs_to :language
# .duplicate.count.size returns the number of URLs with multiple external works
scope :duplicate, -> { group(:url).having("count(DISTINCT id) > 1") }
scope :for_blurb, -> { includes(:language, :tags) }
AUTHOR_LENGTH_MAX = 500
validates_presence_of :title
validates_length_of :title, minimum: ArchiveConfig.TITLE_MIN,
too_short: ts("must be at least %{min} characters long.",
min: ArchiveConfig.TITLE_MIN)
validates_length_of :title, maximum: ArchiveConfig.TITLE_MAX,
too_long: ts("must be less than %{max} characters long.",
max: ArchiveConfig.TITLE_MAX)
validates_length_of :summary, allow_blank: true, maximum: ArchiveConfig.SUMMARY_MAX,
too_long: ts("must be less than %{max} characters long.",
max: ArchiveConfig.SUMMARY_MAX)
validates :author, presence: { message: ts("can't be blank") }
validates_length_of :author, maximum: AUTHOR_LENGTH_MAX,
too_long: ts("must be less than %{max} characters long.",
max: AUTHOR_LENGTH_MAX)
validates :user_defined_tags_count,
at_most: { maximum: proc { ArchiveConfig.USER_DEFINED_TAGS_MAX } }
# TODO: External works should have fandoms, but they currently don't get added through the
# post new work form so we can't validate them
#validates_presence_of :fandoms
before_validation :cleanup_url
# i18n-tasks-use t("errors.attributes.url.invalid")
validates :url, presence: true, url_format: true, url_active: true
def cleanup_url
self.url = Addressable::URI.heuristic_parse(self.url) if self.url
rescue Addressable::URI::InvalidURIError
# url_format validation creates the error message
end
# Allow encoded characters to display correctly in titles
def title
read_attribute(:title).try(:html_safe)
end
########################################################################
# VISIBILITY
########################################################################
# Adapted from work.rb
scope :visible_to_all, -> { where(hidden_by_admin: false) }
scope :visible_to_registered_user, -> { where(hidden_by_admin: false) }
scope :visible_to_admin, -> { where("") }
# a complicated dynamic scope here:
# if the user is an Admin, we use the "visible_to_admin" scope
# if the user is not a logged-in User, we use the "visible_to_all" scope
# otherwise, we use a join to get userids and then get all posted works that are either unhidden OR belong to this user.
# Note: in that last case we have to use select("DISTINCT works.") because of cases where the same user appears twice
# on a work.
scope :visible_to_user, lambda {|user| user.is_a?(Admin) ? visible_to_admin : visible_to_all}
# Use the current user to determine what external works are visible
scope :visible, -> { visible_to_user(User.current_user) }
# Visible unless we're hidden by admin, in which case only an Admin can see.
def visible?(user=User.current_user)
self.hidden_by_admin? ? user.kind_of?(Admin) : true
end
# Visibility has changed, which means we need to reindex
# the external work's bookmarker pseuds, to update their bookmark counts.
def should_reindex_pseuds?
pertinent_attributes = %w[id hidden_by_admin]
destroyed? || (saved_changes.keys & pertinent_attributes).present?
end
######################
# SEARCH
######################
def bookmarkable_json
as_json(
root: false,
only: [
:title, :summary, :hidden_by_admin, :created_at
],
methods: [
:posted, :restricted, :tag, :filter_ids, :rating_ids,
:archive_warning_ids, :category_ids, :fandom_ids, :character_ids,
:relationship_ids, :freeform_ids, :creators, :revised_at
]
).merge(
language_id: language&.short,
bookmarkable_type: "ExternalWork",
bookmarkable_join: { name: "bookmarkable" }
)
end
def posted
true
end
alias_method :posted?, :posted
def restricted
false
end
alias_method :restricted?, :restricted
def creators
[author]
end
def revised_at
created_at
end
end