@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,139 +0,0 @@
|
|
|
1
|
-
import AtpAgent, { AppBskyLabelerDefs } from '@atproto/api'
|
|
2
|
-
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
3
|
-
import { OzoneConfig } from '../config/index.js'
|
|
4
|
-
import {
|
|
5
|
-
REASONAPPEAL,
|
|
6
|
-
REASONMISLEADING,
|
|
7
|
-
REASONOTHER,
|
|
8
|
-
REASONRUDE,
|
|
9
|
-
REASONSEXUAL,
|
|
10
|
-
REASONSPAM,
|
|
11
|
-
REASONVIOLATION,
|
|
12
|
-
} from '../lexicon/types/com/atproto/moderation/defs.js'
|
|
13
|
-
import { httpLogger } from '../logger.js'
|
|
14
|
-
|
|
15
|
-
// Reverse mapping from new ozone namespaced reason types to old com.atproto namespaced reason types
|
|
16
|
-
export const NEW_TO_OLD_REASON_MAPPING: Record<string, string> = {
|
|
17
|
-
'tools.ozone.report.defs#reasonAppeal': REASONAPPEAL,
|
|
18
|
-
'tools.ozone.report.defs#reasonOther': REASONOTHER,
|
|
19
|
-
|
|
20
|
-
'tools.ozone.report.defs#reasonViolenceAnimal': REASONVIOLATION,
|
|
21
|
-
'tools.ozone.report.defs#reasonViolenceThreats': REASONVIOLATION,
|
|
22
|
-
'tools.ozone.report.defs#reasonViolenceGraphicContent': REASONVIOLATION,
|
|
23
|
-
'tools.ozone.report.defs#reasonViolenceGlorification': REASONVIOLATION,
|
|
24
|
-
'tools.ozone.report.defs#reasonViolenceExtremistContent': REASONVIOLATION,
|
|
25
|
-
'tools.ozone.report.defs#reasonViolenceTrafficking': REASONVIOLATION,
|
|
26
|
-
'tools.ozone.report.defs#reasonViolenceOther': REASONVIOLATION,
|
|
27
|
-
|
|
28
|
-
'tools.ozone.report.defs#reasonSexualAbuseContent': REASONSEXUAL,
|
|
29
|
-
'tools.ozone.report.defs#reasonSexualNCII': REASONSEXUAL,
|
|
30
|
-
'tools.ozone.report.defs#reasonSexualDeepfake': REASONSEXUAL,
|
|
31
|
-
'tools.ozone.report.defs#reasonSexualAnimal': REASONSEXUAL,
|
|
32
|
-
'tools.ozone.report.defs#reasonSexualUnlabeled': REASONSEXUAL,
|
|
33
|
-
'tools.ozone.report.defs#reasonSexualOther': REASONSEXUAL,
|
|
34
|
-
|
|
35
|
-
'tools.ozone.report.defs#reasonChildSafetyCSAM': REASONVIOLATION,
|
|
36
|
-
'tools.ozone.report.defs#reasonChildSafetyGroom': REASONVIOLATION,
|
|
37
|
-
'tools.ozone.report.defs#reasonChildSafetyPrivacy': REASONVIOLATION,
|
|
38
|
-
'tools.ozone.report.defs#reasonChildSafetyHarassment': REASONVIOLATION,
|
|
39
|
-
'tools.ozone.report.defs#reasonChildSafetyOther': REASONVIOLATION,
|
|
40
|
-
|
|
41
|
-
'tools.ozone.report.defs#reasonHarassmentTroll': REASONRUDE,
|
|
42
|
-
'tools.ozone.report.defs#reasonHarassmentTargeted': REASONRUDE,
|
|
43
|
-
'tools.ozone.report.defs#reasonHarassmentHateSpeech': REASONRUDE,
|
|
44
|
-
'tools.ozone.report.defs#reasonHarassmentDoxxing': REASONRUDE,
|
|
45
|
-
'tools.ozone.report.defs#reasonHarassmentOther': REASONRUDE,
|
|
46
|
-
|
|
47
|
-
'tools.ozone.report.defs#reasonMisleadingBot': REASONMISLEADING,
|
|
48
|
-
'tools.ozone.report.defs#reasonMisleadingImpersonation': REASONMISLEADING,
|
|
49
|
-
'tools.ozone.report.defs#reasonMisleadingSpam': REASONSPAM,
|
|
50
|
-
'tools.ozone.report.defs#reasonMisleadingScam': REASONMISLEADING,
|
|
51
|
-
'tools.ozone.report.defs#reasonMisleadingElections': REASONMISLEADING,
|
|
52
|
-
'tools.ozone.report.defs#reasonMisleadingOther': REASONMISLEADING,
|
|
53
|
-
|
|
54
|
-
'tools.ozone.report.defs#reasonRuleSiteSecurity': REASONVIOLATION,
|
|
55
|
-
'tools.ozone.report.defs#reasonRuleProhibitedSales': REASONVIOLATION,
|
|
56
|
-
'tools.ozone.report.defs#reasonRuleBanEvasion': REASONVIOLATION,
|
|
57
|
-
'tools.ozone.report.defs#reasonRuleOther': REASONVIOLATION,
|
|
58
|
-
|
|
59
|
-
'tools.ozone.report.defs#reasonSelfHarmContent': REASONVIOLATION,
|
|
60
|
-
'tools.ozone.report.defs#reasonSelfHarmED': REASONVIOLATION,
|
|
61
|
-
'tools.ozone.report.defs#reasonSelfHarmStunts': REASONVIOLATION,
|
|
62
|
-
'tools.ozone.report.defs#reasonSelfHarmSubstances': REASONVIOLATION,
|
|
63
|
-
'tools.ozone.report.defs#reasonSelfHarmOther': REASONVIOLATION,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
interface CacheEntry {
|
|
67
|
-
profile: AppBskyLabelerDefs.LabelerViewDetailed | null
|
|
68
|
-
timestamp: number
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export type ModerationServiceProfileCreator = () => ModerationServiceProfile
|
|
72
|
-
|
|
73
|
-
export class ModerationServiceProfile {
|
|
74
|
-
private cache: CacheEntry | null = null
|
|
75
|
-
private CACHE_TTL: number
|
|
76
|
-
|
|
77
|
-
constructor(
|
|
78
|
-
private cfg: OzoneConfig,
|
|
79
|
-
private appviewAgent: AtpAgent,
|
|
80
|
-
cacheTTL?: number,
|
|
81
|
-
) {
|
|
82
|
-
this.CACHE_TTL = cacheTTL || cfg.service.serviceRecordCacheTTL
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
static creator(
|
|
86
|
-
cfg: OzoneConfig,
|
|
87
|
-
appviewAgent: AtpAgent,
|
|
88
|
-
): ModerationServiceProfileCreator {
|
|
89
|
-
return () => new ModerationServiceProfile(cfg, appviewAgent)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async getProfile() {
|
|
93
|
-
const now = Date.now()
|
|
94
|
-
|
|
95
|
-
if (!this.cache || now - this.cache.timestamp > this.CACHE_TTL) {
|
|
96
|
-
try {
|
|
97
|
-
const { data } = await this.appviewAgent.app.bsky.labeler.getServices({
|
|
98
|
-
dids: [this.cfg.service.did],
|
|
99
|
-
detailed: true,
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
if (AppBskyLabelerDefs.isLabelerViewDetailed(data.views?.[0])) {
|
|
103
|
-
this.cache = {
|
|
104
|
-
profile: data.views[0],
|
|
105
|
-
timestamp: now,
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
} catch (e) {
|
|
109
|
-
// On error, fail open
|
|
110
|
-
httpLogger.error(`Failed to fetch labeler profile: ${e?.['message']}`)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return this.cache?.profile || null
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async validateReasonType(reasonType: string): Promise<string> {
|
|
118
|
-
const profile = await this.getProfile()
|
|
119
|
-
|
|
120
|
-
if (!Array.isArray(profile?.reasonTypes)) {
|
|
121
|
-
return reasonType
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const supportedReasonTypes = profile.reasonTypes
|
|
125
|
-
|
|
126
|
-
// Check if the reason type is directly supported
|
|
127
|
-
if (supportedReasonTypes.includes(reasonType)) {
|
|
128
|
-
return reasonType
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Allow new reason types only if they map to a supported old reason type
|
|
132
|
-
const mappedOldReason = NEW_TO_OLD_REASON_MAPPING[reasonType]
|
|
133
|
-
if (mappedOldReason && supportedReasonTypes.includes(mappedOldReason)) {
|
|
134
|
-
return reasonType
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
throw new InvalidRequestError(`Invalid reason type: ${reasonType}`)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
@@ -1,429 +0,0 @@
|
|
|
1
|
-
import { sql } from 'kysely'
|
|
2
|
-
import { AtUri } from '@atproto/syntax'
|
|
3
|
-
import { Database } from '../db/index.js'
|
|
4
|
-
import { Report } from '../db/schema/report.js'
|
|
5
|
-
import { QueryParams } from '../lexicon/types/tools/ozone/report/queryReports.js'
|
|
6
|
-
import {
|
|
7
|
-
AlreadyInTargetState,
|
|
8
|
-
InvalidStateTransition,
|
|
9
|
-
handleReportUpdate,
|
|
10
|
-
} from '../report/handle-report-update.js'
|
|
11
|
-
|
|
12
|
-
export type ReportWithEvent = Omit<Report, 'id'> & {
|
|
13
|
-
id: number
|
|
14
|
-
subjectDid: string
|
|
15
|
-
subjectUri: string | null
|
|
16
|
-
subjectCid: string | null
|
|
17
|
-
reportedBy: string
|
|
18
|
-
comment: string | null
|
|
19
|
-
meta: Record<string, string | boolean | number> | null
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type QueryReportsResult = {
|
|
23
|
-
reports: ReportWithEvent[]
|
|
24
|
-
cursor: string | undefined
|
|
25
|
-
}
|
|
26
|
-
function reportQuery(db: Database) {
|
|
27
|
-
return db.db
|
|
28
|
-
.selectFrom('report as r')
|
|
29
|
-
.innerJoin('moderation_event as me', 'me.id', 'r.eventId')
|
|
30
|
-
.where('me.action', '=', 'tools.ozone.moderation.defs#modEventReport')
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function queryReports(
|
|
34
|
-
db: Database,
|
|
35
|
-
params: QueryParams,
|
|
36
|
-
): Promise<QueryReportsResult> {
|
|
37
|
-
let builder = reportQuery(db)
|
|
38
|
-
|
|
39
|
-
if (params.queueId !== undefined) {
|
|
40
|
-
builder = builder.where('r.queueId', '=', params.queueId)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
builder = builder.where('r.status', '=', params.status)
|
|
44
|
-
|
|
45
|
-
if (params.subject) {
|
|
46
|
-
const isRecord = params.subject.startsWith('at://')
|
|
47
|
-
if (isRecord) {
|
|
48
|
-
const uri = new AtUri(params.subject)
|
|
49
|
-
builder = builder
|
|
50
|
-
.where('r.did', '=', uri.host)
|
|
51
|
-
.where('r.recordPath', '=', `${uri.collection}/${uri.rkey}`)
|
|
52
|
-
} else {
|
|
53
|
-
builder = builder
|
|
54
|
-
.where('r.did', '=', params.subject)
|
|
55
|
-
.where('r.recordPath', '=', '')
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (params.did) {
|
|
60
|
-
builder = builder.where('r.did', '=', params.did)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (params.subjectType) {
|
|
64
|
-
const normalizedType = params.subjectType as 'account' | 'record'
|
|
65
|
-
if (normalizedType === 'account') {
|
|
66
|
-
builder = builder.where('r.recordPath', '=', '')
|
|
67
|
-
} else if (normalizedType === 'record') {
|
|
68
|
-
builder = builder.where('r.recordPath', '!=', '')
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (params.collections?.length) {
|
|
73
|
-
// Filter by collection prefix on recordPath (uses text_pattern_ops index)
|
|
74
|
-
const collectionConditions = params.collections.map(
|
|
75
|
-
(collection) => sql`r."recordPath" LIKE ${`${collection}/%`}`,
|
|
76
|
-
)
|
|
77
|
-
builder = builder.where(
|
|
78
|
-
sql<boolean>`(${sql.join(collectionConditions, sql` OR `)})`,
|
|
79
|
-
)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (params.reportTypes?.length) {
|
|
83
|
-
builder = builder.where('r.reportType', 'in', params.reportTypes)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (params.isMuted !== undefined) {
|
|
87
|
-
builder = builder.where('r.isMuted', '=', params.isMuted)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (params.reportedAfter) {
|
|
91
|
-
builder = builder.where('r.createdAt', '>', params.reportedAfter)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (params.reportedBefore) {
|
|
95
|
-
builder = builder.where('r.createdAt', '<', params.reportedBefore)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (params.assignedTo) {
|
|
99
|
-
builder = builder.where('r.assignedTo', '=', params.assignedTo)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const sortField = params.sortField ?? 'createdAt'
|
|
103
|
-
const sortDirection = params.sortDirection ?? 'desc'
|
|
104
|
-
|
|
105
|
-
builder = builder
|
|
106
|
-
.orderBy(
|
|
107
|
-
sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt',
|
|
108
|
-
sortDirection,
|
|
109
|
-
)
|
|
110
|
-
.orderBy('r.id', 'desc')
|
|
111
|
-
|
|
112
|
-
const limit = params.limit ?? 50
|
|
113
|
-
if (params.cursor) {
|
|
114
|
-
const [sortValue, id] = params.cursor.split('::')
|
|
115
|
-
const sortCol = sortField === 'updatedAt' ? 'r.updatedAt' : 'r.createdAt'
|
|
116
|
-
if (sortDirection === 'desc') {
|
|
117
|
-
builder = builder.where(sql<boolean>`(
|
|
118
|
-
${sql.ref(sortCol)} < ${sortValue}
|
|
119
|
-
OR (${sql.ref(sortCol)} = ${sortValue} AND r.id < ${Number(id)})
|
|
120
|
-
)`)
|
|
121
|
-
} else {
|
|
122
|
-
builder = builder.where(sql<boolean>`(
|
|
123
|
-
${sql.ref(sortCol)} > ${sortValue}
|
|
124
|
-
OR (${sql.ref(sortCol)} = ${sortValue} AND r.id > ${Number(id)})
|
|
125
|
-
)`)
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const finalQuery = builder
|
|
130
|
-
.selectAll('r')
|
|
131
|
-
.select([
|
|
132
|
-
'me.subjectDid',
|
|
133
|
-
'me.subjectUri',
|
|
134
|
-
'me.subjectCid',
|
|
135
|
-
'me.createdBy as reportedBy',
|
|
136
|
-
'me.comment',
|
|
137
|
-
'me.meta',
|
|
138
|
-
])
|
|
139
|
-
.limit(limit + 1)
|
|
140
|
-
|
|
141
|
-
const reports = await finalQuery.execute()
|
|
142
|
-
|
|
143
|
-
let cursor: string | undefined
|
|
144
|
-
const hasMore = reports.length > limit
|
|
145
|
-
if (hasMore) {
|
|
146
|
-
const last = reports[limit - 1]
|
|
147
|
-
const sortValue =
|
|
148
|
-
sortField === 'updatedAt' ? last.updatedAt : last.createdAt
|
|
149
|
-
cursor = `${sortValue}::${last.id}`
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const reportsToReturn = hasMore ? reports.slice(0, limit) : reports
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
reports: reportsToReturn,
|
|
156
|
-
cursor,
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export async function getReportById(
|
|
161
|
-
db: Database,
|
|
162
|
-
id: number,
|
|
163
|
-
): Promise<ReportWithEvent | undefined> {
|
|
164
|
-
return reportQuery(db)
|
|
165
|
-
.where('r.id', '=', id)
|
|
166
|
-
.selectAll('r')
|
|
167
|
-
.select([
|
|
168
|
-
'me.subjectDid',
|
|
169
|
-
'me.subjectUri',
|
|
170
|
-
'me.subjectCid',
|
|
171
|
-
'me.createdBy as reportedBy',
|
|
172
|
-
'me.comment',
|
|
173
|
-
'me.meta',
|
|
174
|
-
])
|
|
175
|
-
.executeTakeFirst()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
export async function getReportsByIds(
|
|
179
|
-
db: Database,
|
|
180
|
-
ids: number[],
|
|
181
|
-
): Promise<ReportWithEvent[]> {
|
|
182
|
-
if (!ids.length) return []
|
|
183
|
-
return reportQuery(db)
|
|
184
|
-
.where('r.id', 'in', ids)
|
|
185
|
-
.selectAll('r')
|
|
186
|
-
.select([
|
|
187
|
-
'me.subjectDid',
|
|
188
|
-
'me.subjectUri',
|
|
189
|
-
'me.subjectCid',
|
|
190
|
-
'me.createdBy as reportedBy',
|
|
191
|
-
'me.comment',
|
|
192
|
-
'me.meta',
|
|
193
|
-
])
|
|
194
|
-
.execute()
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export async function getLatestReport(
|
|
198
|
-
db: Database,
|
|
199
|
-
): Promise<ReportWithEvent | undefined> {
|
|
200
|
-
return reportQuery(db)
|
|
201
|
-
.selectAll('r')
|
|
202
|
-
.select([
|
|
203
|
-
'me.subjectDid',
|
|
204
|
-
'me.subjectUri',
|
|
205
|
-
'me.subjectCid',
|
|
206
|
-
'me.createdBy as reportedBy',
|
|
207
|
-
'me.comment',
|
|
208
|
-
'me.meta',
|
|
209
|
-
])
|
|
210
|
-
.orderBy('r.id', 'desc')
|
|
211
|
-
.limit(1)
|
|
212
|
-
.executeTakeFirst()
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export type FindReportsForSubjectParams = {
|
|
216
|
-
subjectDid: string
|
|
217
|
-
subjectUri?: string | null
|
|
218
|
-
reportIds?: number[]
|
|
219
|
-
reportTypes?: string[]
|
|
220
|
-
targetAll?: boolean
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export type ReportResult = {
|
|
224
|
-
id: number
|
|
225
|
-
eventId: number
|
|
226
|
-
queueId: number | null
|
|
227
|
-
queuedAt: string | null
|
|
228
|
-
actionEventIds: number[] | null
|
|
229
|
-
actionNote: string | null
|
|
230
|
-
isMuted: boolean
|
|
231
|
-
status: string
|
|
232
|
-
createdAt: string
|
|
233
|
-
updatedAt: string
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export async function findReportsForSubject(
|
|
237
|
-
db: Database,
|
|
238
|
-
params: FindReportsForSubjectParams,
|
|
239
|
-
): Promise<ReportResult[]> {
|
|
240
|
-
let builder = reportQuery(db).where('r.did', '=', params.subjectDid)
|
|
241
|
-
|
|
242
|
-
// Filter by subject URI (if provided, match exactly; if null/undefined, match repo-level)
|
|
243
|
-
if (params.subjectUri) {
|
|
244
|
-
const uri = new AtUri(params.subjectUri)
|
|
245
|
-
builder = builder.where(
|
|
246
|
-
'r.recordPath',
|
|
247
|
-
'=',
|
|
248
|
-
`${uri.collection}/${uri.rkey}`,
|
|
249
|
-
)
|
|
250
|
-
} else {
|
|
251
|
-
builder = builder.where('r.recordPath', '=', '')
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (params.targetAll) {
|
|
255
|
-
// Target all open/escalated reports on the subject
|
|
256
|
-
builder = builder.where('r.status', 'not in', ['closed'])
|
|
257
|
-
} else if (params.reportIds?.length) {
|
|
258
|
-
// Target specific report IDs — still enforce state transition rules
|
|
259
|
-
builder = builder
|
|
260
|
-
.where('r.id', 'in', params.reportIds)
|
|
261
|
-
.where('r.status', 'not in', ['closed'])
|
|
262
|
-
} else if (params.reportTypes?.length) {
|
|
263
|
-
// Target reports matching specific report types
|
|
264
|
-
builder = builder
|
|
265
|
-
.where('r.reportType', 'in', params.reportTypes)
|
|
266
|
-
.where('r.status', 'not in', ['closed'])
|
|
267
|
-
} else {
|
|
268
|
-
// No targeting criteria provided
|
|
269
|
-
return []
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const reports = await builder.selectAll('r').execute()
|
|
273
|
-
|
|
274
|
-
return reports
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export type ProcessReportActionParams = {
|
|
278
|
-
db: Database
|
|
279
|
-
reportAction: {
|
|
280
|
-
ids?: number[]
|
|
281
|
-
types?: string[]
|
|
282
|
-
all?: boolean
|
|
283
|
-
note?: string
|
|
284
|
-
}
|
|
285
|
-
subjectDid: string
|
|
286
|
-
subjectUri: string | null
|
|
287
|
-
eventId: number
|
|
288
|
-
eventType: string
|
|
289
|
-
createdBy: string
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Validates and processes a report action by:
|
|
294
|
-
* 1. Finding matching reports based on targeting criteria
|
|
295
|
-
* 2. Validating that specified report IDs exist and belong to the subject
|
|
296
|
-
* 3. Bulk-updating reports with the action event ID, note, and status
|
|
297
|
-
* 4. Bulk-inserting a report_activity row for each updated report
|
|
298
|
-
*
|
|
299
|
-
* @throws InvalidRequestError if validation fails
|
|
300
|
-
*/
|
|
301
|
-
export async function processReportAction(
|
|
302
|
-
params: ProcessReportActionParams,
|
|
303
|
-
): Promise<number> {
|
|
304
|
-
const {
|
|
305
|
-
db,
|
|
306
|
-
reportAction,
|
|
307
|
-
subjectDid,
|
|
308
|
-
subjectUri,
|
|
309
|
-
eventId,
|
|
310
|
-
eventType,
|
|
311
|
-
createdBy,
|
|
312
|
-
} = params
|
|
313
|
-
|
|
314
|
-
// Find reports matching the criteria
|
|
315
|
-
const matchingReports = await findReportsForSubject(db, {
|
|
316
|
-
subjectDid,
|
|
317
|
-
subjectUri,
|
|
318
|
-
reportIds: reportAction.ids,
|
|
319
|
-
reportTypes: reportAction.types,
|
|
320
|
-
targetAll: reportAction.all,
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
// Validate that reports were found for ids and types
|
|
324
|
-
if (matchingReports.length === 0) {
|
|
325
|
-
if (reportAction.ids?.length) {
|
|
326
|
-
throw new Error(
|
|
327
|
-
'No matching reports found for the specified report IDs on this subject',
|
|
328
|
-
)
|
|
329
|
-
} else if (reportAction.types?.length) {
|
|
330
|
-
throw new Error(
|
|
331
|
-
'No matching reports found for the specified report types on this subject',
|
|
332
|
-
)
|
|
333
|
-
}
|
|
334
|
-
// For 'all', it's okay if no reports exist
|
|
335
|
-
return 0
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Validate that all specified report IDs were found
|
|
339
|
-
if (reportAction.ids?.length) {
|
|
340
|
-
const foundIds = new Set(matchingReports.map((r) => r.id))
|
|
341
|
-
const requestedIds = new Set(reportAction.ids)
|
|
342
|
-
const missingIds = [...requestedIds].filter((id) => !foundIds.has(id))
|
|
343
|
-
|
|
344
|
-
if (missingIds.length > 0) {
|
|
345
|
-
throw new Error(
|
|
346
|
-
`Report IDs ${missingIds.join(', ')} do not exist, are already closed, or do not belong to this subject`,
|
|
347
|
-
)
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Determine per-report transitions via the pure state machine.
|
|
352
|
-
// Skip reports whose current status doesn't allow the transition.
|
|
353
|
-
const validUpdates: {
|
|
354
|
-
id: number
|
|
355
|
-
nextStatus: string
|
|
356
|
-
activityType: string
|
|
357
|
-
previousStatus: string
|
|
358
|
-
}[] = []
|
|
359
|
-
|
|
360
|
-
for (const report of matchingReports) {
|
|
361
|
-
try {
|
|
362
|
-
const result = handleReportUpdate(report.status, {
|
|
363
|
-
type: 'event',
|
|
364
|
-
eventType,
|
|
365
|
-
})
|
|
366
|
-
if (result.nextStatus && result.activity) {
|
|
367
|
-
validUpdates.push({
|
|
368
|
-
id: report.id,
|
|
369
|
-
nextStatus: result.nextStatus,
|
|
370
|
-
activityType: result.activity.activityType,
|
|
371
|
-
previousStatus: result.activity.previousStatus,
|
|
372
|
-
})
|
|
373
|
-
}
|
|
374
|
-
} catch (err) {
|
|
375
|
-
if (
|
|
376
|
-
err instanceof AlreadyInTargetState ||
|
|
377
|
-
err instanceof InvalidStateTransition
|
|
378
|
-
) {
|
|
379
|
-
// Skip reports that can't transition — silent per design
|
|
380
|
-
continue
|
|
381
|
-
}
|
|
382
|
-
throw err
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if (!validUpdates.length) {
|
|
387
|
-
return 0
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
const now = new Date().toISOString()
|
|
391
|
-
const updateIds = validUpdates.map((u) => u.id)
|
|
392
|
-
|
|
393
|
-
// Bulk UPDATE reports that passed validation
|
|
394
|
-
// All valid reports share the same target status since they come from the
|
|
395
|
-
// same event type, so a single UPDATE is sufficient.
|
|
396
|
-
const status = validUpdates[0].nextStatus
|
|
397
|
-
const closedAt = status === 'closed' ? now : null
|
|
398
|
-
await db.db
|
|
399
|
-
.updateTable('report')
|
|
400
|
-
.set({
|
|
401
|
-
actionEventIds: sql`COALESCE("actionEventIds", '[]'::jsonb) || ${JSON.stringify(eventId)}::jsonb`,
|
|
402
|
-
actionNote: reportAction.note ?? null,
|
|
403
|
-
status,
|
|
404
|
-
updatedAt: now,
|
|
405
|
-
closedAt,
|
|
406
|
-
})
|
|
407
|
-
.where('id', 'in', updateIds)
|
|
408
|
-
.execute()
|
|
409
|
-
|
|
410
|
-
// Bulk INSERT one activity per updated report
|
|
411
|
-
await db.db
|
|
412
|
-
.insertInto('report_activity')
|
|
413
|
-
.values(
|
|
414
|
-
validUpdates.map((u) => ({
|
|
415
|
-
reportId: u.id,
|
|
416
|
-
activityType: u.activityType,
|
|
417
|
-
previousStatus: u.previousStatus,
|
|
418
|
-
internalNote: null,
|
|
419
|
-
publicNote: reportAction.note ?? null,
|
|
420
|
-
meta: null,
|
|
421
|
-
isAutomated: false,
|
|
422
|
-
createdBy,
|
|
423
|
-
createdAt: now,
|
|
424
|
-
})),
|
|
425
|
-
)
|
|
426
|
-
.execute()
|
|
427
|
-
|
|
428
|
-
return validUpdates.length
|
|
429
|
-
}
|