@atproto/ozone 0.1.10 → 0.1.12
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 +16 -0
- package/dist/api/moderation/emitEvent.d.ts.map +1 -1
- package/dist/api/moderation/emitEvent.js +4 -0
- package/dist/api/moderation/emitEvent.js.map +1 -1
- package/dist/api/moderation/queryStatuses.d.ts.map +1 -1
- package/dist/api/moderation/queryStatuses.js +2 -1
- package/dist/api/moderation/queryStatuses.js.map +1 -1
- package/dist/api/util.d.ts +1 -1
- package/dist/api/util.d.ts.map +1 -1
- package/dist/api/util.js +2 -0
- package/dist/api/util.js.map +1 -1
- package/dist/db/migrations/20240408T192432676Z-mute-reporting.d.ts +4 -0
- package/dist/db/migrations/20240408T192432676Z-mute-reporting.d.ts.map +1 -0
- package/dist/db/migrations/20240408T192432676Z-mute-reporting.js +18 -0
- package/dist/db/migrations/20240408T192432676Z-mute-reporting.js.map +1 -0
- package/dist/db/migrations/index.d.ts +1 -0
- package/dist/db/migrations/index.d.ts.map +1 -1
- package/dist/db/migrations/index.js +2 -1
- package/dist/db/migrations/index.js.map +1 -1
- package/dist/db/schema/moderation_event.d.ts +1 -1
- package/dist/db/schema/moderation_event.d.ts.map +1 -1
- package/dist/db/schema/moderation_subject_status.d.ts +1 -0
- package/dist/db/schema/moderation_subject_status.d.ts.map +1 -1
- package/dist/lexicon/lexicons.d.ts +41 -0
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +50 -1
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/defs.d.ts +1 -0
- package/dist/lexicon/types/app/bsky/feed/defs.d.ts.map +1 -1
- package/dist/lexicon/types/app/bsky/feed/defs.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts +22 -2
- package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/defs.js +22 -2
- package/dist/lexicon/types/tools/ozone/moderation/defs.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/emitEvent.d.ts +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/emitEvent.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/queryStatuses.d.ts +2 -0
- package/dist/lexicon/types/tools/ozone/moderation/queryStatuses.d.ts.map +1 -1
- package/dist/mod-service/index.d.ts +6 -2
- package/dist/mod-service/index.d.ts.map +1 -1
- package/dist/mod-service/index.js +25 -1
- package/dist/mod-service/index.js.map +1 -1
- package/dist/mod-service/status.d.ts +21 -1
- package/dist/mod-service/status.d.ts.map +1 -1
- package/dist/mod-service/status.js +23 -0
- package/dist/mod-service/status.js.map +1 -1
- package/dist/mod-service/views.d.ts.map +1 -1
- package/dist/mod-service/views.js +3 -0
- package/dist/mod-service/views.js.map +1 -1
- package/package.json +3 -3
- package/src/api/moderation/emitEvent.ts +9 -0
- package/src/api/moderation/queryStatuses.ts +2 -0
- package/src/api/util.ts +2 -0
- package/src/db/migrations/20240408T192432676Z-mute-reporting.ts +15 -0
- package/src/db/migrations/index.ts +1 -0
- package/src/db/schema/moderation_event.ts +3 -0
- package/src/db/schema/moderation_subject_status.ts +1 -0
- package/src/lexicon/lexicons.ts +53 -1
- package/src/lexicon/types/app/bsky/feed/defs.ts +1 -0
- package/src/lexicon/types/tools/ozone/moderation/defs.ts +56 -0
- package/src/lexicon/types/tools/ozone/moderation/emitEvent.ts +3 -1
- package/src/lexicon/types/tools/ozone/moderation/queryStatuses.ts +2 -0
- package/src/mod-service/index.ts +33 -0
- package/src/mod-service/status.ts +26 -0
- package/src/mod-service/views.ts +3 -0
- package/tests/__snapshots__/moderation-events.test.ts.snap +7 -0
- package/tests/report-muting.test.ts +100 -0
|
@@ -57,6 +57,15 @@ const getSubjectStatusForModerationEvent = ({
|
|
|
57
57
|
suspendUntil: null,
|
|
58
58
|
lastReviewedAt: createdAt,
|
|
59
59
|
}
|
|
60
|
+
case 'tools.ozone.moderation.defs#modEventUnmuteReporter':
|
|
61
|
+
return {
|
|
62
|
+
lastReviewedBy: createdBy,
|
|
63
|
+
muteReportingUntil: null,
|
|
64
|
+
// It's not likely to receive an unmute event that does not already have a status row
|
|
65
|
+
// but if it does happen, default to unnecessary
|
|
66
|
+
reviewState: defaultReviewState,
|
|
67
|
+
lastReviewedAt: createdAt,
|
|
68
|
+
}
|
|
60
69
|
case 'tools.ozone.moderation.defs#modEventUnmute':
|
|
61
70
|
return {
|
|
62
71
|
lastReviewedBy: createdBy,
|
|
@@ -76,6 +85,18 @@ const getSubjectStatusForModerationEvent = ({
|
|
|
76
85
|
? new Date(Date.now() + durationInHours * HOUR).toISOString()
|
|
77
86
|
: null,
|
|
78
87
|
}
|
|
88
|
+
case 'tools.ozone.moderation.defs#modEventMuteReporter':
|
|
89
|
+
return {
|
|
90
|
+
lastReviewedBy: createdBy,
|
|
91
|
+
lastReviewedAt: createdAt,
|
|
92
|
+
// By default, mute for 24hrs
|
|
93
|
+
muteReportingUntil: new Date(
|
|
94
|
+
Date.now() + (durationInHours || 24) * HOUR,
|
|
95
|
+
).toISOString(),
|
|
96
|
+
// It's not likely to receive a mute event on a subject that does not already have a status row
|
|
97
|
+
// but if it does happen, default to unnecessary
|
|
98
|
+
reviewState: defaultReviewState,
|
|
99
|
+
}
|
|
79
100
|
case 'tools.ozone.moderation.defs#modEventMute':
|
|
80
101
|
return {
|
|
81
102
|
lastReviewedBy: createdBy,
|
|
@@ -140,6 +161,11 @@ export const adjustModerationSubjectStatus = async (
|
|
|
140
161
|
.selectAll()
|
|
141
162
|
.executeTakeFirst()
|
|
142
163
|
|
|
164
|
+
// If reporting is muted for this reporter, we don't want to update the subject status
|
|
165
|
+
if (meta?.isReporterMuted) {
|
|
166
|
+
return currentStatus || null
|
|
167
|
+
}
|
|
168
|
+
|
|
143
169
|
const isAppealEvent =
|
|
144
170
|
action === 'tools.ozone.moderation.defs#modEventReport' &&
|
|
145
171
|
meta?.reportType === REASONAPPEAL
|
package/src/mod-service/views.ts
CHANGED
|
@@ -108,6 +108,7 @@ export class ModerationViews {
|
|
|
108
108
|
|
|
109
109
|
if (
|
|
110
110
|
[
|
|
111
|
+
'tools.ozone.moderation.defs#modEventMuteReporter',
|
|
111
112
|
'tools.ozone.moderation.defs#modEventTakedown',
|
|
112
113
|
'tools.ozone.moderation.defs#modEventMute',
|
|
113
114
|
].includes(event.action)
|
|
@@ -157,6 +158,7 @@ export class ModerationViews {
|
|
|
157
158
|
eventView.event = {
|
|
158
159
|
...eventView.event,
|
|
159
160
|
reportType: event.meta?.reportType ?? undefined,
|
|
161
|
+
isReporterMuted: !!event.meta?.isReporterMuted,
|
|
160
162
|
}
|
|
161
163
|
}
|
|
162
164
|
|
|
@@ -500,6 +502,7 @@ export class ModerationViews {
|
|
|
500
502
|
lastReportedAt: status.lastReportedAt ?? undefined,
|
|
501
503
|
lastAppealedAt: status.lastAppealedAt ?? undefined,
|
|
502
504
|
muteUntil: status.muteUntil ?? undefined,
|
|
505
|
+
muteReportingUntil: status.muteReportingUntil ?? undefined,
|
|
503
506
|
suspendUntil: status.suspendUntil ?? undefined,
|
|
504
507
|
takendown: status.takendown ?? undefined,
|
|
505
508
|
appealed: status.appealed ?? undefined,
|
|
@@ -7,6 +7,7 @@ Object {
|
|
|
7
7
|
"event": Object {
|
|
8
8
|
"$type": "tools.ozone.moderation.defs#modEventReport",
|
|
9
9
|
"comment": "X",
|
|
10
|
+
"isReporterMuted": false,
|
|
10
11
|
"reportType": "com.atproto.moderation.defs#reasonMisleading",
|
|
11
12
|
},
|
|
12
13
|
"id": 1,
|
|
@@ -77,6 +78,7 @@ Array [
|
|
|
77
78
|
"event": Object {
|
|
78
79
|
"$type": "tools.ozone.moderation.defs#modEventReport",
|
|
79
80
|
"comment": "X",
|
|
81
|
+
"isReporterMuted": false,
|
|
80
82
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
81
83
|
},
|
|
82
84
|
"id": 11,
|
|
@@ -90,6 +92,7 @@ Array [
|
|
|
90
92
|
Object {
|
|
91
93
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
92
94
|
"createdBy": "user(2)",
|
|
95
|
+
"creatorHandle": "mod-authority.test",
|
|
93
96
|
"event": Object {
|
|
94
97
|
"$type": "tools.ozone.moderation.defs#modEventTag",
|
|
95
98
|
"add": Array [
|
|
@@ -113,6 +116,7 @@ Array [
|
|
|
113
116
|
"event": Object {
|
|
114
117
|
"$type": "tools.ozone.moderation.defs#modEventReport",
|
|
115
118
|
"comment": "X",
|
|
119
|
+
"isReporterMuted": false,
|
|
116
120
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
117
121
|
},
|
|
118
122
|
"id": 5,
|
|
@@ -135,6 +139,7 @@ Array [
|
|
|
135
139
|
"event": Object {
|
|
136
140
|
"$type": "tools.ozone.moderation.defs#modEventReport",
|
|
137
141
|
"comment": "X",
|
|
142
|
+
"isReporterMuted": false,
|
|
138
143
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
139
144
|
},
|
|
140
145
|
"id": 10,
|
|
@@ -149,6 +154,7 @@ Array [
|
|
|
149
154
|
Object {
|
|
150
155
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
151
156
|
"createdBy": "user(1)",
|
|
157
|
+
"creatorHandle": "mod-authority.test",
|
|
152
158
|
"event": Object {
|
|
153
159
|
"$type": "tools.ozone.moderation.defs#modEventTag",
|
|
154
160
|
"add": Array [
|
|
@@ -172,6 +178,7 @@ Array [
|
|
|
172
178
|
"event": Object {
|
|
173
179
|
"$type": "tools.ozone.moderation.defs#modEventReport",
|
|
174
180
|
"comment": "X",
|
|
181
|
+
"isReporterMuted": false,
|
|
175
182
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
176
183
|
},
|
|
177
184
|
"id": 3,
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TestNetwork,
|
|
3
|
+
SeedClient,
|
|
4
|
+
basicSeed,
|
|
5
|
+
ModeratorClient,
|
|
6
|
+
} from '@atproto/dev-env'
|
|
7
|
+
import {
|
|
8
|
+
ComAtprotoModerationDefs,
|
|
9
|
+
ToolsOzoneModerationDefs,
|
|
10
|
+
} from '@atproto/api'
|
|
11
|
+
import {
|
|
12
|
+
REVIEWNONE,
|
|
13
|
+
REVIEWOPEN,
|
|
14
|
+
} from '../src/lexicon/types/tools/ozone/moderation/defs'
|
|
15
|
+
|
|
16
|
+
describe('report-muting', () => {
|
|
17
|
+
let network: TestNetwork
|
|
18
|
+
let sc: SeedClient
|
|
19
|
+
let modClient: ModeratorClient
|
|
20
|
+
|
|
21
|
+
beforeAll(async () => {
|
|
22
|
+
network = await TestNetwork.create({
|
|
23
|
+
dbPostgresSchema: 'ozone_report_muting',
|
|
24
|
+
})
|
|
25
|
+
sc = network.getSeedClient()
|
|
26
|
+
modClient = network.ozone.getModClient()
|
|
27
|
+
await basicSeed(sc)
|
|
28
|
+
await network.processAll()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
afterAll(async () => {
|
|
32
|
+
await network.close()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const assertSubjectStatus = async (
|
|
36
|
+
subject: string,
|
|
37
|
+
status?: string,
|
|
38
|
+
): Promise<ToolsOzoneModerationDefs.SubjectStatusView | undefined> => {
|
|
39
|
+
const res = await modClient.queryStatuses({
|
|
40
|
+
subject,
|
|
41
|
+
})
|
|
42
|
+
expect(res.subjectStatuses[0]?.reviewState).toEqual(status)
|
|
43
|
+
return res.subjectStatuses[0]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
it('does not change reviewState when muted reporter reports', async () => {
|
|
47
|
+
const bobsPostSubject = {
|
|
48
|
+
$type: 'com.atproto.repo.strongRef',
|
|
49
|
+
uri: sc.posts[sc.dids.bob][1].ref.uriStr,
|
|
50
|
+
cid: sc.posts[sc.dids.bob][1].ref.cidStr,
|
|
51
|
+
}
|
|
52
|
+
const carolsAccountSubject = {
|
|
53
|
+
$type: 'com.atproto.admin.defs#repoRef',
|
|
54
|
+
did: sc.dids.carol,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await modClient.emitEvent({
|
|
58
|
+
event: {
|
|
59
|
+
$type: 'tools.ozone.moderation.defs#modEventMuteReporter',
|
|
60
|
+
durationInHours: 24,
|
|
61
|
+
},
|
|
62
|
+
subject: carolsAccountSubject,
|
|
63
|
+
})
|
|
64
|
+
await sc.createReport({
|
|
65
|
+
reportedBy: sc.dids.carol,
|
|
66
|
+
reasonType: ComAtprotoModerationDefs.REASONMISLEADING,
|
|
67
|
+
reason: 'misleading',
|
|
68
|
+
subject: bobsPostSubject,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
// Verify that a subject status was not created for bob's post since the reporter was muted
|
|
72
|
+
await assertSubjectStatus(bobsPostSubject.uri, undefined)
|
|
73
|
+
// Verify, however, that the event was logged
|
|
74
|
+
await modClient.queryEvents({
|
|
75
|
+
subject: bobsPostSubject.uri,
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// Verify that reporting mute duration is stored for the reporter
|
|
79
|
+
const carolsStatus = await assertSubjectStatus(sc.dids.carol, REVIEWNONE)
|
|
80
|
+
expect(
|
|
81
|
+
new Date(`${carolsStatus?.muteReportingUntil}`).getTime(),
|
|
82
|
+
).toBeGreaterThan(Date.now())
|
|
83
|
+
|
|
84
|
+
await modClient.emitEvent({
|
|
85
|
+
event: {
|
|
86
|
+
$type: 'tools.ozone.moderation.defs#modEventUnmuteReporter',
|
|
87
|
+
},
|
|
88
|
+
subject: carolsAccountSubject,
|
|
89
|
+
})
|
|
90
|
+
await sc.createReport({
|
|
91
|
+
reportedBy: sc.dids.carol,
|
|
92
|
+
reasonType: ComAtprotoModerationDefs.REASONMISLEADING,
|
|
93
|
+
reason: 'misleading',
|
|
94
|
+
subject: bobsPostSubject,
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// Verify that a subject status was created for bob's post since the reporter was no longer muted
|
|
98
|
+
await assertSubjectStatus(bobsPostSubject.uri, REVIEWOPEN)
|
|
99
|
+
})
|
|
100
|
+
})
|