@atproto/ozone 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/package.json +25 -21
- package/bin/migration-create.ts +0 -38
- package/jest.config.cjs +0 -22
- package/src/api/chat/getActorMetadata.ts +0 -23
- package/src/api/chat/getConvo.ts +0 -23
- package/src/api/chat/getConvoMembers.ts +0 -23
- package/src/api/chat/getConvos.ts +0 -23
- package/src/api/chat/getMessageContext.ts +0 -42
- package/src/api/chat/index.ts +0 -16
- package/src/api/communication/createTemplate.ts +0 -51
- package/src/api/communication/deleteTemplate.ts +0 -23
- package/src/api/communication/listTemplates.ts +0 -31
- package/src/api/communication/updateTemplate.ts +0 -51
- package/src/api/health.ts +0 -27
- package/src/api/index.ts +0 -146
- package/src/api/label/fetchLabels.ts +0 -32
- package/src/api/label/queryLabels.ts +0 -57
- package/src/api/label/subscribeLabels.ts +0 -25
- package/src/api/moderation/cancelScheduledActions.ts +0 -72
- package/src/api/moderation/emitEvent.ts +0 -475
- package/src/api/moderation/getAccountTimeline.ts +0 -160
- package/src/api/moderation/getEvent.ts +0 -19
- package/src/api/moderation/getRecord.ts +0 -40
- package/src/api/moderation/getRecords.ts +0 -50
- package/src/api/moderation/getRepo.ts +0 -34
- package/src/api/moderation/getReporterStats.ts +0 -18
- package/src/api/moderation/getRepos.ts +0 -41
- package/src/api/moderation/getSubjects.ts +0 -101
- package/src/api/moderation/listScheduledActions.ts +0 -45
- package/src/api/moderation/queryEvents.ts +0 -72
- package/src/api/moderation/queryStatuses.ts +0 -23
- package/src/api/moderation/scheduleAction.ts +0 -129
- package/src/api/moderation/searchRepos.ts +0 -46
- package/src/api/moderation/util.ts +0 -96
- package/src/api/proxied.ts +0 -327
- package/src/api/queue/assignModerator.ts +0 -31
- package/src/api/queue/createQueue.ts +0 -62
- package/src/api/queue/deleteQueue.ts +0 -56
- package/src/api/queue/getAssignments.ts +0 -19
- package/src/api/queue/listQueues.ts +0 -39
- package/src/api/queue/routeReports.ts +0 -44
- package/src/api/queue/unassignModerator.ts +0 -26
- package/src/api/queue/updateQueue.ts +0 -54
- package/src/api/report/assignModerator.ts +0 -36
- package/src/api/report/createActivity.ts +0 -57
- package/src/api/report/createReport.ts +0 -93
- package/src/api/report/getAssignments.ts +0 -20
- package/src/api/report/getHistoricalStats.ts +0 -41
- package/src/api/report/getLatestReport.ts +0 -44
- package/src/api/report/getLiveStats.ts +0 -26
- package/src/api/report/getReport.ts +0 -55
- package/src/api/report/listActivities.ts +0 -37
- package/src/api/report/queryActivities.ts +0 -64
- package/src/api/report/queryReports.ts +0 -44
- package/src/api/report/reassignQueue.ts +0 -68
- package/src/api/report/refreshStats.ts +0 -27
- package/src/api/report/unassignModerator.ts +0 -21
- package/src/api/safelink/addRule.ts +0 -48
- package/src/api/safelink/queryEvents.ts +0 -32
- package/src/api/safelink/queryRules.ts +0 -58
- package/src/api/safelink/removeRule.ts +0 -42
- package/src/api/safelink/updateRule.ts +0 -48
- package/src/api/server/getConfig.ts +0 -35
- package/src/api/set/addValues.ts +0 -28
- package/src/api/set/deleteSet.ts +0 -34
- package/src/api/set/deleteValues.ts +0 -31
- package/src/api/set/getValues.ts +0 -42
- package/src/api/set/querySets.ts +0 -36
- package/src/api/set/upsertSet.ts +0 -38
- package/src/api/setting/listOptions.ts +0 -44
- package/src/api/setting/removeOptions.ts +0 -64
- package/src/api/setting/upsertOption.ts +0 -156
- package/src/api/team/addMember.ts +0 -51
- package/src/api/team/deleteMember.ts +0 -29
- package/src/api/team/listMembers.ts +0 -20
- package/src/api/team/updateMember.ts +0 -47
- package/src/api/util.ts +0 -265
- package/src/api/verification/grantVerifications.ts +0 -90
- package/src/api/verification/listVerifications.ts +0 -44
- package/src/api/verification/revokeVerifications.ts +0 -43
- package/src/api/well-known.ts +0 -46
- package/src/assignment/index.ts +0 -728
- package/src/auth-verifier.ts +0 -227
- package/src/background.ts +0 -183
- package/src/communication-service/template.ts +0 -110
- package/src/communication-service/util.ts +0 -8
- package/src/config/config.ts +0 -211
- package/src/config/env.ts +0 -95
- package/src/config/index.ts +0 -3
- package/src/config/secrets.ts +0 -17
- package/src/context.ts +0 -399
- package/src/daemon/blob-diverter.ts +0 -186
- package/src/daemon/context.ts +0 -247
- package/src/daemon/event-pusher.ts +0 -363
- package/src/daemon/event-reverser.ts +0 -128
- package/src/daemon/index.ts +0 -33
- package/src/daemon/job-cursor.ts +0 -33
- package/src/daemon/materialized-view-refresher.ts +0 -33
- package/src/daemon/queue-router.ts +0 -101
- package/src/daemon/scheduled-action-processor.ts +0 -304
- package/src/daemon/stats-computer.ts +0 -101
- package/src/daemon/strike-expiry-processor.ts +0 -95
- package/src/daemon/team-profile-synchronizer.ts +0 -15
- package/src/daemon/verification-listener.ts +0 -169
- package/src/db/index.ts +0 -203
- package/src/db/migrations/20231219T205730722Z-init.ts +0 -170
- package/src/db/migrations/20240116T085607200Z-communication-template.ts +0 -23
- package/src/db/migrations/20240201T051104136Z-mod-event-blobs.ts +0 -15
- package/src/db/migrations/20240208T213404429Z-add-tags-column-to-moderation-subject.ts +0 -31
- package/src/db/migrations/20240228T003647759Z-add-label-sigs.ts +0 -25
- package/src/db/migrations/20240408T192432676Z-mute-reporting.ts +0 -15
- package/src/db/migrations/20240506T225055595Z-message-subject.ts +0 -21
- package/src/db/migrations/20240521T211332580Z-member.ts +0 -17
- package/src/db/migrations/20240814T003647759Z-event-created-at-index.ts +0 -13
- package/src/db/migrations/20240903T205730722Z-add-template-lang.ts +0 -12
- package/src/db/migrations/20240904T205730722Z-add-subject-did-index.ts +0 -13
- package/src/db/migrations/20241001T205730722Z-subject-status-review-state-index.ts +0 -15
- package/src/db/migrations/20241008T205730722Z-sets.ts +0 -53
- package/src/db/migrations/20241018T205730722Z-setting.ts +0 -27
- package/src/db/migrations/20241026T205730722Z-add-hosting-status-to-subject-status.ts +0 -57
- package/src/db/migrations/20241220T144630860Z-stats-materialized-views.ts +0 -215
- package/src/db/migrations/20250204T003647759Z-add-subject-priority-score.ts +0 -22
- package/src/db/migrations/20250211T003647759Z-add-reporter-stats-index.ts +0 -38
- package/src/db/migrations/20250211T132135150Z-moderation-event-message-partial-idx.ts +0 -26
- package/src/db/migrations/20250221T132135150Z-member-details.ts +0 -14
- package/src/db/migrations/20250404T201720309Z-subject-status-sort-idxs.ts +0 -18
- package/src/db/migrations/20250415T201720309Z-verification.ts +0 -34
- package/src/db/migrations/20250417T201720309Z-firehose-cursor.ts +0 -16
- package/src/db/migrations/20250609T110704000Z-safelink.ts +0 -53
- package/src/db/migrations/20250618T180246000Z-add-mod-tool-to-moderation-event.ts +0 -18
- package/src/db/migrations/20250701T000000000Z-add-age-assurance-state.ts +0 -25
- package/src/db/migrations/20250715T000000000Z-add-mod-event-external-id.ts +0 -15
- package/src/db/migrations/20250718T150931000Z-update-appeal-reason-stats.ts +0 -310
- package/src/db/migrations/20250813T000000000Z-mod-tool-batch-id-index.ts +0 -14
- package/src/db/migrations/20250923T000000000Z-scheduled-actions.ts +0 -56
- package/src/db/migrations/20251008T120000000Z-add-strike-system.ts +0 -87
- package/src/db/migrations/20260210T154806448Z-mod-event-created-by-indexes.ts +0 -22
- package/src/db/migrations/20260219T164523000Z-create-report-table.ts +0 -155
- package/src/db/migrations/20260219T165302248Z-moderator-assignment.ts +0 -42
- package/src/db/migrations/20260225T000000000Z-add-report-queue-table.ts +0 -41
- package/src/db/migrations/20260313T000000000Z-add-report-activity-table.ts +0 -48
- package/src/db/migrations/20260318T152058935Z-add-report-stat.ts +0 -35
- package/src/db/migrations/20260428T000000000Z-add-expiring-tag-table.ts +0 -32
- package/src/db/migrations/20260513T202941104Z-add-subject-convo-id.ts +0 -114
- package/src/db/migrations/20260602T120000000Z-add-report-activity-created-index.ts +0 -17
- package/src/db/migrations/index.ts +0 -44
- package/src/db/migrations/provider.ts +0 -26
- package/src/db/pagination.ts +0 -335
- package/src/db/schema/account_events_stats.ts +0 -16
- package/src/db/schema/account_record_events_stats.ts +0 -15
- package/src/db/schema/account_record_status_stats.ts +0 -15
- package/src/db/schema/account_strike.ts +0 -13
- package/src/db/schema/blob_push_event.ts +0 -21
- package/src/db/schema/communication_template.ts +0 -19
- package/src/db/schema/expiring_tag.ts +0 -18
- package/src/db/schema/firehose_cursor.ts +0 -13
- package/src/db/schema/index.ts +0 -60
- package/src/db/schema/job_cursor.ts +0 -13
- package/src/db/schema/label.ts +0 -22
- package/src/db/schema/member.ts +0 -22
- package/src/db/schema/moderation_event.ts +0 -61
- package/src/db/schema/moderation_subject_status.ts +0 -52
- package/src/db/schema/moderator_assignment.ts +0 -16
- package/src/db/schema/ozone_set.ts +0 -24
- package/src/db/schema/record_events_stats.ts +0 -15
- package/src/db/schema/record_push_event.ts +0 -21
- package/src/db/schema/repo_push_event.ts +0 -19
- package/src/db/schema/report.ts +0 -28
- package/src/db/schema/report_activity.ts +0 -22
- package/src/db/schema/report_queue.ts +0 -21
- package/src/db/schema/report_stat.ts +0 -27
- package/src/db/schema/safelink.ts +0 -39
- package/src/db/schema/scheduled-action.ts +0 -25
- package/src/db/schema/setting.ts +0 -24
- package/src/db/schema/signing_key.ts +0 -10
- package/src/db/schema/verification.ts +0 -21
- package/src/db/types.ts +0 -24
- package/src/error.ts +0 -12
- package/src/image-invalidator.ts +0 -7
- package/src/index.ts +0 -154
- package/src/jetstream/service.ts +0 -107
- package/src/logger.ts +0 -29
- package/src/mod-service/expiring-tags.ts +0 -104
- package/src/mod-service/index.ts +0 -1842
- package/src/mod-service/profile.ts +0 -139
- package/src/mod-service/report.ts +0 -429
- package/src/mod-service/status.ts +0 -549
- package/src/mod-service/strike.ts +0 -96
- package/src/mod-service/subject.ts +0 -311
- package/src/mod-service/types.ts +0 -96
- package/src/mod-service/util.ts +0 -99
- package/src/mod-service/views.ts +0 -912
- package/src/queue/service.ts +0 -603
- package/src/report/activity.ts +0 -281
- package/src/report/handle-report-update.ts +0 -209
- package/src/report/reassign.ts +0 -109
- package/src/report/stats.ts +0 -852
- package/src/report/views.ts +0 -239
- package/src/safelink/service.ts +0 -304
- package/src/scheduled-action/service.ts +0 -281
- package/src/scheduled-action/types.ts +0 -17
- package/src/sequencer/index.ts +0 -2
- package/src/sequencer/outbox.ts +0 -123
- package/src/sequencer/sequencer.ts +0 -147
- package/src/set/service.ts +0 -230
- package/src/setting/constants.ts +0 -3
- package/src/setting/service.ts +0 -148
- package/src/setting/types.ts +0 -3
- package/src/setting/validators.ts +0 -333
- package/src/tag-service/content-tagger.ts +0 -30
- package/src/tag-service/embed-tagger.ts +0 -70
- package/src/tag-service/index.ts +0 -70
- package/src/tag-service/language-data.ts +0 -561
- package/src/tag-service/language-tagger.ts +0 -101
- package/src/tag-service/util.ts +0 -13
- package/src/team/index.ts +0 -296
- package/src/util.ts +0 -230
- package/src/verification/issuer.ts +0 -146
- package/src/verification/service.ts +0 -208
- package/src/verification/util.ts +0 -53
- package/test.env +0 -2
- package/tests/3p-labeler.test.ts +0 -288
- package/tests/__snapshots__/account-strikes.test.ts.snap +0 -159
- package/tests/__snapshots__/age-assurance.test.ts.snap +0 -66
- package/tests/__snapshots__/blob-divert.test.ts.snap +0 -219
- package/tests/__snapshots__/get-account-timeline.test.ts.snap +0 -36
- package/tests/__snapshots__/get-record.test.ts.snap +0 -271
- package/tests/__snapshots__/get-records.test.ts.snap +0 -175
- package/tests/__snapshots__/get-repo.test.ts.snap +0 -91
- package/tests/__snapshots__/get-repos.test.ts.snap +0 -127
- package/tests/__snapshots__/get-starter-pack.test.ts.snap +0 -535
- package/tests/__snapshots__/get-subjects.test.ts.snap +0 -529
- package/tests/__snapshots__/moderation-events.test.ts.snap +0 -347
- package/tests/__snapshots__/moderation-statuses.test.ts.snap +0 -276
- package/tests/__snapshots__/moderation.test.ts.snap +0 -85
- package/tests/__snapshots__/report-reason.test.ts.snap +0 -14
- package/tests/__snapshots__/safelink.test.ts.snap +0 -179
- package/tests/__snapshots__/scheduled-action.test.ts.snap +0 -61
- package/tests/__snapshots__/sets.test.ts.snap +0 -46
- package/tests/__snapshots__/settings.test.ts.snap +0 -52
- package/tests/__snapshots__/team.test.ts.snap +0 -374
- package/tests/__snapshots__/verification-listener.test.ts.snap +0 -152
- package/tests/__snapshots__/verification.test.ts.snap +0 -302
- package/tests/_util.ts +0 -242
- package/tests/account-strikes.test.ts +0 -184
- package/tests/ack-all-subjects-of-account.test.ts +0 -177
- package/tests/age-assurance.test.ts +0 -372
- package/tests/blob-divert.test.ts +0 -106
- package/tests/communication-templates.test.ts +0 -149
- package/tests/content-tagger.test.ts +0 -170
- package/tests/db.test.ts +0 -184
- package/tests/expiring-label.test.ts +0 -72
- package/tests/expiring-tags.test.ts +0 -232
- package/tests/get-account-timeline.test.ts +0 -85
- package/tests/get-config.test.ts +0 -55
- package/tests/get-lists.test.ts +0 -111
- package/tests/get-profiles.test.ts +0 -70
- package/tests/get-record.test.ts +0 -130
- package/tests/get-records.test.ts +0 -91
- package/tests/get-repo.test.ts +0 -171
- package/tests/get-report.test.ts +0 -136
- package/tests/get-reporter-stats.test.ts +0 -132
- package/tests/get-repos.test.ts +0 -91
- package/tests/get-starter-pack.test.ts +0 -115
- package/tests/get-subjects.test.ts +0 -81
- package/tests/mod-tool.test.ts +0 -268
- package/tests/moderation-appeals.test.ts +0 -260
- package/tests/moderation-events.test.ts +0 -756
- package/tests/moderation-status-tags.test.ts +0 -140
- package/tests/moderation-statuses.test.ts +0 -495
- package/tests/moderation.test.ts +0 -992
- package/tests/protected-tags.test.ts +0 -218
- package/tests/query-labels.test.ts +0 -238
- package/tests/query-reports.test.ts +0 -608
- package/tests/queue-assignment.test.ts +0 -428
- package/tests/queue-router.test.ts +0 -306
- package/tests/queues.test.ts +0 -690
- package/tests/record-and-account-events.test.ts +0 -197
- package/tests/repo-search.test.ts +0 -136
- package/tests/report-action.test.ts +0 -308
- package/tests/report-activity.test.ts +0 -711
- package/tests/report-assignment.test.ts +0 -517
- package/tests/report-muting.test.ts +0 -100
- package/tests/report-reason.test.ts +0 -154
- package/tests/report-reassign-queue.test.ts +0 -340
- package/tests/report-routing.test.ts +0 -245
- package/tests/report-stats.test.ts +0 -545
- package/tests/revoke-account-credentials.test.ts +0 -54
- package/tests/safelink.test.ts +0 -534
- package/tests/scheduled-action-processor.test.ts +0 -488
- package/tests/scheduled-action.test.ts +0 -334
- package/tests/sequencer.test.ts +0 -227
- package/tests/server.test.ts +0 -62
- package/tests/sets.test.ts +0 -246
- package/tests/settings.test.ts +0 -308
- package/tests/strike-expiry-processor.test.ts +0 -299
- package/tests/subject-priority-score.test.ts +0 -96
- package/tests/takedown.test.ts +0 -105
- package/tests/team.test.ts +0 -216
- package/tests/verification-listener.test.ts +0 -129
- package/tests/verification.test.ts +0 -186
- package/tsconfig.build.json +0 -9
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import AtpAgent from '@atproto/api'
|
|
2
|
-
import { SeedClient, TestNetwork, basicSeed } from '@atproto/dev-env'
|
|
3
|
-
import {
|
|
4
|
-
REASONRUDE,
|
|
5
|
-
REASONSPAM,
|
|
6
|
-
} from '../src/lexicon/types/com/atproto/moderation/defs.js'
|
|
7
|
-
import { ModerationServiceProfile } from '../src/mod-service/profile.js'
|
|
8
|
-
import { forSnapshot } from './_util.js'
|
|
9
|
-
|
|
10
|
-
describe('report reason', () => {
|
|
11
|
-
let network: TestNetwork
|
|
12
|
-
let sc: SeedClient
|
|
13
|
-
let pdsAgent: AtpAgent
|
|
14
|
-
|
|
15
|
-
const repoSubject = (did: string) => ({
|
|
16
|
-
$type: 'com.atproto.admin.defs#repoRef',
|
|
17
|
-
did,
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
beforeAll(async () => {
|
|
21
|
-
network = await TestNetwork.create({
|
|
22
|
-
dbPostgresSchema: 'ozone_report',
|
|
23
|
-
})
|
|
24
|
-
sc = network.getSeedClient()
|
|
25
|
-
await basicSeed(sc)
|
|
26
|
-
|
|
27
|
-
// Login with ozone's service account owner and update the service profile definition
|
|
28
|
-
pdsAgent = network.pds.getAgent()
|
|
29
|
-
await pdsAgent.login({
|
|
30
|
-
identifier: 'mod-authority.test',
|
|
31
|
-
password: 'hunter2',
|
|
32
|
-
})
|
|
33
|
-
await pdsAgent.com.atproto.repo.putRecord({
|
|
34
|
-
repo: network.ozone.ctx.cfg.service.did,
|
|
35
|
-
collection: 'app.bsky.labeler.service',
|
|
36
|
-
rkey: 'self',
|
|
37
|
-
record: {
|
|
38
|
-
policies: { labelValues: [] },
|
|
39
|
-
reasonTypes: ['tools.ozone.report.defs#reasonHarassmentTroll'],
|
|
40
|
-
createdAt: new Date().toISOString(),
|
|
41
|
-
},
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
await network.processAll()
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
afterAll(async () => {
|
|
48
|
-
await network?.close()
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
describe('createReport', () => {
|
|
52
|
-
it('only passes for allowed reason types', async () => {
|
|
53
|
-
await expect(
|
|
54
|
-
sc.createReport({
|
|
55
|
-
reasonType: 'tools.ozone.report.defs#reasonHarassmentFake',
|
|
56
|
-
subject: repoSubject(sc.dids.bob),
|
|
57
|
-
reportedBy: sc.dids.alice,
|
|
58
|
-
}),
|
|
59
|
-
).rejects.toThrow('Invalid reason type')
|
|
60
|
-
|
|
61
|
-
const validReport = await sc.createReport({
|
|
62
|
-
reasonType: 'tools.ozone.report.defs#reasonHarassmentTroll',
|
|
63
|
-
subject: repoSubject(sc.dids.bob),
|
|
64
|
-
reportedBy: sc.dids.alice,
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
expect(forSnapshot(validReport)).toMatchSnapshot()
|
|
68
|
-
})
|
|
69
|
-
})
|
|
70
|
-
describe('ModerationServiceProfile', () => {
|
|
71
|
-
it('should validate against updated labeler profile when cache expires', async () => {
|
|
72
|
-
const moderationServiceProfile = new ModerationServiceProfile(
|
|
73
|
-
network.ozone.ctx.cfg,
|
|
74
|
-
network.ozone.ctx.appviewAgent,
|
|
75
|
-
500,
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
await expect(
|
|
79
|
-
moderationServiceProfile.validateReasonType(
|
|
80
|
-
'tools.ozone.report.defs#reasonHarassmentFake',
|
|
81
|
-
),
|
|
82
|
-
).rejects.toThrow('Invalid reason type')
|
|
83
|
-
|
|
84
|
-
// Update labeler profile to add the new reason type
|
|
85
|
-
await pdsAgent.com.atproto.repo.putRecord({
|
|
86
|
-
repo: network.ozone.ctx.cfg.service.did,
|
|
87
|
-
collection: 'app.bsky.labeler.service',
|
|
88
|
-
rkey: 'self',
|
|
89
|
-
record: {
|
|
90
|
-
policies: { labelValues: [] },
|
|
91
|
-
reasonTypes: ['tools.ozone.report.defs#reasonHarassmentFake'],
|
|
92
|
-
createdAt: new Date().toISOString(),
|
|
93
|
-
},
|
|
94
|
-
})
|
|
95
|
-
await network.processAll()
|
|
96
|
-
|
|
97
|
-
// immediately after the update, the reason type still fails due to cache
|
|
98
|
-
await expect(
|
|
99
|
-
moderationServiceProfile.validateReasonType(
|
|
100
|
-
'tools.ozone.report.defs#reasonHarassmentFake',
|
|
101
|
-
),
|
|
102
|
-
).rejects.toThrow('Invalid reason type')
|
|
103
|
-
|
|
104
|
-
// add some manual delay to ensure cache is expired and try again
|
|
105
|
-
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
106
|
-
await expect(
|
|
107
|
-
moderationServiceProfile.validateReasonType(
|
|
108
|
-
'tools.ozone.report.defs#reasonHarassmentFake',
|
|
109
|
-
),
|
|
110
|
-
).resolves.toEqual('tools.ozone.report.defs#reasonHarassmentFake')
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('should validate mapped reason types', async () => {
|
|
114
|
-
const moderationServiceProfile = new ModerationServiceProfile(
|
|
115
|
-
network.ozone.ctx.cfg,
|
|
116
|
-
network.ozone.ctx.appviewAgent,
|
|
117
|
-
500,
|
|
118
|
-
)
|
|
119
|
-
|
|
120
|
-
// Set up labeler profile with old reason types only
|
|
121
|
-
await pdsAgent.com.atproto.repo.putRecord({
|
|
122
|
-
repo: network.ozone.ctx.cfg.service.did,
|
|
123
|
-
collection: 'app.bsky.labeler.service',
|
|
124
|
-
rkey: 'self',
|
|
125
|
-
record: {
|
|
126
|
-
policies: { labelValues: [] },
|
|
127
|
-
reasonTypes: [REASONSPAM, REASONRUDE],
|
|
128
|
-
createdAt: new Date().toISOString(),
|
|
129
|
-
},
|
|
130
|
-
})
|
|
131
|
-
await network.processAll()
|
|
132
|
-
|
|
133
|
-
await new Promise((resolve) => setTimeout(resolve, 500))
|
|
134
|
-
|
|
135
|
-
await expect(
|
|
136
|
-
moderationServiceProfile.validateReasonType(
|
|
137
|
-
'tools.ozone.report.defs#reasonMisleadingSpam',
|
|
138
|
-
),
|
|
139
|
-
).resolves.toEqual('tools.ozone.report.defs#reasonMisleadingSpam')
|
|
140
|
-
|
|
141
|
-
// directly supported old reason types work
|
|
142
|
-
await expect(
|
|
143
|
-
moderationServiceProfile.validateReasonType(REASONSPAM),
|
|
144
|
-
).resolves.toEqual(REASONSPAM)
|
|
145
|
-
|
|
146
|
-
// new reason types that don't map to supported old reason types are rejected
|
|
147
|
-
await expect(
|
|
148
|
-
moderationServiceProfile.validateReasonType(
|
|
149
|
-
'tools.ozone.report.defs#reasonViolenceThreats',
|
|
150
|
-
),
|
|
151
|
-
).rejects.toThrow('Invalid reason type')
|
|
152
|
-
})
|
|
153
|
-
})
|
|
154
|
-
})
|
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
import AtpAgent from '@atproto/api'
|
|
2
|
-
import { SeedClient, TestNetwork, basicSeed } from '@atproto/dev-env'
|
|
3
|
-
import { ids } from '../src/lexicon/lexicons.js'
|
|
4
|
-
import { REASONSPAM } from '../src/lexicon/types/com/atproto/moderation/defs.js'
|
|
5
|
-
|
|
6
|
-
const DEFS = 'tools.ozone.report.defs'
|
|
7
|
-
|
|
8
|
-
describe('report-reassign-queue', () => {
|
|
9
|
-
let network: TestNetwork
|
|
10
|
-
let agent: AtpAgent
|
|
11
|
-
let sc: SeedClient
|
|
12
|
-
|
|
13
|
-
// Track queue IDs created during each test so afterEach can soft-delete them.
|
|
14
|
-
// Soft-deleted queues are filtered out of `checkConflict`, so tests are free
|
|
15
|
-
// to reuse the same queue configuration without tripping ConflictingQueue.
|
|
16
|
-
const createdQueueIds: number[] = []
|
|
17
|
-
|
|
18
|
-
const modHeaders = async (
|
|
19
|
-
nsid: string,
|
|
20
|
-
role: 'admin' | 'moderator' | 'triage' = 'admin',
|
|
21
|
-
) => network.ozone.modHeaders(nsid, role)
|
|
22
|
-
|
|
23
|
-
const createReport = async (subjectDid: string) => {
|
|
24
|
-
await sc.createReport({
|
|
25
|
-
reasonType: REASONSPAM,
|
|
26
|
-
subject: {
|
|
27
|
-
$type: 'com.atproto.admin.defs#repoRef',
|
|
28
|
-
did: subjectDid,
|
|
29
|
-
},
|
|
30
|
-
reportedBy: sc.dids.bob,
|
|
31
|
-
})
|
|
32
|
-
await network.processAll()
|
|
33
|
-
|
|
34
|
-
const { data } = await agent.tools.ozone.report.queryReports(
|
|
35
|
-
{ status: 'open', subject: subjectDid },
|
|
36
|
-
{ headers: await modHeaders(ids.ToolsOzoneReportQueryReports) },
|
|
37
|
-
)
|
|
38
|
-
const report = data.reports[0]
|
|
39
|
-
if (!report) throw new Error(`No report found for subject ${subjectDid}`)
|
|
40
|
-
return report
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const createQueue = async (
|
|
44
|
-
overrides: {
|
|
45
|
-
name?: string
|
|
46
|
-
subjectTypes?: string[]
|
|
47
|
-
reportTypes?: string[]
|
|
48
|
-
} = {},
|
|
49
|
-
) => {
|
|
50
|
-
const name = overrides.name ?? `q-${Date.now()}-${Math.random()}`
|
|
51
|
-
const input = {
|
|
52
|
-
name,
|
|
53
|
-
subjectTypes: overrides.subjectTypes ?? ['account'],
|
|
54
|
-
reportTypes: overrides.reportTypes ?? [
|
|
55
|
-
'com.atproto.moderation.defs#reasonSpam',
|
|
56
|
-
],
|
|
57
|
-
}
|
|
58
|
-
const { data } = await agent.tools.ozone.queue.createQueue(input, {
|
|
59
|
-
encoding: 'application/json',
|
|
60
|
-
headers: await modHeaders(ids.ToolsOzoneQueueCreateQueue),
|
|
61
|
-
})
|
|
62
|
-
createdQueueIds.push(data.queue.id)
|
|
63
|
-
return data
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const deleteQueue = async (queueId: number) =>
|
|
67
|
-
agent.tools.ozone.queue.deleteQueue(
|
|
68
|
-
{ queueId },
|
|
69
|
-
{
|
|
70
|
-
encoding: 'application/json',
|
|
71
|
-
headers: await modHeaders(ids.ToolsOzoneQueueDeleteQueue),
|
|
72
|
-
},
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
const closeReport = async (reportId: number) => {
|
|
76
|
-
await agent.tools.ozone.report.createActivity(
|
|
77
|
-
{
|
|
78
|
-
reportId,
|
|
79
|
-
activity: { $type: `${DEFS}#closeActivity` },
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
encoding: 'application/json',
|
|
83
|
-
headers: await modHeaders(ids.ToolsOzoneReportCreateActivity),
|
|
84
|
-
},
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const disableQueue = async (queueId: number) => {
|
|
89
|
-
return agent.tools.ozone.queue.updateQueue(
|
|
90
|
-
{ queueId, enabled: false },
|
|
91
|
-
{
|
|
92
|
-
encoding: 'application/json',
|
|
93
|
-
headers: await modHeaders(ids.ToolsOzoneQueueUpdateQueue),
|
|
94
|
-
},
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const escalateReport = async (reportId: number) => {
|
|
99
|
-
await agent.tools.ozone.report.createActivity(
|
|
100
|
-
{
|
|
101
|
-
reportId,
|
|
102
|
-
activity: { $type: `${DEFS}#escalationActivity` },
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
encoding: 'application/json',
|
|
106
|
-
headers: await modHeaders(ids.ToolsOzoneReportCreateActivity),
|
|
107
|
-
},
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const reassignQueue = async (
|
|
112
|
-
input: { reportId: number; queueId: number; comment?: string },
|
|
113
|
-
role: 'admin' | 'moderator' | 'triage' = 'admin',
|
|
114
|
-
) => {
|
|
115
|
-
return agent.tools.ozone.report.reassignQueue(input, {
|
|
116
|
-
encoding: 'application/json',
|
|
117
|
-
headers: await modHeaders(ids.ToolsOzoneReportReassignQueue, role),
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const listActivities = async (reportId: number) => {
|
|
122
|
-
const { data } = await agent.tools.ozone.report.listActivities(
|
|
123
|
-
{ reportId },
|
|
124
|
-
{ headers: await modHeaders(ids.ToolsOzoneReportListActivities) },
|
|
125
|
-
)
|
|
126
|
-
return data
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
beforeAll(async () => {
|
|
130
|
-
network = await TestNetwork.create({
|
|
131
|
-
dbPostgresSchema: 'ozone_report_reassign_queue',
|
|
132
|
-
})
|
|
133
|
-
agent = network.ozone.getAgent()
|
|
134
|
-
sc = network.getSeedClient()
|
|
135
|
-
await basicSeed(sc)
|
|
136
|
-
await network.processAll()
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
afterEach(async () => {
|
|
140
|
-
await Promise.all(
|
|
141
|
-
createdQueueIds.splice(0).map((id) => deleteQueue(id).catch(() => {})),
|
|
142
|
-
)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
afterAll(async () => {
|
|
146
|
-
await network?.close()
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
describe('happy path: assigning to a real queue', () => {
|
|
150
|
-
it('transitions open → queued and writes an activity row', async () => {
|
|
151
|
-
const report = await createReport(sc.dids.alice)
|
|
152
|
-
const queue = await createQueue()
|
|
153
|
-
|
|
154
|
-
const { data } = await reassignQueue({
|
|
155
|
-
reportId: report.id,
|
|
156
|
-
queueId: queue.queue.id,
|
|
157
|
-
comment: 'Routing to spam queue for review',
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
expect(data.report.id).toBe(report.id)
|
|
161
|
-
expect(data.report.status).toBe('queued')
|
|
162
|
-
expect(data.report.queue?.id).toBe(queue.queue.id)
|
|
163
|
-
expect(data.report.queuedAt).toBeDefined()
|
|
164
|
-
|
|
165
|
-
const activities = await listActivities(report.id)
|
|
166
|
-
const queueActivity = activities.activities.find(
|
|
167
|
-
(a) => a.activity.$type === `${DEFS}#queueActivity`,
|
|
168
|
-
)
|
|
169
|
-
expect(queueActivity).toBeDefined()
|
|
170
|
-
expect(queueActivity!.internalNote).toBe(
|
|
171
|
-
'Routing to spam queue for review',
|
|
172
|
-
)
|
|
173
|
-
expect(queueActivity!.publicNote).toBeUndefined()
|
|
174
|
-
expect(queueActivity!.isAutomated).toBe(false)
|
|
175
|
-
expect((queueActivity!.activity as any).previousStatus).toBe('open')
|
|
176
|
-
expect(queueActivity!.meta!.toQueueId).toEqual(queue.queue.id)
|
|
177
|
-
})
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
describe('queue-to-queue reassignment', () => {
|
|
181
|
-
it('keeps status queued and records fromQueueId correctly', async () => {
|
|
182
|
-
const report = await createReport(sc.dids.carol)
|
|
183
|
-
const queueA = await createQueue()
|
|
184
|
-
// Second queue needs a distinct config to avoid ConflictingQueue.
|
|
185
|
-
const queueB = await createQueue({
|
|
186
|
-
reportTypes: ['com.atproto.moderation.defs#reasonViolation'],
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
await reassignQueue({ reportId: report.id, queueId: queueA.queue.id })
|
|
190
|
-
|
|
191
|
-
const { data } = await reassignQueue({
|
|
192
|
-
reportId: report.id,
|
|
193
|
-
queueId: queueB.queue.id,
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
expect(data.report.status).toBe('queued')
|
|
197
|
-
expect(data.report.queue?.id).toBe(queueB.queue.id)
|
|
198
|
-
|
|
199
|
-
const activities = await listActivities(report.id)
|
|
200
|
-
const queueActivities = activities.activities.filter(
|
|
201
|
-
(a) => a.activity.$type === `${DEFS}#queueActivity`,
|
|
202
|
-
)
|
|
203
|
-
// Sorted DESC, so [0] is the most recent.
|
|
204
|
-
expect(queueActivities.length).toBeGreaterThanOrEqual(2)
|
|
205
|
-
expect((queueActivities[0].activity as any).previousStatus).toBe('queued')
|
|
206
|
-
expect(queueActivities[0].meta).toEqual({
|
|
207
|
-
fromQueueId: queueA.queue.id,
|
|
208
|
-
toQueueId: queueB.queue.id,
|
|
209
|
-
})
|
|
210
|
-
})
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
describe('unassignment (queueId = -1)', () => {
|
|
214
|
-
it('transitions queued → open and clears queuedAt', async () => {
|
|
215
|
-
const report = await createReport(sc.dids.dan)
|
|
216
|
-
const queue = await createQueue()
|
|
217
|
-
|
|
218
|
-
await reassignQueue({ reportId: report.id, queueId: queue.queue.id })
|
|
219
|
-
|
|
220
|
-
const { data } = await reassignQueue({
|
|
221
|
-
reportId: report.id,
|
|
222
|
-
queueId: -1,
|
|
223
|
-
})
|
|
224
|
-
|
|
225
|
-
expect(data.report.status).toBe('open')
|
|
226
|
-
expect(data.report.queue).toBeUndefined()
|
|
227
|
-
expect(data.report.queuedAt).toBeUndefined()
|
|
228
|
-
|
|
229
|
-
const activities = await listActivities(report.id)
|
|
230
|
-
const latest = activities.activities[0]
|
|
231
|
-
expect(latest.activity.$type).toBe(`${DEFS}#queueActivity`)
|
|
232
|
-
expect((latest.activity as any).previousStatus).toBe('queued')
|
|
233
|
-
expect(latest.meta).toEqual({
|
|
234
|
-
fromQueueId: queue.queue.id,
|
|
235
|
-
toQueueId: -1,
|
|
236
|
-
})
|
|
237
|
-
})
|
|
238
|
-
})
|
|
239
|
-
|
|
240
|
-
describe('errors', () => {
|
|
241
|
-
it('throws ReportClosed when report is closed', async () => {
|
|
242
|
-
const report = await createReport(sc.dids.alice)
|
|
243
|
-
await closeReport(report.id)
|
|
244
|
-
const queue = await createQueue()
|
|
245
|
-
|
|
246
|
-
await expect(
|
|
247
|
-
reassignQueue({ reportId: report.id, queueId: queue.queue.id }),
|
|
248
|
-
).rejects.toThrow(/ReportClosed|closed/)
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
it('throws AlreadyInTargetQueue when target equals current queue', async () => {
|
|
252
|
-
const report = await createReport(sc.dids.alice)
|
|
253
|
-
const queue = await createQueue()
|
|
254
|
-
await reassignQueue({ reportId: report.id, queueId: queue.queue.id })
|
|
255
|
-
|
|
256
|
-
await expect(
|
|
257
|
-
reassignQueue({ reportId: report.id, queueId: queue.queue.id }),
|
|
258
|
-
).rejects.toThrow(/AlreadyInTargetQueue|already/)
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
it('throws AlreadyInTargetQueue when unassigning a never-queued report', async () => {
|
|
262
|
-
const report = await createReport(sc.dids.alice)
|
|
263
|
-
|
|
264
|
-
await expect(
|
|
265
|
-
reassignQueue({ reportId: report.id, queueId: -1 }),
|
|
266
|
-
).rejects.toThrow(/AlreadyInTargetQueue|already/)
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
it('throws QueueNotFound when target queue does not exist', async () => {
|
|
270
|
-
const report = await createReport(sc.dids.alice)
|
|
271
|
-
|
|
272
|
-
await expect(
|
|
273
|
-
reassignQueue({ reportId: report.id, queueId: 999999 }),
|
|
274
|
-
).rejects.toThrow(/QueueNotFound|not found/)
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
it('throws QueueNotFound when target queue is soft-deleted', async () => {
|
|
278
|
-
const report = await createReport(sc.dids.alice)
|
|
279
|
-
const queue = await createQueue()
|
|
280
|
-
await deleteQueue(queue.queue.id)
|
|
281
|
-
|
|
282
|
-
await expect(
|
|
283
|
-
reassignQueue({ reportId: report.id, queueId: queue.queue.id }),
|
|
284
|
-
).rejects.toThrow(/QueueNotFound|not found/)
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
it('throws QueueDisabled when target queue is disabled', async () => {
|
|
288
|
-
const report = await createReport(sc.dids.alice)
|
|
289
|
-
const queue = await createQueue()
|
|
290
|
-
await disableQueue(queue.queue.id)
|
|
291
|
-
|
|
292
|
-
await expect(
|
|
293
|
-
reassignQueue({ reportId: report.id, queueId: queue.queue.id }),
|
|
294
|
-
).rejects.toThrow(/QueueDisabled|disabled/)
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
it('throws ReportNotFound when report does not exist', async () => {
|
|
298
|
-
const queue = await createQueue()
|
|
299
|
-
|
|
300
|
-
await expect(
|
|
301
|
-
reassignQueue({ reportId: 999999, queueId: queue.queue.id }),
|
|
302
|
-
).rejects.toThrow(/ReportNotFound|not found/)
|
|
303
|
-
})
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
describe('status-preserving cases', () => {
|
|
307
|
-
it('keeps escalated status when reassigning an escalated report', async () => {
|
|
308
|
-
const report = await createReport(sc.dids.alice)
|
|
309
|
-
await escalateReport(report.id)
|
|
310
|
-
const queue = await createQueue()
|
|
311
|
-
|
|
312
|
-
const { data } = await reassignQueue({
|
|
313
|
-
reportId: report.id,
|
|
314
|
-
queueId: queue.queue.id,
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
expect(data.report.status).toBe('escalated')
|
|
318
|
-
expect(data.report.queue?.id).toBe(queue.queue.id)
|
|
319
|
-
|
|
320
|
-
const activities = await listActivities(report.id)
|
|
321
|
-
const latest = activities.activities[0]
|
|
322
|
-
expect(latest.activity.$type).toBe(`${DEFS}#queueActivity`)
|
|
323
|
-
expect((latest.activity as any).previousStatus).toBe('escalated')
|
|
324
|
-
})
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
describe('auth', () => {
|
|
328
|
-
it('allows triage role to reassign', async () => {
|
|
329
|
-
const report = await createReport(sc.dids.alice)
|
|
330
|
-
const queue = await createQueue()
|
|
331
|
-
|
|
332
|
-
const { data } = await reassignQueue(
|
|
333
|
-
{ reportId: report.id, queueId: queue.queue.id },
|
|
334
|
-
'triage',
|
|
335
|
-
)
|
|
336
|
-
|
|
337
|
-
expect(data.report.status).toBe('queued')
|
|
338
|
-
})
|
|
339
|
-
})
|
|
340
|
-
})
|