@atproto/ozone 0.0.11 → 0.0.13
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 +17 -0
- package/dist/api/label/queryLabels.d.ts +3 -0
- package/dist/api/label/subscribeLabels.d.ts +3 -0
- package/dist/config/config.d.ts +3 -0
- package/dist/config/env.d.ts +3 -0
- package/dist/context.d.ts +3 -0
- package/dist/db/index.js +3 -1
- package/dist/db/index.js.map +2 -2
- package/dist/db/schema/label.d.ts +4 -0
- package/dist/index.js +875 -454
- package/dist/index.js.map +3 -3
- package/dist/lexicon/index.d.ts +2 -0
- package/dist/lexicon/lexicons.d.ts +27 -0
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts +1 -1
- package/dist/lexicon/types/com/atproto/admin/updateAccountPassword.d.ts +26 -0
- package/dist/logger.d.ts +1 -0
- package/dist/mod-service/util.d.ts +3 -0
- package/dist/sequencer/index.d.ts +2 -0
- package/dist/sequencer/outbox.d.ts +16 -0
- package/dist/sequencer/sequencer.d.ts +33 -0
- package/package.json +10 -10
- package/src/api/admin/emitModerationEvent.ts +16 -10
- package/src/api/index.ts +4 -0
- package/src/api/label/queryLabels.ts +58 -0
- package/src/api/label/subscribeLabels.ts +25 -0
- package/src/api/temp/fetchLabels.ts +2 -4
- package/src/config/config.ts +6 -0
- package/src/config/env.ts +6 -0
- package/src/context.ts +12 -0
- package/src/db/migrations/20231219T205730722Z-init.ts +7 -1
- package/src/db/schema/label.ts +7 -0
- package/src/index.ts +2 -0
- package/src/lexicon/index.ts +12 -0
- package/src/lexicon/lexicons.ts +32 -1
- package/src/lexicon/types/app/bsky/actor/defs.ts +2 -0
- package/src/lexicon/types/com/atproto/admin/updateAccountPassword.ts +39 -0
- package/src/logger.ts +2 -0
- package/src/mod-service/index.ts +73 -72
- package/src/mod-service/status.ts +3 -0
- package/src/mod-service/util.ts +17 -0
- package/src/mod-service/views.ts +2 -5
- package/src/sequencer/index.ts +2 -0
- package/src/sequencer/outbox.ts +122 -0
- package/src/sequencer/sequencer.ts +143 -0
- package/tests/__snapshots__/moderation-events.test.ts.snap +53 -75
- package/tests/__snapshots__/moderation.test.ts.snap +4 -4
- package/tests/moderation-appeals.test.ts +19 -7
- package/tests/moderation-events.test.ts +7 -7
- package/tests/moderation-statuses.test.ts +2 -2
- package/tests/moderation.test.ts +14 -13
- package/tests/query-labels.test.ts +163 -0
- package/tests/repo-search.test.ts +0 -1
- package/tests/sequencer.test.ts +222 -0
- package/tests/server.test.ts +2 -0
|
@@ -5,85 +5,63 @@ Object {
|
|
|
5
5
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
6
6
|
"createdBy": "user(2)",
|
|
7
7
|
"event": Object {
|
|
8
|
-
"$type": "com.atproto.admin.defs#
|
|
9
|
-
"comment": "
|
|
10
|
-
"
|
|
11
|
-
"test-label",
|
|
12
|
-
],
|
|
13
|
-
"negateLabelVals": Array [],
|
|
8
|
+
"$type": "com.atproto.admin.defs#modEventReport",
|
|
9
|
+
"comment": "X",
|
|
10
|
+
"reportType": "com.atproto.moderation.defs#reasonMisleading",
|
|
14
11
|
},
|
|
15
12
|
"id": 1,
|
|
16
13
|
"subject": Object {
|
|
17
|
-
"$type": "com.atproto.admin.defs#
|
|
18
|
-
"
|
|
19
|
-
"
|
|
14
|
+
"$type": "com.atproto.admin.defs#repoView",
|
|
15
|
+
"did": "user(0)",
|
|
16
|
+
"handle": "alice.test",
|
|
20
17
|
"indexedAt": "1970-01-01T00:00:00.000Z",
|
|
21
|
-
"moderation": Object {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"lastReviewedBy": "user(1)",
|
|
33
|
-
"reviewState": "com.atproto.admin.defs#reviewEscalated",
|
|
34
|
-
"subject": Object {
|
|
35
|
-
"$type": "com.atproto.admin.defs#repoRef",
|
|
36
|
-
"did": "user(0)",
|
|
37
|
-
},
|
|
38
|
-
"subjectBlobCids": Array [],
|
|
39
|
-
"subjectRepoHandle": "alice.test",
|
|
40
|
-
"tags": Array [
|
|
41
|
-
"lang:und",
|
|
42
|
-
],
|
|
43
|
-
"takendown": false,
|
|
44
|
-
"updatedAt": "1970-01-01T00:00:00.000Z",
|
|
18
|
+
"moderation": Object {
|
|
19
|
+
"subjectStatus": Object {
|
|
20
|
+
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
21
|
+
"id": 1,
|
|
22
|
+
"lastReportedAt": "1970-01-01T00:00:00.000Z",
|
|
23
|
+
"lastReviewedAt": "1970-01-01T00:00:00.000Z",
|
|
24
|
+
"lastReviewedBy": "user(1)",
|
|
25
|
+
"reviewState": "com.atproto.admin.defs#reviewEscalated",
|
|
26
|
+
"subject": Object {
|
|
27
|
+
"$type": "com.atproto.admin.defs#repoRef",
|
|
28
|
+
"did": "user(0)",
|
|
45
29
|
},
|
|
30
|
+
"subjectBlobCids": Array [],
|
|
31
|
+
"subjectRepoHandle": "alice.test",
|
|
32
|
+
"tags": Array [
|
|
33
|
+
"lang:und",
|
|
34
|
+
],
|
|
35
|
+
"takendown": false,
|
|
36
|
+
"updatedAt": "1970-01-01T00:00:00.000Z",
|
|
46
37
|
},
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"size": 3976,
|
|
57
|
-
},
|
|
58
|
-
"description": "its me!",
|
|
59
|
-
"displayName": "ali",
|
|
60
|
-
"labels": Object {
|
|
61
|
-
"$type": "com.atproto.label.defs#selfLabels",
|
|
62
|
-
"values": Array [
|
|
63
|
-
Object {
|
|
64
|
-
"val": "self-label-a",
|
|
65
|
-
},
|
|
66
|
-
Object {
|
|
67
|
-
"val": "self-label-b",
|
|
68
|
-
},
|
|
69
|
-
],
|
|
38
|
+
},
|
|
39
|
+
"relatedRecords": Array [
|
|
40
|
+
Object {
|
|
41
|
+
"$type": "app.bsky.actor.profile",
|
|
42
|
+
"avatar": Object {
|
|
43
|
+
"$type": "blob",
|
|
44
|
+
"mimeType": "image/jpeg",
|
|
45
|
+
"ref": Object {
|
|
46
|
+
"$link": "cids(0)",
|
|
70
47
|
},
|
|
48
|
+
"size": 3976,
|
|
71
49
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
50
|
+
"description": "its me!",
|
|
51
|
+
"displayName": "ali",
|
|
52
|
+
"labels": Object {
|
|
53
|
+
"$type": "com.atproto.label.defs#selfLabels",
|
|
54
|
+
"values": Array [
|
|
55
|
+
Object {
|
|
56
|
+
"val": "self-label-a",
|
|
57
|
+
},
|
|
58
|
+
Object {
|
|
59
|
+
"val": "self-label-b",
|
|
60
|
+
},
|
|
61
|
+
],
|
|
83
62
|
},
|
|
84
63
|
},
|
|
85
|
-
|
|
86
|
-
},
|
|
64
|
+
],
|
|
87
65
|
},
|
|
88
66
|
"subjectBlobCids": Array [],
|
|
89
67
|
"subjectBlobs": Array [],
|
|
@@ -101,7 +79,7 @@ Array [
|
|
|
101
79
|
"comment": "X",
|
|
102
80
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
103
81
|
},
|
|
104
|
-
"id":
|
|
82
|
+
"id": 11,
|
|
105
83
|
"subject": Object {
|
|
106
84
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
107
85
|
"did": "user(0)",
|
|
@@ -120,7 +98,7 @@ Array [
|
|
|
120
98
|
],
|
|
121
99
|
"remove": Array [],
|
|
122
100
|
},
|
|
123
|
-
"id":
|
|
101
|
+
"id": 6,
|
|
124
102
|
"subject": Object {
|
|
125
103
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
126
104
|
"did": "user(0)",
|
|
@@ -137,7 +115,7 @@ Array [
|
|
|
137
115
|
"comment": "X",
|
|
138
116
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
139
117
|
},
|
|
140
|
-
"id":
|
|
118
|
+
"id": 5,
|
|
141
119
|
"subject": Object {
|
|
142
120
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
143
121
|
"did": "user(0)",
|
|
@@ -159,7 +137,7 @@ Array [
|
|
|
159
137
|
"comment": "X",
|
|
160
138
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
161
139
|
},
|
|
162
|
-
"id":
|
|
140
|
+
"id": 10,
|
|
163
141
|
"subject": Object {
|
|
164
142
|
"$type": "com.atproto.repo.strongRef",
|
|
165
143
|
"cid": "cids(0)",
|
|
@@ -178,7 +156,7 @@ Array [
|
|
|
178
156
|
],
|
|
179
157
|
"remove": Array [],
|
|
180
158
|
},
|
|
181
|
-
"id":
|
|
159
|
+
"id": 4,
|
|
182
160
|
"subject": Object {
|
|
183
161
|
"$type": "com.atproto.repo.strongRef",
|
|
184
162
|
"cid": "cids(0)",
|
|
@@ -196,7 +174,7 @@ Array [
|
|
|
196
174
|
"comment": "X",
|
|
197
175
|
"reportType": "com.atproto.moderation.defs#reasonSpam",
|
|
198
176
|
},
|
|
199
|
-
"id":
|
|
177
|
+
"id": 3,
|
|
200
178
|
"subject": Object {
|
|
201
179
|
"$type": "com.atproto.repo.strongRef",
|
|
202
180
|
"cid": "cids(0)",
|
|
@@ -4,7 +4,7 @@ exports[`moderation reporting creates reports of a record. 1`] = `
|
|
|
4
4
|
Array [
|
|
5
5
|
Object {
|
|
6
6
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
7
|
-
"id":
|
|
7
|
+
"id": 5,
|
|
8
8
|
"reasonType": "com.atproto.moderation.defs#reasonSpam",
|
|
9
9
|
"reportedBy": "user(0)",
|
|
10
10
|
"subject": Object {
|
|
@@ -15,7 +15,7 @@ Array [
|
|
|
15
15
|
},
|
|
16
16
|
Object {
|
|
17
17
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
18
|
-
"id":
|
|
18
|
+
"id": 7,
|
|
19
19
|
"reason": "defamation",
|
|
20
20
|
"reasonType": "com.atproto.moderation.defs#reasonOther",
|
|
21
21
|
"reportedBy": "user(1)",
|
|
@@ -32,7 +32,7 @@ exports[`moderation reporting creates reports of a repo. 1`] = `
|
|
|
32
32
|
Array [
|
|
33
33
|
Object {
|
|
34
34
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
35
|
-
"id":
|
|
35
|
+
"id": 1,
|
|
36
36
|
"reasonType": "com.atproto.moderation.defs#reasonSpam",
|
|
37
37
|
"reportedBy": "user(0)",
|
|
38
38
|
"subject": Object {
|
|
@@ -42,7 +42,7 @@ Array [
|
|
|
42
42
|
},
|
|
43
43
|
Object {
|
|
44
44
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
45
|
-
"id":
|
|
45
|
+
"id": 3,
|
|
46
46
|
"reason": "impersonation",
|
|
47
47
|
"reasonType": "com.atproto.moderation.defs#reasonOther",
|
|
48
48
|
"reportedBy": "user(2)",
|
|
@@ -118,7 +118,7 @@ describe('moderation-appeals', () => {
|
|
|
118
118
|
})
|
|
119
119
|
|
|
120
120
|
// Verify that appeal status changed when appeal report was emitted by moderator
|
|
121
|
-
const status = await assertBobsPostStatus(
|
|
121
|
+
const status = await assertBobsPostStatus(REVIEWESCALATED, true)
|
|
122
122
|
expect(status?.appealedAt).not.toBeNull()
|
|
123
123
|
|
|
124
124
|
// Create a report as normal user for carol's post
|
|
@@ -143,7 +143,11 @@ describe('moderation-appeals', () => {
|
|
|
143
143
|
subject: getCarolPostSubject(),
|
|
144
144
|
})
|
|
145
145
|
// Verify that the appeal status on carol's post is true
|
|
146
|
-
await assertSubjectStatus(
|
|
146
|
+
await assertSubjectStatus(
|
|
147
|
+
getCarolPostSubject().uri,
|
|
148
|
+
REVIEWESCALATED,
|
|
149
|
+
true,
|
|
150
|
+
)
|
|
147
151
|
})
|
|
148
152
|
it('allows multiple appeals and updates last appealed timestamp', async () => {
|
|
149
153
|
// Resolve appeal with acknowledge
|
|
@@ -155,7 +159,7 @@ describe('moderation-appeals', () => {
|
|
|
155
159
|
createdBy: sc.dids.carol,
|
|
156
160
|
})
|
|
157
161
|
|
|
158
|
-
const previousStatus = await assertBobsPostStatus(
|
|
162
|
+
const previousStatus = await assertBobsPostStatus(REVIEWESCALATED, false)
|
|
159
163
|
|
|
160
164
|
await emitModerationEvent({
|
|
161
165
|
event: {
|
|
@@ -167,7 +171,7 @@ describe('moderation-appeals', () => {
|
|
|
167
171
|
})
|
|
168
172
|
|
|
169
173
|
// Verify that even after the appeal event by bob for his post, the appeal status is true again with new timestamp
|
|
170
|
-
const newStatus = await assertBobsPostStatus(
|
|
174
|
+
const newStatus = await assertBobsPostStatus(REVIEWESCALATED, true)
|
|
171
175
|
expect(
|
|
172
176
|
new Date(`${previousStatus?.lastAppealedAt}`).getTime(),
|
|
173
177
|
).toBeLessThan(new Date(`${newStatus?.lastAppealedAt}`).getTime())
|
|
@@ -210,7 +214,11 @@ describe('moderation-appeals', () => {
|
|
|
210
214
|
createdBy: sc.dids.alice,
|
|
211
215
|
})
|
|
212
216
|
|
|
213
|
-
await assertSubjectStatus(
|
|
217
|
+
await assertSubjectStatus(
|
|
218
|
+
getAlicesPostSubject().uri,
|
|
219
|
+
REVIEWESCALATED,
|
|
220
|
+
true,
|
|
221
|
+
)
|
|
214
222
|
|
|
215
223
|
// Bob reports it again
|
|
216
224
|
await emitModerationEvent({
|
|
@@ -222,8 +230,12 @@ describe('moderation-appeals', () => {
|
|
|
222
230
|
createdBy: sc.dids.bob,
|
|
223
231
|
})
|
|
224
232
|
|
|
225
|
-
// Assert that the status is still
|
|
226
|
-
await assertSubjectStatus(
|
|
233
|
+
// Assert that the status is still REVIEWESCALATED, as report events are meant to do
|
|
234
|
+
await assertSubjectStatus(
|
|
235
|
+
getAlicesPostSubject().uri,
|
|
236
|
+
REVIEWESCALATED,
|
|
237
|
+
true,
|
|
238
|
+
)
|
|
227
239
|
|
|
228
240
|
// Emit an escalation event
|
|
229
241
|
await emitModerationEvent({
|
|
@@ -22,13 +22,13 @@ describe('moderation-events', () => {
|
|
|
22
22
|
) => {
|
|
23
23
|
return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, {
|
|
24
24
|
encoding: 'application/json',
|
|
25
|
-
headers: network.
|
|
25
|
+
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
26
26
|
})
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
const queryModerationEvents = (eventQuery) =>
|
|
30
30
|
agent.api.com.atproto.admin.queryModerationEvents(eventQuery, {
|
|
31
|
-
headers: network.
|
|
31
|
+
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
const seedEvents = async () => {
|
|
@@ -203,11 +203,11 @@ describe('moderation-events', () => {
|
|
|
203
203
|
const defaultEvents = await getPaginatedEvents()
|
|
204
204
|
const reversedEvents = await getPaginatedEvents('asc')
|
|
205
205
|
|
|
206
|
-
expect(allEvents.data.events.length).toEqual(
|
|
206
|
+
expect(allEvents.data.events.length).toEqual(6)
|
|
207
207
|
expect(defaultEvents.length).toEqual(allEvents.data.events.length)
|
|
208
208
|
expect(reversedEvents.length).toEqual(allEvents.data.events.length)
|
|
209
209
|
// First event in the reversed list is the last item in the default list
|
|
210
|
-
expect(reversedEvents[0].id).toEqual(defaultEvents[
|
|
210
|
+
expect(reversedEvents[0].id).toEqual(defaultEvents[5].id)
|
|
211
211
|
})
|
|
212
212
|
|
|
213
213
|
it('returns report events matching reportType filters', async () => {
|
|
@@ -240,7 +240,7 @@ describe('moderation-events', () => {
|
|
|
240
240
|
|
|
241
241
|
expect(eventsWithX.data.events.length).toEqual(10)
|
|
242
242
|
expect(eventsWithTest.data.events.length).toEqual(0)
|
|
243
|
-
expect(eventsWithComment.data.events.length).toEqual(
|
|
243
|
+
expect(eventsWithComment.data.events.length).toEqual(10)
|
|
244
244
|
})
|
|
245
245
|
|
|
246
246
|
it('returns events matching filter params for labels', async () => {
|
|
@@ -325,7 +325,7 @@ describe('moderation-events', () => {
|
|
|
325
325
|
})
|
|
326
326
|
const addEvent = await tagEvent({ add: ['L1', 'L2'], remove: [] })
|
|
327
327
|
const addAndRemoveEvent = await tagEvent({ add: ['L3'], remove: ['L2'] })
|
|
328
|
-
const [addFinder, addAndRemoveFinder,
|
|
328
|
+
const [addFinder, addAndRemoveFinder, _removeFinder] = await Promise.all([
|
|
329
329
|
queryModerationEvents({
|
|
330
330
|
addedTags: ['L1'],
|
|
331
331
|
}),
|
|
@@ -356,7 +356,7 @@ describe('moderation-events', () => {
|
|
|
356
356
|
it('gets an event by specific id', async () => {
|
|
357
357
|
const { data } = await pdsAgent.api.com.atproto.admin.getModerationEvent(
|
|
358
358
|
{ id: 1 },
|
|
359
|
-
{ headers: network.
|
|
359
|
+
{ headers: network.ozone.adminAuthHeaders('moderator') },
|
|
360
360
|
)
|
|
361
361
|
expect(forSnapshot(data)).toMatchSnapshot()
|
|
362
362
|
})
|
|
@@ -19,13 +19,13 @@ describe('moderation-statuses', () => {
|
|
|
19
19
|
const emitModerationEvent = async (eventData) => {
|
|
20
20
|
return pdsAgent.api.com.atproto.admin.emitModerationEvent(eventData, {
|
|
21
21
|
encoding: 'application/json',
|
|
22
|
-
headers: network.
|
|
22
|
+
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
23
23
|
})
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const queryModerationStatuses = (statusQuery) =>
|
|
27
27
|
agent.api.com.atproto.admin.queryModerationStatuses(statusQuery, {
|
|
28
|
-
headers: network.
|
|
28
|
+
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
const seedEvents = async () => {
|
package/tests/moderation.test.ts
CHANGED
|
@@ -607,7 +607,7 @@ describe('moderation', () => {
|
|
|
607
607
|
},
|
|
608
608
|
{
|
|
609
609
|
encoding: 'application/json',
|
|
610
|
-
headers: network.
|
|
610
|
+
headers: network.ozone.adminAuthHeaders('triage'),
|
|
611
611
|
},
|
|
612
612
|
)
|
|
613
613
|
await expect(attemptLabel).rejects.toThrow(
|
|
@@ -748,7 +748,7 @@ describe('moderation', () => {
|
|
|
748
748
|
},
|
|
749
749
|
{
|
|
750
750
|
encoding: 'application/json',
|
|
751
|
-
headers: network.
|
|
751
|
+
headers: network.ozone.adminAuthHeaders('moderator'),
|
|
752
752
|
},
|
|
753
753
|
)
|
|
754
754
|
// cleanup
|
|
@@ -775,11 +775,11 @@ describe('moderation', () => {
|
|
|
775
775
|
},
|
|
776
776
|
{
|
|
777
777
|
encoding: 'application/json',
|
|
778
|
-
headers: network.
|
|
778
|
+
headers: network.ozone.adminAuthHeaders('triage'),
|
|
779
779
|
},
|
|
780
780
|
)
|
|
781
781
|
await expect(attemptTakedownTriage).rejects.toThrow(
|
|
782
|
-
'Must be a full moderator to
|
|
782
|
+
'Must be a full moderator to take this type of action',
|
|
783
783
|
)
|
|
784
784
|
})
|
|
785
785
|
|
|
@@ -800,7 +800,7 @@ describe('moderation', () => {
|
|
|
800
800
|
const { data: statusesAfterTakedown } =
|
|
801
801
|
await agent.api.com.atproto.admin.queryModerationStatuses(
|
|
802
802
|
{ subject: sc.dids.bob },
|
|
803
|
-
{ headers: network.
|
|
803
|
+
{ headers: network.ozone.adminAuthHeaders('moderator') },
|
|
804
804
|
)
|
|
805
805
|
|
|
806
806
|
expect(statusesAfterTakedown.subjectStatuses[0]).toMatchObject({
|
|
@@ -818,11 +818,11 @@ describe('moderation', () => {
|
|
|
818
818
|
const [{ data: eventList }, { data: statuses }] = await Promise.all([
|
|
819
819
|
agent.api.com.atproto.admin.queryModerationEvents(
|
|
820
820
|
{ subject: sc.dids.bob },
|
|
821
|
-
{ headers: network.
|
|
821
|
+
{ headers: network.ozone.adminAuthHeaders('moderator') },
|
|
822
822
|
),
|
|
823
823
|
agent.api.com.atproto.admin.queryModerationStatuses(
|
|
824
824
|
{ subject: sc.dids.bob },
|
|
825
|
-
{ headers: network.
|
|
825
|
+
{ headers: network.ozone.adminAuthHeaders('moderator') },
|
|
826
826
|
),
|
|
827
827
|
])
|
|
828
828
|
|
|
@@ -879,7 +879,7 @@ describe('moderation', () => {
|
|
|
879
879
|
},
|
|
880
880
|
{
|
|
881
881
|
encoding: 'application/json',
|
|
882
|
-
headers: network.
|
|
882
|
+
headers: network.ozone.adminAuthHeaders(),
|
|
883
883
|
},
|
|
884
884
|
)
|
|
885
885
|
return result.data
|
|
@@ -901,7 +901,7 @@ describe('moderation', () => {
|
|
|
901
901
|
},
|
|
902
902
|
{
|
|
903
903
|
encoding: 'application/json',
|
|
904
|
-
headers: network.
|
|
904
|
+
headers: network.ozone.adminAuthHeaders(),
|
|
905
905
|
},
|
|
906
906
|
)
|
|
907
907
|
}
|
|
@@ -909,7 +909,7 @@ describe('moderation', () => {
|
|
|
909
909
|
async function getRecordLabels(uri: string) {
|
|
910
910
|
const result = await agent.api.com.atproto.admin.getRecord(
|
|
911
911
|
{ uri },
|
|
912
|
-
{ headers: network.
|
|
912
|
+
{ headers: network.ozone.adminAuthHeaders() },
|
|
913
913
|
)
|
|
914
914
|
const labels = result.data.labels ?? []
|
|
915
915
|
return labels.map((l) => l.val)
|
|
@@ -918,7 +918,7 @@ describe('moderation', () => {
|
|
|
918
918
|
async function getRepoLabels(did: string) {
|
|
919
919
|
const result = await agent.api.com.atproto.admin.getRepo(
|
|
920
920
|
{ did },
|
|
921
|
-
{ headers: network.
|
|
921
|
+
{ headers: network.ozone.adminAuthHeaders() },
|
|
922
922
|
)
|
|
923
923
|
const labels = result.data.labels ?? []
|
|
924
924
|
return labels.map((l) => l.val)
|
|
@@ -933,7 +933,7 @@ describe('moderation', () => {
|
|
|
933
933
|
const { ctx } = network.bsky
|
|
934
934
|
post = sc.posts[sc.dids.carol][0]
|
|
935
935
|
blob = post.images[1]
|
|
936
|
-
imageUri = ctx.imgUriBuilder
|
|
936
|
+
imageUri = ctx.views.imgUriBuilder
|
|
937
937
|
.getPresetUri(
|
|
938
938
|
'feed_thumbnail',
|
|
939
939
|
sc.dids.carol,
|
|
@@ -974,7 +974,8 @@ describe('moderation', () => {
|
|
|
974
974
|
})
|
|
975
975
|
})
|
|
976
976
|
|
|
977
|
-
|
|
977
|
+
// @TODO add back in with image invalidation, see bluesky-social/atproto#2087
|
|
978
|
+
it.skip('prevents image blob from being served, even when cached.', async () => {
|
|
978
979
|
const fetchImage = await fetch(imageUri)
|
|
979
980
|
expect(fetchImage.status).toEqual(404)
|
|
980
981
|
expect(await fetchImage.json()).toEqual({ message: 'Image not found' })
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import AtpAgent from '@atproto/api'
|
|
2
|
+
import { TestNetwork } from '@atproto/dev-env'
|
|
3
|
+
import { DisconnectError, Subscription } from '@atproto/xrpc-server'
|
|
4
|
+
import { ids, lexicons } from '../src/lexicon/lexicons'
|
|
5
|
+
import { Label } from '../src/lexicon/types/com/atproto/label/defs'
|
|
6
|
+
import {
|
|
7
|
+
OutputSchema as LabelMessage,
|
|
8
|
+
isLabels,
|
|
9
|
+
} from '../src/lexicon/types/com/atproto/label/subscribeLabels'
|
|
10
|
+
|
|
11
|
+
describe('ozone query labels', () => {
|
|
12
|
+
let network: TestNetwork
|
|
13
|
+
let agent: AtpAgent
|
|
14
|
+
|
|
15
|
+
let labels: Label[]
|
|
16
|
+
|
|
17
|
+
beforeAll(async () => {
|
|
18
|
+
network = await TestNetwork.create({
|
|
19
|
+
dbPostgresSchema: 'ozone_query_labels',
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
agent = network.ozone.getClient()
|
|
23
|
+
|
|
24
|
+
labels = [
|
|
25
|
+
{
|
|
26
|
+
src: 'did:example:labeler',
|
|
27
|
+
uri: 'did:example:blah',
|
|
28
|
+
val: 'spam',
|
|
29
|
+
neg: false,
|
|
30
|
+
cts: new Date().toISOString(),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
src: 'did:example:labeler',
|
|
34
|
+
uri: 'did:example:blah',
|
|
35
|
+
val: 'impersonation',
|
|
36
|
+
neg: false,
|
|
37
|
+
cts: new Date().toISOString(),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
src: 'did:example:labeler',
|
|
41
|
+
uri: 'at://did:example:blah/app.bsky.feed.post/1234abcde',
|
|
42
|
+
val: 'spam',
|
|
43
|
+
neg: false,
|
|
44
|
+
cts: new Date().toISOString(),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
src: 'did:example:labeler',
|
|
48
|
+
uri: 'at://did:example:blah/app.bsky.feed.post/1234abcfg',
|
|
49
|
+
val: 'spam',
|
|
50
|
+
neg: false,
|
|
51
|
+
cts: new Date().toISOString(),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
src: 'did:example:labeler',
|
|
55
|
+
uri: 'at://did:example:blah/app.bsky.actor.profile/self',
|
|
56
|
+
val: 'spam',
|
|
57
|
+
neg: false,
|
|
58
|
+
cts: new Date().toISOString(),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
src: 'did:example:labeler',
|
|
62
|
+
uri: 'did:example:thing',
|
|
63
|
+
val: 'spam',
|
|
64
|
+
neg: false,
|
|
65
|
+
cts: new Date().toISOString(),
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
const modService = network.ozone.ctx.modService(network.ozone.ctx.db)
|
|
70
|
+
await modService.createLabels(labels)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
afterAll(async () => {
|
|
74
|
+
await network.close()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('returns all labels', async () => {
|
|
78
|
+
const res = await agent.api.com.atproto.label.queryLabels({
|
|
79
|
+
uriPatterns: ['*'],
|
|
80
|
+
})
|
|
81
|
+
expect(res.data.labels).toEqual(labels)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('returns all labels even when an additional pattern is supplied', async () => {
|
|
85
|
+
const res = await agent.api.com.atproto.label.queryLabels({
|
|
86
|
+
uriPatterns: ['*', 'did:example:blah'],
|
|
87
|
+
})
|
|
88
|
+
expect(res.data.labels).toEqual(labels)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('returns all labels that match an exact uri pattern', async () => {
|
|
92
|
+
const res = await agent.api.com.atproto.label.queryLabels({
|
|
93
|
+
uriPatterns: ['did:example:blah'],
|
|
94
|
+
})
|
|
95
|
+
expect(res.data.labels).toEqual(labels.slice(0, 2))
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('returns all labels that match one of multiple exact uris', async () => {
|
|
99
|
+
const res = await agent.api.com.atproto.label.queryLabels({
|
|
100
|
+
uriPatterns: [
|
|
101
|
+
'at://did:example:blah/app.bsky.feed.post/1234abcfg',
|
|
102
|
+
'at://did:example:blah/app.bsky.actor.profile/self',
|
|
103
|
+
],
|
|
104
|
+
})
|
|
105
|
+
expect(res.data.labels).toEqual(labels.slice(3, 5))
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('returns all labels that match one of multiple uris, exact & glob', async () => {
|
|
109
|
+
const res = await agent.api.com.atproto.label.queryLabels({
|
|
110
|
+
uriPatterns: ['at://did:example:blah/app.bsky*', 'did:example:blah'],
|
|
111
|
+
})
|
|
112
|
+
expect(res.data.labels).toEqual(labels.slice(0, 5))
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('paginates', async () => {
|
|
116
|
+
const res1 = await agent.api.com.atproto.label.queryLabels({
|
|
117
|
+
uriPatterns: ['at://did:example:blah/app.bsky*', 'did:example:blah'],
|
|
118
|
+
limit: 3,
|
|
119
|
+
})
|
|
120
|
+
const res2 = await agent.api.com.atproto.label.queryLabels({
|
|
121
|
+
uriPatterns: ['at://did:example:blah/app.bsky*', 'did:example:blah'],
|
|
122
|
+
limit: 3,
|
|
123
|
+
cursor: res1.data.cursor,
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
expect([...res1.data.labels, ...res2.data.labels]).toEqual(
|
|
127
|
+
labels.slice(0, 5),
|
|
128
|
+
)
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
describe('subscribeLabels', () => {
|
|
132
|
+
it('streams all labels from initial cursor.', async () => {
|
|
133
|
+
const ac = new AbortController()
|
|
134
|
+
let doneTimer: NodeJS.Timeout
|
|
135
|
+
const resetDoneTimer = () => {
|
|
136
|
+
clearTimeout(doneTimer)
|
|
137
|
+
doneTimer = setTimeout(() => ac.abort(new DisconnectError()), 100)
|
|
138
|
+
}
|
|
139
|
+
const sub = new Subscription({
|
|
140
|
+
signal: ac.signal,
|
|
141
|
+
service: agent.service.origin.replace('http://', 'ws://'),
|
|
142
|
+
method: ids.ComAtprotoLabelSubscribeLabels,
|
|
143
|
+
getParams() {
|
|
144
|
+
return { cursor: 0 }
|
|
145
|
+
},
|
|
146
|
+
validate(obj) {
|
|
147
|
+
return lexicons.assertValidXrpcMessage<LabelMessage>(
|
|
148
|
+
ids.ComAtprotoLabelSubscribeLabels,
|
|
149
|
+
obj,
|
|
150
|
+
)
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
const streamedLabels: Label[] = []
|
|
154
|
+
for await (const message of sub) {
|
|
155
|
+
resetDoneTimer()
|
|
156
|
+
if (isLabels(message)) {
|
|
157
|
+
streamedLabels.push(...message.labels)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
expect(streamedLabels).toEqual(labels)
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
})
|