Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions app/models/discourse_automation/automation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Automation < ActiveRecord::Base
foreign_key: "automation_id"

validates :script, presence: true
validate :validate_trigger_fields

attr_accessor :running_in_background

Expand Down Expand Up @@ -71,6 +72,10 @@ def trigger_field(name)
field ? field.metadata : {}
end

def has_trigger_field?(name)
!!fields.find_by(target: "trigger", name: name)
end

def script_field(name)
field = fields.find_by(target: "script", name: name)
field ? field.metadata : {}
Expand Down Expand Up @@ -160,5 +165,11 @@ def reset!
pending_pms.delete_all
scriptable&.on_reset&.call(self)
end

private

def validate_trigger_fields
!triggerable || triggerable.valid?(self)
end
end
end
22 changes: 13 additions & 9 deletions assets/javascripts/discourse/components/fields/da-period-field.gjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,8 @@ export default class PeriodField extends BaseField {
constructor() {
super(...arguments);

if (!this.args.field.metadata.value) {
this.args.field.metadata.value = new TrackedObject({
interval: 1,
frequency: null,
});
}

this.interval = this.args.field.metadata.value.interval;
this.frequency = this.args.field.metadata.value.frequency;
this.interval = this.args.field.metadata.value?.interval || 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the problem with this code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh it totally exploded in dev, it complained that metadata.value was changed twice in one render run or something

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, generally you can get around this, by wrapping in a next(() => {}) block, this might be better than the ensureValue() function

this.frequency = this.args.field.metadata.value?.frequency;
}

get recurringLabel() {
Expand All @@ -41,13 +34,24 @@ export default class PeriodField extends BaseField {
});
}

ensureValue() {
if (!this.args.field.metadata.value) {
this.args.field.metadata.value = new TrackedObject({
interval: this.interval,
frequency: this.frequency,
});
}
}

@action
mutInterval(event) {
this.ensureValue();
this.args.field.metadata.value.interval = event.target.value;
}

@action
mutFrequency(value) {
this.ensureValue();
this.args.field.metadata.value.frequency = value;
this.frequency = value;
}
Expand Down
2 changes: 2 additions & 0 deletions config/locales/server.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ en:
invalid_field: Field’s component `%{component}` is not usable on `%{target}:%{target_name}.`
invalid_metadata: Data for `%{field}` is invalid or component `%{component}` is unknown.
triggerables:
errors:
custom_fields_or_user_profile_required: "At least one of 'custom_fields' or 'user_profile' must be provided."
user_badge_granted:
title: User badge granted
doc: Triggers an automation when a user is granted a badge.
Expand Down
11 changes: 7 additions & 4 deletions lib/discourse_automation/scripts/post.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@
topic = Topic.find_by(id: topic_id)

if context["kind"] == DiscourseAutomation::Triggerable::USER_UPDATED
user = context["user"]
user_data = context["user_data"]
user_profile_data = user_data[:profile_data]
user_custom_fields =
user_data[:custom_fields].each_with_object({}) do |(k, v), hash|
hash[k.gsub(/\s+/, "_").underscore] = v
end
user_custom_fields = {}
user_data[:custom_fields]&.each do |k, v|
user_custom_fields[k.gsub(/\s+/, "_").underscore] = v
end
user = User.find(context["user"].id)
placeholders["username"] = user.username
placeholders["name"] = user.name
placeholders = placeholders.merge(user_profile_data, user_custom_fields)

post_raw = utils.apply_placeholders(post_raw, placeholders)
Expand Down
11 changes: 11 additions & 0 deletions lib/discourse_automation/triggerable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def initialize(name)
@on_update_block = proc {}
@on_call_block = proc {}
@not_found = false
@validations = []

eval! if @name
end
Expand All @@ -30,6 +31,16 @@ def triggerable?
true
end

def validate(&block)
@validations << block
end

def valid?(automation)
@validations.each { |block| automation.instance_exec(&block) }

automation.errors.blank?
end

def placeholders
@placeholders.uniq.compact
end
Expand Down
24 changes: 21 additions & 3 deletions lib/discourse_automation/triggers/user_updated.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
# frozen_string_literal: true

DiscourseAutomation::Triggerable::USER_UPDATED = "user_updated"
class DiscourseAutomation::Triggerable
USER_UPDATED = "user_updated"
end

DiscourseAutomation::Triggerable.add(DiscourseAutomation::Triggerable::USER_UPDATED) do
field :automation_name, component: :text, required: true
field :custom_fields, component: :custom_fields, required: true
field :user_profile, component: :user_profile, required: true
field :custom_fields, component: :custom_fields
field :user_profile, component: :user_profile
field :first_post_only, component: :boolean

validate do
has_triggers = has_trigger_field?(:custom_fields) && has_trigger_field?(:user_profile)
custom_fields = trigger_field(:custom_fields)["value"]
user_profile = trigger_field(:user_profile)["value"]

if has_triggers && custom_fields.blank? && user_profile.blank?
errors.add(
:base,
I18n.t("discourse_automation.triggerables.errors.custom_fields_or_user_profile_required"),
)
false
else
true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we consider that if we don't return false it's validated?

end
end
end
26 changes: 26 additions & 0 deletions spec/triggers/user_updated_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,32 @@
automation
end

context "when custom_fields and user_profile are blank" do
let(:automation) do
Fabricate(
:automation,
trigger: DiscourseAutomation::Triggerable::USER_UPDATED,
).tap do |automation|
automation.upsert_field!(
"automation_name",
"text",
{ value: "Test Automation" },
target: "trigger",
)
automation.upsert_field!("custom_fields", "custom_fields", { value: [] }, target: "trigger")
automation.upsert_field!("user_profile", "user_profile", { value: [] }, target: "trigger")
end
end

it "adds an error to the automation" do
expect(automation.save).to eq(false)
errors = automation.errors.full_messages
expect(errors).to include(
I18n.t("discourse_automation.triggerables.errors.custom_fields_or_user_profile_required"),
)
end
end

it "has the correct data" do
script_input = capture_contexts { UserUpdater.new(user, user).update(location: "Japan") }
script_input = script_input.first
Expand Down