# frozen_string_literal: true require "rails_helper" module DiscourseAi module Automation describe ReportRunner do fab!(:user) fab!(:receiver) { Fabricate(:user) } fab!(:post) { Fabricate(:post, user: user) } fab!(:group) fab!(:secure_category) { Fabricate(:private_category, group: group) } fab!(:secure_topic) { Fabricate(:topic, category: secure_category) } fab!(:secure_post) { Fabricate(:post, raw: "Top secret date !!!!", topic: secure_topic) } fab!(:category) fab!(:topic_in_category) { Fabricate(:topic, category: category) } fab!(:post_in_category) do Fabricate(:post, raw: "I am in a category", topic: topic_in_category) end fab!(:tag) fab!(:hidden_tag) { Fabricate(:tag, name: "hidden-tag") } fab!(:tag_group) do tag_group = TagGroup.new(name: "test tag group") tag_group.tag_group_permissions.build(group_id: Group::AUTO_GROUPS[:trust_level_1]) tag_group.save! TagGroupMembership.create!(tag_group_id: tag_group.id, tag_id: hidden_tag.id) tag_group end fab!(:topic_with_tag) { Fabricate(:topic, tags: [tag, hidden_tag]) } fab!(:post_with_tag) { Fabricate(:post, raw: "I am in a tag", topic: topic_with_tag) } fab!(:llm_model) describe "#run!" do it "is able to generate email reports" do freeze_time DiscourseAi::Completions::Llm.with_prepared_responses(["magical report"]) do ReportRunner.run!( sender_username: user.username, receivers: ["fake@discourse.com"], title: "test report %DATE%", model: "custom:#{llm_model.id}", category_ids: nil, tags: nil, allow_secure_categories: false, sample_size: 100, instructions: "make a magic report", days: 7, offset: 0, priority_group_id: nil, tokens_per_post: 150, debug_mode: nil, ) end expect(ActionMailer::Base.deliveries.length).to eq(1) expect(ActionMailer::Base.deliveries.first.subject).to eq( "test report #{7.days.ago.strftime("%Y-%m-%d")} - #{Time.zone.now.strftime("%Y-%m-%d")}", ) end it "can exclude categories (including sub categories)" do subcategory = Fabricate(:category, parent_category_id: category.id) topic_in_subcategory = Fabricate(:topic, category: subcategory) post_in_subcategory = Fabricate(:post, raw: "I am in a subcategory abcd", topic: topic_in_subcategory) other_category = Fabricate(:category) topic2 = Fabricate(:topic, category: other_category) post2 = Fabricate(:post, raw: "I am in another category 123", topic: topic2) freeze_time DiscourseAi::Completions::Llm.with_prepared_responses(["magical report"]) do ReportRunner.run!( sender_username: user.username, receivers: [receiver.username], title: "test report", model: "custom:#{llm_model.id}", category_ids: nil, tags: nil, allow_secure_categories: false, debug_mode: true, sample_size: 100, instructions: "make a magic report", days: 7, offset: 0, priority_group_id: nil, tokens_per_post: 150, exclude_category_ids: [category.id], ) end report = Topic.where(title: "test report").first debugging = report.ordered_posts.last.raw expect(debugging).not_to include(post_in_category.raw) expect(debugging).not_to include(post_in_subcategory.raw) expect(debugging).to include(post2.raw) expect(debugging).to include(post_with_tag.raw) expect(debugging).to include(tag.name) expect(debugging).not_to include(hidden_tag.name) end it "can suppress notifications by remapping content" do user = Fabricate(:user) markdown = <<~MD @#{user.username} is a person [test1](/test) is an internal link [test2](/test?1=2) is an internal link [test3](https://example.com) is an external link [test4](#{Discourse.base_url}) is an internal link test5 is an internal link [test6](/test?test=test#anchor) is an internal link with fragment [test7](//[[test) is a link with an invalid URL MD DiscourseAi::Completions::Llm.with_prepared_responses([markdown]) do ReportRunner.run!( sender_username: user.username, receivers: [receiver.username], title: "test report", model: "custom:#{llm_model.id}", category_ids: nil, tags: nil, allow_secure_categories: false, debug_mode: false, sample_size: 100, instructions: "make a magic report", days: 7, offset: 0, priority_group_id: nil, tokens_per_post: 150, suppress_notifications: true, ) end report = Topic.where(title: "test report").first # note, magic surprise & is correct HTML 5 representation expected = <<~HTML
#{user.username} is a person
test1 is an internal link
test2 is an internal link
test3 is an external link
test4 is an internal link
test5 is an internal link
test6 is an internal link with fragment
test7 is a link with an invalid URL