FEATURE: allows to invite people to public events

FEATURE: allows to invite people to public events

diff --git a/app/controllers/discourse_calendar/post_events_controller.rb b/app/controllers/discourse_calendar/post_events_controller.rb
index 7ee1f8d..1f19d5d 100644
--- a/app/controllers/discourse_calendar/post_events_controller.rb
+++ b/app/controllers/discourse_calendar/post_events_controller.rb
@@ -33,6 +33,23 @@ module DiscourseCalendar
         scope: guardian).as_json
     end
 
+    def invite
+      post_event = PostEvent.find(params[:id])
+      guardian.ensure_can_act_on_post_event!(post_event)
+      invites = Array(params.permit(invites: [])['invites'])
+      users = User.where(
+        id: GroupUser.where(
+          group_id: Group.where(name: invites).select(:id)
+        ).select(:user_id)
+      ).or(User.where(username: invites))
+
+      users.each do |user|
+        post_event.create_notification!(user, post_event.post)
+      end
+
+      render json: success_json
+    end
+
     def show
       post_event = DiscourseCalendar::PostEvent.find(params[:id])
       guardian.ensure_can_see!(post_event.post)
diff --git a/app/models/discourse_calendar/post_event.rb b/app/models/discourse_calendar/post_event.rb
index 9817352..8392cb0 100644
--- a/app/models/discourse_calendar/post_event.rb
+++ b/app/models/discourse_calendar/post_event.rb
@@ -46,20 +46,24 @@ module DiscourseCalendar
 
     def notify_invitees!
       self.invitees.where(notified: false).each do |invitee|
-        invitee.user.notifications.create!(
-          notification_type: Notification.types[:custom],
-          topic_id: self.post.topic_id,
-          post_number: self.post.post_number,
-          data: {
-            topic_title: self.post.topic.title,
-            display_username: self.post.user.username,
-            message: 'discourse_calendar.invite_user_notification'
-          }.to_json
-        )
+        create_notification!(invitee.user, self.post)
         invitee.update!(notified: true)
       end
     end
 
+    def create_notification!(user, post)
+      user.notifications.create!(
+        notification_type: Notification.types[:custom],
+        topic_id: post.topic_id,
+        post_number: post.post_number,
+        data: {
+          topic_title: post.topic.title,
+          display_username: post.user.username,
+          message: 'discourse_calendar.invite_user_notification'
+        }.to_json
+      )
+    end
+
     def self.statuses
       @statuses ||= Enum.new(standalone: 0, public: 1, private: 2)
     end
diff --git a/assets/javascripts/discourse/controllers/invite-user-or-group.js.es6 b/assets/javascripts/discourse/controllers/invite-user-or-group.js.es6
new file mode 100644
index 0000000..976e392
--- /dev/null
+++ b/assets/javascripts/discourse/controllers/invite-user-or-group.js.es6
@@ -0,0 +1,27 @@
+import ModalFunctionality from "discourse/mixins/modal-functionality";
+import Controller from "@ember/controller";
+import { action } from "@ember/object";
+import { extractError } from "discourse/lib/ajax-error";
+import { ajax } from "discourse/lib/ajax";
+
+export default Controller.extend(ModalFunctionality, {
+  invitedNames: null,
+
+  @action
+  setInvitedNames(_, invitedNames) {
+    this.set("invitedNames", invitedNames);
+  },
+
+  @action
+  invite() {
+    return ajax(
+      `/discourse-calendar/post-events/${this.model.id}/invite.json`,
+      {
+        data: { invites: this.invitedNames || [] },
+        type: "POST"
+      }
+    )
+      .then(() => this.send("closeModal"))
+      .catch(e => this.flash(extractError(e), "error"));
+  }
+});
diff --git a/assets/javascripts/discourse/models/post-event.js.es6 b/assets/javascripts/discourse/models/post-event.js.es6
index 9e04f1d..e3d662a 100644
--- a/assets/javascripts/discourse/models/post-event.js.es6
+++ b/assets/javascripts/discourse/models/post-event.js.es6
@@ -1,7 +1,4 @@
 import RestModel from "discourse/models/rest";
-// import { ajax } from "discourse/lib/ajax";
-
-// const BASE_URL = "/discourse-calendar/post-events";
 
 const ATTRIBUTES = {
   id: {},
diff --git a/assets/javascripts/discourse/templates/components/event-field.hbs b/assets/javascripts/discourse/templates/components/event-field.hbs
index 7be8e11..52be09a 100644
--- a/assets/javascripts/discourse/templates/components/event-field.hbs
+++ b/assets/javascripts/discourse/templates/components/event-field.hbs
@@ -1,8 +1,10 @@
 {{#if enabled}}
   <div class="event-field {{class}}">
-    <div class="event-field-label">
-      <span class="label">{{i18n label}}</span>
-    </div>
+    {{#if label}}
+      <div class="event-field-label">
+        <span class="label">{{i18n label}}</span>
+      </div>
+    {{/if}}
     <div class="event-field-control">
       {{yield}}
     </div>
diff --git a/assets/javascripts/discourse/templates/modal/event-ui-builder.hbs b/assets/javascripts/discourse/templates/modal/event-ui-builder.hbs
index b39a168..902e041 100644
--- a/assets/javascripts/discourse/templates/modal/event-ui-builder.hbs
+++ b/assets/javascripts/discourse/templates/modal/event-ui-builder.hbs
@@ -17,6 +17,7 @@
       to=endsAt
       onChange=(action "onChangeDates")
     }}
+
     {{#event-field label="event.ui_builder.status.label"}}
       <label class="radio-label">
         {{radio-button
diff --git a/assets/javascripts/discourse/templates/modal/invite-user-or-group.hbs b/assets/javascripts/discourse/templates/modal/invite-user-or-group.hbs
new file mode 100644
index 0000000..908b81a
--- /dev/null
+++ b/assets/javascripts/discourse/templates/modal/invite-user-or-group.hbs
@@ -0,0 +1,29 @@
+{{#d-modal-body
+  title="event.invite_user_or_group.title"
+  class="invite-user-or-group"
+}}
+  {{#event-field}}
+    {{user-selector
+      single=false
+      onChangeCallback=(action "setInvitedNames")
+      fullWidthWrap=true
+      allowAny=false
+      includeMessageableGroups=true
+      placeholderKey="composer.users_placeholder"
+      tabindex="1"
+      usernames=invitedNames
+      hasGroups=true
+      autocomplete="discourse"
+      excludeCurrentUser=true
+    }}
+  {{/event-field}}
+{{/d-modal-body}}
+
+<div class="modal-footer">
+  {{d-button
+    type="button"
+    class="btn-primary"
+    label="event.invite_user_or_group.invite"
+    action=(action "invite")
+  }}
+</div>
diff --git a/assets/javascripts/discourse/widgets/post-event.js.es6 b/assets/javascripts/discourse/widgets/post-event.js.es6
index 2681175..5bce405 100644
--- a/assets/javascripts/discourse/widgets/post-event.js.es6
+++ b/assets/javascripts/discourse/widgets/post-event.js.es6
@@ -21,6 +21,14 @@ export default createWidget("post-event", {
     }
   },
 
+  inviteUserOrGroup(postId) {
+    this.store.find("post-event", postId).then(postEvent => {
+      showModal("invite-user-or-group", {
+        model: postEvent
+      });
+    });
+  },
+
   showAllInvitees(postId) {
     this.store.find("post-event", postId).then(postEvent => {
       showModal("post-event-invitees", {
@@ -98,7 +106,8 @@ export default createWidget("post-event", {
       startsAtDay: moment(postEvent.starts_at).format("D"),
       postEventName: postEvent.name || postEvent.post.topic.title,
       statusClass: `status ${postEvent.status}`,
-      statusIcon: iconNode(statusIcon)
+      statusIcon: iconNode(statusIcon),
+      isPublicEvent: postEvent.status === "public"
     };
   },
 
@@ -178,6 +187,20 @@ export default createWidget("post-event", {
             action="sendPMToCreator"
           )
         }}
+        {{#if state.postEvent.can_act_on_post_event}}
+        {{#if transformed.isPublicEvent}}
+          {{attach
+            widget="button"
+            attrs=(hash
+              className="btn-small"
+              icon="user-plus"
+              label="event.post_ui.invite"
+              action="inviteUserOrGroup"
+              actionParam=state.postEvent.id
+            )
+          }}
+        {{/if}}
+        {{/if}}
       </footer>
     {{/if}}
   `
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml

[... diff too long, it was truncated ...]

GitHub sha: 36d39f08

params is a HashWithIndifferentAccess so you can use [:invites] here.

Is this going to cause problems when a group and user have the same name?

I suppose any issue here is going to be common to {{user-selector}}.

Kind of awkward - just use the singular for button text?

That’s not possible AFAIK

1 Like