@atproto/ozone 0.1.57 → 0.1.59

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/api/moderation/emitEvent.d.ts.map +1 -1
  3. package/dist/api/moderation/emitEvent.js +35 -24
  4. package/dist/api/moderation/emitEvent.js.map +1 -1
  5. package/dist/lexicon/lexicons.d.ts +22250 -9820
  6. package/dist/lexicon/lexicons.d.ts.map +1 -1
  7. package/dist/lexicon/lexicons.js +13 -1
  8. package/dist/lexicon/lexicons.js.map +1 -1
  9. package/dist/lexicon/types/app/bsky/notification/listNotifications.d.ts +2 -0
  10. package/dist/lexicon/types/app/bsky/notification/listNotifications.d.ts.map +1 -1
  11. package/dist/lexicon/types/app/bsky/notification/listNotifications.js.map +1 -1
  12. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts +2 -0
  13. package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts.map +1 -1
  14. package/dist/lexicon/types/tools/ozone/moderation/defs.js.map +1 -1
  15. package/dist/lexicon/types/tools/ozone/moderation/queryEvents.d.ts +1 -1
  16. package/dist/lexicon/types/tools/ozone/moderation/queryEvents.d.ts.map +1 -1
  17. package/dist/mod-service/index.d.ts +14 -14
  18. package/dist/mod-service/index.d.ts.map +1 -1
  19. package/dist/mod-service/index.js +22 -5
  20. package/dist/mod-service/index.js.map +1 -1
  21. package/dist/mod-service/views.d.ts.map +1 -1
  22. package/dist/mod-service/views.js +3 -2
  23. package/dist/mod-service/views.js.map +1 -1
  24. package/package.json +8 -8
  25. package/src/api/moderation/emitEvent.ts +74 -45
  26. package/src/lexicon/lexicons.ts +18 -3
  27. package/src/lexicon/types/app/bsky/notification/listNotifications.ts +2 -0
  28. package/src/lexicon/types/tools/ozone/moderation/defs.ts +2 -0
  29. package/src/lexicon/types/tools/ozone/moderation/queryEvents.ts +1 -1
  30. package/src/mod-service/index.ts +30 -7
  31. package/src/mod-service/views.ts +3 -2
  32. package/tests/__snapshots__/moderation-events.test.ts.snap +123 -0
  33. package/tests/ack-all-subjects-of-account.test.ts +77 -31
  34. package/tests/get-profiles.test.ts +71 -0
  35. package/tests/moderation-events.test.ts +40 -0
  36. package/tests/protected-tags.test.ts +16 -0
  37. package/tsconfig.tests.tsbuildinfo +1 -1
@@ -19,7 +19,7 @@ import {
19
19
  import { isRepoRef } from '../src/lexicon/types/com/atproto/admin/defs'
20
20
  import { ComAtprotoRepoStrongRef } from '@atproto/api'
21
21
 
22
- describe('moderation', () => {
22
+ describe('acknowledge all subjects of account', () => {
23
23
  let network: TestNetwork
24
24
  let sc: SeedClient
25
25
  let modClient: ModeratorClient
@@ -35,28 +35,28 @@ describe('moderation', () => {
35
35
  cid: ref.cidStr,
36
36
  })
37
37
 
38
- beforeAll(async () => {
39
- network = await TestNetwork.create({
40
- dbPostgresSchema: 'ozone_ack_all_subjects_of_account',
38
+ const getReviewStateBySubject = (subjects: SubjectStatusView[]) => {
39
+ const states = new Map<string, SubjectStatusView>()
40
+
41
+ subjects.forEach((item) => {
42
+ if (ComAtprotoRepoStrongRef.isMain(item.subject)) {
43
+ states.set(item.subject.uri, item)
44
+ } else if (isRepoRef(item.subject)) {
45
+ states.set(item.subject.did, item)
46
+ }
41
47
  })
42
- sc = network.getSeedClient()
43
- modClient = network.ozone.getModClient()
44
- await basicSeed(sc)
45
- await network.processAll()
46
- })
47
48
 
48
- afterAll(async () => {
49
- await network.close()
50
- })
49
+ return states
50
+ }
51
51
 
52
- it('acknowledges all open/escalated review subjects.', async () => {
53
- const postOne = sc.posts[sc.dids.bob][0].ref
54
- const postTwo = sc.posts[sc.dids.bob][1].ref
52
+ const reportUserAndPost = async (did: string) => {
53
+ const postOne = sc.posts[did][0].ref
54
+ const postTwo = sc.posts[did][1].ref
55
55
  await Promise.all([
56
56
  sc.createReport({
57
57
  reasonType: REASONSPAM,
58
- subject: repoSubject(sc.dids.bob),
59
- reportedBy: sc.dids.alice,
58
+ subject: repoSubject(did),
59
+ reportedBy: sc.dids.carol,
60
60
  }),
61
61
  sc.createReport({
62
62
  reasonType: REASONOTHER,
@@ -71,7 +71,6 @@ describe('moderation', () => {
71
71
  reportedBy: sc.dids.carol,
72
72
  }),
73
73
  ])
74
-
75
74
  await modClient.emitEvent({
76
75
  event: {
77
76
  $type: 'tools.ozone.moderation.defs#modEventReport',
@@ -80,6 +79,26 @@ describe('moderation', () => {
80
79
  subject: recordSubject(postTwo),
81
80
  })
82
81
 
82
+ return { postOne, postTwo }
83
+ }
84
+
85
+ beforeAll(async () => {
86
+ network = await TestNetwork.create({
87
+ dbPostgresSchema: 'ozone_ack_all_subjects_of_account',
88
+ })
89
+ sc = network.getSeedClient()
90
+ modClient = network.ozone.getModClient()
91
+ await basicSeed(sc)
92
+ await network.processAll()
93
+ })
94
+
95
+ afterAll(async () => {
96
+ await network.close()
97
+ })
98
+
99
+ it('acknowledges all open/escalated review subjects with takedown.', async () => {
100
+ const { postOne, postTwo } = await reportUserAndPost(sc.dids.bob)
101
+
83
102
  const { subjectStatuses: statusesBefore } = await modClient.queryStatuses({
84
103
  subject: sc.dids.bob,
85
104
  includeAllUserRecords: true,
@@ -95,19 +114,46 @@ describe('moderation', () => {
95
114
  includeAllUserRecords: true,
96
115
  })
97
116
 
98
- const getReviewStateBySubject = (subjects: SubjectStatusView[]) => {
99
- const states = new Map<string, SubjectStatusView>()
117
+ const reviewStatesBefore = getReviewStateBySubject(statusesBefore)
118
+ const reviewStatesAfter = getReviewStateBySubject(statusesAfter)
100
119
 
101
- subjects.forEach((item) => {
102
- if (ComAtprotoRepoStrongRef.isMain(item.subject)) {
103
- states.set(item.subject.uri, item)
104
- } else if (isRepoRef(item.subject)) {
105
- states.set(item.subject.did, item)
106
- }
107
- })
120
+ // Check that review states before were different for different subjects
121
+ expect(reviewStatesBefore.get(postOne.uriStr)?.reviewState).toBe(REVIEWOPEN)
122
+ expect(reviewStatesBefore.get(postTwo.uriStr)?.reviewState).toBe(
123
+ REVIEWESCALATED,
124
+ )
125
+ expect(reviewStatesBefore.get(sc.dids.bob)?.reviewState).toBe(REVIEWOPEN)
126
+
127
+ // Check that review states after are all closed
128
+ expect(reviewStatesAfter.get(postOne.uriStr)?.reviewState).toBe(
129
+ REVIEWCLOSED,
130
+ )
131
+ expect(reviewStatesAfter.get(postTwo.uriStr)?.reviewState).toBe(
132
+ REVIEWCLOSED,
133
+ )
134
+ expect(reviewStatesAfter.get(sc.dids.bob)?.reviewState).toBe(REVIEWCLOSED)
135
+ })
108
136
 
109
- return states
110
- }
137
+ it('acknowledges all open/escalated review subjects with acknowledge.', async () => {
138
+ const { postOne, postTwo } = await reportUserAndPost(sc.dids.alice)
139
+
140
+ const { subjectStatuses: statusesBefore } = await modClient.queryStatuses({
141
+ subject: sc.dids.alice,
142
+ includeAllUserRecords: true,
143
+ })
144
+
145
+ await modClient.emitEvent({
146
+ subject: repoSubject(sc.dids.alice),
147
+ event: {
148
+ $type: 'tools.ozone.moderation.defs#modEventAcknowledge',
149
+ acknowledgeAccountSubjects: true,
150
+ },
151
+ })
152
+
153
+ const { subjectStatuses: statusesAfter } = await modClient.queryStatuses({
154
+ subject: sc.dids.alice,
155
+ includeAllUserRecords: true,
156
+ })
111
157
 
112
158
  const reviewStatesBefore = getReviewStateBySubject(statusesBefore)
113
159
  const reviewStatesAfter = getReviewStateBySubject(statusesAfter)
@@ -117,7 +163,7 @@ describe('moderation', () => {
117
163
  expect(reviewStatesBefore.get(postTwo.uriStr)?.reviewState).toBe(
118
164
  REVIEWESCALATED,
119
165
  )
120
- expect(reviewStatesBefore.get(sc.dids.bob)?.reviewState).toBe(REVIEWOPEN)
166
+ expect(reviewStatesBefore.get(sc.dids.alice)?.reviewState).toBe(REVIEWOPEN)
121
167
 
122
168
  // Check that review states after are all closed
123
169
  expect(reviewStatesAfter.get(postOne.uriStr)?.reviewState).toBe(
@@ -126,6 +172,6 @@ describe('moderation', () => {
126
172
  expect(reviewStatesAfter.get(postTwo.uriStr)?.reviewState).toBe(
127
173
  REVIEWCLOSED,
128
174
  )
129
- expect(reviewStatesAfter.get(sc.dids.bob)?.reviewState).toBe(REVIEWCLOSED)
175
+ expect(reviewStatesAfter.get(sc.dids.alice)?.reviewState).toBe(REVIEWCLOSED)
130
176
  })
131
177
  })
@@ -0,0 +1,71 @@
1
+ import {
2
+ TestNetwork,
3
+ SeedClient,
4
+ basicSeed,
5
+ ModeratorClient,
6
+ } from '@atproto/dev-env'
7
+ import { ids } from '../src/lexicon/lexicons'
8
+
9
+ describe('get profiles through ozone', () => {
10
+ let network: TestNetwork
11
+ let sc: SeedClient
12
+ let modClient: ModeratorClient
13
+
14
+ const repoSubject = (did: string) => ({
15
+ $type: 'com.atproto.admin.defs#repoRef',
16
+ did,
17
+ })
18
+
19
+ beforeAll(async () => {
20
+ network = await TestNetwork.create({
21
+ dbPostgresSchema: 'ozone_get_profiles',
22
+ })
23
+ sc = network.getSeedClient()
24
+ modClient = network.ozone.getModClient()
25
+ await basicSeed(sc)
26
+ await network.processAll()
27
+ })
28
+
29
+ afterAll(async () => {
30
+ await network.close()
31
+ })
32
+
33
+ it('allows getting profiles by dids for takendown accounts.', async () => {
34
+ const getProfiles = async (actors: string[]) => {
35
+ const { data } = await modClient.agent.app.bsky.actor.getProfiles(
36
+ { actors },
37
+ {
38
+ headers: await network.ozone.modHeaders(
39
+ 'app.bsky.actor.getProfiles',
40
+ 'admin',
41
+ ),
42
+ },
43
+ )
44
+
45
+ return data.profiles
46
+ }
47
+ const profilesBefore = await getProfiles([sc.dids.bob, sc.dids.carol])
48
+
49
+ await modClient.performTakedown({
50
+ subject: repoSubject(sc.dids.bob),
51
+ })
52
+
53
+ const profilesAfterFromOzone = await getProfiles([
54
+ sc.dids.bob,
55
+ sc.dids.carol,
56
+ ])
57
+
58
+ const appviewAgent = network.bsky.getClient()
59
+ const {
60
+ data: { profiles: profilesFromAppview },
61
+ } = await appviewAgent.app.bsky.actor.getProfiles({
62
+ actors: [sc.dids.bob, sc.dids.carol],
63
+ })
64
+
65
+ expect(profilesBefore.length).toEqual(profilesAfterFromOzone.length)
66
+ expect(
67
+ profilesAfterFromOzone.find((p) => p.did === sc.dids.bob),
68
+ ).toBeTruthy()
69
+ expect(profilesFromAppview.find((p) => p.did === sc.dids.bob)).toBeFalsy()
70
+ })
71
+ })
@@ -224,6 +224,46 @@ describe('moderation-events', () => {
224
224
  expect(eventsWithComment.events.length).toEqual(10)
225
225
  })
226
226
 
227
+ it('returns events matching multiple keywords in comment', async () => {
228
+ await sc.createReport({
229
+ reasonType: REASONSPAM,
230
+ reason: 'november rain',
231
+ subject: {
232
+ $type: 'com.atproto.admin.defs#repoRef',
233
+ did: sc.dids.alice,
234
+ },
235
+ reportedBy: sc.dids.bob,
236
+ })
237
+ await sc.createReport({
238
+ reasonType: REASONSPAM,
239
+ reason: 'rainy days feel lazy',
240
+ subject: {
241
+ $type: 'com.atproto.admin.defs#repoRef',
242
+ did: sc.dids.alice,
243
+ },
244
+ reportedBy: sc.dids.bob,
245
+ })
246
+ const [eventsMatchingBothKeywords, unusedTrailingSeparator, extraSpaces] =
247
+ await Promise.all([
248
+ modClient.queryEvents({
249
+ hasComment: true,
250
+ comment: 'november||lazy',
251
+ }),
252
+ modClient.queryEvents({
253
+ hasComment: true,
254
+ comment: 'november||lazy||',
255
+ }),
256
+ modClient.queryEvents({
257
+ hasComment: true,
258
+ comment: '||november||lazy|| ',
259
+ }),
260
+ ])
261
+
262
+ expect(forSnapshot(eventsMatchingBothKeywords.events)).toMatchSnapshot()
263
+ expect(forSnapshot(unusedTrailingSeparator.events)).toMatchSnapshot()
264
+ expect(forSnapshot(extraSpaces.events)).toMatchSnapshot()
265
+ })
266
+
227
267
  it('returns events matching filter params for labels', async () => {
228
268
  const [negatedLabelEvent, createdLabelEvent] = await Promise.all([
229
269
  modClient.emitEvent({
@@ -145,6 +145,22 @@ describe('protected-tags', () => {
145
145
  },
146
146
  }),
147
147
  ).rejects.toThrow(/Can not manage tag vip/gi)
148
+
149
+ // Verify that since admins are configured to manage this tag, admin actions go through
150
+ const removeTag = await modClient.emitEvent(
151
+ {
152
+ subject: {
153
+ $type: 'com.atproto.admin.defs#repoRef',
154
+ did: sc.dids.bob,
155
+ },
156
+ event: {
157
+ $type: 'tools.ozone.moderation.defs#modEventTakedown',
158
+ },
159
+ },
160
+ 'admin',
161
+ )
162
+
163
+ expect(removeTag.id).toBeTruthy()
148
164
  })
149
165
  it('only allows configured moderators to add/remove protected tags', async () => {
150
166
  await modClient.upsertSettingOption({
@@ -1 +1 @@
1
- {"root":["./tests/3p-labeler.test.ts","./tests/_util.ts","./tests/ack-all-subjects-of-account.test.ts","./tests/blob-divert.test.ts","./tests/communication-templates.test.ts","./tests/content-tagger.test.ts","./tests/db.test.ts","./tests/get-config.test.ts","./tests/get-lists.test.ts","./tests/get-record.test.ts","./tests/get-records.test.ts","./tests/get-repo.test.ts","./tests/get-repos.test.ts","./tests/get-starter-pack.test.ts","./tests/moderation-appeals.test.ts","./tests/moderation-events.test.ts","./tests/moderation-status-tags.test.ts","./tests/moderation-statuses.test.ts","./tests/moderation.test.ts","./tests/protected-tags.test.ts","./tests/query-labels.test.ts","./tests/record-and-account-events.test.ts","./tests/repo-search.test.ts","./tests/report-muting.test.ts","./tests/sequencer.test.ts","./tests/server.test.ts","./tests/sets.test.ts","./tests/settings.test.ts","./tests/team.test.ts"],"version":"5.6.3"}
1
+ {"root":["./tests/3p-labeler.test.ts","./tests/_util.ts","./tests/ack-all-subjects-of-account.test.ts","./tests/blob-divert.test.ts","./tests/communication-templates.test.ts","./tests/content-tagger.test.ts","./tests/db.test.ts","./tests/get-config.test.ts","./tests/get-lists.test.ts","./tests/get-profiles.test.ts","./tests/get-record.test.ts","./tests/get-records.test.ts","./tests/get-repo.test.ts","./tests/get-repos.test.ts","./tests/get-starter-pack.test.ts","./tests/moderation-appeals.test.ts","./tests/moderation-events.test.ts","./tests/moderation-status-tags.test.ts","./tests/moderation-statuses.test.ts","./tests/moderation.test.ts","./tests/protected-tags.test.ts","./tests/query-labels.test.ts","./tests/record-and-account-events.test.ts","./tests/repo-search.test.ts","./tests/report-muting.test.ts","./tests/sequencer.test.ts","./tests/server.test.ts","./tests/sets.test.ts","./tests/settings.test.ts","./tests/team.test.ts"],"version":"5.6.3"}