Skip to content

Commit 9466280

Browse files
committed
AO3-6830 Add creator IDs to abuse reports
1 parent fd5046c commit 9466280

File tree

4 files changed

+192
-12
lines changed

4 files changed

+192
-12
lines changed

app/models/abuse_report.rb

+30-5
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,17 @@ def email_and_send
106106
end
107107

108108
def send_report
109-
return unless %w(staging production).include?(Rails.env)
109+
return unless zoho_enabled?
110+
110111
reporter = AbuseReporter.new(
111112
title: summary,
112113
description: comment,
113114
language: language,
114115
email: email,
115116
username: username,
116117
ip_address: ip_address,
117-
url: url
118+
url: url,
119+
creator_ids: creator_ids
118120
)
119121
response = reporter.send_report!
120122
ticket_id = response["id"]
@@ -123,10 +125,27 @@ def send_report
123125
attach_work_download(ticket_id)
124126
end
125127

128+
def creator_ids
129+
work_id = reported_work_id
130+
return unless work_id
131+
132+
work = Work.find_by(id: work_id)
133+
return "deletedwork" unless work
134+
135+
ids = work.pseuds.pluck(:user_id).push(*work.original_creators.pluck(:user_id)).uniq.sort!
136+
ids.prepend("orphanedwork") if ids.delete(User.orphan_account.id)
137+
ids.join(", ")
138+
end
139+
140+
# ID of the reported work, unless the report is about comment(s) on the work
141+
def reported_work_id
142+
comments = url[%r{/comments/}, 0]
143+
url[%r{/works/(\d+)}, 1] if comments.nil?
144+
end
145+
126146
def attach_work_download(ticket_id)
127-
is_not_comments = url[%r{/comments/}, 0].nil?
128-
work_id = url[%r{/works/(\d+)}, 1]
129-
return unless work_id && is_not_comments
147+
work_id = reported_work_id
148+
return unless work_id
130149

131150
work = Work.find_by(id: work_id)
132151
ReportAttachmentJob.perform_later(ticket_id, work) if work
@@ -174,4 +193,10 @@ def email_is_not_over_reporting
174193
out violations to report, but only report violations you
175194
encounter during your normal browsing."))
176195
end
196+
197+
private
198+
199+
def zoho_enabled?
200+
%w[staging production].include?(Rails.env)
201+
end
177202
end

app/models/feedback_reporters/abuse_reporter.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
class AbuseReporter < FeedbackReporter
2+
attr_accessor :creator_ids
3+
24
def report_attributes
35
super.deep_merge(
46
"departmentId" => department_id,
@@ -13,7 +15,8 @@ def report_attributes
1315
def custom_zoho_fields
1416
{
1517
"cf_ip" => ip_address.presence || "Unknown IP",
16-
"cf_url" => url.presence || "Unknown URL"
18+
"cf_url" => url.presence || "Unknown URL",
19+
"cf_user_id" => creator_ids.presence || ""
1720
}
1821
end
1922

spec/models/abuse_report_spec.rb

+146-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require 'spec_helper'
1+
require "spec_helper"
22

33
describe AbuseReport do
44
context "when report is not spam" do
@@ -9,7 +9,7 @@
99
end
1010

1111
context "comment missing" do
12-
let(:report_without_comment) {build(:abuse_report, comment: nil)}
12+
let(:report_without_comment) { build(:abuse_report, comment: nil) }
1313
it "is invalid" do
1414
expect(report_without_comment.save).to be_falsey
1515
expect(report_without_comment.errors[:comment]).not_to be_empty
@@ -328,8 +328,8 @@
328328

329329
context "when report is spam" do
330330
let(:legit_user) { create(:user) }
331-
let(:spam_report) { build(:abuse_report, username: 'viagra-test-123') }
332-
let!(:safe_report) { build(:abuse_report, username: 'viagra-test-123', email: legit_user.email) }
331+
let(:spam_report) { build(:abuse_report, username: "viagra-test-123") }
332+
let!(:safe_report) { build(:abuse_report, username: "viagra-test-123", email: legit_user.email) }
333333

334334
before do
335335
allow(Akismetor).to receive(:spam?).and_return(true)
@@ -380,4 +380,146 @@
380380
.to have_enqueued_job
381381
end
382382
end
383+
384+
describe "#creator_ids" do
385+
it "returns no creator ids for non-work URLs" do
386+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/users/someone/")
387+
388+
expect(subject.creator_ids).to be_nil
389+
end
390+
391+
it "returns no creator ids for comment sub-URLs" do
392+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/123/comments/")
393+
394+
expect(subject.creator_ids).to be_nil
395+
end
396+
397+
context "for work URLs" do
398+
it "returns deletedwork for a work that doesn't exist" do
399+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/000/")
400+
401+
expect(subject.creator_ids).to eq("deletedwork")
402+
end
403+
404+
context "for a single creator" do
405+
let(:work) { create(:work) }
406+
407+
it "returns a single creator id" do
408+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
409+
410+
expect(subject.creator_ids).to eq(work.users.first.id.to_s)
411+
end
412+
end
413+
414+
context "for an anonymous work" do
415+
let(:anonymous_collection) { create(:anonymous_collection) }
416+
let(:work) { create(:work, collections: [anonymous_collection]) }
417+
418+
it "returns a single creator id" do
419+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
420+
421+
expect(subject.creator_ids).to eq(work.users.first.id.to_s)
422+
end
423+
end
424+
425+
context "for an unrevealed work" do
426+
let(:unrevealed_collection) { create(:unrevealed_collection) }
427+
let(:work) { create(:work, collections: [unrevealed_collection]) }
428+
429+
it "returns a single creator id" do
430+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
431+
432+
expect(subject.creator_ids).to eq(work.users.first.id.to_s)
433+
end
434+
end
435+
436+
context "for multiple pseuds of one creator" do
437+
let(:user) { create(:user) }
438+
let(:pseud) { create(:pseud, user: user) }
439+
let(:work) { create(:work, authors: [pseud, user.default_pseud]) }
440+
441+
it "returns a single creator id" do
442+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
443+
444+
expect(subject.creator_ids).to eq(user.id.to_s)
445+
end
446+
end
447+
448+
context "for multiple creators" do
449+
let(:user1) { create(:user, id: 10) }
450+
let(:user2) { create(:user, id: 11) }
451+
let(:work) { create(:work, authors: [user2.default_pseud, user1.default_pseud]) }
452+
453+
it "returns a sorted list of creator ids" do
454+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
455+
456+
expect(subject.creator_ids).to eq("#{user1.id}, #{user2.id}")
457+
end
458+
end
459+
460+
context "for an invited co-creator that hasn't accepted yet" do
461+
let(:user) { create(:user) }
462+
let(:invited) { create(:user) }
463+
let(:work) { create(:work, authors: [user.default_pseud, invited.default_pseud]) }
464+
let(:creatorship) { work.creatorships.last }
465+
466+
before do
467+
creatorship.approved = false
468+
creatorship.save!(validate: false)
469+
end
470+
471+
it "returns only the creator" do
472+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
473+
474+
expect(subject.creator_ids).to eq(user.id.to_s)
475+
end
476+
end
477+
end
478+
479+
context "for an orphaned work" do
480+
let!(:orphan_account) { create(:user, login: "orphan_account") }
481+
let(:orphaneer) { create(:user, id: 20) }
482+
let(:work) { create(:work, authors: [orphaneer.default_pseud]) }
483+
484+
context "recently orphaned" do
485+
before do
486+
Creatorship.orphan([orphaneer.default_pseud], [work], false)
487+
end
488+
489+
it "returns orphanedwork and the original creator" do
490+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
491+
492+
expect(subject.creator_ids).to eq("orphanedwork, #{orphaneer.id}")
493+
end
494+
end
495+
496+
context "orphaned a long time ago" do
497+
before do
498+
Creatorship.orphan([orphaneer.default_pseud], [work], false)
499+
work.original_creators.destroy_all
500+
end
501+
502+
it "returns orphanedwork" do
503+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
504+
505+
expect(subject.creator_ids).to eq("orphanedwork")
506+
end
507+
end
508+
509+
context "partially orphaned" do
510+
let(:cocreator) { create(:user, id: 21) }
511+
let(:work) { create(:work, authors: [cocreator.default_pseud, orphaneer.default_pseud]) }
512+
513+
before do
514+
Creatorship.orphan([orphaneer.default_pseud], [work], false)
515+
end
516+
517+
it "returns a sorted list of orphanedwork, the co-creator and the original creator" do
518+
allow(subject).to receive(:url).and_return("http://archiveofourown.org/works/#{work.id}/")
519+
520+
expect(subject.creator_ids).to eq("orphanedwork, #{orphaneer.id}, #{cocreator.id}")
521+
end
522+
end
523+
end
524+
end
383525
end

spec/models/feedback_reporters/abuse_reporter_spec.rb

+12-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
1414
username: "Walrus",
1515
ip_address: "127.0.0.1",
16-
url: "http://localhost"
16+
url: "http://localhost",
17+
creator_ids: "3, 4"
1718
}
1819
end
1920

@@ -28,7 +29,8 @@
2829
"cf_language" => "English",
2930
"cf_name" => "Walrus",
3031
"cf_ip" => "127.0.0.1",
31-
"cf_url" => "http://localhost"
32+
"cf_url" => "http://localhost",
33+
"cf_user_id" => "3, 4"
3234
}
3335
}
3436
end
@@ -87,5 +89,13 @@
8789
expect(subject.report_attributes.fetch("description")).to eq("Hi!http://example.com/Camera-icon.svgBye!")
8890
end
8991
end
92+
93+
context "if the report does not have creator_ids" do
94+
it "returns a hash containing a blank string for the user id" do
95+
allow(subject).to receive(:creator_ids).and_return(nil)
96+
97+
expect(subject.report_attributes.fetch("cf").fetch("cf_user_id")).to eq("")
98+
end
99+
end
90100
end
91101
end

0 commit comments

Comments
 (0)