mirror of
				https://github.com/discourse/discourse-ai.git
				synced 2025-11-02 23:48:37 +00:00 
			
		
		
		
	* DEV: Remove old code now that features rely on LlmModels. * Hide old settings and migrate persona llm overrides * Remove shadowing special URL + seeding code. Use srv:// prefix instead.
		
			
				
	
	
		
			226 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
# 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
 | 
						|
            <a href='/test'>test5</a> 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
 | 
						|
            <p><a class="mention" href="/u/#{user.username}">#{user.username}</a> is a person<br>
 | 
						|
            <a href="/test?silent=true">test1</a> is an internal link<br>
 | 
						|
            <a href="/test?1=2&silent=true">test2</a> is an internal link<br>
 | 
						|
            <a href="https://example.com" rel="noopener nofollow ugc">test3</a> is an external link<br>
 | 
						|
            <a href="http://test.localhost?silent=true">test4</a> is an internal link<br>
 | 
						|
            <a href="/test?silent=true">test5</a> is an internal link<br>
 | 
						|
            <a href="/test?test=test&silent=true#anchor">test6</a> is an internal link with fragment<br>
 | 
						|
            <a href="//%5B%5Btest?silent=true" rel="noopener nofollow ugc">test7</a> is a link with an invalid URL</p>
 | 
						|
          HTML
 | 
						|
 | 
						|
          post = report.ordered_posts.first
 | 
						|
 | 
						|
          expect(post.mentions.to_a).to eq([])
 | 
						|
          expect(post.raw.strip).to eq(expected.strip)
 | 
						|
        end
 | 
						|
 | 
						|
        it "can exclude tags" do
 | 
						|
          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_tags: [tag.name],
 | 
						|
            )
 | 
						|
          end
 | 
						|
 | 
						|
          report = Topic.where(title: "test report").first
 | 
						|
          debugging = report.ordered_posts.last.raw
 | 
						|
 | 
						|
          expect(debugging).to include(post_in_category.raw)
 | 
						|
          expect(debugging).not_to include(post_with_tag.raw)
 | 
						|
        end
 | 
						|
 | 
						|
        it "generates correctly respects the params" do
 | 
						|
          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,
 | 
						|
            )
 | 
						|
          end
 | 
						|
 | 
						|
          report = Topic.where(title: "test report").first
 | 
						|
          expect(report.ordered_posts.first.raw).to eq("magical report")
 | 
						|
          debugging = report.ordered_posts.last.raw
 | 
						|
 | 
						|
          expect(debugging).to include(post.raw)
 | 
						|
          expect(debugging).to include(post_in_category.raw)
 | 
						|
          expect(debugging).to include(post_with_tag.raw)
 | 
						|
          expect(debugging).not_to include(secure_post.raw)
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 |