Skip to content

Commit

Permalink
✨ Allow creating labels with expiry (#3476)
Browse files Browse the repository at this point in the history
* ✨ Allow creating labels with expiry

* 🧹 Cleanup
  • Loading branch information
foysalit authored Jan 31, 2025
1 parent 8fd5dce commit d377d1a
Show file tree
Hide file tree
Showing 11 changed files with 64 additions and 5 deletions.
4 changes: 4 additions & 0 deletions lexicons/tools/ozone/moderation/defs.json
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@
"negateLabelVals": {
"type": "array",
"items": { "type": "string" }
},
"durationInHours": {
"type": "integer",
"description": "Indicates how long the label will remain on the subject. Only applies on labels that are being added."
}
}
},
Expand Down
5 changes: 5 additions & 0 deletions packages/api/src/client/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11549,6 +11549,11 @@ export const schemaDict = {
type: 'string',
},
},
durationInHours: {
type: 'integer',
description:
'Indicates how long the label will remain on the subject. Only applies on labels that are being added.',
},
},
},
modEventAcknowledge: {
Expand Down
2 changes: 2 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 @@ -347,6 +347,8 @@ export interface ModEventLabel {
comment?: string
createLabelVals: string[]
negateLabelVals: string[]
/** Indicates how long the label will remain on the subject. Only applies on labels that are being added. */
durationInHours?: number
[k: string]: unknown
}

Expand Down
1 change: 1 addition & 0 deletions packages/ozone/src/api/moderation/emitEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ const handleModerationEvent = async ({
? result.event.negateLabelVals.split(' ')
: undefined,
},
result.event.durationInHours ?? undefined,
)
}

Expand Down
5 changes: 5 additions & 0 deletions packages/ozone/src/lexicon/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11549,6 +11549,11 @@ export const schemaDict = {
type: 'string',
},
},
durationInHours: {
type: 'integer',
description:
'Indicates how long the label will remain on the subject. Only applies on labels that are being added.',
},
},
},
modEventAcknowledge: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ export interface ModEventLabel {
comment?: string
createLabelVals: string[]
negateLabelVals: string[]
/** Indicates how long the label will remain on the subject. Only applies on labels that are being added. */
durationInHours?: number
[k: string]: unknown
}

Expand Down
6 changes: 6 additions & 0 deletions packages/ozone/src/mod-service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1159,13 +1159,19 @@ export class ModerationService {
uri: string,
cid: string | null,
labels: { create?: string[]; negate?: string[] },
durationInHours?: number,
): Promise<Label[]> {
const exp =
durationInHours !== undefined
? addHoursToDate(durationInHours).toISOString()
: undefined
const { create = [], negate = [] } = labels
const toCreate = create.map((val) => ({
src: this.cfg.service.did,
uri,
cid: cid ?? undefined,
val,
exp,
cts: new Date().toISOString(),
}))
const toNegate = negate.map((val) => ({
Expand Down
1 change: 1 addition & 0 deletions packages/ozone/src/mod-service/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export class ModerationViews {
[
'tools.ozone.moderation.defs#modEventMuteReporter',
'tools.ozone.moderation.defs#modEventTakedown',
'tools.ozone.moderation.defs#modEventLabel',
'tools.ozone.moderation.defs#modEventMute',
].includes(event.action)
) {
Expand Down
36 changes: 31 additions & 5 deletions packages/ozone/tests/moderation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { EventReverser } from '../src'
import { ImageInvalidator } from '../src/image-invalidator'
import { TAKEDOWN_LABEL } from '../src/mod-service'
import { ids } from '../src/lexicon/lexicons'
import { HOUR } from '@atproto/common'

describe('moderation', () => {
let network: TestNetwork
Expand Down Expand Up @@ -514,6 +515,24 @@ describe('moderation', () => {
await expect(getRepoLabels(sc.dids.bob)).resolves.toEqual(['kittens'])
})

it('creates expiring label', async () => {
await emitLabelEvent({
createLabelVals: ['temp'],
negateLabelVals: [],
subject: {
$type: 'com.atproto.admin.defs#repoRef',
did: sc.dids.bob,
},
durationInHours: 24,
})
const repo = await getRepo(sc.dids.bob)
// Losely check that the expiry date is set to above 23 hours from now
expect(
`${repo?.labels?.[0].exp}` >
new Date(Date.now() + 23 * HOUR).toISOString(),
).toBeTruthy()
})

it('does not allow triage moderators to label.', async () => {
const attemptLabel = modClient.emitEvent(
{
Expand Down Expand Up @@ -708,14 +727,16 @@ describe('moderation', () => {
subject: ToolsOzoneModerationEmitEvent.InputSchema['subject']
createLabelVals: ModEventLabel['createLabelVals']
negateLabelVals: ModEventLabel['negateLabelVals']
durationInHours?: ModEventLabel['durationInHours']
},
) {
const { createLabelVals, negateLabelVals } = opts
const { createLabelVals, negateLabelVals, durationInHours } = opts
const result = await modClient.emitEvent({
event: {
$type: 'tools.ozone.moderation.defs#modEventLabel',
createLabelVals,
negateLabelVals,
durationInHours,
},
createdBy: 'did:example:admin',
reason: 'Y',
Expand All @@ -740,7 +761,7 @@ describe('moderation', () => {
}

async function getRecordLabels(uri: string) {
const result = await agent.api.tools.ozone.moderation.getRecord(
const result = await agent.tools.ozone.moderation.getRecord(
{ uri },
{
headers: await network.ozone.modHeaders(
Expand All @@ -752,16 +773,21 @@ describe('moderation', () => {
return labels.map((l) => l.val)
}

async function getRepoLabels(did: string) {
const result = await agent.api.tools.ozone.moderation.getRepo(
async function getRepo(did: string) {
const result = await agent.tools.ozone.moderation.getRepo(
{ did },
{
headers: await network.ozone.modHeaders(
ids.ToolsOzoneModerationGetRepo,
),
},
)
const labels = result.data.labels ?? []
return result.data
}

async function getRepoLabels(did: string) {
const result = await getRepo(did)
const labels = result.labels ?? []
return labels.map((l) => l.val)
}
})
Expand Down
5 changes: 5 additions & 0 deletions packages/pds/src/lexicon/lexicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11549,6 +11549,11 @@ export const schemaDict = {
type: 'string',
},
},
durationInHours: {
type: 'integer',
description:
'Indicates how long the label will remain on the subject. Only applies on labels that are being added.',
},
},
},
modEventAcknowledge: {
Expand Down
2 changes: 2 additions & 0 deletions packages/pds/src/lexicon/types/tools/ozone/moderation/defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ export interface ModEventLabel {
comment?: string
createLabelVals: string[]
negateLabelVals: string[]
/** Indicates how long the label will remain on the subject. Only applies on labels that are being added. */
durationInHours?: number
[k: string]: unknown
}

Expand Down

0 comments on commit d377d1a

Please sign in to comment.