otwarchive-symphonyarchive/app/models/challenge_signup_summary.rb
2026-03-11 22:22:11 +00:00

151 lines
4.4 KiB
Ruby

class ChallengeSignupSummary
attr_reader :collection, :challenge
def initialize(collection)
@collection = collection
@challenge = collection.challenge
end
######################################################################
# CALCULATING INFO FOR THE SUMMARY
######################################################################
# The type of tags to be summarized.
#
# For a multi-fandom challenge, this is probably fandom, but for a
# single-fandom challenge, it will probably be character or relationship (or
# one of the other tag types, if the challenge doesn't include either).
#
# Note that this returns the lowercase tag type.
def tag_type
@tag_type = collection.challenge.topmost_tag_type
end
# Returns an array of tag listings that includes the number of requests and
# offers each tag has in this challenge, sorted by least-offered and most-requested
def summary
@summary ||= tags.map { |tag| tag_summary(tag) }.compact.sort
end
private
# The class of tags to be summarized. Calls tag_type to retrieve the type.
def tag_class
raise "Redshirt: Attempted to constantize invalid class initialize tag_class #{tag_type.classify}" unless Tag::TYPES.include?(tag_type.classify)
tag_type.classify.constantize
end
# All of the tags of the desired type that have been
# used in requests or offers for this challenge
def tags
@tags ||= tag_class.in_challenge(collection)
end
def tag_summary(tag)
request_count = Request.in_collection(collection).with_tag(tag).count
offer_count = Offer.in_collection(collection).with_tag(tag).count
if request_count > 0
ChallengeSignupTagSummary.new(tag.id, tag.name, request_count, offer_count)
end
end
public
######################################################################
# GENERATING THE SUMMARY IN RESQUE
######################################################################
@queue = :collection
# The action to be performed when this class is enqueued using Resque.
def self.perform(collection_id)
collection = Collection.find(collection_id)
summary = ChallengeSignupSummary.new(collection)
summary.generate_in_background
end
# Asynchronously generate the cached version.
def enqueue_for_generation
Resque.enqueue(ChallengeSignupSummary, collection.id)
end
# Write the summary to Memcached, so that it can be retrieved and displayed.
def generate_in_background
locals = {
challenge_collection: collection,
tag_type: self.tag_type,
summary_tags: self.summary,
generated_live: false
}
partial = "challenge/#{self.challenge.class.name.demodulize.tableize.singularize}/challenge_signups_summary"
self.cached_contents = ChallengeSignupsController.render(partial: partial,
locals: locals)
end
######################################################################
# CACHING THE SUMMARY
######################################################################
# Retrieve the value of the cache for this signup summary.
def cached_contents
cached_info[:contents]
end
# Retrieve the time that the cache was last updated.
def cached_time
cached_info[:time]
end
# The equivalent of touching a file in the file system. Update the
# modification time.
def touch_cache
data = cached_info.dup
data[:time] = Time.now
Rails.cache.write(cache_key, data)
end
private
# Set the value of the cache for this signup summary.
def cached_contents=(value)
data = {
contents: value,
time: Time.now
}
Rails.cache.write(cache_key, data)
end
# Retrieve the hash containing cached info: the value being cached (if it
# exists), and the time that it was updated.
def cached_info
Rails.cache.read(cache_key) || {}
end
# The key used to store info about the signup summary in memcached.
def cache_key
"/v1/challenge_signup_summaries/#{collection.id}"
end
end
class ChallengeSignupTagSummary < Struct.new(:id, :name, :requests, :offers)
# Prioritize tags with the fewest offers and most requests
# If they have the same number of offers and requests, sort by name
def <=>(other)
if self.offers == other.offers
if self.requests == other.requests
self.name <=> other.name
else
other.requests <=> self.requests
end
else
self.offers <=> other.offers
end
end
end