otwarchive-symphonyarchive/app/models/challenge_claim.rb

156 lines
6 KiB
Ruby
Raw Permalink Normal View History

2026-03-11 22:22:11 +00:00
class ChallengeClaim < ApplicationRecord
belongs_to :claiming_user, class_name: "User", inverse_of: :request_claims
belongs_to :collection
belongs_to :request_signup, class_name: "ChallengeSignup"
belongs_to :request_prompt, class_name: "Prompt"
belongs_to :creation, polymorphic: true
before_create :inherit_fields_from_request_prompt
def inherit_fields_from_request_prompt
return unless request_prompt
self.collection = request_prompt.collection
self.request_signup = request_prompt.challenge_signup
end
scope :for_request_signup, lambda {|signup|
where('request_signup_id = ?', signup.id)
}
scope :by_claiming_user, lambda {|user|
select('DISTINCT challenge_claims.*')
.joins("INNER JOIN users ON challenge_claims.claiming_user_id = users.id")
.where('users.id = ?', user.id)
}
scope :in_collection, lambda {|collection|
where('challenge_claims.collection_id = ?', collection.id)
}
scope :with_request, -> { where('request_signup IS NOT NULL') }
scope :with_no_request, -> { where('request_signup_id IS NULL') }
REQUESTING_PSEUD_JOIN = "INNER JOIN challenge_signups ON (challenge_claims.request_signup_id = challenge_signups.id)
INNER JOIN pseuds ON challenge_signups.pseud_id = pseuds.id"
CLAIMING_PSEUD_JOIN = "INNER JOIN users ON challenge_claims.claiming_user_id = users.id"
COLLECTION_ITEMS_JOIN = "INNER JOIN collection_items ON (collection_items.collection_id = challenge_claims.collection_id AND
collection_items.item_id = challenge_claims.creation_id AND
collection_items.item_type = challenge_claims.creation_type)"
COLLECTION_ITEMS_LEFT_JOIN = "LEFT JOIN collection_items ON (collection_items.collection_id = challenge_claims.collection_id AND
collection_items.item_id = challenge_claims.creation_id AND
collection_items.item_type = challenge_claims.creation_type)"
scope :order_by_date, -> { order("created_at ASC") }
def self.order_by_requesting_pseud(dir="ASC")
if dir.casecmp("ASC").zero?
joins(REQUESTING_PSEUD_JOIN).order("pseuds.name ASC")
else
joins(REQUESTING_PSEUD_JOIN).order("pseuds.name DESC")
end
end
def self.order_by_offering_pseud(dir="ASC")
if dir.casecmp("ASC").zero?
joins(CLAIMING_PSEUD_JOIN).order("pseuds.name ASC")
else
joins(CLAIMING_PSEUD_JOIN).order("pseuds.name DESC")
end
end
WORKS_JOIN = "INNER JOIN works ON works.id = challenge_claims.creation_id AND challenge_claims.creation_type = 'Work'"
WORKS_LEFT_JOIN = "LEFT JOIN works ON works.id = challenge_claims.creation_id AND challenge_claims.creation_type = 'Work'"
scope :fulfilled, -> {
joins(COLLECTION_ITEMS_JOIN).joins(WORKS_JOIN)
.where("challenge_claims.creation_id IS NOT NULL AND collection_items.user_approval_status = ? AND collection_items.collection_approval_status = ? AND works.posted = 1",
CollectionItem.user_approval_statuses[:approved], CollectionItem.collection_approval_statuses[:approved])
}
scope :posted, -> { joins(WORKS_JOIN).where("challenge_claims.creation_id IS NOT NULL AND works.posted = 1") }
# should be faster than unfulfilled scope because no giant left joins
def self.unfulfilled_in_collection(collection)
fulfilled_ids = ChallengeClaim.in_collection(collection).fulfilled.pluck(:id)
fulfilled_ids.empty? ? in_collection(collection) : in_collection(collection).where("challenge_claims.id NOT IN (?)", fulfilled_ids)
end
# faster than unposted scope because no left join!
def self.unposted_in_collection(collection)
posted_ids = ChallengeClaim.in_collection(collection).posted.pluck(:id)
posted_ids.empty? ? in_collection(collection) : in_collection(collection).where("challenge_claims.creation_id IS NULL OR challenge_claims.id NOT IN (?)", posted_ids)
end
# has to be a left join to get works that don't have a collection item
scope :unfulfilled, -> {
joins(COLLECTION_ITEMS_LEFT_JOIN).joins(WORKS_LEFT_JOIN)
.where("challenge_claims.creation_id IS NULL OR collection_items.user_approval_status != ? OR collection_items.collection_approval_status != ? OR works.posted = 0",
CollectionItem.user_approval_statuses[:approved], CollectionItem.collection_approval_statuses[:approved])
}
# ditto
scope :unposted, -> { joins(WORKS_LEFT_JOIN).where("challenge_claims.creation_id IS NULL OR works.posted = 0") }
scope :unstarted, -> { where("challenge_claims.creation_id IS NULL") }
def self.unposted_for_user(user)
all_claims = ChallengeClaim.by_claiming_user(user)
posted_ids = all_claims.posted.pluck(:id)
all_claims.where("challenge_claims.id NOT IN (?)", posted_ids)
end
def get_collection_item
return nil unless self.creation
CollectionItem.where('collection_id = ? AND item_id = ? AND item_type = ?', self.collection_id, self.creation_id, self.creation_type).first
end
def fulfilled?
self.creation && (item = get_collection_item) && item.approved?
end
def title
if !self.request_prompt.title.blank?
title = request_prompt.title
else
title = ts("Untitled Prompt")
end
title += " " + ts("in") + " #{self.collection.title}"
if self.request_prompt.anonymous?
title += " " + ts("(Anonymous)")
else
title += " (#{self.request_byline})"
end
return title
end
def claiming_pseud
claiming_user.try(:default_pseud)
end
def requesting_pseud
request_signup ? request_signup.pseud : nil
end
def claim_byline
claiming_pseud.try(:byline) || "deleted user"
end
def request_byline
request_signup ? request_signup.pseud.byline : "- None -"
end
def user_allowed_to_destroy?(current_user)
(self.claiming_user == current_user) || self.collection.user_is_maintainer?(current_user)
end
def prompt_description
request_prompt&.description || ""
end
end