FIX: prevents custom fields to override raw_invitees

FIX: prevents custom fields to override raw_invitees

This commit also refactors specs to better test this behavior and enforces the validation of raw invitees.

diff --git a/app/controllers/discourse_post_event/events_controller.rb b/app/controllers/discourse_post_event/events_controller.rb
index 2c01a7f..08ca1a2 100644
--- a/app/controllers/discourse_post_event/events_controller.rb
+++ b/app/controllers/discourse_post_event/events_controller.rb
@@ -50,27 +50,21 @@ module DiscoursePostEvent
       render json: success_json
     end
 
+    # update is only used for custom fields
+    # everything else is managed by cooking the post
     def update
       DistributedMutex.synchronize("discourse-post-event[event-update]") do
+        event_params[:custom_fields] = (event_params[:custom_fields] || {}).reject { |_, value| value.blank? }
+
         event = Event.find(params[:id])
         guardian.ensure_can_edit!(event.post)
         guardian.ensure_can_act_on_discourse_post_event!(event)
-        event.update_with_params!(event_params)
+        event.update!(event_params)
         serializer = EventSerializer.new(event, scope: guardian)
         render_json_dump(serializer)
       end
     end
 
-    def create
-      event = Event.new(id: event_params[:id])
-      guardian.ensure_can_edit!(event.post)
-      guardian.ensure_can_create_discourse_post_event!
-      event.update_with_params!(event_params)
-      event.publish_update!
-      serializer = EventSerializer.new(event, scope: guardian)
-      render_json_dump(serializer)
-    end
-
     def csv_bulk_invite
       require 'csv'
 
@@ -136,17 +130,7 @@ module DiscoursePostEvent
 
       params
         .require(:event)
-        .permit(
-          :id,
-          :name,
-          :starts_at,
-          :ends_at,
-          :status,
-          :url,
-          :recurrence,
-          custom_fields: allowed_custom_fields,
-          raw_invitees: [],
-        )
+        .permit(custom_fields: allowed_custom_fields)
     end
 
     def ics_request?
diff --git a/app/models/discourse_post_event/event.rb b/app/models/discourse_post_event/event.rb
index 94488e3..d2ff53b 100644
--- a/app/models/discourse_post_event/event.rb
+++ b/app/models/discourse_post_event/event.rb
@@ -101,6 +101,13 @@ module DiscoursePostEvent
       end
     end
 
+    validate :raw_invitees_are_groups
+    def raw_invitees_are_groups
+      if self.raw_invitees && User.select(:id).where(username: self.raw_invitees).limit(1).count > 0
+        errors.add(:base, I18n.t('discourse_post_event.errors.models.event.raw_invitees.only_group'))
+      end
+    end
+
     validate :ends_before_start
     def ends_before_start
       if self.starts_at && self.ends_at && self.starts_at >= self.ends_at
@@ -284,17 +291,14 @@ module DiscoursePostEvent
     end
 
     def update_with_params!(params)
-      params[:custom_fields] =
-        (params[:custom_fields] || {}).reject { |_, value| value.blank? }
-
       case params[:status] ? params[:status].to_i : self.status
       when Event.statuses[:private]
-        raw_invitees =
-          Set.new(
-            Array(self.raw_invitees) + Array(params[:raw_invitees]) -
-              [PUBLIC_GROUP]
-          ).to_a
-        self.update!(params.merge(raw_invitees: raw_invitees))
+        if params.key?(:raw_invitees)
+          params = params.merge(raw_invitees: Array(params[:raw_invitees]) - [PUBLIC_GROUP])
+        else
+          params = params.merge(raw_invitees: Array(self.raw_invitees) - [PUBLIC_GROUP])
+        end
+        self.update!(params)
         self.enforce_private_invitees!
       when Event.statuses[:public]
         self.update!(params.merge(raw_invitees: [PUBLIC_GROUP]))
diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index c75ba8d..9195fc6 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -49,6 +49,7 @@ en:
       models:
         event:
           only_one_event: A post can only have one event.
+          only_group: An event accepts only group names.
           must_be_in_first_post: An event can only be in the first post of a topic.
           raw_invitees_length: "An event is limited to %{count} users/groups."
           ends_at_before_starts_at: "An event can't end before it starts."
diff --git a/lib/discourse_post_event/event_validator.rb b/lib/discourse_post_event/event_validator.rb
index 3f9d329..18f4013 100644
--- a/lib/discourse_post_event/event_validator.rb
+++ b/lib/discourse_post_event/event_validator.rb
@@ -54,7 +54,7 @@ module DiscoursePostEvent
         end
       end
 
-      if extracted_event[:name].present? && extracted_event[:name]
+      if extracted_event[:name].present?
         if !(Event::MIN_NAME_LENGTH..Event::MAX_NAME_LENGTH).cover?(extracted_event[:name].length)
           @post.errors.add(:base, I18n.t('discourse_post_event.errors.models.event.name.length', minimum: Event::MIN_NAME_LENGTH, maximum: Event::MAX_NAME_LENGTH))
           return false
diff --git a/spec/acceptance/post_spec.rb b/spec/acceptance/post_spec.rb
index 1e8ea3e..3f2b851 100644
--- a/spec/acceptance/post_spec.rb
+++ b/spec/acceptance/post_spec.rb
@@ -19,7 +19,7 @@ describe Post do
 
   context 'public event' do
     let(:post_1) { Fabricate(:post) }
-    let(:event_1) { Fabricate(:event, post: post_1) }
+    let(:event_1) { Fabricate(:event, post: post_1, raw_invitees: ['trust_level_0']) }
 
     context 'when a post is updated' do
       context 'when the post has a valid event' do
@@ -161,6 +161,33 @@ describe Post do
               end
             end
           end
+
+          context 'updating raw_invitees' do
+            let(:lurker_1) { Fabricate(:user) }
+            let(:group_1) { Fabricate(:group) }
+
+            it 'doesn’t accept usernames' do
+              event_1.update_with_params!(raw_invitees: [lurker_1.username])
+              expect(event_1.raw_invitees).to eq(['trust_level_0'])
+            end
+
+            it 'doesn’t accept another group than trust_level_0' do
+              event_1.update_with_params!(raw_invitees: [group_1.name])
+              expect(event_1.raw_invitees).to eq(['trust_level_0'])
+            end
+          end
+
+          context 'updating status to private' do
+            it 'it changes the status and force invitees' do
+              expect(event_1.raw_invitees).to eq(['trust_level_0'])
+              expect(event_1.status).to eq(Event.statuses[:public])
+
+              event_1.update_with_params!(status: Event.statuses[:private])
+
+              expect(event_1.raw_invitees).to eq([])
+              expect(event_1.status).to eq(Event.statuses[:private])
+            end
+          end
         end
       end
     end
@@ -451,13 +478,24 @@ describe Post do
         post: post_1,
         status: Event.statuses[:private],
         raw_invitees: [group_1.name],
-        recurrence: 'FREQ=WEEKLY;BYDAY=MO',
         starts_at: 3.hours.ago,
         ends_at: nil
       )
     }
 
     context 'an event with recurrence' do
+      let(:event_1) {
+        Fabricate(
+          :event,
+          post: post_1,
+          status: Event.statuses[:private],
+          raw_invitees: [group_1.name],
+          recurrence: 'FREQ=WEEKLY;BYDAY=MO',
+          starts_at: 3.hours.ago,
+          ends_at: nil
+        )
+      }
+
       before do
         Invitee.create_attendance!(invitee_1.id, event_1.id, :going)
 
@@ -466,15 +504,43 @@ describe Post do
         Jobs.run_later!
       end
 
-      context 'when the event ends' do
+      context 'updating the end' do
         it 'resends event creation notification to invitees and possible invitees' do
           expect(event_1.invitees.count).to eq(1)
 
-          expect { event_1.update_with_params!(ends_at: Time.now) }.to change {
+          expect { event_1.update_with_params!(ends_at: 2.hours.ago) }.to change {
             invitee_1.notifications.count + invitee_2.notifications.count
           }.by(2)
         end
       end
     end
+
+    context 'updating raw_invitees' do
+      let(:lurker_1) { Fabricate(:user) }
+      let(:group_2) { Fabricate(:group) }
+

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

GitHub sha: 04abec77