hensei-api/app/models/party_share.rb
Justin Edmund 5597cab95c
Party sharing into crews (#207)
* add party_shares table and model with associations

* add party share errors and blueprint

* add party shares controller and routes

* include shared parties in listings and show

* add party share factory and model specs

* add party shares controller specs

* include shares in party response for owners

* add crew shared_parties endpoint
2026-01-05 02:39:32 -08:00

63 lines
1.9 KiB
Ruby

# frozen_string_literal: true
##
# PartyShare represents a sharing relationship between a party and a group (e.g., a crew).
# It allows party owners to share their parties with specific groups, granting view access
# to members of those groups without changing the party's base visibility.
#
# @!attribute [rw] party
# @return [Party] the party being shared.
# @!attribute [rw] shareable
# @return [Crew] the polymorphic group the party is shared with.
# @!attribute [rw] shared_by
# @return [User] the user who created this share.
class PartyShare < ApplicationRecord
# Associations
belongs_to :party
belongs_to :shareable, polymorphic: true
belongs_to :shared_by, class_name: 'User'
# Validations
validates :party_id, uniqueness: {
scope: [:shareable_type, :shareable_id],
message: 'has already been shared with this group'
}
validate :owner_can_share
validate :sharer_is_member_of_shareable
# Scopes
scope :for_crew, ->(crew) { where(shareable_type: 'Crew', shareable_id: crew.id) }
scope :for_crews, ->(crew_ids) { where(shareable_type: 'Crew', shareable_id: crew_ids) }
scope :for_party, ->(party) { where(party_id: party.id) }
##
# Returns the blueprint class for serialization.
#
# @return [Class] the PartyShareBlueprint class.
def blueprint
PartyShareBlueprint
end
private
##
# Validates that only the party owner can share the party.
#
# @return [void]
def owner_can_share
return if party&.user_id == shared_by_id
errors.add(:shared_by, 'must be the party owner')
end
##
# Validates that the sharer is a member of the group they're sharing to.
#
# @return [void]
def sharer_is_member_of_shareable
return unless shareable_type == 'Crew'
return if shareable&.active_memberships&.exists?(user_id: shared_by_id)
errors.add(:shareable, 'you must be a member of this crew')
end
end