Skip to content

Commit

Permalink
FEATURE: closed events (#564)
Browse files Browse the repository at this point in the history
Adds support for "closed" events instead of just relying on the start & end dates.

An event might now be "expired" when it happened in the past.

An event might now also be "closed", if for whatever reasons, the author decides to "cancel" it.

Context - https://meta.discourse.org/t/when-closing-event-it-moves-it-to-todays-date-time/307292
  • Loading branch information
ZogStriP committed May 14, 2024
1 parent f21a2e4 commit acb0681
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 101 deletions.
35 changes: 13 additions & 22 deletions app/models/discourse_post_event/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -230,9 +230,9 @@ def create_notification!(user, post, predefined_attendance: false)
end

def ongoing?
(
self.ends_at ? (self.starts_at..self.ends_at).cover?(Time.now) : self.starts_at >= Time.now
) && !self.expired?
return false if self.closed || self.expired?
finishes_at = self.ends_at || self.starts_at.end_of_day
(self.starts_at..finishes_at).cover?(Time.now)
end

def self.statuses
Expand Down Expand Up @@ -284,16 +284,13 @@ def enforce_private_invitees!
end

def can_user_update_attendance(user)
!self.expired? &&
return false if self.closed || self.expired?
return true if self.public?

self.private? &&
(
self.public? ||
(
self.private? &&
(
self.invitees.exists?(user_id: user.id) ||
(user.groups.pluck(:name) & self.raw_invitees).any?
)
)
self.invitees.exists?(user_id: user.id) ||
(user.groups.pluck(:name) & self.raw_invitees).any?
)
end

Expand All @@ -315,18 +312,11 @@ def self.update_from_raw(post)
url: event_params[:url],
recurrence: event_params[:recurrence],
timezone: event_params[:timezone],
status:
(
if event_params[:status].present?
Event.statuses[event_params[:status].to_sym]
else
event.status
end
),
status: Event.statuses[event_params[:status]&.to_sym] || event.status,
reminders: event_params[:reminders],
raw_invitees:
event_params[:"allowed-groups"] ? event_params[:"allowed-groups"].split(",") : nil,
raw_invitees: event_params[:"allowed-groups"]&.split(","),
minimal: event_params[:minimal],
closed: event_params[:closed] || false,
}

params[:custom_fields] = {}
Expand Down Expand Up @@ -417,4 +407,5 @@ def calculate_next_date(start_date: nil)
# recurrence :string
# timezone :string
# minimal :boolean default(FALSE), not null
# closed :boolean default(FALSE), not null
#
49 changes: 27 additions & 22 deletions app/serializers/discourse_post_event/event_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,34 @@

module DiscoursePostEvent
class EventSerializer < ApplicationSerializer
attributes :id
attributes :creator
attributes :sample_invitees
attributes :watching_invitee
attributes :starts_at
attributes :ends_at
attributes :timezone
attributes :stats
attributes :status
attributes :raw_invitees
attributes :post
attributes :name
attributes :can_act_on_discourse_post_event
attributes :can_update_attendance
attributes :category_id
attributes :creator
attributes :custom_fields
attributes :ends_at
attributes :id
attributes :is_closed
attributes :is_expired
attributes :is_ongoing
attributes :should_display_invitees
attributes :url
attributes :custom_fields
attributes :is_public
attributes :is_private
attributes :is_public
attributes :is_standalone
attributes :reminders
attributes :recurrence
attributes :minimal
attributes :category_id
attributes :name
attributes :post
attributes :raw_invitees
attributes :recurrence
attributes :recurrence_rule
attributes :reminders
attributes :sample_invitees
attributes :should_display_invitees
attributes :starts_at
attributes :stats
attributes :status
attributes :timezone
attributes :url
attributes :watching_invitee

def can_act_on_discourse_post_event
scope.can_act_on_discourse_post_event?(object)
Expand All @@ -55,15 +56,19 @@ def is_ongoing
end

def is_public
object.status === Event.statuses[:public]
object.public?
end

def is_private
object.status === Event.statuses[:private]
object.private?
end

def is_standalone
object.status === Event.statuses[:standalone]
object.standalone?
end

def is_closed
object.closed
end

def status
Expand Down
4 changes: 4 additions & 0 deletions assets/javascripts/discourse/lib/raw-event-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export function buildParams(startsAt, endsAt, eventModel, siteSettings) {

params.start = moment(startsAt).tz(eventTz).format("YYYY-MM-DD HH:mm");

if (eventModel.closed) {
params.closed = "true";
}

if (eventModel.status) {
params.status = eventModel.status;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,28 @@ export default createWidget("discourse-post-event-dates", {
});
},

html(attrs) {
html({ localDates, eventModel }) {
const content = [
iconNode("clock"),
h("span.date", new RawHtml({ html: `<span>${attrs.localDates}</span>` })),
h("span.date", new RawHtml({ html: `<span>${localDates}</span>` })),
];

if (
attrs.eventModel.is_expired &&
attrs.eventModel.status !== "standalone"
eventModel.is_expired &&
!eventModel.is_closed &&
!eventModel.is_standalone
) {
let participants;
const label = I18n.t(
"discourse_calendar.discourse_post_event.event_ui.participants",
{
count: attrs.eventModel.stats.going,
count: eventModel.stats.going,
}
);
if (attrs.eventModel.stats.going > 0) {
if (eventModel.stats.going > 0) {
participants = this.attach("link", {
action: "showAllParticipatingInvitees",
actionParam: attrs.eventModel.id,
actionParam: eventModel.id,
contents: () => label,
});
} else {
Expand Down
77 changes: 57 additions & 20 deletions assets/javascripts/discourse/widgets/discourse-post-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,23 +82,58 @@ export default createWidget("discourse-post-event", {
),
didConfirm: () => {
return this.store.find("post", eventModel.id).then((post) => {
const raw = post.raw;
const startsAt = eventModel.starts_at
? moment(eventModel.starts_at)
: moment();
eventModel.closed = true;

const eventParams = buildParams(
moment().isBefore(startsAt) ? moment() : startsAt,
moment().isBefore(startsAt) ? moment().add(1, "minute") : moment(),
eventModel.starts_at,
eventModel.ends_at,
eventModel,
this.siteSettings
);
const newRaw = replaceRaw(eventParams, raw);

const newRaw = replaceRaw(eventParams, post.raw);

if (newRaw) {
const props = {
raw: newRaw,
edit_reason: I18n.t(
"discourse_calendar.discourse_post_event.edit_reason_closed"
),
};

return cook(newRaw).then((cooked) => {
props.cooked = cooked.string;
return post.save(props);
});
}
});
},
});
},

openEvent(eventModel) {
this.dialog.yesNoConfirm({
message: I18n.t(
"discourse_calendar.discourse_post_event.builder_modal.confirm_open"
),
didConfirm: () => {
return this.store.find("post", eventModel.id).then((post) => {
eventModel.closed = false;

const eventParams = buildParams(
eventModel.starts_at,
eventModel.ends_at,
eventModel,
this.siteSettings
);

const newRaw = replaceRaw(eventParams, post.raw);

if (newRaw) {
const props = {
raw: newRaw,
edit_reason: I18n.t(
"discourse_calendar.discourse_post_event.edit_reason"
"discourse_calendar.discourse_post_event.edit_reason_opened"
),
};

Expand Down Expand Up @@ -249,18 +284,20 @@ export default createWidget("discourse-post-event", {
{{{transformed.eventName}}}
</span>
<div class="status-and-creators">
{{#unless transformed.isStandaloneEvent}}
{{#if state.eventModel.is_expired}}
<span class="status expired">
{{i18n "discourse_calendar.discourse_post_event.models.event.expired"}}
</span>
{{else}}
<span class={{transformed.statusClass}} title={{transformed.eventStatusDescription}}>
{{transformed.eventStatusLabel}}
</span>
{{/if}}
<span class="separator">·</span>
{{/unless}}
{{#if state.eventModel.is_expired}}
<span class="status expired">
{{i18n "discourse_calendar.discourse_post_event.models.event.expired"}}
</span>
{{else if state.eventModel.is_closed}}
<span class="status closed">
{{i18n "discourse_calendar.discourse_post_event.models.event.closed"}}
</span>
{{else}}
<span class={{transformed.statusClass}} title={{transformed.eventStatusDescription}}>
{{transformed.eventStatusLabel}}
</span>
{{/if}}
<span class="separator">·</span>
<span class="creators">
<span class="created-by">{{i18n "discourse_calendar.discourse_post_event.event_ui.created_by"}}</span>
{{attach widget="discourse-post-event-creator" attrs=(hash user=state.eventModel.creator)}}
Expand Down

0 comments on commit acb0681

Please sign in to comment.