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