diff --git a/plugins/automation/app/models/discourse_automation/automation.rb b/plugins/automation/app/models/discourse_automation/automation.rb index 15b7b0ccc0f..f1509b6939d 100644 --- a/plugins/automation/app/models/discourse_automation/automation.rb +++ b/plugins/automation/app/models/discourse_automation/automation.rb @@ -20,6 +20,10 @@ module DiscourseAutomation validates :script, presence: true validate :validate_trigger_fields + after_destroy do |automation| + UserCustomField.where(name: automation.new_user_custom_field_name).destroy_all + end + attr_accessor :running_in_background def running_in_background! @@ -163,6 +167,10 @@ module DiscourseAutomation scriptable&.on_reset&.call(self) end + def new_user_custom_field_name + "automation_#{self.id}_new_user" + end + private def validate_trigger_fields diff --git a/plugins/automation/config/locales/client.en.yml b/plugins/automation/config/locales/client.en.yml index 8e68eef23b7..5a7308f5831 100644 --- a/plugins/automation/config/locales/client.en.yml +++ b/plugins/automation/config/locales/client.en.yml @@ -175,6 +175,9 @@ en: once_per_user: label: Once per user description: Will trigger only once per user + new_users_only: + label: New users only + description: Will trigger only for new users that join after this automation is enabled category_created_edited: fields: restricted_category: diff --git a/plugins/automation/lib/discourse_automation/event_handlers.rb b/plugins/automation/lib/discourse_automation/event_handlers.rb index 7e6b9dc849b..81d6144fe08 100644 --- a/plugins/automation/lib/discourse_automation/event_handlers.rb +++ b/plugins/automation/lib/discourse_automation/event_handlers.rb @@ -65,7 +65,7 @@ module DiscourseAutomation end end - def self.handle_user_updated(user) + def self.handle_user_updated(user, new_user: false) return if user.id < 0 name = DiscourseAutomation::Triggers::USER_UPDATED @@ -79,6 +79,13 @@ module DiscourseAutomation next end + new_users_only = automation.trigger_field("new_users_only")["value"] + + new_user_custom_field = automation.new_user_custom_field_name + new_user ||= user.custom_fields[new_user_custom_field].present? + + next if new_users_only && !new_user + required_custom_fields = automation.trigger_field("custom_fields") user_data = {} user_custom_fields_data = DB.query <<-SQL @@ -87,16 +94,22 @@ module DiscourseAutomation JOIN user_custom_fields ucf ON CONCAT('user_field_', uf.id) = ucf.name WHERE ucf.user_id = #{user.id}; SQL + user_custom_fields_data = user_custom_fields_data.each_with_object({}) do |obj, hash| field_name = obj.field_name field_value = obj.field_value hash[field_name] = field_value end + if required_custom_fields["value"] if required_custom_fields["value"].any? { |field| user_custom_fields_data[field].blank? } + if new_users_only + user.custom_fields[new_user_custom_field] = "1" + user.save_custom_fields + end next end user_data[:custom_fields] = user_custom_fields_data @@ -108,11 +121,20 @@ module DiscourseAutomation if required_user_profile_fields["value"].any? { |field| user_profile_data[field].blank? } + if new_users_only + user.custom_fields[new_user_custom_field] = "1" + user.save_custom_fields + end next end user_data[:profile_data] = user_profile_data end + if new_users_only && once_per_user + user.custom_fields.delete(new_user_custom_field) + user.save_custom_fields + end + automation.attach_custom_field(user) automation.trigger!("kind" => name, "user" => user, "user_data" => user_data) end diff --git a/plugins/automation/lib/discourse_automation/triggers/user_updated.rb b/plugins/automation/lib/discourse_automation/triggers/user_updated.rb index 6080f4caa7e..b9ba3936082 100644 --- a/plugins/automation/lib/discourse_automation/triggers/user_updated.rb +++ b/plugins/automation/lib/discourse_automation/triggers/user_updated.rb @@ -8,6 +8,7 @@ DiscourseAutomation::Triggerable.add(DiscourseAutomation::Triggers::USER_UPDATED field :custom_fields, component: :custom_fields field :user_profile, component: :user_profile field :once_per_user, component: :boolean + field :new_users_only, component: :boolean validate do has_triggers = has_trigger_field?(:custom_fields) && has_trigger_field?(:user_profile) diff --git a/plugins/automation/plugin.rb b/plugins/automation/plugin.rb index ed8f9d08f76..f45eabf8dff 100644 --- a/plugins/automation/plugin.rb +++ b/plugins/automation/plugin.rb @@ -208,6 +208,9 @@ after_initialize do register_topic_custom_field_type(DiscourseAutomation::AUTO_RESPONDER_TRIGGERED_IDS, [:integer]) on(:user_updated) { |user| DiscourseAutomation::EventHandlers.handle_user_updated(user) } + on(:user_created) do |user| + DiscourseAutomation::EventHandlers.handle_user_updated(user, new_user: true) + end register_user_custom_field_type(DiscourseAutomation::CUSTOM_FIELD, [:integer]) register_post_custom_field_type(DiscourseAutomation::CUSTOM_FIELD, [:integer]) diff --git a/plugins/automation/spec/models/automation_spec.rb b/plugins/automation/spec/models/automation_spec.rb index 5420e7976cf..838ed261375 100644 --- a/plugins/automation/spec/models/automation_spec.rb +++ b/plugins/automation/spec/models/automation_spec.rb @@ -165,4 +165,21 @@ describe DiscourseAutomation::Automation do end end end + + describe "after_destroy" do + fab!(:automation) { Fabricate(:automation, enabled: false) } + fab!(:automation2) { Fabricate(:automation, enabled: false) } + + it "deletes user custom fields that indicate new users" do + user = Fabricate(:user) + user.custom_fields[automation.new_user_custom_field_name] = "1" + user.custom_fields[automation2.new_user_custom_field_name] = "1" + user.save_custom_fields + + automation.destroy! + user.reload + + expect(user.custom_fields).to eq({ automation2.new_user_custom_field_name => "1" }) + end + end end diff --git a/plugins/automation/spec/triggers/user_updated_spec.rb b/plugins/automation/spec/triggers/user_updated_spec.rb index aebd21be6da..ebe881e22db 100644 --- a/plugins/automation/spec/triggers/user_updated_spec.rb +++ b/plugins/automation/spec/triggers/user_updated_spec.rb @@ -93,7 +93,7 @@ describe "UserUpdated" do end end - context "when once_per_user is no set" do + context "when once_per_user is not set" do it "triggers every time" do output = capture_contexts { UserUpdater.new(user, user).update(location: "Japan", bio_raw: "fine") } @@ -124,4 +124,138 @@ describe "UserUpdated" do expect(output.first["kind"]).to eq("user_updated") end end + + context "when new_users_only is set" do + before do + automation.upsert_field!("new_users_only", "boolean", { value: true }, target: "trigger") + end + + it "triggers for new users" do + user = nil + output = + capture_contexts do + user = Fabricate(:user) + user.set_user_field(user_field_1.id, "Answer new custom 1") + user.set_user_field(user_field_2.id, "Answer new custom 2") + UserUpdater.new(user, user).update(location: "Japan", bio_raw: "fine") + end + + expect(output.size).to eq(1) + expect(output.first["kind"]).to eq("user_updated") + expect(output.first["user"].id).to eq(user.id) + expect(output.first["user_data"][:custom_fields]).to eq( + { "custom field 1" => "Answer new custom 1", "custom field 2" => "Answer new custom 2" }, + ) + expect(output.first["user_data"][:profile_data]["location"]).to eq("Japan") + expect(output.first["user_data"][:profile_data]["bio_raw"]).to eq("fine") + + output = + capture_contexts do + UserUpdater.new(user, user).update(location: "Japan22", bio_raw: "finegood") + end + expect(output.size).to eq(1) + expect(output.first["kind"]).to eq("user_updated") + expect(output.first["user"].id).to eq(user.id) + expect(output.first["user_data"][:profile_data]["location"]).to eq("Japan22") + expect(output.first["user_data"][:profile_data]["bio_raw"]).to eq("finegood") + end + + it "doesn't trigger for existing users" do + output = + capture_contexts { UserUpdater.new(user, user).update(location: "Japan", bio_raw: "fine") } + + expect(output).to eq([]) + end + + context "when once_per_user is set" do + before do + automation.upsert_field!("once_per_user", "boolean", { value: true }, target: "trigger") + end + + it "triggers only once for a new user" do + user = nil + output = + capture_contexts do + user = Fabricate(:user) + user.set_user_field(user_field_1.id, "Answer new custom 1") + user.set_user_field(user_field_2.id, "Answer new custom 2") + UserUpdater.new(user, user).update(location: "Japan", bio_raw: "fine") + end + + expect(output.size).to eq(1) + expect(output.first["kind"]).to eq("user_updated") + expect(output.first["user"].id).to eq(user.id) + expect(output.first["user_data"][:custom_fields]).to eq( + { "custom field 1" => "Answer new custom 1", "custom field 2" => "Answer new custom 2" }, + ) + expect(output.first["user_data"][:profile_data]["location"]).to eq("Japan") + expect(output.first["user_data"][:profile_data]["bio_raw"]).to eq("fine") + + output = + capture_contexts do + UserUpdater.new(user, user).update(location: "Japan22", bio_raw: "finegood") + end + expect(output).to eq([]) + end + + it "doesn't trigger for an existing user" do + output = + capture_contexts do + UserUpdater.new(user, user).update(location: "Japan", bio_raw: "fine") + end + + expect(output).to eq([]) + end + end + end + + context "when new_users_only is not set" do + before do + automation.upsert_field!("new_users_only", "boolean", { value: false }, target: "trigger") + end + + it "triggers for new users" do + user = nil + output = + capture_contexts do + user = Fabricate(:user) + user.set_user_field(user_field_1.id, "Answer new custom 1") + user.set_user_field(user_field_2.id, "Answer new custom 2") + UserUpdater.new(user, user).update(location: "Japan", bio_raw: "fine") + end + + expect(output.size).to eq(1) + expect(output.first["kind"]).to eq("user_updated") + expect(output.first["user"].id).to eq(user.id) + expect(output.first["user_data"][:custom_fields]).to eq( + { "custom field 1" => "Answer new custom 1", "custom field 2" => "Answer new custom 2" }, + ) + expect(output.first["user_data"][:profile_data]["location"]).to eq("Japan") + expect(output.first["user_data"][:profile_data]["bio_raw"]).to eq("fine") + end + + it "triggers for existing users" do + output = + capture_contexts { UserUpdater.new(user, user).update(location: "Japan", bio_raw: "fine") } + + expect(output.size).to eq(1) + expect(output.first["kind"]).to eq("user_updated") + expect(output.first["user"].id).to eq(user.id) + expect(output.first["user_data"][:custom_fields]).to eq( + { "custom field 1" => "Answer custom 1", "custom field 2" => "Answer custom 2" }, + ) + expect(output.first["user_data"][:profile_data]["location"]).to eq("Japan") + expect(output.first["user_data"][:profile_data]["bio_raw"]).to eq("fine") + + output = + capture_contexts do + UserUpdater.new(user, user).update(location: "Japan22", bio_raw: "finegood") + end + expect(output.size).to eq(1) + expect(output.first["kind"]).to eq("user_updated") + expect(output.first["user"].id).to eq(user.id) + expect(output.first["user_data"][:profile_data]["location"]).to eq("Japan22") + expect(output.first["user_data"][:profile_data]["bio_raw"]).to eq("finegood") + end + end end