diff --git a/db/post_migrate/20250404045050_migrate_users_to_email_group.rb b/db/post_migrate/20250404045050_migrate_users_to_email_group.rb new file mode 100644 index 00000000..3711a2d3 --- /dev/null +++ b/db/post_migrate/20250404045050_migrate_users_to_email_group.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +class MigrateUsersToEmailGroup < ActiveRecord::Migration[7.2] + def up + execute <<~SQL + UPDATE discourse_automation_fields + SET component = 'email_group_user' + WHERE + component = 'users' AND + name = 'receivers' AND + automation_id IN (SELECT id FROM discourse_automation_automations WHERE script = 'llm_report') + SQL + end + + def down + execute <<~SQL + UPDATE discourse_automation_fields + SET component = 'users' + WHERE + component = 'email_group_user' AND + name = 'receivers' AND + automation_id IN (SELECT id FROM discourse_automation_automations WHERE script = 'llm_report') + SQL + end +end diff --git a/discourse_automation/llm_report.rb b/discourse_automation/llm_report.rb index 49c4b637..f75bf01d 100644 --- a/discourse_automation/llm_report.rb +++ b/discourse_automation/llm_report.rb @@ -9,7 +9,7 @@ if defined?(DiscourseAutomation) triggerables %i[recurring] field :sender, component: :user, required: true - field :receivers, component: :users + field :receivers, component: :email_group_user field :topic_id, component: :text field :title, component: :text field :days, component: :text, required: true, default_value: 7 diff --git a/lib/automation/report_context_generator.rb b/lib/automation/report_context_generator.rb index d15eac80..60061c93 100644 --- a/lib/automation/report_context_generator.rb +++ b/lib/automation/report_context_generator.rb @@ -65,11 +65,15 @@ module DiscourseAi @posts = @posts.where(topic_id: topic_ids_with_tags) end - @solutions = - DiscourseSolved::SolvedTopic - .where(topic_id: @posts.select(:topic_id)) - .pluck(:topic_id, :answer_post_id) - .to_h + if defined?(::DiscourseSolved) + @solutions = + DiscourseSolved::SolvedTopic + .where(topic_id: @posts.select(:topic_id)) + .pluck(:topic_id, :answer_post_id) + .to_h + else + @solutions = {} + end end def format_topic(topic) diff --git a/lib/automation/report_runner.rb b/lib/automation/report_runner.rb index 5d30ec2d..9031a4db 100644 --- a/lib/automation/report_runner.rb +++ b/lib/automation/report_runner.rb @@ -57,7 +57,15 @@ module DiscourseAi automation: nil ) @sender = User.find_by(username: sender_username) - @receivers = User.where(username: receivers) + receivers_without_emails = receivers&.reject { |r| r.include? "@" } + if receivers_without_emails.present? + @group_receivers = Group.where(name: receivers_without_emails) + receivers_without_emails -= @group_receivers.pluck(:name) + @receivers = User.where(username: receivers_without_emails) + else + @group_receivers = [] + @receivers = [] + end @email_receivers = receivers&.filter { |r| r.include? "@" } @title = if title.present? @@ -88,7 +96,8 @@ module DiscourseAi @temperature = nil if temperature.to_f < 0 @suppress_notifications = suppress_notifications - if !@topic_id && !@receivers.present? && !@email_receivers.present? + if !@topic_id && !@receivers.present? && !@group_receivers.present? && + !@email_receivers.present? raise ArgumentError, "Must specify topic_id or receivers" end @automation = automation @@ -165,6 +174,7 @@ Follow the provided writing composition instructions carefully and precisely ste end receiver_usernames = @receivers.map(&:username).join(",") + receiver_groupnames = @group_receivers.map(&:name).join(",") result = suppress_notifications(result) if @suppress_notifications @@ -173,7 +183,7 @@ Follow the provided writing composition instructions carefully and precisely ste # no debug mode for topics, it is too noisy end - if receiver_usernames.present? + if receiver_usernames.present? || receiver_groupnames.present? post = PostCreator.create!( @sender, @@ -181,6 +191,7 @@ Follow the provided writing composition instructions carefully and precisely ste title: title, archetype: Archetype.private_message, target_usernames: receiver_usernames, + target_group_names: receiver_groupnames, skip_validations: true, ) diff --git a/spec/lib/discourse_automation/llm_report_spec.rb b/spec/lib/discourse_automation/llm_report_spec.rb index fe9f5662..c05f9df0 100644 --- a/spec/lib/discourse_automation/llm_report_spec.rb +++ b/spec/lib/discourse_automation/llm_report_spec.rb @@ -23,7 +23,7 @@ describe DiscourseAutomation do it "can trigger via automation" do add_automation_field("sender", user.username, type: "user") - add_automation_field("receivers", [user.username], type: "users") + add_automation_field("receivers", [user.username], type: "email_group_user") add_automation_field("model", "custom:#{llm_model.id}") add_automation_field("title", "Weekly report") diff --git a/spec/lib/modules/automation/report_runner_spec.rb b/spec/lib/modules/automation/report_runner_spec.rb index 5f9b6b45..c9864e5c 100644 --- a/spec/lib/modules/automation/report_runner_spec.rb +++ b/spec/lib/modules/automation/report_runner_spec.rb @@ -190,6 +190,38 @@ module DiscourseAi expect(debugging).not_to include(post_with_tag.raw) end + it "can send reports to groups only" do + group_for_reports = Fabricate(:group) + group_member = Fabricate(:user) + group_for_reports.add(group_member) + + DiscourseAi::Completions::Llm.with_prepared_responses(["group report"]) do + ReportRunner.run!( + sender_username: user.username, + receivers: [group_for_reports.name], + title: "group report", + model: "custom:#{llm_model.id}", + category_ids: nil, + tags: nil, + allow_secure_categories: false, + debug_mode: false, + sample_size: 100, + instructions: "make a group report", + days: 7, + offset: 0, + priority_group_id: nil, + tokens_per_post: 150, + ) + end + + report_topic = + Topic.where(title: "group report", archetype: Archetype.private_message).first + expect(report_topic).to be_present + expect(report_topic.allowed_groups.map(&:id)).to eq([group_for_reports.id]) + expect(report_topic.allowed_users.map(&:id)).to eq([user.id]) + expect(report_topic.ordered_posts.first.raw).to eq("group report") + end + it "generates correctly respects the params" do DiscourseAi::Completions::Llm.with_prepared_responses(["magical report"]) do ReportRunner.run!(