@atproto/bsky 0.0.11 → 0.0.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 +13 -0
- package/dist/api/com/atproto/admin/util.d.ts +5 -0
- package/dist/context.d.ts +6 -1
- package/dist/db/index.js +51 -2
- package/dist/db/index.js.map +3 -3
- package/dist/db/migrations/20230929T192920807Z-record-cursor-indexes.d.ts +3 -0
- package/dist/db/migrations/index.d.ts +1 -0
- package/dist/did-cache.d.ts +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1381 -530
- package/dist/index.js.map +3 -3
- package/dist/lexicon/index.d.ts +8 -0
- package/dist/lexicon/lexicons.d.ts +231 -3
- package/dist/lexicon/types/app/bsky/actor/defs.d.ts +1 -0
- package/dist/lexicon/types/com/atproto/admin/defs.d.ts +28 -0
- package/dist/lexicon/types/com/atproto/admin/getAccountInfo.d.ts +29 -0
- package/dist/lexicon/types/com/atproto/admin/getSubjectStatus.d.ts +39 -0
- package/dist/lexicon/types/com/atproto/admin/searchRepos.d.ts +0 -1
- package/dist/lexicon/types/com/atproto/admin/updateSubjectStatus.d.ts +46 -0
- package/dist/lexicon/types/com/atproto/server/createAccount.d.ts +2 -0
- package/dist/lexicon/types/com/atproto/server/createSession.d.ts +1 -0
- package/dist/lexicon/types/com/atproto/server/refreshSession.d.ts +1 -0
- package/dist/lexicon/types/com/atproto/server/reserveSigningKey.d.ts +30 -0
- package/dist/lexicon/types/com/atproto/sync/listRepos.d.ts +1 -0
- package/dist/services/actor/types.d.ts +1 -0
- package/dist/services/graph/index.d.ts +2 -0
- package/dist/services/moderation/index.d.ts +13 -3
- package/package.json +13 -14
- package/src/api/app/bsky/feed/getAuthorFeed.ts +2 -2
- package/src/api/app/bsky/feed/getPostThread.ts +2 -2
- package/src/api/app/bsky/notification/listNotifications.ts +33 -22
- package/src/api/com/atproto/admin/getModerationAction.ts +28 -2
- package/src/api/com/atproto/admin/getModerationReport.ts +27 -2
- package/src/api/com/atproto/admin/getRecord.ts +14 -2
- package/src/api/com/atproto/admin/getRepo.ts +13 -2
- package/src/api/com/atproto/admin/reverseModerationAction.ts +31 -5
- package/src/api/com/atproto/admin/searchRepos.ts +2 -5
- package/src/api/com/atproto/admin/takeModerationAction.ts +41 -7
- package/src/api/com/atproto/admin/util.ts +50 -0
- package/src/api/well-known.ts +8 -0
- package/src/auth.ts +12 -5
- package/src/auto-moderator/index.ts +1 -0
- package/src/context.ts +25 -1
- package/src/db/migrations/20230929T192920807Z-record-cursor-indexes.ts +40 -0
- package/src/db/migrations/index.ts +1 -0
- package/src/did-cache.ts +29 -14
- package/src/feed-gen/with-friends.ts +2 -2
- package/src/index.ts +4 -1
- package/src/indexer/subscription.ts +1 -21
- package/src/lexicon/index.ts +48 -0
- package/src/lexicon/lexicons.ts +246 -4
- package/src/lexicon/types/app/bsky/actor/defs.ts +1 -0
- package/src/lexicon/types/com/atproto/admin/defs.ts +61 -0
- package/src/lexicon/types/com/atproto/admin/getAccountInfo.ts +41 -0
- package/src/lexicon/types/com/atproto/admin/getSubjectStatus.ts +54 -0
- package/src/lexicon/types/com/atproto/admin/searchRepos.ts +0 -1
- package/src/lexicon/types/com/atproto/admin/updateSubjectStatus.ts +61 -0
- package/src/lexicon/types/com/atproto/server/createAccount.ts +2 -0
- package/src/lexicon/types/com/atproto/server/createSession.ts +1 -0
- package/src/lexicon/types/com/atproto/server/refreshSession.ts +1 -0
- package/src/lexicon/types/com/atproto/server/reserveSigningKey.ts +44 -0
- package/src/lexicon/types/com/atproto/sync/listRepos.ts +1 -0
- package/src/logger.ts +8 -0
- package/src/services/actor/index.ts +7 -1
- package/src/services/actor/types.ts +1 -0
- package/src/services/actor/views.ts +26 -8
- package/src/services/graph/index.ts +26 -7
- package/src/services/indexing/index.ts +15 -17
- package/src/services/moderation/index.ts +94 -14
- package/src/services/moderation/views.ts +1 -0
- package/tests/__snapshots__/feed-generation.test.ts.snap +12 -12
- package/tests/__snapshots__/indexing.test.ts.snap +4 -4
- package/tests/admin/__snapshots__/get-moderation-action.test.ts.snap +172 -0
- package/tests/admin/__snapshots__/get-moderation-actions.test.ts.snap +178 -0
- package/tests/admin/__snapshots__/get-moderation-report.test.ts.snap +177 -0
- package/tests/admin/__snapshots__/get-moderation-reports.test.ts.snap +307 -0
- package/tests/admin/__snapshots__/get-record.test.ts.snap +275 -0
- package/tests/admin/__snapshots__/get-repo.test.ts.snap +103 -0
- package/tests/admin/get-moderation-action.test.ts +100 -0
- package/tests/admin/get-moderation-actions.test.ts +164 -0
- package/tests/admin/get-moderation-report.test.ts +100 -0
- package/tests/admin/get-moderation-reports.test.ts +332 -0
- package/tests/admin/get-record.test.ts +115 -0
- package/tests/admin/get-repo.test.ts +101 -0
- package/tests/{moderation.test.ts → admin/moderation.test.ts} +107 -9
- package/tests/admin/repo-search.test.ts +124 -0
- package/tests/algos/hot-classic.test.ts +3 -5
- package/tests/algos/whats-hot.test.ts +3 -5
- package/tests/algos/with-friends.test.ts +2 -4
- package/tests/auth.test.ts +64 -0
- package/tests/auto-moderator/fuzzy-matcher.test.ts +2 -3
- package/tests/auto-moderator/labeler.test.ts +5 -7
- package/tests/auto-moderator/takedowns.test.ts +11 -12
- package/tests/blob-resolver.test.ts +1 -3
- package/tests/did-cache.test.ts +2 -5
- package/tests/feed-generation.test.ts +8 -6
- package/tests/handle-invalidation.test.ts +2 -3
- package/tests/image/server.test.ts +1 -4
- package/tests/image/sharp.test.ts +1 -1
- package/tests/indexing.test.ts +4 -4
- package/tests/notification-server.test.ts +2 -3
- package/tests/pipeline/backpressure.test.ts +2 -3
- package/tests/pipeline/reingest.test.ts +7 -4
- package/tests/pipeline/repartition.test.ts +2 -3
- package/tests/reprocessing.test.ts +2 -6
- package/tests/seeds/basic.ts +4 -4
- package/tests/seeds/follows.ts +1 -1
- package/tests/seeds/likes.ts +1 -1
- package/tests/seeds/reposts.ts +1 -1
- package/tests/seeds/users-bulk.ts +1 -1
- package/tests/seeds/users.ts +1 -1
- package/tests/server.test.ts +1 -3
- package/tests/subscription/repo.test.ts +2 -4
- package/tests/views/__snapshots__/author-feed.test.ts.snap +24 -24
- package/tests/views/__snapshots__/block-lists.test.ts.snap +42 -7
- package/tests/views/__snapshots__/blocks.test.ts.snap +2 -2
- package/tests/views/__snapshots__/list-feed.test.ts.snap +6 -6
- package/tests/views/__snapshots__/mute-lists.test.ts.snap +15 -4
- package/tests/views/__snapshots__/mutes.test.ts.snap +2 -2
- package/tests/views/__snapshots__/notifications.test.ts.snap +2 -2
- package/tests/views/__snapshots__/posts.test.ts.snap +8 -8
- package/tests/views/__snapshots__/thread.test.ts.snap +10 -10
- package/tests/views/__snapshots__/timeline.test.ts.snap +58 -58
- package/tests/views/actor-likes.test.ts +2 -3
- package/tests/views/actor-search.test.ts +5 -5
- package/tests/views/admin/repo-search.test.ts +2 -4
- package/tests/views/author-feed.test.ts +2 -4
- package/tests/views/block-lists.test.ts +34 -7
- package/tests/views/blocks.test.ts +6 -3
- package/tests/views/follows.test.ts +2 -4
- package/tests/views/likes.test.ts +2 -5
- package/tests/views/list-feed.test.ts +2 -4
- package/tests/views/mute-lists.test.ts +23 -5
- package/tests/views/mutes.test.ts +2 -5
- package/tests/views/notifications.test.ts +2 -4
- package/tests/views/posts.test.ts +2 -5
- package/tests/views/profile.test.ts +4 -5
- package/tests/views/reposts.test.ts +2 -4
- package/tests/views/suggested-follows.test.ts +2 -3
- package/tests/views/suggestions.test.ts +2 -4
- package/tests/views/thread.test.ts +2 -4
- package/tests/views/threadgating.test.ts +2 -3
- package/tests/views/timeline.test.ts +2 -4
- package/dist/env.d.ts +0 -1
- package/example.dev.env +0 -5
- package/src/env.ts +0 -9
- package/tests/seeds/client.ts +0 -466
- /package/tests/{__snapshots__ → admin/__snapshots__}/moderation.test.ts.snap +0 -0
- /package/tests/{image/fixtures → sample-img}/at.png +0 -0
- /package/tests/{image/fixtures → sample-img}/hd-key.jpg +0 -0
- /package/tests/{image/fixtures → sample-img}/key-alt.jpg +0 -0
- /package/tests/{image/fixtures → sample-img}/key-landscape-large.jpg +0 -0
- /package/tests/{image/fixtures → sample-img}/key-landscape-small.jpg +0 -0
- /package/tests/{image/fixtures → sample-img}/key-portrait-large.jpg +0 -0
- /package/tests/{image/fixtures → sample-img}/key-portrait-small.jpg +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GENERATED CODE - DO NOT MODIFY
|
|
3
|
+
*/
|
|
4
|
+
import express from 'express'
|
|
5
|
+
import { ValidationResult, BlobRef } from '@atproto/lexicon'
|
|
6
|
+
import { lexicons } from '../../../../lexicons'
|
|
7
|
+
import { isObj, hasProp } from '../../../../util'
|
|
8
|
+
import { CID } from 'multiformats/cid'
|
|
9
|
+
import { HandlerAuth } from '@atproto/xrpc-server'
|
|
10
|
+
|
|
11
|
+
export interface QueryParams {}
|
|
12
|
+
|
|
13
|
+
export type InputSchema = undefined
|
|
14
|
+
|
|
15
|
+
export interface OutputSchema {
|
|
16
|
+
/** Public signing key in the form of a did:key. */
|
|
17
|
+
signingKey: string
|
|
18
|
+
[k: string]: unknown
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type HandlerInput = undefined
|
|
22
|
+
|
|
23
|
+
export interface HandlerSuccess {
|
|
24
|
+
encoding: 'application/json'
|
|
25
|
+
body: OutputSchema
|
|
26
|
+
headers?: { [key: string]: string }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface HandlerError {
|
|
30
|
+
status: number
|
|
31
|
+
message?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type HandlerOutput = HandlerError | HandlerSuccess
|
|
35
|
+
export type HandlerReqCtx<HA extends HandlerAuth = never> = {
|
|
36
|
+
auth: HA
|
|
37
|
+
params: QueryParams
|
|
38
|
+
input: HandlerInput
|
|
39
|
+
req: express.Request
|
|
40
|
+
res: express.Response
|
|
41
|
+
}
|
|
42
|
+
export type Handler<HA extends HandlerAuth = never> = (
|
|
43
|
+
ctx: HandlerReqCtx<HA>,
|
|
44
|
+
) => Promise<HandlerOutput> | HandlerOutput
|
package/src/logger.ts
CHANGED
|
@@ -66,7 +66,13 @@ export class ActorService {
|
|
|
66
66
|
qb = qb.orWhere('actor.did', 'in', dids)
|
|
67
67
|
}
|
|
68
68
|
if (handles.length) {
|
|
69
|
-
qb = qb.orWhere(
|
|
69
|
+
qb = qb.orWhere(
|
|
70
|
+
'actor.handle',
|
|
71
|
+
'in',
|
|
72
|
+
handles.length === 1
|
|
73
|
+
? [handles[0], handles[0]] // a silly (but worthwhile) optimization to avoid usage of actor_handle_tgrm_idx
|
|
74
|
+
: handles,
|
|
75
|
+
)
|
|
70
76
|
}
|
|
71
77
|
return qb
|
|
72
78
|
})
|
|
@@ -137,10 +137,13 @@ export class ActorViews {
|
|
|
137
137
|
),
|
|
138
138
|
])
|
|
139
139
|
const listUris = mapDefined(profiles, ({ did }) => {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
const muteList = viewer && bam.muteList([viewer, did])
|
|
141
|
+
const blockList = viewer && bam.blockList([viewer, did])
|
|
142
|
+
const lists: string[] = []
|
|
143
|
+
if (muteList) lists.push(muteList)
|
|
144
|
+
if (blockList) lists.push(blockList)
|
|
145
|
+
return lists
|
|
146
|
+
}).flat()
|
|
144
147
|
const lists = await this.services.graph.getListViews(listUris, viewer)
|
|
145
148
|
return { profilesDetailed: toMapByDid(profiles), labels, bam, lists }
|
|
146
149
|
}
|
|
@@ -168,6 +171,11 @@ export class ActorViews {
|
|
|
168
171
|
mutedByListUri && lists[mutedByListUri]
|
|
169
172
|
? this.services.graph.formatListViewBasic(lists[mutedByListUri])
|
|
170
173
|
: undefined
|
|
174
|
+
const blockingByListUri = viewer && bam.blockList([viewer, did])
|
|
175
|
+
const blockingByList =
|
|
176
|
+
blockingByListUri && lists[blockingByListUri]
|
|
177
|
+
? this.services.graph.formatListViewBasic(lists[blockingByListUri])
|
|
178
|
+
: undefined
|
|
171
179
|
const actorLabels = labels[did] ?? []
|
|
172
180
|
const selfLabels = getSelfLabels({
|
|
173
181
|
uri: prof.profileUri,
|
|
@@ -194,6 +202,7 @@ export class ActorViews {
|
|
|
194
202
|
mutedByList,
|
|
195
203
|
blockedBy: !!bam.blockedBy([viewer, did]),
|
|
196
204
|
blocking: bam.blocking([viewer, did]) ?? undefined,
|
|
205
|
+
blockingByList,
|
|
197
206
|
following:
|
|
198
207
|
prof?.viewerFollowing && !bam.block([viewer, did])
|
|
199
208
|
? prof.viewerFollowing
|
|
@@ -265,10 +274,13 @@ export class ActorViews {
|
|
|
265
274
|
),
|
|
266
275
|
])
|
|
267
276
|
const listUris = mapDefined(profiles, ({ did }) => {
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
277
|
+
const muteList = viewer && bam.muteList([viewer, did])
|
|
278
|
+
const blockList = viewer && bam.blockList([viewer, did])
|
|
279
|
+
const lists: string[] = []
|
|
280
|
+
if (muteList) lists.push(muteList)
|
|
281
|
+
if (blockList) lists.push(blockList)
|
|
282
|
+
return lists
|
|
283
|
+
}).flat()
|
|
272
284
|
const lists = await this.services.graph.getListViews(listUris, viewer)
|
|
273
285
|
return { profiles: toMapByDid(profiles), labels, bam, lists }
|
|
274
286
|
}
|
|
@@ -298,6 +310,11 @@ export class ActorViews {
|
|
|
298
310
|
mutedByListUri && lists[mutedByListUri]
|
|
299
311
|
? this.services.graph.formatListViewBasic(lists[mutedByListUri])
|
|
300
312
|
: undefined
|
|
313
|
+
const blockingByListUri = viewer && bam.blockList([viewer, did])
|
|
314
|
+
const blockingByList =
|
|
315
|
+
blockingByListUri && lists[blockingByListUri]
|
|
316
|
+
? this.services.graph.formatListViewBasic(lists[blockingByListUri])
|
|
317
|
+
: undefined
|
|
301
318
|
const actorLabels = labels[did] ?? []
|
|
302
319
|
const selfLabels = getSelfLabels({
|
|
303
320
|
uri: prof.profileUri,
|
|
@@ -320,6 +337,7 @@ export class ActorViews {
|
|
|
320
337
|
mutedByList,
|
|
321
338
|
blockedBy: !!bam.blockedBy([viewer, did]),
|
|
322
339
|
blocking: bam.blocking([viewer, did]) ?? undefined,
|
|
340
|
+
blockingByList,
|
|
323
341
|
following:
|
|
324
342
|
prof?.viewerFollowing && !bam.block([viewer, did])
|
|
325
343
|
? prof.viewerFollowing
|
|
@@ -267,28 +267,44 @@ export type RelationshipPair = [didA: string, didB: string]
|
|
|
267
267
|
export class BlockAndMuteState {
|
|
268
268
|
hasIdx = new Map<string, Set<string>>() // did -> did
|
|
269
269
|
blockIdx = new Map<string, Map<string, string>>() // did -> did -> block uri
|
|
270
|
+
blockListIdx = new Map<string, Map<string, string>>() // did -> did -> list uri
|
|
270
271
|
muteIdx = new Map<string, Set<string>>() // did -> did
|
|
271
272
|
muteListIdx = new Map<string, Map<string, string>>() // did -> did -> list uri
|
|
272
273
|
constructor(items: BlockAndMuteInfo[] = []) {
|
|
273
274
|
items.forEach((item) => this.add(item))
|
|
274
275
|
}
|
|
275
276
|
add(item: BlockAndMuteInfo) {
|
|
276
|
-
|
|
277
|
-
|
|
277
|
+
if (item.source === item.target) {
|
|
278
|
+
return // we do not respect self-blocks or self-mutes
|
|
279
|
+
}
|
|
280
|
+
if (item.blocking) {
|
|
278
281
|
const map = this.blockIdx.get(item.source) ?? new Map()
|
|
279
|
-
map.set(item.target, blocking)
|
|
282
|
+
map.set(item.target, item.blocking)
|
|
280
283
|
if (!this.blockIdx.has(item.source)) {
|
|
281
284
|
this.blockIdx.set(item.source, map)
|
|
282
285
|
}
|
|
283
286
|
}
|
|
284
|
-
|
|
285
|
-
|
|
287
|
+
if (item.blockingViaList) {
|
|
288
|
+
const map = this.blockListIdx.get(item.source) ?? new Map()
|
|
289
|
+
map.set(item.target, item.blockingViaList)
|
|
290
|
+
if (!this.blockListIdx.has(item.source)) {
|
|
291
|
+
this.blockListIdx.set(item.source, map)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (item.blockedBy) {
|
|
286
295
|
const map = this.blockIdx.get(item.target) ?? new Map()
|
|
287
|
-
map.set(item.source, blockedBy)
|
|
296
|
+
map.set(item.source, item.blockedBy)
|
|
288
297
|
if (!this.blockIdx.has(item.target)) {
|
|
289
298
|
this.blockIdx.set(item.target, map)
|
|
290
299
|
}
|
|
291
300
|
}
|
|
301
|
+
if (item.blockedByViaList) {
|
|
302
|
+
const map = this.blockListIdx.get(item.target) ?? new Map()
|
|
303
|
+
map.set(item.source, item.blockedByViaList)
|
|
304
|
+
if (!this.blockListIdx.has(item.target)) {
|
|
305
|
+
this.blockListIdx.set(item.target, map)
|
|
306
|
+
}
|
|
307
|
+
}
|
|
292
308
|
if (item.muting) {
|
|
293
309
|
const set = this.muteIdx.get(item.source) ?? new Set()
|
|
294
310
|
set.add(item.target)
|
|
@@ -314,7 +330,7 @@ export class BlockAndMuteState {
|
|
|
314
330
|
}
|
|
315
331
|
// block or list uri
|
|
316
332
|
blocking(pair: RelationshipPair): string | null {
|
|
317
|
-
return this.blockIdx.get(pair[0])?.get(pair[1]) ??
|
|
333
|
+
return this.blockIdx.get(pair[0])?.get(pair[1]) ?? this.blockList(pair)
|
|
318
334
|
}
|
|
319
335
|
// block or list uri
|
|
320
336
|
blockedBy(pair: RelationshipPair): string | null {
|
|
@@ -324,6 +340,9 @@ export class BlockAndMuteState {
|
|
|
324
340
|
return !!this.muteIdx.get(pair[0])?.has(pair[1]) || !!this.muteList(pair)
|
|
325
341
|
}
|
|
326
342
|
// list uri
|
|
343
|
+
blockList(pair: RelationshipPair): string | null {
|
|
344
|
+
return this.blockListIdx.get(pair[0])?.get(pair[1]) ?? null
|
|
345
|
+
}
|
|
327
346
|
muteList(pair: RelationshipPair): string | null {
|
|
328
347
|
return this.muteListIdx.get(pair[0])?.get(pair[1]) ?? null
|
|
329
348
|
}
|
|
@@ -144,24 +144,22 @@ export class IndexingService {
|
|
|
144
144
|
const handle: string | null =
|
|
145
145
|
did === handleToDid ? atpData.handle.toLowerCase() : null
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
: null
|
|
147
|
+
const actorWithHandle =
|
|
148
|
+
handle !== null
|
|
149
|
+
? await this.db.db
|
|
150
|
+
.selectFrom('actor')
|
|
151
|
+
.where('handle', '=', handle)
|
|
152
|
+
.selectAll()
|
|
153
|
+
.executeTakeFirst()
|
|
154
|
+
: null
|
|
156
155
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
156
|
+
// handle contention
|
|
157
|
+
if (handle && actorWithHandle && did !== actorWithHandle.did) {
|
|
158
|
+
await this.db.db
|
|
159
|
+
.updateTable('actor')
|
|
160
|
+
.where('actor.did', '=', actorWithHandle.did)
|
|
161
|
+
.set({ handle: null })
|
|
162
|
+
.execute()
|
|
165
163
|
}
|
|
166
164
|
|
|
167
165
|
const actorInfo = { handle, indexedAt: timestamp }
|
|
@@ -7,7 +7,12 @@ import { ModerationAction, ModerationReport } from '../../db/tables/moderation'
|
|
|
7
7
|
import { ModerationViews } from './views'
|
|
8
8
|
import { ImageUriBuilder } from '../../image/uri'
|
|
9
9
|
import { ImageInvalidator } from '../../image/invalidator'
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
RepoRef,
|
|
12
|
+
RepoBlobRef,
|
|
13
|
+
TAKEDOWN,
|
|
14
|
+
} from '../../lexicon/types/com/atproto/admin/defs'
|
|
15
|
+
import { Main as StrongRef } from '../../lexicon/types/com/atproto/repo/strongRef'
|
|
11
16
|
import { addHoursToDate } from '../../util/date'
|
|
12
17
|
|
|
13
18
|
export class ModerationService {
|
|
@@ -355,7 +360,10 @@ export class ModerationService {
|
|
|
355
360
|
createdBy,
|
|
356
361
|
createdAt,
|
|
357
362
|
reason,
|
|
358
|
-
}: ReversibleModerationAction) {
|
|
363
|
+
}: ReversibleModerationAction): Promise<{
|
|
364
|
+
result: ModerationActionRow
|
|
365
|
+
restored?: TakedownSubjects
|
|
366
|
+
}> {
|
|
359
367
|
this.db.assertTransaction()
|
|
360
368
|
const result = await this.logReverseAction({
|
|
361
369
|
id,
|
|
@@ -364,6 +372,8 @@ export class ModerationService {
|
|
|
364
372
|
reason,
|
|
365
373
|
})
|
|
366
374
|
|
|
375
|
+
let restored: TakedownSubjects | undefined
|
|
376
|
+
|
|
367
377
|
if (
|
|
368
378
|
result.action === TAKEDOWN &&
|
|
369
379
|
result.subjectType === 'com.atproto.admin.defs#repoRef' &&
|
|
@@ -372,6 +382,15 @@ export class ModerationService {
|
|
|
372
382
|
await this.reverseTakedownRepo({
|
|
373
383
|
did: result.subjectDid,
|
|
374
384
|
})
|
|
385
|
+
restored = {
|
|
386
|
+
did: result.subjectDid,
|
|
387
|
+
subjects: [
|
|
388
|
+
{
|
|
389
|
+
$type: 'com.atproto.admin.defs#repoRef',
|
|
390
|
+
did: result.subjectDid,
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
}
|
|
375
394
|
}
|
|
376
395
|
|
|
377
396
|
if (
|
|
@@ -379,12 +398,35 @@ export class ModerationService {
|
|
|
379
398
|
result.subjectType === 'com.atproto.repo.strongRef' &&
|
|
380
399
|
result.subjectUri
|
|
381
400
|
) {
|
|
401
|
+
const uri = new AtUri(result.subjectUri)
|
|
382
402
|
await this.reverseTakedownRecord({
|
|
383
|
-
uri
|
|
403
|
+
uri,
|
|
384
404
|
})
|
|
405
|
+
const did = uri.hostname
|
|
406
|
+
const actionBlobs = await this.db.db
|
|
407
|
+
.selectFrom('moderation_action_subject_blob')
|
|
408
|
+
.where('actionId', '=', id)
|
|
409
|
+
.select('cid')
|
|
410
|
+
.execute()
|
|
411
|
+
restored = {
|
|
412
|
+
did,
|
|
413
|
+
subjects: [
|
|
414
|
+
{
|
|
415
|
+
$type: 'com.atproto.repo.strongRef',
|
|
416
|
+
uri: result.subjectUri,
|
|
417
|
+
cid: result.subjectCid ?? '',
|
|
418
|
+
},
|
|
419
|
+
...actionBlobs.map((row) => ({
|
|
420
|
+
$type: 'com.atproto.admin.defs#repoBlobRef',
|
|
421
|
+
did,
|
|
422
|
+
cid: row.cid,
|
|
423
|
+
recordUri: result.subjectUri,
|
|
424
|
+
})),
|
|
425
|
+
],
|
|
426
|
+
}
|
|
385
427
|
}
|
|
386
428
|
|
|
387
|
-
return result
|
|
429
|
+
return { result, restored }
|
|
388
430
|
}
|
|
389
431
|
|
|
390
432
|
async logReverseAction(
|
|
@@ -410,13 +452,27 @@ export class ModerationService {
|
|
|
410
452
|
return result
|
|
411
453
|
}
|
|
412
454
|
|
|
413
|
-
async takedownRepo(info: {
|
|
455
|
+
async takedownRepo(info: {
|
|
456
|
+
takedownId: number
|
|
457
|
+
did: string
|
|
458
|
+
}): Promise<TakedownSubjects> {
|
|
459
|
+
const { takedownId, did } = info
|
|
414
460
|
await this.db.db
|
|
415
461
|
.updateTable('actor')
|
|
416
|
-
.set({ takedownId
|
|
417
|
-
.where('did', '=',
|
|
462
|
+
.set({ takedownId })
|
|
463
|
+
.where('did', '=', did)
|
|
418
464
|
.where('takedownId', 'is', null)
|
|
419
465
|
.executeTakeFirst()
|
|
466
|
+
|
|
467
|
+
return {
|
|
468
|
+
did,
|
|
469
|
+
subjects: [
|
|
470
|
+
{
|
|
471
|
+
$type: 'com.atproto.admin.defs#repoRef',
|
|
472
|
+
did,
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
}
|
|
420
476
|
}
|
|
421
477
|
|
|
422
478
|
async reverseTakedownRepo(info: { did: string }) {
|
|
@@ -430,26 +486,45 @@ export class ModerationService {
|
|
|
430
486
|
async takedownRecord(info: {
|
|
431
487
|
takedownId: number
|
|
432
488
|
uri: AtUri
|
|
489
|
+
cid: CID
|
|
433
490
|
blobCids?: CID[]
|
|
434
|
-
}) {
|
|
491
|
+
}): Promise<TakedownSubjects> {
|
|
492
|
+
const { takedownId, uri, cid, blobCids } = info
|
|
493
|
+
const did = uri.hostname
|
|
435
494
|
this.db.assertTransaction()
|
|
436
495
|
await this.db.db
|
|
437
496
|
.updateTable('record')
|
|
438
|
-
.set({ takedownId
|
|
439
|
-
.where('uri', '=',
|
|
497
|
+
.set({ takedownId })
|
|
498
|
+
.where('uri', '=', uri.toString())
|
|
440
499
|
.where('takedownId', 'is', null)
|
|
441
500
|
.executeTakeFirst()
|
|
442
|
-
if (
|
|
501
|
+
if (blobCids) {
|
|
443
502
|
await Promise.all(
|
|
444
|
-
|
|
503
|
+
blobCids.map(async (cid) => {
|
|
445
504
|
const paths = ImageUriBuilder.presets.map((id) => {
|
|
446
|
-
const
|
|
447
|
-
return
|
|
505
|
+
const imgUri = this.imgUriBuilder.getPresetUri(id, uri.host, cid)
|
|
506
|
+
return imgUri.replace(this.imgUriBuilder.endpoint, '')
|
|
448
507
|
})
|
|
449
508
|
await this.imgInvalidator.invalidate(cid.toString(), paths)
|
|
450
509
|
}),
|
|
451
510
|
)
|
|
452
511
|
}
|
|
512
|
+
return {
|
|
513
|
+
did,
|
|
514
|
+
subjects: [
|
|
515
|
+
{
|
|
516
|
+
$type: 'com.atproto.repo.strongRef',
|
|
517
|
+
uri: uri.toString(),
|
|
518
|
+
cid: cid.toString(),
|
|
519
|
+
},
|
|
520
|
+
...(blobCids || []).map((cid) => ({
|
|
521
|
+
$type: 'com.atproto.admin.defs#repoBlobRef',
|
|
522
|
+
did,
|
|
523
|
+
cid: cid.toString(),
|
|
524
|
+
recordUri: uri.toString(),
|
|
525
|
+
})),
|
|
526
|
+
],
|
|
527
|
+
}
|
|
453
528
|
}
|
|
454
529
|
|
|
455
530
|
async reverseTakedownRecord(info: { uri: AtUri }) {
|
|
@@ -563,6 +638,11 @@ export class ModerationService {
|
|
|
563
638
|
}
|
|
564
639
|
}
|
|
565
640
|
|
|
641
|
+
export type TakedownSubjects = {
|
|
642
|
+
did: string
|
|
643
|
+
subjects: (RepoRef | RepoBlobRef | StrongRef)[]
|
|
644
|
+
}
|
|
645
|
+
|
|
566
646
|
export type ModerationActionRow = Selectable<ModerationAction>
|
|
567
647
|
export type ReversibleModerationAction = Pick<
|
|
568
648
|
ModerationActionRow,
|
|
@@ -211,6 +211,7 @@ export class ModerationViews {
|
|
|
211
211
|
.selectFrom('moderation_report')
|
|
212
212
|
.where('subjectType', '=', 'com.atproto.repo.strongRef')
|
|
213
213
|
.where('subjectUri', '=', result.uri)
|
|
214
|
+
.leftJoin('actor', 'actor.did', 'moderation_report.subjectDid')
|
|
214
215
|
.orderBy('id', 'desc')
|
|
215
216
|
.selectAll()
|
|
216
217
|
.execute(),
|
|
@@ -419,12 +419,12 @@ Array [
|
|
|
419
419
|
"$type": "app.bsky.embed.images#view",
|
|
420
420
|
"images": Array [
|
|
421
421
|
Object {
|
|
422
|
-
"alt": "tests/
|
|
422
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
423
423
|
"fullsize": "https://bsky.public.url/img/feed_fullsize/plain/user(5)/cids(5)@jpeg",
|
|
424
424
|
"thumb": "https://bsky.public.url/img/feed_thumbnail/plain/user(5)/cids(5)@jpeg",
|
|
425
425
|
},
|
|
426
426
|
Object {
|
|
427
|
-
"alt": "tests/
|
|
427
|
+
"alt": "tests/sample-img/key-alt.jpg",
|
|
428
428
|
"fullsize": "https://bsky.public.url/img/feed_fullsize/plain/user(5)/cids(6)@jpeg",
|
|
429
429
|
"thumb": "https://bsky.public.url/img/feed_thumbnail/plain/user(5)/cids(6)@jpeg",
|
|
430
430
|
},
|
|
@@ -475,7 +475,7 @@ Array [
|
|
|
475
475
|
"$type": "app.bsky.embed.images",
|
|
476
476
|
"images": Array [
|
|
477
477
|
Object {
|
|
478
|
-
"alt": "tests/
|
|
478
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
479
479
|
"image": Object {
|
|
480
480
|
"$type": "blob",
|
|
481
481
|
"mimeType": "image/jpeg",
|
|
@@ -486,7 +486,7 @@ Array [
|
|
|
486
486
|
},
|
|
487
487
|
},
|
|
488
488
|
Object {
|
|
489
|
-
"alt": "tests/
|
|
489
|
+
"alt": "tests/sample-img/key-alt.jpg",
|
|
490
490
|
"image": Object {
|
|
491
491
|
"$type": "blob",
|
|
492
492
|
"mimeType": "image/jpeg",
|
|
@@ -679,12 +679,12 @@ Array [
|
|
|
679
679
|
"$type": "app.bsky.embed.images#view",
|
|
680
680
|
"images": Array [
|
|
681
681
|
Object {
|
|
682
|
-
"alt": "tests/
|
|
682
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
683
683
|
"fullsize": "https://bsky.public.url/img/feed_fullsize/plain/user(5)/cids(5)@jpeg",
|
|
684
684
|
"thumb": "https://bsky.public.url/img/feed_thumbnail/plain/user(5)/cids(5)@jpeg",
|
|
685
685
|
},
|
|
686
686
|
Object {
|
|
687
|
-
"alt": "tests/
|
|
687
|
+
"alt": "tests/sample-img/key-alt.jpg",
|
|
688
688
|
"fullsize": "https://bsky.public.url/img/feed_fullsize/plain/user(5)/cids(6)@jpeg",
|
|
689
689
|
"thumb": "https://bsky.public.url/img/feed_thumbnail/plain/user(5)/cids(6)@jpeg",
|
|
690
690
|
},
|
|
@@ -735,7 +735,7 @@ Array [
|
|
|
735
735
|
"$type": "app.bsky.embed.images",
|
|
736
736
|
"images": Array [
|
|
737
737
|
Object {
|
|
738
|
-
"alt": "tests/
|
|
738
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
739
739
|
"image": Object {
|
|
740
740
|
"$type": "blob",
|
|
741
741
|
"mimeType": "image/jpeg",
|
|
@@ -746,7 +746,7 @@ Array [
|
|
|
746
746
|
},
|
|
747
747
|
},
|
|
748
748
|
Object {
|
|
749
|
-
"alt": "tests/
|
|
749
|
+
"alt": "tests/sample-img/key-alt.jpg",
|
|
750
750
|
"image": Object {
|
|
751
751
|
"$type": "blob",
|
|
752
752
|
"mimeType": "image/jpeg",
|
|
@@ -906,12 +906,12 @@ Array [
|
|
|
906
906
|
"$type": "app.bsky.embed.images#view",
|
|
907
907
|
"images": Array [
|
|
908
908
|
Object {
|
|
909
|
-
"alt": "tests/
|
|
909
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
910
910
|
"fullsize": "https://bsky.public.url/img/feed_fullsize/plain/user(5)/cids(4)@jpeg",
|
|
911
911
|
"thumb": "https://bsky.public.url/img/feed_thumbnail/plain/user(5)/cids(4)@jpeg",
|
|
912
912
|
},
|
|
913
913
|
Object {
|
|
914
|
-
"alt": "tests/
|
|
914
|
+
"alt": "tests/sample-img/key-alt.jpg",
|
|
915
915
|
"fullsize": "https://bsky.public.url/img/feed_fullsize/plain/user(5)/cids(5)@jpeg",
|
|
916
916
|
"thumb": "https://bsky.public.url/img/feed_thumbnail/plain/user(5)/cids(5)@jpeg",
|
|
917
917
|
},
|
|
@@ -962,7 +962,7 @@ Array [
|
|
|
962
962
|
"$type": "app.bsky.embed.images",
|
|
963
963
|
"images": Array [
|
|
964
964
|
Object {
|
|
965
|
-
"alt": "tests/
|
|
965
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
966
966
|
"image": Object {
|
|
967
967
|
"$type": "blob",
|
|
968
968
|
"mimeType": "image/jpeg",
|
|
@@ -973,7 +973,7 @@ Array [
|
|
|
973
973
|
},
|
|
974
974
|
},
|
|
975
975
|
Object {
|
|
976
|
-
"alt": "tests/
|
|
976
|
+
"alt": "tests/sample-img/key-alt.jpg",
|
|
977
977
|
"image": Object {
|
|
978
978
|
"$type": "blob",
|
|
979
979
|
"mimeType": "image/jpeg",
|
|
@@ -101,7 +101,7 @@ Array [
|
|
|
101
101
|
"$type": "app.bsky.embed.images#view",
|
|
102
102
|
"images": Array [
|
|
103
103
|
Object {
|
|
104
|
-
"alt": "tests/
|
|
104
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
105
105
|
"fullsize": "https://bsky.public.url/img/feed_fullsize/plain/user(2)/cids(5)@jpeg",
|
|
106
106
|
"thumb": "https://bsky.public.url/img/feed_thumbnail/plain/user(2)/cids(5)@jpeg",
|
|
107
107
|
},
|
|
@@ -134,7 +134,7 @@ Array [
|
|
|
134
134
|
"$type": "app.bsky.embed.images",
|
|
135
135
|
"images": Array [
|
|
136
136
|
Object {
|
|
137
|
-
"alt": "tests/
|
|
137
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
138
138
|
"image": Object {
|
|
139
139
|
"$type": "blob",
|
|
140
140
|
"mimeType": "image/jpeg",
|
|
@@ -245,7 +245,7 @@ Array [
|
|
|
245
245
|
"$type": "app.bsky.embed.images",
|
|
246
246
|
"images": Array [
|
|
247
247
|
Object {
|
|
248
|
-
"alt": "tests/
|
|
248
|
+
"alt": "tests/sample-img/key-landscape-small.jpg",
|
|
249
249
|
"image": Object {
|
|
250
250
|
"$type": "blob",
|
|
251
251
|
"mimeType": "image/jpeg",
|
|
@@ -256,7 +256,7 @@ Array [
|
|
|
256
256
|
},
|
|
257
257
|
},
|
|
258
258
|
Object {
|
|
259
|
-
"alt": "tests/
|
|
259
|
+
"alt": "tests/sample-img/key-alt.jpg",
|
|
260
260
|
"image": Object {
|
|
261
261
|
"$type": "blob",
|
|
262
262
|
"mimeType": "image/jpeg",
|