Skip to content

Commit

Permalink
✨ Allow searching reports by moderator did (#1283)
Browse files Browse the repository at this point in the history
* ✨ Allow searching reports by moderator did

* ✅ Remove .only flags on tests

* ✅ Update snapshot

* ✅ Add checks for did match in actions
  • Loading branch information
foysalit authored Jul 14, 2023
1 parent 53c4956 commit b9ca76f
Show file tree
Hide file tree
Showing 13 changed files with 151 additions and 15 deletions.
5 changes: 5 additions & 0 deletions lexicons/com/atproto/admin/getModerationReports.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
"properties": {
"subject": { "type": "string" },
"ignoreSubjects": { "type": "array", "items": { "type": "string" } },
"actionedBy": {
"type": "string",
"format": "did",
"description": "Get all reports that were actioned by a specific moderator"
},
"reporters": {
"type": "array",
"items": { "type": "string" },
Expand Down
8 changes: 7 additions & 1 deletion packages/api/src/client/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,12 @@ export const schemaDict = {
type: 'string',
},
},
actionedBy: {
type: 'string',
format: 'did',
description:
'Get all reports that were actioned by a specific moderator',
},
reporters: {
type: 'array',
items: {
Expand Down Expand Up @@ -6327,7 +6333,7 @@ export const schemaDict = {
defs: {
main: {
type: 'query',
description: 'A skeleton of a timeline',
description: 'A skeleton of a timeline - UNSPECCED & WILL GO AWAY SOON',
parameters: {
type: 'params',
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import * as ComAtprotoAdminDefs from './defs'
export interface QueryParams {
subject?: string
ignoreSubjects?: string[]
/** Get all reports that were actioned by a specific moderator */
actionedBy?: string
/** Filter reports made by one or more DIDs */
reporters?: string[]
resolved?: boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default function (server: Server, ctx: AppContext) {
ignoreSubjects,
reverse = false,
reporters = [],
actionedBy,
} = params
const moderationService = services.moderation(db)
const results = await moderationService.getReports({
Expand All @@ -26,6 +27,7 @@ export default function (server: Server, ctx: AppContext) {
ignoreSubjects,
reverse,
reporters,
actionedBy,
})
return {
encoding: 'application/json',
Expand Down
8 changes: 7 additions & 1 deletion packages/bsky/src/lexicon/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,12 @@ export const schemaDict = {
type: 'string',
},
},
actionedBy: {
type: 'string',
format: 'did',
description:
'Get all reports that were actioned by a specific moderator',
},
reporters: {
type: 'array',
items: {
Expand Down Expand Up @@ -6327,7 +6333,7 @@ export const schemaDict = {
defs: {
main: {
type: 'query',
description: 'A skeleton of a timeline',
description: 'A skeleton of a timeline - UNSPECCED & WILL GO AWAY SOON',
parameters: {
type: 'params',
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import * as ComAtprotoAdminDefs from './defs'
export interface QueryParams {
subject?: string
ignoreSubjects?: string[]
/** Get all reports that were actioned by a specific moderator */
actionedBy?: string
/** Filter reports made by one or more DIDs */
reporters?: string[]
resolved?: boolean
Expand Down
26 changes: 20 additions & 6 deletions packages/bsky/src/services/moderation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export class ModerationService {
ignoreSubjects?: string[]
reverse?: boolean
reporters?: string[]
actionedBy?: string
}): Promise<ModerationReportRowWithHandle[]> {
const {
subject,
Expand All @@ -94,6 +95,7 @@ export class ModerationService {
ignoreSubjects,
reverse = false,
reporters,
actionedBy,
} = opts
const { ref } = this.db.db.dynamic
let builder = this.db.db.selectFrom('moderation_report')
Expand Down Expand Up @@ -148,8 +150,8 @@ export class ModerationService {
? builder.whereExists(resolutionsQuery)
: builder.whereNotExists(resolutionsQuery)
}
if (actionType !== undefined) {
const resolutionActionsQuery = this.db.db
if (actionType !== undefined || actionedBy !== undefined) {
let resolutionActionsQuery = this.db.db
.selectFrom('moderation_report_resolution')
.innerJoin(
'moderation_action',
Expand All @@ -161,10 +163,22 @@ export class ModerationService {
'=',
ref('moderation_report.id'),
)
.where('moderation_action.action', '=', sql`${actionType}`)
.where('moderation_action.reversedAt', 'is', null)
.selectAll()
builder = builder.whereExists(resolutionActionsQuery)

if (actionType) {
resolutionActionsQuery = resolutionActionsQuery
.where('moderation_action.action', '=', sql`${actionType}`)
.where('moderation_action.reversedAt', 'is', null)
}

if (actionedBy) {
resolutionActionsQuery = resolutionActionsQuery.where(
'moderation_action.createdBy',
'=',
actionedBy,
)
}

builder = builder.whereExists(resolutionActionsQuery.selectAll())
}
if (cursor) {
const cursorNumeric = parseInt(cursor, 10)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export default function (server: Server, ctx: AppContext) {
ignoreSubjects = [],
reverse = false,
reporters = [],
actionedBy,
} = params
const moderationService = services.moderation(db)
const results = await moderationService.getReports({
Expand All @@ -26,6 +27,7 @@ export default function (server: Server, ctx: AppContext) {
ignoreSubjects,
reverse,
reporters,
actionedBy,
})
return {
encoding: 'application/json',
Expand Down
8 changes: 7 additions & 1 deletion packages/pds/src/lexicon/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,12 @@ export const schemaDict = {
type: 'string',
},
},
actionedBy: {
type: 'string',
format: 'did',
description:
'Get all reports that were actioned by a specific moderator',
},
reporters: {
type: 'array',
items: {
Expand Down Expand Up @@ -6327,7 +6333,7 @@ export const schemaDict = {
defs: {
main: {
type: 'query',
description: 'A skeleton of a timeline',
description: 'A skeleton of a timeline - UNSPECCED & WILL GO AWAY SOON',
parameters: {
type: 'params',
properties: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import * as ComAtprotoAdminDefs from './defs'
export interface QueryParams {
subject?: string
ignoreSubjects?: string[]
/** Get all reports that were actioned by a specific moderator */
actionedBy?: string
/** Filter reports made by one or more DIDs */
reporters?: string[]
resolved?: boolean
Expand Down
26 changes: 20 additions & 6 deletions packages/pds/src/services/moderation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export class ModerationService {
ignoreSubjects?: string[]
reverse?: boolean
reporters?: string[]
actionedBy?: string
}): Promise<ModerationReportRowWithHandle[]> {
const {
subject,
Expand All @@ -112,6 +113,7 @@ export class ModerationService {
ignoreSubjects,
reverse = false,
reporters,
actionedBy,
} = opts
const { ref } = this.db.db.dynamic
let builder = this.db.db.selectFrom('moderation_report')
Expand Down Expand Up @@ -166,8 +168,8 @@ export class ModerationService {
? builder.whereExists(resolutionsQuery)
: builder.whereNotExists(resolutionsQuery)
}
if (actionType !== undefined) {
const resolutionActionsQuery = this.db.db
if (actionType !== undefined || actionedBy !== undefined) {
let resolutionActionsQuery = this.db.db
.selectFrom('moderation_report_resolution')
.innerJoin(
'moderation_action',
Expand All @@ -179,10 +181,22 @@ export class ModerationService {
'=',
ref('moderation_report.id'),
)
.where('moderation_action.action', '=', sql`${actionType}`)
.where('moderation_action.reversedAt', 'is', null)
.selectAll()
builder = builder.whereExists(resolutionActionsQuery)

if (actionType) {
resolutionActionsQuery = resolutionActionsQuery
.where('moderation_action.action', '=', sql`${actionType}`)
.where('moderation_action.reversedAt', 'is', null)
}

if (actionedBy) {
resolutionActionsQuery = resolutionActionsQuery.where(
'moderation_action.createdBy',
'=',
actionedBy,
)
}

builder = builder.whereExists(resolutionActionsQuery.selectAll())
}

if (cursor) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`pds admin get moderation reports view gets all moderation reports actioned by a certain moderator. 1`] = `
Array [
Object {
"createdAt": "1970-01-01T00:00:00.000Z",
"id": 1,
"reasonType": "com.atproto.moderation.defs#reasonOther",
"reportedBy": "user(0)",
"resolvedByActionIds": Array [
2,
],
"subject": Object {
"$type": "com.atproto.repo.strongRef",
"cid": "cids(0)",
"uri": "record(0)",
},
"subjectRepoHandle": "alice.test",
},
]
`;

exports[`pds admin get moderation reports view gets all moderation reports actioned by a certain moderator. 2`] = `
Array [
Object {
"createdAt": "1970-01-01T00:00:00.000Z",
"id": 3,
"reasonType": "com.atproto.moderation.defs#reasonOther",
"reportedBy": "user(0)",
"resolvedByActionIds": Array [
4,
],
"subject": Object {
"$type": "com.atproto.repo.strongRef",
"cid": "cids(0)",
"uri": "record(0)",
},
"subjectRepoHandle": "bob.test",
},
]
`;

exports[`pds admin get moderation reports view gets all moderation reports by active resolution action type. 1`] = `
Array [
Object {
Expand Down
35 changes: 35 additions & 0 deletions packages/pds/tests/views/admin/get-moderation-reports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ describe('pds admin get moderation reports view', () => {
uri: report.subject.uri,
cid: report.subject.cid,
},
createdBy: `did:example:admin${i}`,
})
if (ab) {
await sc.resolveReports({
Expand Down Expand Up @@ -241,6 +242,40 @@ describe('pds admin get moderation reports view', () => {
expect(forSnapshot(reportsWithTakedown.data.reports)).toMatchSnapshot()
})

it('gets all moderation reports actioned by a certain moderator.', async () => {
const adminDidOne = 'did:example:admin0'
const adminDidTwo = 'did:example:admin2'
const [actionedByAdminOne, actionedByAdminTwo] = await Promise.all([
agent.api.com.atproto.admin.getModerationReports(
{ actionedBy: adminDidOne },
{ headers: { authorization: adminAuth() } },
),
agent.api.com.atproto.admin.getModerationReports(
{ actionedBy: adminDidTwo },
{ headers: { authorization: adminAuth() } },
),
])
const [fullReportOne, fullReportTwo] = await Promise.all([
agent.api.com.atproto.admin.getModerationReport(
{ id: actionedByAdminOne.data.reports[0].id },
{ headers: { authorization: adminAuth() } },
),
agent.api.com.atproto.admin.getModerationReport(
{ id: actionedByAdminTwo.data.reports[0].id },
{ headers: { authorization: adminAuth() } },
),
])

expect(forSnapshot(actionedByAdminOne.data.reports)).toMatchSnapshot()
expect(fullReportOne.data.resolvedByActions[0].createdBy).toEqual(
adminDidOne,
)
expect(forSnapshot(actionedByAdminTwo.data.reports)).toMatchSnapshot()
expect(fullReportTwo.data.resolvedByActions[0].createdBy).toEqual(
adminDidTwo,
)
})

it('paginates.', async () => {
const results = (results) => results.flatMap((res) => res.reports)
const paginator = async (cursor?: string) => {
Expand Down

0 comments on commit b9ca76f

Please sign in to comment.