Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
matthieusieben committed Dec 12, 2024
1 parent 9fd65ba commit 19b7605
Show file tree
Hide file tree
Showing 15 changed files with 345 additions and 158 deletions.
10 changes: 9 additions & 1 deletion lexicons/tools/ozone/moderation/defs.json
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,15 @@
"tags": {
"type": "array",
"items": { "type": "string" }
}
},
"accountSuspended": { "type": "boolean" },
"accountTakendown": { "type": "boolean" },
"accountLabels": { "type": "array", "items": { "type": "string" } },
"recordsReported": { "type": "integer" },
"recordsReportsOpen": { "type": "integer" },
"recordsReportsClosed": { "type": "integer" },
"recordsTakendown": { "type": "integer" },
"recordsLabeled": { "type": "integer" }
}
},
"subjectReviewState": {
Expand Down
27 changes: 27 additions & 0 deletions packages/api/src/client/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11179,6 +11179,33 @@ export const schemaDict = {
type: 'string',
},
},
accountSuspended: {
type: 'boolean',
},
accountTakendown: {
type: 'boolean',
},
accountLabels: {
type: 'array',
items: {
type: 'string',
},
},
recordsReported: {
type: 'integer',
},
recordsReportsOpen: {
type: 'integer',
},
recordsReportsClosed: {
type: 'integer',
},
recordsTakendown: {
type: 'integer',
},
recordsLabeled: {
type: 'integer',
},
},
},
subjectReviewState: {
Expand Down
8 changes: 8 additions & 0 deletions packages/api/src/client/types/tools/ozone/moderation/defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ export interface SubjectStatusView {
appealed?: boolean
suspendUntil?: string
tags?: string[]
accountSuspended?: boolean
accountTakendown?: boolean
accountLabels?: string[]
recordsReported?: number
recordsReportsOpen?: number
recordsReportsClosed?: number
recordsTakendown?: number
recordsLabeled?: number
[k: string]: unknown
}

Expand Down
4 changes: 2 additions & 2 deletions packages/oauth/oauth-client-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
"directory": "packages/oauth/oauth-client-browser"
},
"type": "commonjs",
"main": "dist/index.js",
"main": "dist/index.cjs",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
"default": "./dist/index.cjs"
}
},
"files": [
Expand Down
6 changes: 3 additions & 3 deletions packages/ozone/src/api/moderation/queryStatuses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export default function (server: Server, ctx: AppContext) {
onlyMuted = false,
limit = 50,
cursor,
tags = [],
excludeTags = [],
collections = [],
tags,
excludeTags,
collections,
subjectType,
} = params
const db = ctx.db
Expand Down
2 changes: 1 addition & 1 deletion packages/ozone/src/daemon/event-reverser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class EventReverser {

// We shouldn't have too many actions due for reversal at any given time, so running in parallel is probably fine
// Internally, each reversal runs within its own transaction
await Promise.all(subjectsDueForReversal.map(this.revertState.bind(this)))
await Promise.all(subjectsDueForReversal.map(this.revertState, this))
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/ozone/src/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class Database {

this.pool = pool
this.db = new Kysely<DatabaseSchemaType>({
log: ['query', 'error'],
dialect: new PostgresDialect({ pool }),
})
}
Expand Down
27 changes: 27 additions & 0 deletions packages/ozone/src/lexicon/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11179,6 +11179,33 @@ export const schemaDict = {
type: 'string',
},
},
accountSuspended: {
type: 'boolean',
},
accountTakendown: {
type: 'boolean',
},
accountLabels: {
type: 'array',
items: {
type: 'string',
},
},
recordsReported: {
type: 'integer',
},
recordsReportsOpen: {
type: 'integer',
},
recordsReportsClosed: {
type: 'integer',
},
recordsTakendown: {
type: 'integer',
},
recordsLabeled: {
type: 'integer',
},
},
},
subjectReviewState: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ export interface SubjectStatusView {
appealed?: boolean
suspendUntil?: string
tags?: string[]
accountSuspended?: boolean
accountTakendown?: boolean
accountLabels?: string[]
recordsReported?: number
recordsReportsOpen?: number
recordsReportsClosed?: number
recordsTakendown?: number
recordsLabeled?: number
[k: string]: unknown
}

Expand Down
112 changes: 46 additions & 66 deletions packages/ozone/src/mod-service/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import net from 'node:net'
import { Insertable, sql } from 'kysely'
import { CID } from 'multiformats/cid'
import { AtUri, INVALID_HANDLE } from '@atproto/syntax'
import { InvalidRequestError } from '@atproto/xrpc-server'
import { addHoursToDate, chunkArray } from '@atproto/common'
Expand Down Expand Up @@ -29,6 +28,7 @@ import { RepoRef, RepoBlobRef } from '../lexicon/types/com/atproto/admin/defs'
import {
adjustModerationSubjectStatus,
getStatusIdentifierFromSubject,
moderationSubjectStatusQueryBuilder,
} from './status'
import {
ModEventType,
Expand Down Expand Up @@ -302,19 +302,6 @@ export class ModerationService {
.executeTakeFirst()
}

async getCurrentStatus(
subject: { did: string } | { uri: AtUri } | { cids: CID[] },
) {
let builder = this.db.db.selectFrom('moderation_subject_status').selectAll()
if ('did' in subject) {
builder = builder.where('did', '=', subject.did)
} else if ('uri' in subject) {
builder = builder.where('recordPath', '=', subject.uri.toString())
}
// TODO: Handle the cid status
return await builder.execute()
}

async resolveSubjectsForAccount(
did: string,
createdBy: string,
Expand Down Expand Up @@ -841,146 +828,139 @@ export class ModerationService {
sortDirection: 'asc' | 'desc'
lastReviewedBy?: string
sortField: 'lastReviewedAt' | 'lastReportedAt'
tags: string[]
excludeTags: string[]
collections: string[]
tags?: string[]
excludeTags?: string[]
collections?: string[]
subjectType?: string
}) {
let builder = this.db.db.selectFrom('moderation_subject_status').selectAll()
let builder = moderationSubjectStatusQueryBuilder(this.db.db)

const { ref } = this.db.db.dynamic

if (subject) {
const subjectInfo = getStatusIdentifierFromSubject(subject)
builder = builder.where(
'moderation_subject_status.did',
'=',
subjectInfo.did,
)
builder = builder.where('mss.did', '=', subjectInfo.did)

if (!includeAllUserRecords) {
builder = builder.where((qb) =>
subjectInfo.recordPath
? qb.where('recordPath', '=', subjectInfo.recordPath)
: qb.where('recordPath', '=', ''),
? qb.where('mss.recordPath', '=', subjectInfo.recordPath)
: qb.where('mss.recordPath', '=', ''),
)
}
} else if (subjectType === 'account') {
builder = builder.where('recordPath', '=', '')
builder = builder.where('mss.recordPath', '=', '')
} else if (subjectType === 'record') {
builder = builder.where('recordPath', '!=', '')
builder = builder.where('mss.recordPath', '!=', '')
}

// If subjectType is set to 'account' let that take priority and ignore collections filter
if (collections.length && subjectType !== 'account') {
builder = builder.where('recordPath', '!=', '').where((qb) => {
collections.forEach((collection) => {
qb = qb.orWhere('recordPath', 'like', `${collection}/%`)
})
return qb
})
if (subjectType !== 'account' && collections?.length) {
builder = builder
.where('mss.recordPath', '!=', '')
.where((qb) =>
collections.reduce(
(qb, collection) =>
qb.orWhere('mss.recordPath', 'like', `${collection}/%`),
qb.where(sql`false`),
),
)
}

if (ignoreSubjects?.length) {
builder = builder
.where('did', 'not in', ignoreSubjects)
.where('recordPath', 'not in', ignoreSubjects)
.where('mss.did', 'not in', ignoreSubjects)
.where('mss.recordPath', 'not in', ignoreSubjects)
}

if (reviewState) {
builder = builder.where('reviewState', '=', reviewState)
builder = builder.where('mss.reviewState', '=', reviewState)
}

if (lastReviewedBy) {
builder = builder.where('lastReviewedBy', '=', lastReviewedBy)
builder = builder.where('mss.lastReviewedBy', '=', lastReviewedBy)
}

if (reviewedAfter) {
builder = builder.where('lastReviewedAt', '>', reviewedAfter)
builder = builder.where('mss.lastReviewedAt', '>', reviewedAfter)
}

if (reviewedBefore) {
builder = builder.where('lastReviewedAt', '<', reviewedBefore)
builder = builder.where('mss.lastReviewedAt', '<', reviewedBefore)
}

if (hostingUpdatedAfter) {
builder = builder.where('hostingUpdatedAt', '>', hostingUpdatedAfter)
builder = builder.where('mss.hostingUpdatedAt', '>', hostingUpdatedAfter)
}

if (hostingUpdatedBefore) {
builder = builder.where('hostingUpdatedAt', '<', hostingUpdatedBefore)
builder = builder.where('mss.hostingUpdatedAt', '<', hostingUpdatedBefore)
}

if (hostingDeletedAfter) {
builder = builder.where('hostingDeletedAt', '>', hostingDeletedAfter)
builder = builder.where('mss.hostingDeletedAt', '>', hostingDeletedAfter)
}

if (hostingDeletedBefore) {
builder = builder.where('hostingDeletedAt', '<', hostingDeletedBefore)
builder = builder.where('mss.hostingDeletedAt', '<', hostingDeletedBefore)
}

if (hostingStatuses?.length) {
builder = builder.where('hostingStatus', 'in', hostingStatuses)
builder = builder.where('mss.hostingStatus', 'in', hostingStatuses)
}

if (reportedAfter) {
builder = builder.where('lastReviewedAt', '>', reportedAfter)
builder = builder.where('mss.lastReviewedAt', '>', reportedAfter)
}

if (reportedBefore) {
builder = builder.where('lastReportedAt', '<', reportedBefore)
builder = builder.where('mss.lastReportedAt', '<', reportedBefore)
}

if (takendown) {
builder = builder.where('takendown', '=', true)
builder = builder.where('mss.takendown', '=', true)
}

if (appealed !== undefined) {
builder =
appealed === false
? builder.where('appealed', 'is', null)
: builder.where('appealed', '=', appealed)
? builder.where('mss.appealed', 'is', null)
: builder.where('mss.appealed', '=', appealed)
}

if (!includeMuted) {
builder = builder.where((qb) =>
qb
.where('muteUntil', '<', new Date().toISOString())
.orWhere('muteUntil', 'is', null),
.where('mss.muteUntil', '<', new Date().toISOString())
.orWhere('mss.muteUntil', 'is', null),
)
}

if (onlyMuted) {
builder = builder.where((qb) =>
qb
.where('muteUntil', '>', new Date().toISOString())
.orWhere('muteReportingUntil', '>', new Date().toISOString()),
.where('mss.muteUntil', '>', new Date().toISOString())
.orWhere('mss.muteReportingUntil', '>', new Date().toISOString()),
)
}

if (tags.length) {
if (tags?.length) {
builder = builder.where(
sql`${ref('moderation_subject_status.tags')} ?| array[${sql.join(
tags,
)}]::TEXT[]`,
sql`${ref('mss.tags')} ?| array[${sql.join(tags)}]::TEXT[]`,
)
}

if (excludeTags.length) {
if (excludeTags?.length) {
builder = builder.where((qb) =>
qb
.where(
sql`NOT(${ref(
'moderation_subject_status.tags',
)} ?| array[${sql.join(excludeTags)}]::TEXT[])`,
sql`NOT(${ref('mss.tags')} ?| array[${sql.join(excludeTags)}]::TEXT[])`,
)
.orWhere('tags', 'is', null),
)
}

const keyset = new StatusKeyset(
ref(`moderation_subject_status.${sortField}`),
ref('moderation_subject_status.id'),
)
const keyset = new StatusKeyset(ref(`mss.${sortField}`), ref('mss.id'))
const paginatedBuilder = paginate(builder, {
limit,
cursor,
Expand Down
Loading

0 comments on commit 19b7605

Please sign in to comment.