Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit d76d958

Browse files
committed
Link to scanned posts in review queue
1 parent 241e565 commit d76d958

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

app/controllers/discourse_ai/admin/ai_spam_controller.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@ def update
3333

3434
if allowed_params.key?(:is_enabled)
3535
if is_enabled && !AiModerationSetting.spam&.llm_model_id
36-
return render_json_error(I18n.t("discourse_ai.llm.configuration.must_select_model"), status: 422)
36+
return(
37+
render_json_error(
38+
I18n.t("discourse_ai.llm.configuration.must_select_model"),
39+
status: 422,
40+
)
41+
)
3742
end
3843

3944
SiteSetting.ai_spam_detection_enabled = is_enabled
@@ -55,6 +60,12 @@ def spam_config
5560
}
5661

5762
spam_config[:stats] = DiscourseAi::AiModeration::SpamReport.generate(min_date: 1.week.ago)
63+
64+
if spam_config[:stats].scanned_count > 0
65+
spam_config[
66+
:flagging_username
67+
] = DiscourseAi::AiModeration::SpamScanner.flagging_user&.username
68+
end
5869
spam_config
5970
end
6071
end

app/serializers/ai_spam_serializer.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: true
22

33
class AiSpamSerializer < ApplicationSerializer
4-
attributes :is_enabled, :llm_id, :custom_instructions, :available_llms, :stats
4+
attributes :is_enabled, :llm_id, :custom_instructions, :available_llms, :stats, :flagging_username
55

66
def is_enabled
77
object[:enabled]
@@ -21,6 +21,10 @@ def available_llms
2121
end
2222
end
2323

24+
def flagging_username
25+
object[:flagging_username]
26+
end
27+
2428
def stats
2529
{
2630
scanned_count: object[:stats].scanned_count.to_i,

assets/javascripts/discourse/components/ai-spam.gjs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import withEventValue from "discourse/helpers/with-event-value";
1212
import { ajax } from "discourse/lib/ajax";
1313
import { popupAjaxError } from "discourse/lib/ajax-error";
1414
import i18n from "discourse-common/helpers/i18n";
15+
import getURL from "discourse-common/lib/get-url";
1516
import ComboBox from "select-kit/components/combo-box";
1617

1718
export default class AiSpam extends Component {
@@ -102,15 +103,21 @@ export default class AiSpam extends Component {
102103
}
103104

104105
get metrics() {
106+
const detected = {
107+
label: "discourse_ai.spam.spam_detected",
108+
value: this.stats.spam_detected,
109+
};
110+
if (this.args.model.flagging_username) {
111+
detected.href = getURL(
112+
"/review?flagged_by=" + this.args.model.flagging_username
113+
);
114+
}
105115
return [
106116
{
107117
label: "discourse_ai.spam.scanned_count",
108118
value: this.stats.scanned_count,
109119
},
110-
{
111-
label: "discourse_ai.spam.spam_detected",
112-
value: this.stats.spam_detected,
113-
},
120+
detected,
114121
{
115122
label: "discourse_ai.spam.false_positives",
116123
value: this.stats.false_positives,
@@ -194,7 +201,13 @@ export default class AiSpam extends Component {
194201
{{#each this.metrics as |metric|}}
195202
<div class="ai-spam__metrics-item">
196203
<span class="ai-spam__metrics-label">{{i18n metric.label}}</span>
197-
<span class="ai-spam__metrics-value">{{metric.value}}</span>
204+
{{#if metric.href}}
205+
<a href={{metric.href}} class="ai-spam__metrics-value">
206+
{{metric.value}}
207+
</a>
208+
{{else}}
209+
<span class="ai-spam__metrics-value">{{metric.value}}</span>
210+
{{/if}}
198211
</div>
199212
{{/each}}
200213
</div>

spec/requests/admin/ai_spam_controller_spec.rb

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@
2626
end
2727

2828
it "can not enable spam detection without a model selected" do
29-
put "/admin/plugins/discourse-ai/ai-spam.json", params: { custom_instructions: "custom instructions" }
29+
put "/admin/plugins/discourse-ai/ai-spam.json",
30+
params: {
31+
custom_instructions: "custom instructions",
32+
}
3033
expect(response.status).to eq(422)
3134
end
3235

3336
it "can not fiddle with custom instructions without an llm" do
34-
put "/admin/plugins/discourse-ai/ai-spam.json", params: { is_enabled: true}
37+
put "/admin/plugins/discourse-ai/ai-spam.json", params: { is_enabled: true }
3538
expect(response.status).to eq(422)
3639
end
3740

@@ -97,6 +100,7 @@
97100

98101
it "return proper settings when spam detection is enabled" do
99102
SiteSetting.ai_spam_detection_enabled = true
103+
100104
AiModerationSetting.create(
101105
{
102106
setting_type: :spam,
@@ -107,15 +111,30 @@
107111
},
108112
)
109113

114+
flagging_user = DiscourseAi::AiModeration::SpamScanner.flagging_user
115+
expect(flagging_user.id).not_to eq(Discourse.system_user.id)
116+
117+
AiSpamLog.create!(post_id: 1, llm_model_id: llm_model.id, is_spam: true, payload: "test")
118+
110119
get "/admin/plugins/discourse-ai/ai-spam.json"
111120

112121
json = response.parsed_body
113122
expect(json["is_enabled"]).to eq(true)
114123
expect(json["llm_id"]).to eq(llm_model.id)
115124
expect(json["custom_instructions"]).to eq("custom instructions")
125+
126+
expect(json["stats"].to_h).to eq(
127+
"scanned_count" => 1,
128+
"spam_detected" => 1,
129+
"false_positives" => 0,
130+
"false_negatives" => 0,
131+
)
132+
133+
expect(json["flagging_username"]).to eq(flagging_user.username)
116134
end
117135

118-
it "includes the correct stats structure" do
136+
it "includes the stats" do
137+
expect(SpamScanner.flagging_user.id).not_to eq(SystemUser.id)
119138
get "/admin/plugins/discourse-ai/ai-spam.json"
120139

121140
json = response.parsed_body

0 commit comments

Comments
 (0)