mirror of
https://github.com/discourse/discourse.git
synced 2025-01-16 17:32:46 +08:00
0d62863951
* FEATURE: default value to fields in automation
This PR adds the property `extra.default_value` to the fields in automation. This property is used to set the default value of the field.
Reducing the nil checks we have to do in automation fields.
I've added only testing in the `da-choices-field-test.js` file, but we could add tests to all the fields.
* FEATURE: Add trigger_on option to `topic_tags_changed` automation
This new field will allow users to specify when the trigger should be fired. The options are:
- `tags_added_or_removed`: The trigger will be fired when tags are added or removed from the topic.
- `tags_added`: The trigger will be fired when tags are added to the topic.
- `tags_removed`: The trigger will be fired when tags are removed from the topic.
This PR also brings a migration to set the `trigger_on` field to `tags_added_or_removed` for all existing `topic_tags_changed` automations.
* DEV: reorganize the specs in context blocks
* DEV: migration to add trigger_on field default value to topic_tags_changed_trigger
* DEV: `down` migration for `add_trigger_on_field_default_value_to_topic_tags_changed_trigger` migration
* Update plugins/automation/lib/discourse_automation/triggers/topic_tags_changed.rb
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
* Update plugins/automation/config/locales/client.en.yml
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
* DEV: lint files and update topic_tags_changed trigger to use `default_value`
* Revert "FEATURE: default value to fields in automation"
This reverts commit 4d32635c69
.
* DEV: remove migration file
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
377 lines
14 KiB
Ruby
377 lines
14 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module DiscourseAutomation
|
|
module EventHandlers
|
|
def self.handle_post_created_edited(post, action)
|
|
return if post.post_type != Post.types[:regular] || post.user_id < 0
|
|
topic = post.topic
|
|
return if topic.blank?
|
|
|
|
name = DiscourseAutomation::Triggers::POST_CREATED_EDITED
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: name, enabled: true)
|
|
.find_each do |automation|
|
|
original_post_only = automation.trigger_field("original_post_only")
|
|
if original_post_only["value"]
|
|
next if topic.posts_count > 1
|
|
end
|
|
|
|
first_post_only = automation.trigger_field("first_post_only")
|
|
if first_post_only["value"]
|
|
next if post.user.user_stat.post_count != 1
|
|
end
|
|
|
|
first_topic_only = automation.trigger_field("first_topic_only")
|
|
if first_topic_only["value"]
|
|
next if post.post_number != 1
|
|
next if post.user.user_stat.topic_count != 1
|
|
end
|
|
|
|
skip_via_email = automation.trigger_field("skip_via_email")
|
|
if skip_via_email["value"]
|
|
next if post.via_email?
|
|
end
|
|
|
|
valid_trust_levels = automation.trigger_field("valid_trust_levels")
|
|
if valid_trust_levels["value"]
|
|
next if valid_trust_levels["value"].exclude?(post.user.trust_level)
|
|
end
|
|
|
|
restricted_category = automation.trigger_field("restricted_category")
|
|
if restricted_category["value"]
|
|
category_ids =
|
|
if topic.category_id.blank?
|
|
[]
|
|
else
|
|
[topic.category_id, topic.category.parent_category_id]
|
|
end
|
|
next if !category_ids.include?(restricted_category["value"])
|
|
end
|
|
|
|
restricted_tags = automation.trigger_field("restricted_tags")
|
|
if restricted_tags["value"]
|
|
next if (restricted_tags["value"] & topic.tags.map(&:name)).empty?
|
|
end
|
|
|
|
restricted_group_ids = automation.trigger_field("restricted_groups")["value"]
|
|
if restricted_group_ids.present?
|
|
next if !topic.private_message?
|
|
|
|
target_group_ids = topic.allowed_groups.pluck(:id)
|
|
next if (restricted_group_ids & target_group_ids).empty?
|
|
|
|
ignore_group_members = automation.trigger_field("ignore_group_members")["value"]
|
|
next if ignore_group_members && post.user.in_any_groups?(restricted_group_ids)
|
|
end
|
|
|
|
ignore_automated = automation.trigger_field("ignore_automated")
|
|
next if ignore_automated["value"] && post.incoming_email&.is_auto_generated?
|
|
|
|
action_type = automation.trigger_field("action_type")
|
|
selected_action = action_type["value"]&.to_sym
|
|
|
|
if selected_action
|
|
next if selected_action == :created && action != :create
|
|
next if selected_action == :edited && action != :edit
|
|
end
|
|
|
|
automation.trigger!(
|
|
"kind" => name,
|
|
"action" => action,
|
|
"post" => post,
|
|
"placeholders" => {
|
|
"topic_url" => topic.relative_url,
|
|
"topic_title" => topic.title,
|
|
},
|
|
)
|
|
end
|
|
end
|
|
|
|
def self.handle_user_updated(user, new_user: false)
|
|
return if user.id < 0
|
|
|
|
name = DiscourseAutomation::Triggers::USER_UPDATED
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: name, enabled: true)
|
|
.find_each do |automation|
|
|
once_per_user = automation.trigger_field("once_per_user")["value"]
|
|
if once_per_user &&
|
|
user.custom_fields[
|
|
DiscourseAutomation::AUTOMATION_IDS_CUSTOM_FIELD
|
|
].presence&.include?(automation.id)
|
|
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
|
|
SELECT uf.name AS field_name, ucf.value AS field_value
|
|
FROM user_fields uf
|
|
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
|
|
end
|
|
|
|
required_user_profile_fields = automation.trigger_field("user_profile")
|
|
user_profile_data = UserProfile.find(user.id).attributes
|
|
if required_user_profile_fields["value"]
|
|
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.add_id_to_custom_field(user, DiscourseAutomation::AUTOMATION_IDS_CUSTOM_FIELD)
|
|
|
|
automation.trigger!("kind" => name, "user" => user, "user_data" => user_data)
|
|
end
|
|
end
|
|
|
|
def self.handle_category_created_edited(category, action)
|
|
name = DiscourseAutomation::Triggers::CATEGORY_CREATED_EDITED
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: name, enabled: true)
|
|
.find_each do |automation|
|
|
restricted_category = automation.trigger_field("restricted_category")
|
|
if restricted_category["value"].present?
|
|
next if restricted_category["value"] != category.parent_category_id
|
|
end
|
|
|
|
automation.trigger!("kind" => name, "action" => action, "category" => category)
|
|
end
|
|
end
|
|
|
|
def self.handle_pm_created(topic)
|
|
return if topic.user_id < 0
|
|
|
|
user = topic.user
|
|
target_usernames = topic.allowed_users.pluck(:username) - [user.username]
|
|
target_group_ids = topic.allowed_groups.pluck(:id)
|
|
return if (target_usernames.length + target_group_ids.length) > 1
|
|
|
|
name = DiscourseAutomation::Triggers::PM_CREATED
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: name, enabled: true)
|
|
.find_each do |automation|
|
|
restricted_username = automation.trigger_field("restricted_user")["value"]
|
|
next if restricted_username.present? && restricted_username != target_usernames.first
|
|
|
|
restricted_group_id = automation.trigger_field("restricted_group")["value"]
|
|
next if restricted_group_id.present? && restricted_group_id != target_group_ids.first
|
|
|
|
ignore_staff = automation.trigger_field("ignore_staff")
|
|
next if ignore_staff["value"] && user.staff?
|
|
|
|
ignore_group_members = automation.trigger_field("ignore_group_members")
|
|
next if ignore_group_members["value"] && user.in_any_groups?([restricted_group_id])
|
|
|
|
ignore_automated = automation.trigger_field("ignore_automated")
|
|
next if ignore_automated["value"] && topic.first_post.incoming_email&.is_auto_generated?
|
|
|
|
valid_trust_levels = automation.trigger_field("valid_trust_levels")
|
|
if valid_trust_levels["value"]
|
|
next if !valid_trust_levels["value"].include?(user.trust_level)
|
|
end
|
|
|
|
automation.trigger!("kind" => name, "post" => topic.first_post)
|
|
end
|
|
end
|
|
|
|
def self.handle_topic_tags_changed(topic, old_tag_names, new_tag_names, user)
|
|
name = DiscourseAutomation::Triggers::TOPIC_TAGS_CHANGED
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: name, enabled: true)
|
|
.find_each do |automation|
|
|
if topic.private_message?
|
|
next if !automation.trigger_field("trigger_with_pms")["value"]
|
|
end
|
|
|
|
watching_categories = automation.trigger_field("watching_categories")
|
|
if watching_categories["value"]
|
|
next if !watching_categories["value"].include?(topic.category_id)
|
|
end
|
|
|
|
removed_tags = old_tag_names - new_tag_names
|
|
added_tags = new_tag_names - old_tag_names
|
|
|
|
watching_tags = automation.trigger_field("watching_tags")
|
|
|
|
if watching_tags["value"]
|
|
changed_tags = (removed_tags | added_tags)
|
|
next if (changed_tags & watching_tags["value"]).empty?
|
|
end
|
|
|
|
trigger_on = automation.trigger_field("trigger_on")["value"]
|
|
|
|
if trigger_on == Triggers::TopicTagsChanged::TriggerOn::TAGS_ADDED && added_tags.empty?
|
|
next
|
|
end
|
|
|
|
if trigger_on == Triggers::TopicTagsChanged::TriggerOn::TAGS_REMOVED &&
|
|
removed_tags.empty?
|
|
next
|
|
end
|
|
|
|
automation.trigger!(
|
|
"kind" => name,
|
|
"topic" => topic,
|
|
"removed_tags" => removed_tags,
|
|
"added_tags" => added_tags,
|
|
"user" => user,
|
|
"placeholders" => {
|
|
"topic_url" => topic.relative_url,
|
|
"topic_title" => topic.title,
|
|
},
|
|
)
|
|
end
|
|
end
|
|
|
|
def self.handle_after_post_cook(post, cooked)
|
|
return cooked if post.post_type != Post.types[:regular] || post.post_number > 1
|
|
|
|
name = DiscourseAutomation::Triggers::AFTER_POST_COOK
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: name, enabled: true)
|
|
.find_each do |automation|
|
|
valid_trust_levels = automation.trigger_field("valid_trust_levels")
|
|
if valid_trust_levels["value"]
|
|
next if valid_trust_levels["value"].exclude?(post.user.trust_level)
|
|
end
|
|
|
|
restricted_category = automation.trigger_field("restricted_category")
|
|
if restricted_category["value"]
|
|
category_ids = [post.topic&.category&.parent_category&.id, post.topic&.category&.id]
|
|
next if !category_ids.compact.include?(restricted_category["value"])
|
|
end
|
|
|
|
restricted_tags = automation.trigger_field("restricted_tags")
|
|
if tag_names = restricted_tags["value"]
|
|
found = false
|
|
next if !post.topic
|
|
|
|
post.topic.tags.each do |tag|
|
|
found ||= tag_names.include?(tag.name)
|
|
break if found
|
|
end
|
|
|
|
next if !found
|
|
end
|
|
|
|
if new_cooked = automation.trigger!("kind" => name, "post" => post, "cooked" => cooked)
|
|
cooked = new_cooked
|
|
end
|
|
end
|
|
|
|
cooked
|
|
end
|
|
|
|
def self.handle_user_promoted(user_id, new_trust_level, old_trust_level)
|
|
trigger = DiscourseAutomation::Triggers::USER_PROMOTED
|
|
user = User.find_by(id: user_id)
|
|
return if user.blank?
|
|
|
|
# don't want to do anything if the user is demoted. this should probably
|
|
# be a separate event in core
|
|
return if new_trust_level < old_trust_level
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: trigger, enabled: true)
|
|
.find_each do |automation|
|
|
trust_level_code_all = DiscourseAutomation::USER_PROMOTED_TRUST_LEVEL_CHOICES.first[:id]
|
|
|
|
restricted_group_id = automation.trigger_field("restricted_group")["value"]
|
|
trust_level_transition = automation.trigger_field("trust_level_transition")["value"]
|
|
trust_level_transition = trust_level_transition || trust_level_code_all
|
|
|
|
if restricted_group_id.present? &&
|
|
!GroupUser.exists?(user_id: user_id, group_id: restricted_group_id)
|
|
next
|
|
end
|
|
|
|
transition_code = "TL#{old_trust_level}#{new_trust_level}"
|
|
if trust_level_transition == trust_level_code_all ||
|
|
trust_level_transition == transition_code
|
|
automation.trigger!(
|
|
"kind" => trigger,
|
|
"usernames" => [user.username],
|
|
"placeholders" => {
|
|
"trust_level_transition" =>
|
|
I18n.t(
|
|
"discourse_automation.triggerables.user_promoted.transition_placeholder",
|
|
from_level_name: TrustLevel.name(old_trust_level),
|
|
to_level_name: TrustLevel.name(new_trust_level),
|
|
),
|
|
},
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.handle_stalled_topic(post)
|
|
return if post.topic.blank?
|
|
return if post.user_id != post.topic.user_id
|
|
|
|
DiscourseAutomation::Automation
|
|
.where(trigger: DiscourseAutomation::Triggers::STALLED_TOPIC)
|
|
.where(enabled: true)
|
|
.find_each do |automation|
|
|
fields = automation.serialized_fields
|
|
|
|
categories = fields.dig("categories", "value")
|
|
next if categories && !categories.include?(post.topic.category_id)
|
|
|
|
tags = fields.dig("tags", "value")
|
|
next if tags&.any? && (tags & post.topic.tags.map(&:name)).empty?
|
|
|
|
DiscourseAutomation::UserGlobalNotice
|
|
.where(identifier: automation.id)
|
|
.where(user_id: post.user_id)
|
|
.destroy_all
|
|
end
|
|
end
|
|
end
|
|
end
|