@atproto/ozone 0.0.16 → 0.0.17-next.0
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/dist/api/moderation/util.d.ts +1 -1
- package/dist/auth-verifier.d.ts +7 -11
- package/dist/config/config.d.ts +1 -0
- package/dist/config/env.d.ts +1 -2
- package/dist/config/secrets.d.ts +0 -2
- package/dist/daemon/event-pusher.d.ts +2 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/schema/moderation_subject_status.d.ts +2 -2
- package/dist/index.js +821 -1055
- package/dist/index.js.map +3 -3
- package/dist/lexicon/index.d.ts +8 -0
- package/dist/lexicon/lexicons.d.ts +298 -0
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts +23 -1
- package/dist/lexicon/types/app/bsky/embed/record.d.ts +2 -1
- package/dist/lexicon/types/app/bsky/labeler/defs.d.ts +41 -0
- package/dist/lexicon/types/app/bsky/labeler/getServices.d.ts +36 -0
- package/dist/lexicon/types/app/bsky/labeler/service.d.ts +14 -0
- package/dist/lexicon/types/com/atproto/admin/defs.d.ts +2 -1
- package/dist/lexicon/types/com/atproto/label/defs.d.ts +18 -0
- package/dist/mod-service/index.d.ts +2 -2
- package/package.json +5 -4
- package/src/api/admin/createCommunicationTemplate.ts +1 -1
- package/src/api/admin/deleteCommunicationTemplate.ts +1 -1
- package/src/api/admin/emitModerationEvent.ts +6 -2
- package/src/api/admin/getModerationEvent.ts +1 -1
- package/src/api/admin/getRecord.ts +1 -1
- package/src/api/admin/getRepo.ts +1 -1
- package/src/api/admin/listCommunicationTemplates.ts +1 -1
- package/src/api/admin/queryModerationEvents.ts +1 -1
- package/src/api/admin/queryModerationStatuses.ts +1 -1
- package/src/api/admin/searchRepos.ts +1 -1
- package/src/api/admin/updateCommunicationTemplate.ts +1 -1
- package/src/api/admin/util.ts +1 -1
- package/src/api/moderation/createReport.ts +1 -2
- package/src/api/proxied.ts +8 -8
- package/src/api/temp/fetchLabels.ts +1 -1
- package/src/auth-verifier.ts +19 -29
- package/src/config/config.ts +10 -7
- package/src/config/env.ts +2 -4
- package/src/config/secrets.ts +0 -6
- package/src/context.ts +1 -3
- package/src/daemon/context.ts +2 -2
- package/src/daemon/event-pusher.ts +9 -1
- package/src/db/schema/moderation_subject_status.ts +6 -1
- package/src/lexicon/index.ts +23 -0
- package/src/lexicon/lexicons.ts +327 -1
- package/src/lexicon/types/app/bsky/actor/defs.ts +57 -1
- package/src/lexicon/types/app/bsky/embed/record.ts +2 -0
- package/src/lexicon/types/app/bsky/labeler/defs.ts +93 -0
- package/src/lexicon/types/app/bsky/labeler/getServices.ts +51 -0
- package/src/lexicon/types/app/bsky/labeler/service.ts +31 -0
- package/src/lexicon/types/com/atproto/admin/defs.ts +3 -0
- package/src/lexicon/types/com/atproto/label/defs.ts +68 -0
- package/src/mod-service/index.ts +4 -3
- package/src/mod-service/status.ts +42 -26
- package/tests/__snapshots__/get-record.test.ts.snap +4 -4
- package/tests/__snapshots__/get-repo.test.ts.snap +2 -2
- package/tests/communication-templates.test.ts +7 -7
- package/tests/get-record.test.ts +17 -7
- package/tests/get-repo.test.ts +24 -12
- package/tests/moderation-appeals.test.ts +24 -52
- package/tests/moderation-events.test.ts +87 -130
- package/tests/moderation-status-tags.test.ts +16 -31
- package/tests/moderation-statuses.test.ts +125 -58
- package/tests/moderation.test.ts +140 -287
- package/tests/repo-search.test.ts +11 -4
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from '@atproto/
|
|
1
|
+
import {
|
|
2
|
+
TestNetwork,
|
|
3
|
+
SeedClient,
|
|
4
|
+
basicSeed,
|
|
5
|
+
ModeratorClient,
|
|
6
|
+
} from '@atproto/dev-env'
|
|
7
|
+
import { ComAtprotoAdminDefs } from '@atproto/api'
|
|
7
8
|
import {
|
|
8
9
|
REASONMISLEADING,
|
|
9
10
|
REASONSPAM,
|
|
@@ -17,33 +18,15 @@ import { REVIEWESCALATED } from '../src/lexicon/types/com/atproto/admin/defs'
|
|
|
17
18
|
|
|
18
19
|
describe('moderation-appeals', () => {
|
|
19
20
|
let network: TestNetwork
|
|
20
|
-
let agent: AtpAgent
|
|
21
|
-
let pdsAgent: AtpAgent
|
|
22
21
|
let sc: SeedClient
|
|
23
|
-
|
|
24
|
-
const emitModerationEvent = async (
|
|
25
|
-
eventData: ComAtprotoAdminEmitModerationEvent.InputSchema,
|
|
26
|
-
) => {
|
|
27
|
-
return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, {
|
|
28
|
-
encoding: 'application/json',
|
|
29
|
-
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const queryModerationStatuses = (
|
|
34
|
-
statusQuery: ComAtprotoAdminQueryModerationStatuses.QueryParams,
|
|
35
|
-
) =>
|
|
36
|
-
agent.api.com.atproto.admin.queryModerationStatuses(statusQuery, {
|
|
37
|
-
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
38
|
-
})
|
|
22
|
+
let modClient: ModeratorClient
|
|
39
23
|
|
|
40
24
|
beforeAll(async () => {
|
|
41
25
|
network = await TestNetwork.create({
|
|
42
26
|
dbPostgresSchema: 'ozone_moderation_appeals',
|
|
43
27
|
})
|
|
44
|
-
agent = network.ozone.getClient()
|
|
45
|
-
pdsAgent = network.pds.getClient()
|
|
46
28
|
sc = network.getSeedClient()
|
|
29
|
+
modClient = network.ozone.getModClient()
|
|
47
30
|
await basicSeed(sc)
|
|
48
31
|
await network.processAll()
|
|
49
32
|
})
|
|
@@ -57,12 +40,12 @@ describe('moderation-appeals', () => {
|
|
|
57
40
|
status: string,
|
|
58
41
|
appealed: boolean | undefined,
|
|
59
42
|
): Promise<ComAtprotoAdminDefs.SubjectStatusView | undefined> => {
|
|
60
|
-
const
|
|
43
|
+
const res = await modClient.queryModerationStatuses({
|
|
61
44
|
subject,
|
|
62
45
|
})
|
|
63
|
-
expect(
|
|
64
|
-
expect(
|
|
65
|
-
return
|
|
46
|
+
expect(res.subjectStatuses[0]?.reviewState).toEqual(status)
|
|
47
|
+
expect(res.subjectStatuses[0]?.appealed).toEqual(appealed)
|
|
48
|
+
return res.subjectStatuses[0]
|
|
66
49
|
}
|
|
67
50
|
|
|
68
51
|
describe('appeals from users', () => {
|
|
@@ -83,13 +66,12 @@ describe('moderation-appeals', () => {
|
|
|
83
66
|
|
|
84
67
|
it('only changes subject status if original author of the content or a moderator is appealing', async () => {
|
|
85
68
|
// Create a report by alice
|
|
86
|
-
await emitModerationEvent({
|
|
69
|
+
await modClient.emitModerationEvent({
|
|
87
70
|
event: {
|
|
88
71
|
$type: 'com.atproto.admin.defs#modEventReport',
|
|
89
72
|
reportType: REASONMISLEADING,
|
|
90
73
|
},
|
|
91
74
|
subject: getBobsPostSubject(),
|
|
92
|
-
createdBy: sc.dids.alice,
|
|
93
75
|
})
|
|
94
76
|
|
|
95
77
|
await assertBobsPostStatus(REVIEWOPEN, undefined)
|
|
@@ -108,13 +90,12 @@ describe('moderation-appeals', () => {
|
|
|
108
90
|
await assertBobsPostStatus(REVIEWOPEN, undefined)
|
|
109
91
|
|
|
110
92
|
// Emit report event as moderator
|
|
111
|
-
await emitModerationEvent({
|
|
93
|
+
await modClient.emitModerationEvent({
|
|
112
94
|
event: {
|
|
113
95
|
$type: 'com.atproto.admin.defs#modEventReport',
|
|
114
96
|
reportType: REASONAPPEAL,
|
|
115
97
|
},
|
|
116
98
|
subject: getBobsPostSubject(),
|
|
117
|
-
createdBy: sc.dids.alice,
|
|
118
99
|
})
|
|
119
100
|
|
|
120
101
|
// Verify that appeal status changed when appeal report was emitted by moderator
|
|
@@ -151,23 +132,21 @@ describe('moderation-appeals', () => {
|
|
|
151
132
|
})
|
|
152
133
|
it('allows multiple appeals and updates last appealed timestamp', async () => {
|
|
153
134
|
// Resolve appeal with acknowledge
|
|
154
|
-
await emitModerationEvent({
|
|
135
|
+
await modClient.emitModerationEvent({
|
|
155
136
|
event: {
|
|
156
137
|
$type: 'com.atproto.admin.defs#modEventResolveAppeal',
|
|
157
138
|
},
|
|
158
139
|
subject: getBobsPostSubject(),
|
|
159
|
-
createdBy: sc.dids.carol,
|
|
160
140
|
})
|
|
161
141
|
|
|
162
142
|
const previousStatus = await assertBobsPostStatus(REVIEWESCALATED, false)
|
|
163
143
|
|
|
164
|
-
await emitModerationEvent({
|
|
144
|
+
await modClient.emitModerationEvent({
|
|
165
145
|
event: {
|
|
166
146
|
$type: 'com.atproto.admin.defs#modEventReport',
|
|
167
147
|
reportType: REASONAPPEAL,
|
|
168
148
|
},
|
|
169
149
|
subject: getBobsPostSubject(),
|
|
170
|
-
createdBy: sc.dids.bob,
|
|
171
150
|
})
|
|
172
151
|
|
|
173
152
|
// Verify that even after the appeal event by bob for his post, the appeal status is true again with new timestamp
|
|
@@ -186,32 +165,29 @@ describe('moderation-appeals', () => {
|
|
|
186
165
|
})
|
|
187
166
|
it('appeal status is maintained while review state changes based on incoming events', async () => {
|
|
188
167
|
// Bob reports alice's post
|
|
189
|
-
await emitModerationEvent({
|
|
168
|
+
await modClient.emitModerationEvent({
|
|
190
169
|
event: {
|
|
191
170
|
$type: 'com.atproto.admin.defs#modEventReport',
|
|
192
171
|
reportType: REASONMISLEADING,
|
|
193
172
|
},
|
|
194
173
|
subject: getAlicesPostSubject(),
|
|
195
|
-
createdBy: sc.dids.bob,
|
|
196
174
|
})
|
|
197
175
|
|
|
198
176
|
// Moderator acknowledges the report, assume a label was applied too
|
|
199
|
-
await emitModerationEvent({
|
|
177
|
+
await modClient.emitModerationEvent({
|
|
200
178
|
event: {
|
|
201
179
|
$type: 'com.atproto.admin.defs#modEventAcknowledge',
|
|
202
180
|
},
|
|
203
181
|
subject: getAlicesPostSubject(),
|
|
204
|
-
createdBy: sc.dids.carol,
|
|
205
182
|
})
|
|
206
183
|
|
|
207
184
|
// Alice appeals the report
|
|
208
|
-
await emitModerationEvent({
|
|
185
|
+
await modClient.emitModerationEvent({
|
|
209
186
|
event: {
|
|
210
187
|
$type: 'com.atproto.admin.defs#modEventReport',
|
|
211
188
|
reportType: REASONAPPEAL,
|
|
212
189
|
},
|
|
213
190
|
subject: getAlicesPostSubject(),
|
|
214
|
-
createdBy: sc.dids.alice,
|
|
215
191
|
})
|
|
216
192
|
|
|
217
193
|
await assertSubjectStatus(
|
|
@@ -221,13 +197,12 @@ describe('moderation-appeals', () => {
|
|
|
221
197
|
)
|
|
222
198
|
|
|
223
199
|
// Bob reports it again
|
|
224
|
-
await emitModerationEvent({
|
|
200
|
+
await modClient.emitModerationEvent({
|
|
225
201
|
event: {
|
|
226
202
|
$type: 'com.atproto.admin.defs#modEventReport',
|
|
227
203
|
reportType: REASONSPAM,
|
|
228
204
|
},
|
|
229
205
|
subject: getAlicesPostSubject(),
|
|
230
|
-
createdBy: sc.dids.bob,
|
|
231
206
|
})
|
|
232
207
|
|
|
233
208
|
// Assert that the status is still REVIEWESCALATED, as report events are meant to do
|
|
@@ -238,12 +213,11 @@ describe('moderation-appeals', () => {
|
|
|
238
213
|
)
|
|
239
214
|
|
|
240
215
|
// Emit an escalation event
|
|
241
|
-
await emitModerationEvent({
|
|
216
|
+
await modClient.emitModerationEvent({
|
|
242
217
|
event: {
|
|
243
218
|
$type: 'com.atproto.admin.defs#modEventEscalate',
|
|
244
219
|
},
|
|
245
220
|
subject: getAlicesPostSubject(),
|
|
246
|
-
createdBy: sc.dids.carol,
|
|
247
221
|
})
|
|
248
222
|
|
|
249
223
|
await assertSubjectStatus(
|
|
@@ -253,25 +227,23 @@ describe('moderation-appeals', () => {
|
|
|
253
227
|
)
|
|
254
228
|
|
|
255
229
|
// Emit an acknowledge event
|
|
256
|
-
await emitModerationEvent({
|
|
230
|
+
await modClient.emitModerationEvent({
|
|
257
231
|
event: {
|
|
258
232
|
$type: 'com.atproto.admin.defs#modEventAcknowledge',
|
|
259
233
|
},
|
|
260
234
|
subject: getAlicesPostSubject(),
|
|
261
|
-
createdBy: sc.dids.carol,
|
|
262
235
|
})
|
|
263
236
|
|
|
264
237
|
// Assert that status moved on to reviewClosed while appealed status is still true
|
|
265
238
|
await assertSubjectStatus(getAlicesPostSubject().uri, REVIEWCLOSED, true)
|
|
266
239
|
|
|
267
240
|
// Emit a resolveAppeal event
|
|
268
|
-
await emitModerationEvent({
|
|
241
|
+
await modClient.emitModerationEvent({
|
|
269
242
|
event: {
|
|
270
243
|
$type: 'com.atproto.admin.defs#modEventResolveAppeal',
|
|
271
244
|
comment: 'lgtm',
|
|
272
245
|
},
|
|
273
246
|
subject: getAlicesPostSubject(),
|
|
274
|
-
createdBy: sc.dids.carol,
|
|
275
247
|
})
|
|
276
248
|
|
|
277
249
|
// Assert that status stayed the same while appealed status is still true
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
2
|
import EventEmitter, { once } from 'node:events'
|
|
3
|
+
import {
|
|
4
|
+
TestNetwork,
|
|
5
|
+
SeedClient,
|
|
6
|
+
basicSeed,
|
|
7
|
+
ModeratorClient,
|
|
8
|
+
} from '@atproto/dev-env'
|
|
9
|
+
import { ComAtprotoAdminDefs } from '@atproto/api'
|
|
3
10
|
import Mail from 'nodemailer/lib/mailer'
|
|
4
|
-
import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env'
|
|
5
|
-
import AtpAgent, {
|
|
6
|
-
ComAtprotoAdminDefs,
|
|
7
|
-
ComAtprotoAdminEmitModerationEvent,
|
|
8
|
-
} from '@atproto/api'
|
|
9
11
|
import { forSnapshot } from './_util'
|
|
10
12
|
import {
|
|
11
13
|
REASONAPPEAL,
|
|
@@ -15,23 +17,8 @@ import {
|
|
|
15
17
|
|
|
16
18
|
describe('moderation-events', () => {
|
|
17
19
|
let network: TestNetwork
|
|
18
|
-
let agent: AtpAgent
|
|
19
|
-
let pdsAgent: AtpAgent
|
|
20
20
|
let sc: SeedClient
|
|
21
|
-
|
|
22
|
-
const emitModerationEvent = async (
|
|
23
|
-
eventData: ComAtprotoAdminEmitModerationEvent.InputSchema,
|
|
24
|
-
) => {
|
|
25
|
-
return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, {
|
|
26
|
-
encoding: 'application/json',
|
|
27
|
-
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const queryModerationEvents = (eventQuery) =>
|
|
32
|
-
agent.api.com.atproto.admin.queryModerationEvents(eventQuery, {
|
|
33
|
-
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
34
|
-
})
|
|
21
|
+
let modClient: ModeratorClient
|
|
35
22
|
|
|
36
23
|
const seedEvents = async () => {
|
|
37
24
|
const bobsAccount = {
|
|
@@ -54,25 +41,19 @@ describe('moderation-events', () => {
|
|
|
54
41
|
}
|
|
55
42
|
|
|
56
43
|
for (let i = 0; i < 4; i++) {
|
|
57
|
-
await
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
reportType: i % 2 ? REASONSPAM : REASONMISLEADING,
|
|
61
|
-
comment: 'X',
|
|
62
|
-
},
|
|
44
|
+
await sc.createReport({
|
|
45
|
+
reasonType: i % 2 ? REASONSPAM : REASONMISLEADING,
|
|
46
|
+
reason: 'X',
|
|
63
47
|
// Report bob's account by alice and vice versa
|
|
64
48
|
subject: i % 2 ? bobsAccount : alicesAccount,
|
|
65
|
-
|
|
49
|
+
reportedBy: i % 2 ? sc.dids.alice : sc.dids.bob,
|
|
66
50
|
})
|
|
67
|
-
await
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
reportType: REASONSPAM,
|
|
71
|
-
comment: 'X',
|
|
72
|
-
},
|
|
51
|
+
await sc.createReport({
|
|
52
|
+
reasonType: REASONSPAM,
|
|
53
|
+
reason: 'X',
|
|
73
54
|
// Report bob's post by alice and vice versa
|
|
74
55
|
subject: i % 2 ? bobsPost : alicesPost,
|
|
75
|
-
|
|
56
|
+
reportedBy: i % 2 ? sc.dids.alice : sc.dids.bob,
|
|
76
57
|
})
|
|
77
58
|
}
|
|
78
59
|
}
|
|
@@ -81,9 +62,8 @@ describe('moderation-events', () => {
|
|
|
81
62
|
network = await TestNetwork.create({
|
|
82
63
|
dbPostgresSchema: 'ozone_moderation_events',
|
|
83
64
|
})
|
|
84
|
-
agent = network.ozone.getClient()
|
|
85
|
-
pdsAgent = network.pds.getClient()
|
|
86
65
|
sc = network.getSeedClient()
|
|
66
|
+
modClient = network.ozone.getModClient()
|
|
87
67
|
await basicSeed(sc)
|
|
88
68
|
await network.processAll()
|
|
89
69
|
await seedEvents()
|
|
@@ -96,16 +76,16 @@ describe('moderation-events', () => {
|
|
|
96
76
|
describe('query events', () => {
|
|
97
77
|
it('returns all events for record or repo', async () => {
|
|
98
78
|
const [bobsEvents, alicesPostEvents] = await Promise.all([
|
|
99
|
-
queryModerationEvents({
|
|
79
|
+
modClient.queryModerationEvents({
|
|
100
80
|
subject: sc.dids.bob,
|
|
101
81
|
}),
|
|
102
|
-
queryModerationEvents({
|
|
82
|
+
modClient.queryModerationEvents({
|
|
103
83
|
subject: sc.posts[sc.dids.alice][0].ref.uriStr,
|
|
104
84
|
}),
|
|
105
85
|
])
|
|
106
86
|
|
|
107
|
-
expect(forSnapshot(bobsEvents.
|
|
108
|
-
expect(forSnapshot(alicesPostEvents.
|
|
87
|
+
expect(forSnapshot(bobsEvents.events)).toMatchSnapshot()
|
|
88
|
+
expect(forSnapshot(alicesPostEvents.events)).toMatchSnapshot()
|
|
109
89
|
})
|
|
110
90
|
|
|
111
91
|
it('filters events by types', async () => {
|
|
@@ -114,66 +94,64 @@ describe('moderation-events', () => {
|
|
|
114
94
|
did: sc.dids.alice,
|
|
115
95
|
}
|
|
116
96
|
await Promise.all([
|
|
117
|
-
emitModerationEvent({
|
|
97
|
+
modClient.emitModerationEvent({
|
|
118
98
|
event: {
|
|
119
99
|
$type: 'com.atproto.admin.defs#modEventComment',
|
|
120
100
|
comment: 'X',
|
|
121
101
|
},
|
|
122
102
|
subject: alicesAccount,
|
|
123
|
-
createdBy: 'did:plc:moderator',
|
|
124
103
|
}),
|
|
125
|
-
emitModerationEvent({
|
|
104
|
+
modClient.emitModerationEvent({
|
|
126
105
|
event: {
|
|
127
106
|
$type: 'com.atproto.admin.defs#modEventEscalate',
|
|
128
107
|
comment: 'X',
|
|
129
108
|
},
|
|
130
109
|
subject: alicesAccount,
|
|
131
|
-
createdBy: 'did:plc:moderator',
|
|
132
110
|
}),
|
|
133
111
|
])
|
|
134
112
|
const [allEvents, reportEvents] = await Promise.all([
|
|
135
|
-
queryModerationEvents({
|
|
113
|
+
modClient.queryModerationEvents({
|
|
136
114
|
subject: sc.dids.alice,
|
|
137
115
|
}),
|
|
138
|
-
queryModerationEvents({
|
|
116
|
+
modClient.queryModerationEvents({
|
|
139
117
|
subject: sc.dids.alice,
|
|
140
118
|
types: ['com.atproto.admin.defs#modEventReport'],
|
|
141
119
|
}),
|
|
142
120
|
])
|
|
143
121
|
|
|
144
|
-
expect(allEvents.
|
|
145
|
-
reportEvents.
|
|
122
|
+
expect(allEvents.events.length).toBeGreaterThan(
|
|
123
|
+
reportEvents.events.length,
|
|
146
124
|
)
|
|
147
125
|
expect(
|
|
148
|
-
[...new Set(reportEvents.
|
|
126
|
+
[...new Set(reportEvents.events.map((e) => e.event.$type))].length,
|
|
149
127
|
).toEqual(1)
|
|
150
128
|
|
|
151
129
|
expect(
|
|
152
|
-
[...new Set(allEvents.
|
|
130
|
+
[...new Set(allEvents.events.map((e) => e.event.$type))].length,
|
|
153
131
|
).toEqual(4)
|
|
154
132
|
})
|
|
155
133
|
|
|
156
134
|
it('returns events for all content by user', async () => {
|
|
157
135
|
const [forAccount, forPost] = await Promise.all([
|
|
158
|
-
queryModerationEvents({
|
|
136
|
+
modClient.queryModerationEvents({
|
|
159
137
|
subject: sc.dids.bob,
|
|
160
138
|
includeAllUserRecords: true,
|
|
161
139
|
}),
|
|
162
|
-
queryModerationEvents({
|
|
140
|
+
modClient.queryModerationEvents({
|
|
163
141
|
subject: sc.posts[sc.dids.bob][0].ref.uriStr,
|
|
164
142
|
includeAllUserRecords: true,
|
|
165
143
|
}),
|
|
166
144
|
])
|
|
167
145
|
|
|
168
|
-
expect(forAccount.
|
|
146
|
+
expect(forAccount.events.length).toEqual(forPost.events.length)
|
|
169
147
|
// Save events are returned from both requests
|
|
170
|
-
expect(forPost.
|
|
171
|
-
forAccount.
|
|
148
|
+
expect(forPost.events.map(({ id }) => id).sort()).toEqual(
|
|
149
|
+
forAccount.events.map(({ id }) => id).sort(),
|
|
172
150
|
)
|
|
173
151
|
})
|
|
174
152
|
|
|
175
153
|
it('returns paginated list of events with cursor', async () => {
|
|
176
|
-
const allEvents = await queryModerationEvents({
|
|
154
|
+
const allEvents = await modClient.queryModerationEvents({
|
|
177
155
|
subject: sc.dids.bob,
|
|
178
156
|
includeAllUserRecords: true,
|
|
179
157
|
})
|
|
@@ -186,15 +164,15 @@ describe('moderation-events', () => {
|
|
|
186
164
|
let count = 0
|
|
187
165
|
do {
|
|
188
166
|
// get 1 event at a time and check we get all events
|
|
189
|
-
const
|
|
167
|
+
const res = await modClient.queryModerationEvents({
|
|
190
168
|
limit: 1,
|
|
191
169
|
subject: sc.dids.bob,
|
|
192
170
|
includeAllUserRecords: true,
|
|
193
171
|
cursor: defaultCursor,
|
|
194
172
|
sortDirection,
|
|
195
173
|
})
|
|
196
|
-
events.push(...
|
|
197
|
-
defaultCursor =
|
|
174
|
+
events.push(...res.events)
|
|
175
|
+
defaultCursor = res.cursor
|
|
198
176
|
count++
|
|
199
177
|
// The count is a circuit breaker to prevent infinite loop in case of failing test
|
|
200
178
|
} while (defaultCursor && count < 10)
|
|
@@ -205,49 +183,51 @@ describe('moderation-events', () => {
|
|
|
205
183
|
const defaultEvents = await getPaginatedEvents()
|
|
206
184
|
const reversedEvents = await getPaginatedEvents('asc')
|
|
207
185
|
|
|
208
|
-
expect(allEvents.
|
|
209
|
-
expect(defaultEvents.length).toEqual(allEvents.
|
|
210
|
-
expect(reversedEvents.length).toEqual(allEvents.
|
|
186
|
+
expect(allEvents.events.length).toEqual(6)
|
|
187
|
+
expect(defaultEvents.length).toEqual(allEvents.events.length)
|
|
188
|
+
expect(reversedEvents.length).toEqual(allEvents.events.length)
|
|
211
189
|
// First event in the reversed list is the last item in the default list
|
|
212
|
-
expect(reversedEvents[0].id).toEqual(
|
|
190
|
+
expect(reversedEvents[0].id).toEqual(
|
|
191
|
+
defaultEvents[defaultEvents.length - 1].id,
|
|
192
|
+
)
|
|
213
193
|
})
|
|
214
194
|
|
|
215
195
|
it('returns report events matching reportType filters', async () => {
|
|
216
196
|
const [spamEvents, misleadingEvents] = await Promise.all([
|
|
217
|
-
queryModerationEvents({
|
|
197
|
+
modClient.queryModerationEvents({
|
|
218
198
|
reportTypes: [REASONSPAM],
|
|
219
199
|
}),
|
|
220
|
-
queryModerationEvents({
|
|
200
|
+
modClient.queryModerationEvents({
|
|
221
201
|
reportTypes: [REASONMISLEADING, REASONAPPEAL],
|
|
222
202
|
}),
|
|
223
203
|
])
|
|
224
204
|
|
|
225
|
-
expect(misleadingEvents.
|
|
226
|
-
expect(spamEvents.
|
|
205
|
+
expect(misleadingEvents.events.length).toEqual(2)
|
|
206
|
+
expect(spamEvents.events.length).toEqual(6)
|
|
227
207
|
})
|
|
228
208
|
|
|
229
209
|
it('returns events matching keyword in comment', async () => {
|
|
230
210
|
const [eventsWithX, eventsWithTest, eventsWithComment] =
|
|
231
211
|
await Promise.all([
|
|
232
|
-
queryModerationEvents({
|
|
212
|
+
modClient.queryModerationEvents({
|
|
233
213
|
comment: 'X',
|
|
234
214
|
}),
|
|
235
|
-
queryModerationEvents({
|
|
215
|
+
modClient.queryModerationEvents({
|
|
236
216
|
comment: 'test',
|
|
237
217
|
}),
|
|
238
|
-
queryModerationEvents({
|
|
218
|
+
modClient.queryModerationEvents({
|
|
239
219
|
hasComment: true,
|
|
240
220
|
}),
|
|
241
221
|
])
|
|
242
222
|
|
|
243
|
-
expect(eventsWithX.
|
|
244
|
-
expect(eventsWithTest.
|
|
245
|
-
expect(eventsWithComment.
|
|
223
|
+
expect(eventsWithX.events.length).toEqual(10)
|
|
224
|
+
expect(eventsWithTest.events.length).toEqual(0)
|
|
225
|
+
expect(eventsWithComment.events.length).toEqual(10)
|
|
246
226
|
})
|
|
247
227
|
|
|
248
228
|
it('returns events matching filter params for labels', async () => {
|
|
249
229
|
const [negatedLabelEvent, createdLabelEvent] = await Promise.all([
|
|
250
|
-
emitModerationEvent({
|
|
230
|
+
modClient.emitModerationEvent({
|
|
251
231
|
event: {
|
|
252
232
|
$type: 'com.atproto.admin.defs#modEventLabel',
|
|
253
233
|
comment: 'X',
|
|
@@ -259,9 +239,8 @@ describe('moderation-events', () => {
|
|
|
259
239
|
$type: 'com.atproto.admin.defs#repoRef',
|
|
260
240
|
did: sc.dids.alice,
|
|
261
241
|
},
|
|
262
|
-
createdBy: sc.dids.bob,
|
|
263
242
|
}),
|
|
264
|
-
emitModerationEvent({
|
|
243
|
+
modClient.emitModerationEvent({
|
|
265
244
|
event: {
|
|
266
245
|
$type: 'com.atproto.admin.defs#modEventLabel',
|
|
267
246
|
comment: 'X',
|
|
@@ -273,36 +252,31 @@ describe('moderation-events', () => {
|
|
|
273
252
|
$type: 'com.atproto.admin.defs#repoRef',
|
|
274
253
|
did: sc.dids.bob,
|
|
275
254
|
},
|
|
276
|
-
createdBy: sc.dids.alice,
|
|
277
255
|
}),
|
|
278
256
|
])
|
|
279
257
|
const [withTwoLabels, withoutTwoLabels, withOneLabel, withoutOneLabel] =
|
|
280
258
|
await Promise.all([
|
|
281
|
-
queryModerationEvents({
|
|
259
|
+
modClient.queryModerationEvents({
|
|
282
260
|
addedLabels: ['L1', 'L3'],
|
|
283
261
|
}),
|
|
284
|
-
queryModerationEvents({
|
|
262
|
+
modClient.queryModerationEvents({
|
|
285
263
|
removedLabels: ['L1', 'L2'],
|
|
286
264
|
}),
|
|
287
|
-
queryModerationEvents({
|
|
265
|
+
modClient.queryModerationEvents({
|
|
288
266
|
addedLabels: ['L1'],
|
|
289
267
|
}),
|
|
290
|
-
queryModerationEvents({
|
|
268
|
+
modClient.queryModerationEvents({
|
|
291
269
|
removedLabels: ['L2'],
|
|
292
270
|
}),
|
|
293
271
|
])
|
|
294
272
|
|
|
295
273
|
// Verify that when querying for events where 2 different labels were added
|
|
296
274
|
// events where all of the labels from the list was added are returned
|
|
297
|
-
expect(withTwoLabels.
|
|
298
|
-
expect(negatedLabelEvent.
|
|
299
|
-
withoutTwoLabels.data.events[0].id,
|
|
300
|
-
)
|
|
275
|
+
expect(withTwoLabels.events.length).toEqual(0)
|
|
276
|
+
expect(negatedLabelEvent.id).toEqual(withoutTwoLabels.events[0].id)
|
|
301
277
|
|
|
302
|
-
expect(createdLabelEvent.
|
|
303
|
-
expect(negatedLabelEvent.
|
|
304
|
-
withoutOneLabel.data.events[0].id,
|
|
305
|
-
)
|
|
278
|
+
expect(createdLabelEvent.id).toEqual(withOneLabel.events[0].id)
|
|
279
|
+
expect(negatedLabelEvent.id).toEqual(withoutOneLabel.events[0].id)
|
|
306
280
|
})
|
|
307
281
|
it('returns events matching filter params for tags', async () => {
|
|
308
282
|
const tagEvent = async ({
|
|
@@ -312,7 +286,7 @@ describe('moderation-events', () => {
|
|
|
312
286
|
add: string[]
|
|
313
287
|
remove: string[]
|
|
314
288
|
}) =>
|
|
315
|
-
emitModerationEvent({
|
|
289
|
+
modClient.emitModerationEvent({
|
|
316
290
|
event: {
|
|
317
291
|
$type: 'com.atproto.admin.defs#modEventTag',
|
|
318
292
|
comment: 'X',
|
|
@@ -323,43 +297,35 @@ describe('moderation-events', () => {
|
|
|
323
297
|
$type: 'com.atproto.admin.defs#repoRef',
|
|
324
298
|
did: sc.dids.carol,
|
|
325
299
|
},
|
|
326
|
-
createdBy: sc.dids.bob,
|
|
327
300
|
})
|
|
328
301
|
const addEvent = await tagEvent({ add: ['L1', 'L2'], remove: [] })
|
|
329
302
|
const addAndRemoveEvent = await tagEvent({ add: ['L3'], remove: ['L2'] })
|
|
330
303
|
const [addFinder, addAndRemoveFinder, _removeFinder] = await Promise.all([
|
|
331
|
-
queryModerationEvents({
|
|
304
|
+
modClient.queryModerationEvents({
|
|
332
305
|
addedTags: ['L1'],
|
|
333
306
|
}),
|
|
334
|
-
queryModerationEvents({
|
|
307
|
+
modClient.queryModerationEvents({
|
|
335
308
|
addedTags: ['L3'],
|
|
336
309
|
removedTags: ['L2'],
|
|
337
310
|
}),
|
|
338
|
-
queryModerationEvents({
|
|
311
|
+
modClient.queryModerationEvents({
|
|
339
312
|
removedTags: ['L2'],
|
|
340
313
|
}),
|
|
341
314
|
])
|
|
342
315
|
|
|
343
|
-
expect(addFinder.
|
|
344
|
-
expect(addEvent.
|
|
316
|
+
expect(addFinder.events.length).toEqual(1)
|
|
317
|
+
expect(addEvent.id).toEqual(addFinder.events[0].id)
|
|
345
318
|
|
|
346
|
-
expect(addAndRemoveEvent.
|
|
347
|
-
|
|
348
|
-
)
|
|
349
|
-
expect(addAndRemoveEvent.
|
|
350
|
-
addAndRemoveFinder.data.events[0].id,
|
|
351
|
-
)
|
|
352
|
-
expect(addAndRemoveEvent.data.event.add).toEqual(['L3'])
|
|
353
|
-
expect(addAndRemoveEvent.data.event.remove).toEqual(['L2'])
|
|
319
|
+
expect(addAndRemoveEvent.id).toEqual(addAndRemoveFinder.events[0].id)
|
|
320
|
+
expect(addAndRemoveEvent.id).toEqual(addAndRemoveFinder.events[0].id)
|
|
321
|
+
expect(addAndRemoveEvent.event.add).toEqual(['L3'])
|
|
322
|
+
expect(addAndRemoveEvent.event.remove).toEqual(['L2'])
|
|
354
323
|
})
|
|
355
324
|
})
|
|
356
325
|
|
|
357
326
|
describe('get event', () => {
|
|
358
327
|
it('gets an event by specific id', async () => {
|
|
359
|
-
const
|
|
360
|
-
{ id: 1 },
|
|
361
|
-
{ headers: network.ozone.adminAuthHeaders('moderator') },
|
|
362
|
-
)
|
|
328
|
+
const data = await modClient.getEvent(1)
|
|
363
329
|
expect(forSnapshot(data)).toMatchSnapshot()
|
|
364
330
|
})
|
|
365
331
|
})
|
|
@@ -368,7 +334,7 @@ describe('moderation-events', () => {
|
|
|
368
334
|
it('are tracked on takedown event', async () => {
|
|
369
335
|
const post = sc.posts[sc.dids.carol][0]
|
|
370
336
|
assert(post.images.length > 1)
|
|
371
|
-
await emitModerationEvent({
|
|
337
|
+
await modClient.emitModerationEvent({
|
|
372
338
|
event: {
|
|
373
339
|
$type: 'com.atproto.admin.defs#modEventTakedown',
|
|
374
340
|
},
|
|
@@ -378,18 +344,13 @@ describe('moderation-events', () => {
|
|
|
378
344
|
cid: post.ref.cidStr,
|
|
379
345
|
},
|
|
380
346
|
subjectBlobCids: [post.images[0].image.ref.toString()],
|
|
381
|
-
createdBy: sc.dids.alice,
|
|
382
347
|
})
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
types: ['com.atproto.admin.defs#modEventTakedown'],
|
|
388
|
-
},
|
|
389
|
-
{ headers: network.ozone.adminAuthHeaders('moderator') },
|
|
390
|
-
)
|
|
348
|
+
const result = await modClient.queryModerationEvents({
|
|
349
|
+
subject: post.ref.uriStr,
|
|
350
|
+
types: ['com.atproto.admin.defs#modEventTakedown'],
|
|
351
|
+
})
|
|
391
352
|
expect(result.events[0]).toMatchObject({
|
|
392
|
-
createdBy:
|
|
353
|
+
createdBy: network.ozone.moderatorAccnt.did,
|
|
393
354
|
event: {
|
|
394
355
|
$type: 'com.atproto.admin.defs#modEventTakedown',
|
|
395
356
|
},
|
|
@@ -399,7 +360,7 @@ describe('moderation-events', () => {
|
|
|
399
360
|
|
|
400
361
|
it("are tracked on reverse-takedown event even if they aren't specified", async () => {
|
|
401
362
|
const post = sc.posts[sc.dids.carol][0]
|
|
402
|
-
await emitModerationEvent({
|
|
363
|
+
await modClient.emitModerationEvent({
|
|
403
364
|
event: {
|
|
404
365
|
$type: 'com.atproto.admin.defs#modEventReverseTakedown',
|
|
405
366
|
},
|
|
@@ -408,15 +369,12 @@ describe('moderation-events', () => {
|
|
|
408
369
|
uri: post.ref.uriStr,
|
|
409
370
|
cid: post.ref.cidStr,
|
|
410
371
|
},
|
|
411
|
-
createdBy: sc.dids.alice,
|
|
412
372
|
})
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
{ headers: network.ozone.adminAuthHeaders('moderator') },
|
|
417
|
-
)
|
|
373
|
+
const result = await modClient.queryModerationEvents({
|
|
374
|
+
subject: post.ref.uriStr,
|
|
375
|
+
})
|
|
418
376
|
expect(result.events[0]).toMatchObject({
|
|
419
|
-
createdBy:
|
|
377
|
+
createdBy: network.ozone.moderatorAccnt.did,
|
|
420
378
|
event: {
|
|
421
379
|
$type: 'com.atproto.admin.defs#modEventReverseTakedown',
|
|
422
380
|
},
|
|
@@ -450,7 +408,7 @@ describe('moderation-events', () => {
|
|
|
450
408
|
|
|
451
409
|
it('sends email via pds.', async () => {
|
|
452
410
|
const mail = await getMailFrom(
|
|
453
|
-
emitModerationEvent({
|
|
411
|
+
modClient.emitModerationEvent({
|
|
454
412
|
event: {
|
|
455
413
|
$type: 'com.atproto.admin.defs#modEventEmail',
|
|
456
414
|
comment: 'Reaching out to Alice',
|
|
@@ -461,7 +419,6 @@ describe('moderation-events', () => {
|
|
|
461
419
|
$type: 'com.atproto.admin.defs#repoRef',
|
|
462
420
|
did: sc.dids.alice,
|
|
463
421
|
},
|
|
464
|
-
createdBy: sc.dids.bob,
|
|
465
422
|
}),
|
|
466
423
|
)
|
|
467
424
|
expect(mail).toEqual({
|