discourse/plugins/discourse-calendar/app/models/discourse_post_event/invitee.rb
Sam ea9f2f532b
FEATURE: introduce max attendees for events (#34313)
Allows to set the max attendees of an event. When an event is full you
can only mark yourself as interested or not going. The going button will
be disabled.

Maximum attendees can be defined in the post builder:
<img width="569" height="106" alt="Screenshot 2025-09-01 at 20 57 16"
src="https://github.com/user-attachments/assets/bf61cd57-d35e-44a7-8d05-263ee9cd7df0"
/>

---------

Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
2025-09-01 22:56:19 +02:00

100 lines
3 KiB
Ruby
Vendored

# frozen_string_literal: true
module DiscoursePostEvent
class Invitee < ActiveRecord::Base
UNKNOWN_ATTENDANCE = "unknown"
self.table_name = "discourse_post_event_invitees"
belongs_to :event, foreign_key: :post_id
belongs_to :user
default_scope { joins(:user).includes(:user).where("users.id IS NOT NULL") }
scope :with_status, ->(status) { where(status: Invitee.statuses[status]) }
after_commit :sync_chat_channel_members
def self.statuses
@statuses ||= Enum.new(going: 0, interested: 1, not_going: 2)
end
def self.create_attendance!(user_id, post_id, status)
event = Event.find(post_id)
if status.to_sym == :going && event.at_capacity?
raise Discourse::InvalidParameters.new(:max_attendees)
end
invitee =
Invitee.create!(status: Invitee.statuses[status.to_sym], post_id: post_id, user_id: user_id)
invitee.event.publish_update!
invitee.update_topic_tracking!
DiscourseEvent.trigger(:discourse_calendar_post_event_invitee_status_changed, invitee)
invitee
rescue ActiveRecord::RecordNotUnique
# do nothing in case multiple new attendances would be created very fast
Invitee.find_by(post_id: post_id, user_id: user_id)
end
def update_attendance!(status)
if status && status.to_sym == :going && event.at_capacity? &&
self.status != Invitee.statuses[:going]
raise Discourse::InvalidParameters.new(:max_attendees)
end
new_status = Invitee.statuses[status.to_sym]
status_changed = self.status != new_status
self.update(status: new_status)
self.event.publish_update!
self.update_topic_tracking! if status_changed
DiscourseEvent.trigger(:discourse_calendar_post_event_invitee_status_changed, self)
self
end
def self.extract_uniq_usernames(groups)
User.real.where(
id: GroupUser.where(group_id: Group.where(name: groups).select(:id)).select(:user_id),
)
end
def sync_chat_channel_members
return if !self.event.chat_enabled?
ChatChannelSync.sync(self.event)
end
def update_topic_tracking!
topic_id = self.event.post.topic.id
user_id = self.user.id
tracking = :regular
case self.status
when Invitee.statuses[:going]
tracking = :watching
when Invitee.statuses[:interested]
tracking = :tracking
end
TopicUser.change(
user_id,
topic_id,
notification_level: TopicUser.notification_levels[tracking],
)
end
end
end
# == Schema Information
#
# Table name: discourse_post_event_invitees
#
# id :bigint not null, primary key
# post_id :integer not null
# user_id :integer not null
# status :integer
# created_at :datetime not null
# updated_at :datetime not null
# notified :boolean default(FALSE), not null
#
# Indexes
#
# discourse_post_event_invitees_post_id_user_id_idx (post_id,user_id) UNIQUE
#