@atproto/ozone 0.1.166 → 0.1.167
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 +11 -0
- package/dist/api/moderation/emitEvent.d.ts.map +1 -1
- package/dist/api/moderation/emitEvent.js +8 -0
- package/dist/api/moderation/emitEvent.js.map +1 -1
- package/dist/api/util.d.ts +1 -1
- package/dist/api/util.d.ts.map +1 -1
- package/dist/api/util.js +1 -0
- package/dist/api/util.js.map +1 -1
- package/dist/db/schema/moderation_event.d.ts +1 -1
- package/dist/db/schema/moderation_event.d.ts.map +1 -1
- package/dist/db/schema/moderation_event.js.map +1 -1
- package/dist/lexicon/lexicons.d.ts +30 -6
- package/dist/lexicon/lexicons.d.ts.map +1 -1
- package/dist/lexicon/lexicons.js +15 -0
- package/dist/lexicon/lexicons.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts +10 -2
- package/dist/lexicon/types/tools/ozone/moderation/defs.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/defs.js +9 -0
- package/dist/lexicon/types/tools/ozone/moderation/defs.js.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/emitEvent.d.ts +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/emitEvent.d.ts.map +1 -1
- package/dist/lexicon/types/tools/ozone/moderation/emitEvent.js.map +1 -1
- package/dist/mod-service/index.d.ts +3 -2
- package/dist/mod-service/index.d.ts.map +1 -1
- package/dist/mod-service/index.js +11 -0
- package/dist/mod-service/index.js.map +1 -1
- package/dist/mod-service/status.d.ts.map +1 -1
- package/dist/mod-service/status.js +7 -0
- package/dist/mod-service/status.js.map +1 -1
- package/package.json +6 -6
- package/src/api/moderation/emitEvent.ts +17 -1
- package/src/api/util.ts +1 -0
- package/src/db/schema/moderation_event.ts +1 -0
- package/src/lexicon/lexicons.ts +16 -0
- package/src/lexicon/types/tools/ozone/moderation/defs.ts +19 -0
- package/src/lexicon/types/tools/ozone/moderation/emitEvent.ts +1 -0
- package/src/mod-service/index.ts +14 -0
- package/src/mod-service/status.ts +8 -0
- package/tests/__snapshots__/get-starter-pack.test.ts.snap +9 -9
- package/tests/__snapshots__/get-subjects.test.ts.snap +2 -2
- package/tests/__snapshots__/team.test.ts.snap +4 -4
- package/tests/__snapshots__/verification-listener.test.ts.snap +2 -2
- package/tests/__snapshots__/verification.test.ts.snap +3 -3
- package/tests/_util.ts +6 -4
- package/tests/age-assurance.test.ts +134 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/mod-service/status.ts"],"names":[],"mappings":"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","sourcesContent":["// This may require better organization but for now, just dumping functions here containing DB queries for moderation status\n\nimport { HOUR } from '@atproto/common'\nimport { AtUri } from '@atproto/syntax'\nimport { isAppealReport } from '../api/util'\nimport { Database } from '../db'\nimport { DatabaseSchema } from '../db/schema'\nimport { jsonb } from '../db/types'\nimport {\n REVIEWCLOSED,\n REVIEWESCALATED,\n REVIEWNONE,\n REVIEWOPEN,\n} from '../lexicon/types/tools/ozone/moderation/defs'\nimport { ModerationEventRow, ModerationSubjectStatusRow } from './types'\n\nconst getSubjectStatusForModerationEvent = ({\n currentStatus,\n action,\n createdBy,\n createdAt,\n durationInHours,\n}: {\n currentStatus?: ModerationSubjectStatusRow\n action: string\n createdBy: string\n createdAt: string\n durationInHours: number | null\n}): Partial<ModerationSubjectStatusRow> => {\n const defaultReviewState = currentStatus\n ? currentStatus.reviewState\n : REVIEWNONE\n\n switch (action) {\n case 'tools.ozone.moderation.defs#modEventAcknowledge':\n return {\n lastReviewedBy: createdBy,\n reviewState: REVIEWCLOSED,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventReport':\n return {\n reviewState: REVIEWOPEN,\n lastReportedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventEscalate':\n return {\n lastReviewedBy: createdBy,\n reviewState: REVIEWESCALATED,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventReverseTakedown':\n return {\n lastReviewedBy: createdBy,\n reviewState: REVIEWCLOSED,\n takendown: false,\n suspendUntil: null,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventUnmuteReporter':\n return {\n lastReviewedBy: createdBy,\n muteReportingUntil: null,\n // It's not likely to receive an unmute event that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventUnmute':\n return {\n lastReviewedBy: createdBy,\n muteUntil: null,\n // It's not likely to receive an unmute event that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventTakedown':\n return {\n // If we are doing a takedown, safe to move the item out of appealed state\n ...(currentStatus?.appealed ? { appealed: false } : {}),\n takendown: true,\n lastReviewedBy: createdBy,\n reviewState: REVIEWCLOSED,\n lastReviewedAt: createdAt,\n suspendUntil: durationInHours\n ? new Date(Date.now() + durationInHours * HOUR).toISOString()\n : null,\n }\n case 'tools.ozone.moderation.defs#modEventMuteReporter':\n return {\n lastReviewedBy: createdBy,\n lastReviewedAt: createdAt,\n // By default, mute for 24hrs\n muteReportingUntil: new Date(\n Date.now() + (durationInHours || 24) * HOUR,\n ).toISOString(),\n // It's not likely to receive a mute event on a subject that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n }\n case 'tools.ozone.moderation.defs#modEventMute':\n return {\n lastReviewedBy: createdBy,\n lastReviewedAt: createdAt,\n // By default, mute for 24hrs\n muteUntil: new Date(\n Date.now() + (durationInHours || 24) * HOUR,\n ).toISOString(),\n // It's not likely to receive a mute event on a subject that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n }\n case 'tools.ozone.moderation.defs#modEventComment':\n return {\n lastReviewedBy: createdBy,\n lastReviewedAt: createdAt,\n reviewState: defaultReviewState,\n }\n case 'tools.ozone.moderation.defs#modEventTag':\n return { tags: [], reviewState: defaultReviewState }\n case 'tools.ozone.moderation.defs#modEventResolveAppeal':\n return {\n appealed: false,\n }\n case 'tools.ozone.moderation.defs#ageAssuranceEvent':\n case 'tools.ozone.moderation.defs#ageAssuranceOverrideEvent':\n return {\n reviewState: defaultReviewState,\n }\n default:\n return {}\n }\n}\n\nconst hostingEvents = [\n 'tools.ozone.moderation.defs#accountEvent',\n 'tools.ozone.moderation.defs#identityEvent',\n 'tools.ozone.moderation.defs#recordEvent',\n]\n\nconst getSubjectStatusForRecordEvent = ({\n event,\n currentStatus,\n}: {\n event: ModerationEventRow\n currentStatus?: ModerationSubjectStatusRow\n}): Partial<ModerationSubjectStatusRow> => {\n const timestamp =\n typeof event.meta?.timestamp === 'string'\n ? event.meta?.timestamp\n : event.createdAt\n\n if (event.action === 'tools.ozone.moderation.defs#recordEvent') {\n if (event.meta?.op === 'delete') {\n return {\n hostingStatus: 'deleted',\n hostingDeletedAt: timestamp,\n }\n } else if (event.meta?.op === 'update') {\n return {\n hostingStatus: 'active',\n hostingUpdatedAt: timestamp,\n }\n }\n return {}\n }\n\n if (event.action === 'tools.ozone.moderation.defs#accountEvent') {\n const status: Partial<ModerationSubjectStatusRow> = {\n hostingUpdatedAt: timestamp,\n }\n\n if (event.meta?.status) {\n status.hostingStatus = `${event.meta?.status}`\n }\n\n if (event.meta?.status === 'deleted') {\n status.hostingDeletedAt = timestamp\n } else if (event.meta?.status === 'deactivated') {\n status.hostingDeactivatedAt = timestamp\n } else {\n // When deactivated accounts are re-activated, we receive the event with just the active flag set to true\n // so we want to make sure that the hostingStatus is not set to an outdated value\n if (\n currentStatus?.hostingStatus === 'deactivated' &&\n event.meta?.active\n ) {\n status.hostingStatus = 'active'\n status.hostingReactivatedAt = timestamp\n }\n }\n\n return status\n }\n\n if (event.action === 'tools.ozone.moderation.defs#identityEvent') {\n const status: Partial<ModerationSubjectStatusRow> = {\n hostingUpdatedAt: timestamp,\n }\n\n if (event.meta?.tombstone) {\n status.hostingStatus = 'tombstoned'\n status.hostingDeletedAt = timestamp\n }\n\n return status\n }\n\n return {}\n}\n\nexport const moderationSubjectStatusQueryBuilder = (db: DatabaseSchema) => {\n // @NOTE: Using select() instead of selectAll() below because the materialized\n // views might be incomplete, and we don't want the null `did` columns to\n // interfere with the (never null) `did` column from the\n // `moderation_subject_status` table in the results\n return db\n .selectFrom('moderation_subject_status')\n .selectAll('moderation_subject_status')\n .leftJoin('account_events_stats', (join) =>\n join.onRef(\n 'moderation_subject_status.did',\n '=',\n 'account_events_stats.subjectDid',\n ),\n )\n .select([\n 'account_events_stats.takedownCount',\n 'account_events_stats.suspendCount',\n 'account_events_stats.escalateCount',\n 'account_events_stats.reportCount',\n 'account_events_stats.appealCount',\n ])\n .leftJoin('account_record_events_stats', (join) =>\n join.onRef(\n 'moderation_subject_status.did',\n '=',\n 'account_record_events_stats.subjectDid',\n ),\n )\n .select([\n 'account_record_events_stats.totalReports',\n 'account_record_events_stats.reportedCount',\n 'account_record_events_stats.escalatedCount',\n 'account_record_events_stats.appealedCount',\n ])\n .leftJoin('account_record_status_stats', (join) =>\n join.onRef(\n 'moderation_subject_status.did',\n '=',\n 'account_record_status_stats.did',\n ),\n )\n .select([\n 'account_record_status_stats.subjectCount',\n 'account_record_status_stats.pendingCount',\n 'account_record_status_stats.processedCount',\n 'account_record_status_stats.takendownCount',\n ])\n .leftJoin('account_strike', (join) =>\n join.onRef('moderation_subject_status.did', '=', 'account_strike.did'),\n )\n .select([\n 'account_strike.activeStrikeCount as strikeCount',\n 'account_strike.totalStrikeCount',\n 'account_strike.firstStrikeAt',\n 'account_strike.lastStrikeAt',\n ])\n}\n\n// Based on a given moderation action event, this function will update the moderation status of the subject\n// If there's no existing status, it will create one\n// If the action event does not affect the status, it will do nothing\nexport const adjustModerationSubjectStatus = async (\n db: Database,\n moderationEvent: ModerationEventRow,\n blobCids?: string[],\n): Promise<ModerationSubjectStatusRow | null> => {\n const {\n action,\n subjectDid,\n subjectUri,\n subjectCid,\n createdBy,\n meta,\n addedTags,\n removedTags,\n comment,\n createdAt,\n } = moderationEvent\n\n // If subjectUri exists, it's not a repoRef so pass along the uri to get identifier back\n const identifier = getStatusIdentifierFromSubject(subjectUri || subjectDid)\n\n db.assertTransaction()\n\n const now = new Date().toISOString()\n const currentStatus = await db.db\n .selectFrom('moderation_subject_status')\n .where('did', '=', identifier.did)\n .where('recordPath', '=', identifier.recordPath)\n // Make sure we respect other updates that may be happening at the same time\n .forUpdate()\n .selectAll()\n .executeTakeFirst()\n\n if (hostingEvents.includes(action)) {\n const newStatus = getSubjectStatusForRecordEvent({\n event: moderationEvent,\n currentStatus,\n })\n if (!Object.keys(newStatus).length) {\n return currentStatus || null\n }\n\n const status = await db.db\n .insertInto('moderation_subject_status')\n .values({\n ...identifier,\n ...newStatus,\n // newStatus doesn't contain a reviewState or takendown so in case this is a new entry\n // we need to set a default values so that the insert doesn't fail\n reviewState: currentStatus ? currentStatus.reviewState : REVIEWNONE,\n // @TODO: should we try to update this based on status property of account event?\n // For now we're the only one emitting takedowns so i don't think it makes too much of a difference\n takendown: currentStatus ? currentStatus.takendown : false,\n ageAssuranceState: currentStatus\n ? currentStatus.ageAssuranceState\n : 'unknown',\n createdAt: now,\n updatedAt: now,\n })\n .onConflict((oc) =>\n oc.constraint('moderation_status_unique_idx').doUpdateSet({\n ...newStatus,\n updatedAt: now,\n }),\n )\n .returningAll()\n .executeTakeFirst()\n\n return status || null\n }\n\n // If reporting is muted for this reporter, we don't want to update the subject status\n if (meta?.isReporterMuted) {\n return currentStatus || null\n }\n\n const isAppealEvent =\n action === 'tools.ozone.moderation.defs#modEventReport' &&\n meta?.reportType &&\n isAppealReport(`${meta.reportType}`)\n\n const subjectStatus = getSubjectStatusForModerationEvent({\n currentStatus,\n action,\n createdBy,\n createdAt,\n durationInHours: moderationEvent.durationInHours,\n })\n\n if (\n currentStatus?.reviewState === REVIEWESCALATED &&\n subjectStatus.reviewState !== REVIEWCLOSED\n ) {\n // If the current status is escalated only allow incoming events to move the state to\n // reviewClosed because escalated subjects should never move to any other state\n subjectStatus.reviewState = REVIEWESCALATED\n }\n\n if (currentStatus && subjectStatus.reviewState === REVIEWNONE) {\n // reviewNone is ONLY allowed when there is no current status\n // If there is a current status, it should not be allowed to move back to reviewNone\n subjectStatus.reviewState = currentStatus.reviewState\n }\n\n // Set these because we don't want to override them if they're already set\n const defaultData = {\n comment: null,\n // Defaulting reviewState to open for any event may not be the desired behavior.\n // For instance, if a subject never had any event and we just want to leave a comment to keep an eye on it\n // that shouldn't mean we want to review the subject\n reviewState: REVIEWNONE,\n recordCid: subjectCid || null,\n ageAssuranceState: currentStatus?.ageAssuranceState || 'unknown',\n }\n const newStatus = {\n ...defaultData,\n ...subjectStatus,\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventPriorityScore' &&\n typeof meta?.priorityScore === 'number'\n ) {\n newStatus.priorityScore = meta?.priorityScore\n subjectStatus.priorityScore = meta?.priorityScore\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventReverseTakedown' &&\n !subjectStatus.takendown\n ) {\n newStatus.takendown = false\n subjectStatus.takendown = false\n }\n\n if (isAppealEvent) {\n newStatus.appealed = true\n subjectStatus.appealed = true\n newStatus.lastAppealedAt = createdAt\n subjectStatus.lastAppealedAt = createdAt\n // Set reviewState to escalated when appeal events are emitted\n subjectStatus.reviewState = REVIEWESCALATED\n newStatus.reviewState = REVIEWESCALATED\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventResolveAppeal' &&\n subjectStatus.appealed\n ) {\n newStatus.appealed = false\n subjectStatus.appealed = false\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventComment' &&\n meta?.sticky\n ) {\n newStatus.comment = comment\n subjectStatus.comment = comment\n }\n\n if (action === 'tools.ozone.moderation.defs#modEventTag') {\n let tags = currentStatus?.tags || []\n if (addedTags?.length) {\n tags = tags.concat(addedTags)\n }\n if (removedTags?.length) {\n tags = tags.filter((tag) => !removedTags.includes(tag))\n }\n newStatus.tags = jsonb([...new Set(tags)]) as unknown as string[]\n subjectStatus.tags = newStatus.tags\n }\n\n if (action === 'tools.ozone.moderation.defs#ageAssuranceEvent') {\n // Only when the last update was made by an admin AND state was set to reset user event can override final state\n if (\n currentStatus?.ageAssuranceUpdatedBy !== 'admin' ||\n currentStatus?.ageAssuranceState === 'reset'\n ) {\n if (typeof meta?.status === 'string') {\n newStatus.ageAssuranceState = meta.status\n subjectStatus.ageAssuranceState = meta.status\n newStatus.ageAssuranceUpdatedBy = 'user'\n subjectStatus.ageAssuranceUpdatedBy = 'user'\n }\n }\n }\n\n if (action === 'tools.ozone.moderation.defs#ageAssuranceOverrideEvent') {\n if (typeof meta?.status === 'string') {\n newStatus.ageAssuranceState = meta.status\n subjectStatus.ageAssuranceState = meta.status\n newStatus.ageAssuranceUpdatedBy = 'admin'\n subjectStatus.ageAssuranceUpdatedBy = 'admin'\n }\n }\n\n if (blobCids?.length) {\n const newBlobCids = jsonb(\n blobCids,\n ) as unknown as ModerationSubjectStatusRow['blobCids']\n newStatus.blobCids = newBlobCids\n subjectStatus.blobCids = newBlobCids\n }\n\n const insertQuery = db.db\n .insertInto('moderation_subject_status')\n .values({\n ...identifier,\n ...newStatus,\n createdAt: now,\n updatedAt: now,\n } as ModerationSubjectStatusRow)\n .onConflict((oc) =>\n oc.constraint('moderation_status_unique_idx').doUpdateSet({\n ...subjectStatus,\n updatedAt: now,\n }),\n )\n\n const status = await insertQuery.returningAll().executeTakeFirst()\n return status || null\n}\n\nexport const getStatusIdentifierFromSubject = (\n subject: string | AtUri,\n): { did: string; recordPath: string } => {\n const isSubjectString = typeof subject === 'string'\n if (isSubjectString && subject.startsWith('did:')) {\n return {\n did: subject,\n recordPath: '',\n }\n }\n\n if (isSubjectString && !subject.startsWith('at://')) {\n throw new Error('Subject is neither a did nor an at-uri')\n }\n\n const uri = isSubjectString ? new AtUri(subject) : subject\n return {\n did: uri.host,\n recordPath: `${uri.collection}/${uri.rkey}`,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/mod-service/status.ts"],"names":[],"mappings":";AAAA,4HAA4H;;;AAE5H,4CAAsC;AACtC,4CAAuC;AACvC,sCAA4C;AAG5C,uCAAmC;AACnC,uEAKqD;AAGrD,MAAM,kCAAkC,GAAG,CAAC,EAC1C,aAAa,EACb,MAAM,EACN,SAAS,EACT,SAAS,EACT,eAAe,GAOhB,EAAuC,EAAE;IACxC,MAAM,kBAAkB,GAAG,aAAa;QACtC,CAAC,CAAC,aAAa,CAAC,WAAW;QAC3B,CAAC,CAAC,iBAAU,CAAA;IAEd,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,iDAAiD;YACpD,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,WAAW,EAAE,mBAAY;gBACzB,cAAc,EAAE,SAAS;aAC1B,CAAA;QACH,KAAK,4CAA4C;YAC/C,OAAO;gBACL,WAAW,EAAE,iBAAU;gBACvB,cAAc,EAAE,SAAS;aAC1B,CAAA;QACH,KAAK,8CAA8C;YACjD,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,WAAW,EAAE,sBAAe;gBAC5B,cAAc,EAAE,SAAS;aAC1B,CAAA;QACH,KAAK,qDAAqD;YACxD,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,WAAW,EAAE,mBAAY;gBACzB,SAAS,EAAE,KAAK;gBAChB,YAAY,EAAE,IAAI;gBAClB,cAAc,EAAE,SAAS;aAC1B,CAAA;QACH,KAAK,oDAAoD;YACvD,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,kBAAkB,EAAE,IAAI;gBACxB,qFAAqF;gBACrF,gDAAgD;gBAChD,WAAW,EAAE,kBAAkB;gBAC/B,cAAc,EAAE,SAAS;aAC1B,CAAA;QACH,KAAK,4CAA4C;YAC/C,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,SAAS,EAAE,IAAI;gBACf,qFAAqF;gBACrF,gDAAgD;gBAChD,WAAW,EAAE,kBAAkB;gBAC/B,cAAc,EAAE,SAAS;aAC1B,CAAA;QACH,KAAK,8CAA8C;YACjD,OAAO;gBACL,0EAA0E;gBAC1E,GAAG,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,SAAS,EAAE,IAAI;gBACf,cAAc,EAAE,SAAS;gBACzB,WAAW,EAAE,mBAAY;gBACzB,cAAc,EAAE,SAAS;gBACzB,YAAY,EAAE,eAAe;oBAC3B,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,GAAG,aAAI,CAAC,CAAC,WAAW,EAAE;oBAC7D,CAAC,CAAC,IAAI;aACT,CAAA;QACH,KAAK,kDAAkD;YACrD,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,cAAc,EAAE,SAAS;gBACzB,6BAA6B;gBAC7B,kBAAkB,EAAE,IAAI,IAAI,CAC1B,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,GAAG,aAAI,CAC5C,CAAC,WAAW,EAAE;gBACf,+FAA+F;gBAC/F,gDAAgD;gBAChD,WAAW,EAAE,kBAAkB;aAChC,CAAA;QACH,KAAK,0CAA0C;YAC7C,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,cAAc,EAAE,SAAS;gBACzB,6BAA6B;gBAC7B,SAAS,EAAE,IAAI,IAAI,CACjB,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,GAAG,aAAI,CAC5C,CAAC,WAAW,EAAE;gBACf,+FAA+F;gBAC/F,gDAAgD;gBAChD,WAAW,EAAE,kBAAkB;aAChC,CAAA;QACH,KAAK,6CAA6C;YAChD,OAAO;gBACL,cAAc,EAAE,SAAS;gBACzB,cAAc,EAAE,SAAS;gBACzB,WAAW,EAAE,kBAAkB;aAChC,CAAA;QACH,KAAK,yCAAyC;YAC5C,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAA;QACtD,KAAK,mDAAmD;YACtD,OAAO;gBACL,QAAQ,EAAE,KAAK;aAChB,CAAA;QACH,KAAK,+CAA+C,CAAC;QACrD,KAAK,uDAAuD,CAAC;QAC7D,KAAK,oDAAoD;YACvD,OAAO;gBACL,WAAW,EAAE,kBAAkB;aAChC,CAAA;QACH;YACE,OAAO,EAAE,CAAA;IACb,CAAC;AACH,CAAC,CAAA;AAED,MAAM,aAAa,GAAG;IACpB,0CAA0C;IAC1C,2CAA2C;IAC3C,yCAAyC;CAC1C,CAAA;AAED,MAAM,8BAA8B,GAAG,CAAC,EACtC,KAAK,EACL,aAAa,GAId,EAAuC,EAAE;IACxC,MAAM,SAAS,GACb,OAAO,KAAK,CAAC,IAAI,EAAE,SAAS,KAAK,QAAQ;QACvC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS;QACvB,CAAC,CAAC,KAAK,CAAC,SAAS,CAAA;IAErB,IAAI,KAAK,CAAC,MAAM,KAAK,yCAAyC,EAAE,CAAC;QAC/D,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,QAAQ,EAAE,CAAC;YAChC,OAAO;gBACL,aAAa,EAAE,SAAS;gBACxB,gBAAgB,EAAE,SAAS;aAC5B,CAAA;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,KAAK,QAAQ,EAAE,CAAC;YACvC,OAAO;gBACL,aAAa,EAAE,QAAQ;gBACvB,gBAAgB,EAAE,SAAS;aAC5B,CAAA;QACH,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,0CAA0C,EAAE,CAAC;QAChE,MAAM,MAAM,GAAwC;YAClD,gBAAgB,EAAE,SAAS;SAC5B,CAAA;QAED,IAAI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;YACvB,MAAM,CAAC,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAA;QAChD,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;YACrC,MAAM,CAAC,gBAAgB,GAAG,SAAS,CAAA;QACrC,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,EAAE,CAAC;YAChD,MAAM,CAAC,oBAAoB,GAAG,SAAS,CAAA;QACzC,CAAC;aAAM,CAAC;YACN,yGAAyG;YACzG,iFAAiF;YACjF,IACE,aAAa,EAAE,aAAa,KAAK,aAAa;gBAC9C,KAAK,CAAC,IAAI,EAAE,MAAM,EAClB,CAAC;gBACD,MAAM,CAAC,aAAa,GAAG,QAAQ,CAAA;gBAC/B,MAAM,CAAC,oBAAoB,GAAG,SAAS,CAAA;YACzC,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,2CAA2C,EAAE,CAAC;QACjE,MAAM,MAAM,GAAwC;YAClD,gBAAgB,EAAE,SAAS;SAC5B,CAAA;QAED,IAAI,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,aAAa,GAAG,YAAY,CAAA;YACnC,MAAM,CAAC,gBAAgB,GAAG,SAAS,CAAA;QACrC,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED,OAAO,EAAE,CAAA;AACX,CAAC,CAAA;AAEM,MAAM,mCAAmC,GAAG,CAAC,EAAkB,EAAE,EAAE;IACxE,8EAA8E;IAC9E,yEAAyE;IACzE,wDAAwD;IACxD,mDAAmD;IACnD,OAAO,EAAE;SACN,UAAU,CAAC,2BAA2B,CAAC;SACvC,SAAS,CAAC,2BAA2B,CAAC;SACtC,QAAQ,CAAC,sBAAsB,EAAE,CAAC,IAAI,EAAE,EAAE,CACzC,IAAI,CAAC,KAAK,CACR,+BAA+B,EAC/B,GAAG,EACH,iCAAiC,CAClC,CACF;SACA,MAAM,CAAC;QACN,oCAAoC;QACpC,mCAAmC;QACnC,oCAAoC;QACpC,kCAAkC;QAClC,kCAAkC;KACnC,CAAC;SACD,QAAQ,CAAC,6BAA6B,EAAE,CAAC,IAAI,EAAE,EAAE,CAChD,IAAI,CAAC,KAAK,CACR,+BAA+B,EAC/B,GAAG,EACH,wCAAwC,CACzC,CACF;SACA,MAAM,CAAC;QACN,0CAA0C;QAC1C,2CAA2C;QAC3C,4CAA4C;QAC5C,2CAA2C;KAC5C,CAAC;SACD,QAAQ,CAAC,6BAA6B,EAAE,CAAC,IAAI,EAAE,EAAE,CAChD,IAAI,CAAC,KAAK,CACR,+BAA+B,EAC/B,GAAG,EACH,iCAAiC,CAClC,CACF;SACA,MAAM,CAAC;QACN,0CAA0C;QAC1C,0CAA0C;QAC1C,4CAA4C;QAC5C,4CAA4C;KAC7C,CAAC;SACD,QAAQ,CAAC,gBAAgB,EAAE,CAAC,IAAI,EAAE,EAAE,CACnC,IAAI,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,EAAE,oBAAoB,CAAC,CACvE;SACA,MAAM,CAAC;QACN,iDAAiD;QACjD,iCAAiC;QACjC,8BAA8B;QAC9B,6BAA6B;KAC9B,CAAC,CAAA;AACN,CAAC,CAAA;AAzDY,QAAA,mCAAmC,uCAyD/C;AAED,2GAA2G;AAC3G,oDAAoD;AACpD,qEAAqE;AAC9D,MAAM,6BAA6B,GAAG,KAAK,EAChD,EAAY,EACZ,eAAmC,EACnC,QAAmB,EACyB,EAAE;IAC9C,MAAM,EACJ,MAAM,EACN,UAAU,EACV,UAAU,EACV,UAAU,EACV,SAAS,EACT,IAAI,EACJ,SAAS,EACT,WAAW,EACX,OAAO,EACP,SAAS,GACV,GAAG,eAAe,CAAA;IAEnB,wFAAwF;IACxF,MAAM,UAAU,GAAG,IAAA,sCAA8B,EAAC,UAAU,IAAI,UAAU,CAAC,CAAA;IAE3E,EAAE,CAAC,iBAAiB,EAAE,CAAA;IAEtB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACpC,MAAM,aAAa,GAAG,MAAM,EAAE,CAAC,EAAE;SAC9B,UAAU,CAAC,2BAA2B,CAAC;SACvC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,CAAC;SACjC,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,UAAU,CAAC,UAAU,CAAC;QAChD,4EAA4E;SAC3E,SAAS,EAAE;SACX,SAAS,EAAE;SACX,gBAAgB,EAAE,CAAA;IAErB,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,8BAA8B,CAAC;YAC/C,KAAK,EAAE,eAAe;YACtB,aAAa;SACd,CAAC,CAAA;QACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,CAAC;YACnC,OAAO,aAAa,IAAI,IAAI,CAAA;QAC9B,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE;aACvB,UAAU,CAAC,2BAA2B,CAAC;aACvC,MAAM,CAAC;YACN,GAAG,UAAU;YACb,GAAG,SAAS;YACZ,sFAAsF;YACtF,kEAAkE;YAClE,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,iBAAU;YACnE,iFAAiF;YACjF,mGAAmG;YACnG,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;YAC1D,iBAAiB,EAAE,aAAa;gBAC9B,CAAC,CAAC,aAAa,CAAC,iBAAiB;gBACjC,CAAC,CAAC,SAAS;YACb,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC;aACD,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CACjB,EAAE,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,WAAW,CAAC;YACxD,GAAG,SAAS;YACZ,SAAS,EAAE,GAAG;SACf,CAAC,CACH;aACA,YAAY,EAAE;aACd,gBAAgB,EAAE,CAAA;QAErB,OAAO,MAAM,IAAI,IAAI,CAAA;IACvB,CAAC;IAED,sFAAsF;IACtF,IAAI,IAAI,EAAE,eAAe,EAAE,CAAC;QAC1B,OAAO,aAAa,IAAI,IAAI,CAAA;IAC9B,CAAC;IAED,MAAM,aAAa,GACjB,MAAM,KAAK,4CAA4C;QACvD,IAAI,EAAE,UAAU;QAChB,IAAA,qBAAc,EAAC,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,CAAA;IAEtC,MAAM,aAAa,GAAG,kCAAkC,CAAC;QACvD,aAAa;QACb,MAAM;QACN,SAAS;QACT,SAAS;QACT,eAAe,EAAE,eAAe,CAAC,eAAe;KACjD,CAAC,CAAA;IAEF,IACE,aAAa,EAAE,WAAW,KAAK,sBAAe;QAC9C,aAAa,CAAC,WAAW,KAAK,mBAAY,EAC1C,CAAC;QACD,qFAAqF;QACrF,+EAA+E;QAC/E,aAAa,CAAC,WAAW,GAAG,sBAAe,CAAA;IAC7C,CAAC;IAED,IAAI,aAAa,IAAI,aAAa,CAAC,WAAW,KAAK,iBAAU,EAAE,CAAC;QAC9D,6DAA6D;QAC7D,oFAAoF;QACpF,aAAa,CAAC,WAAW,GAAG,aAAa,CAAC,WAAW,CAAA;IACvD,CAAC;IAED,0EAA0E;IAC1E,MAAM,WAAW,GAAG;QAClB,OAAO,EAAE,IAAI;QACb,gFAAgF;QAChF,0GAA0G;QAC1G,oDAAoD;QACpD,WAAW,EAAE,iBAAU;QACvB,SAAS,EAAE,UAAU,IAAI,IAAI;QAC7B,iBAAiB,EAAE,aAAa,EAAE,iBAAiB,IAAI,SAAS;KACjE,CAAA;IACD,MAAM,SAAS,GAAG;QAChB,GAAG,WAAW;QACd,GAAG,aAAa;KACjB,CAAA;IAED,IACE,MAAM,KAAK,mDAAmD;QAC9D,OAAO,IAAI,EAAE,aAAa,KAAK,QAAQ,EACvC,CAAC;QACD,SAAS,CAAC,aAAa,GAAG,IAAI,EAAE,aAAa,CAAA;QAC7C,aAAa,CAAC,aAAa,GAAG,IAAI,EAAE,aAAa,CAAA;IACnD,CAAC;IAED,IACE,MAAM,KAAK,qDAAqD;QAChE,CAAC,aAAa,CAAC,SAAS,EACxB,CAAC;QACD,SAAS,CAAC,SAAS,GAAG,KAAK,CAAA;QAC3B,aAAa,CAAC,SAAS,GAAG,KAAK,CAAA;IACjC,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAA;QACzB,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAA;QAC7B,SAAS,CAAC,cAAc,GAAG,SAAS,CAAA;QACpC,aAAa,CAAC,cAAc,GAAG,SAAS,CAAA;QACxC,8DAA8D;QAC9D,aAAa,CAAC,WAAW,GAAG,sBAAe,CAAA;QAC3C,SAAS,CAAC,WAAW,GAAG,sBAAe,CAAA;IACzC,CAAC;IAED,IACE,MAAM,KAAK,mDAAmD;QAC9D,aAAa,CAAC,QAAQ,EACtB,CAAC;QACD,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAA;QAC1B,aAAa,CAAC,QAAQ,GAAG,KAAK,CAAA;IAChC,CAAC;IAED,IACE,MAAM,KAAK,6CAA6C;QACxD,IAAI,EAAE,MAAM,EACZ,CAAC;QACD,SAAS,CAAC,OAAO,GAAG,OAAO,CAAA;QAC3B,aAAa,CAAC,OAAO,GAAG,OAAO,CAAA;IACjC,CAAC;IAED,IAAI,MAAM,KAAK,yCAAyC,EAAE,CAAC;QACzD,IAAI,IAAI,GAAG,aAAa,EAAE,IAAI,IAAI,EAAE,CAAA;QACpC,IAAI,SAAS,EAAE,MAAM,EAAE,CAAC;YACtB,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAC/B,CAAC;QACD,IAAI,WAAW,EAAE,MAAM,EAAE,CAAC;YACxB,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QACzD,CAAC;QACD,SAAS,CAAC,IAAI,GAAG,IAAA,aAAK,EAAC,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAwB,CAAA;QACjE,aAAa,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,CAAA;IACrC,CAAC;IAED,IAAI,MAAM,KAAK,+CAA+C,EAAE,CAAC;QAC/D,gHAAgH;QAChH,IACE,aAAa,EAAE,qBAAqB,KAAK,OAAO;YAChD,aAAa,EAAE,iBAAiB,KAAK,OAAO,EAC5C,CAAC;YACD,IAAI,OAAO,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACrC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAA;gBACzC,aAAa,CAAC,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAA;gBAC7C,SAAS,CAAC,qBAAqB,GAAG,MAAM,CAAA;gBACxC,aAAa,CAAC,qBAAqB,GAAG,MAAM,CAAA;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,MAAM,KAAK,uDAAuD,EAAE,CAAC;QACvE,IAAI,OAAO,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;YACrC,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAA;YACzC,aAAa,CAAC,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAA;YAC7C,SAAS,CAAC,qBAAqB,GAAG,OAAO,CAAA;YACzC,aAAa,CAAC,qBAAqB,GAAG,OAAO,CAAA;QAC/C,CAAC;IACH,CAAC;IAED,IAAI,MAAM,KAAK,oDAAoD,EAAE,CAAC;QACpE,SAAS,CAAC,iBAAiB,GAAG,SAAS,CAAA;QACvC,aAAa,CAAC,iBAAiB,GAAG,SAAS,CAAA;QAC3C,SAAS,CAAC,qBAAqB,GAAG,IAAI,CAAA;QACtC,aAAa,CAAC,qBAAqB,GAAG,IAAI,CAAA;IAC5C,CAAC;IAED,IAAI,QAAQ,EAAE,MAAM,EAAE,CAAC;QACrB,MAAM,WAAW,GAAG,IAAA,aAAK,EACvB,QAAQ,CAC4C,CAAA;QACtD,SAAS,CAAC,QAAQ,GAAG,WAAW,CAAA;QAChC,aAAa,CAAC,QAAQ,GAAG,WAAW,CAAA;IACtC,CAAC;IAED,MAAM,WAAW,GAAG,EAAE,CAAC,EAAE;SACtB,UAAU,CAAC,2BAA2B,CAAC;SACvC,MAAM,CAAC;QACN,GAAG,UAAU;QACb,GAAG,SAAS;QACZ,SAAS,EAAE,GAAG;QACd,SAAS,EAAE,GAAG;KACe,CAAC;SAC/B,UAAU,CAAC,CAAC,EAAE,EAAE,EAAE,CACjB,EAAE,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,WAAW,CAAC;QACxD,GAAG,aAAa;QAChB,SAAS,EAAE,GAAG;KACf,CAAC,CACH,CAAA;IAEH,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,YAAY,EAAE,CAAC,gBAAgB,EAAE,CAAA;IAClE,OAAO,MAAM,IAAI,IAAI,CAAA;AACvB,CAAC,CAAA;AArOY,QAAA,6BAA6B,iCAqOzC;AAEM,MAAM,8BAA8B,GAAG,CAC5C,OAAuB,EACc,EAAE;IACvC,MAAM,eAAe,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAA;IACnD,IAAI,eAAe,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,OAAO;YACL,GAAG,EAAE,OAAO;YACZ,UAAU,EAAE,EAAE;SACf,CAAA;IACH,CAAC;IAED,IAAI,eAAe,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC3D,CAAC;IAED,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,cAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IAC1D,OAAO;QACL,GAAG,EAAE,GAAG,CAAC,IAAI;QACb,UAAU,EAAE,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,IAAI,EAAE;KAC5C,CAAA;AACH,CAAC,CAAA;AApBY,QAAA,8BAA8B,kCAoB1C","sourcesContent":["// This may require better organization but for now, just dumping functions here containing DB queries for moderation status\n\nimport { HOUR } from '@atproto/common'\nimport { AtUri } from '@atproto/syntax'\nimport { isAppealReport } from '../api/util'\nimport { Database } from '../db'\nimport { DatabaseSchema } from '../db/schema'\nimport { jsonb } from '../db/types'\nimport {\n REVIEWCLOSED,\n REVIEWESCALATED,\n REVIEWNONE,\n REVIEWOPEN,\n} from '../lexicon/types/tools/ozone/moderation/defs'\nimport { ModerationEventRow, ModerationSubjectStatusRow } from './types'\n\nconst getSubjectStatusForModerationEvent = ({\n currentStatus,\n action,\n createdBy,\n createdAt,\n durationInHours,\n}: {\n currentStatus?: ModerationSubjectStatusRow\n action: string\n createdBy: string\n createdAt: string\n durationInHours: number | null\n}): Partial<ModerationSubjectStatusRow> => {\n const defaultReviewState = currentStatus\n ? currentStatus.reviewState\n : REVIEWNONE\n\n switch (action) {\n case 'tools.ozone.moderation.defs#modEventAcknowledge':\n return {\n lastReviewedBy: createdBy,\n reviewState: REVIEWCLOSED,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventReport':\n return {\n reviewState: REVIEWOPEN,\n lastReportedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventEscalate':\n return {\n lastReviewedBy: createdBy,\n reviewState: REVIEWESCALATED,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventReverseTakedown':\n return {\n lastReviewedBy: createdBy,\n reviewState: REVIEWCLOSED,\n takendown: false,\n suspendUntil: null,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventUnmuteReporter':\n return {\n lastReviewedBy: createdBy,\n muteReportingUntil: null,\n // It's not likely to receive an unmute event that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventUnmute':\n return {\n lastReviewedBy: createdBy,\n muteUntil: null,\n // It's not likely to receive an unmute event that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n lastReviewedAt: createdAt,\n }\n case 'tools.ozone.moderation.defs#modEventTakedown':\n return {\n // If we are doing a takedown, safe to move the item out of appealed state\n ...(currentStatus?.appealed ? { appealed: false } : {}),\n takendown: true,\n lastReviewedBy: createdBy,\n reviewState: REVIEWCLOSED,\n lastReviewedAt: createdAt,\n suspendUntil: durationInHours\n ? new Date(Date.now() + durationInHours * HOUR).toISOString()\n : null,\n }\n case 'tools.ozone.moderation.defs#modEventMuteReporter':\n return {\n lastReviewedBy: createdBy,\n lastReviewedAt: createdAt,\n // By default, mute for 24hrs\n muteReportingUntil: new Date(\n Date.now() + (durationInHours || 24) * HOUR,\n ).toISOString(),\n // It's not likely to receive a mute event on a subject that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n }\n case 'tools.ozone.moderation.defs#modEventMute':\n return {\n lastReviewedBy: createdBy,\n lastReviewedAt: createdAt,\n // By default, mute for 24hrs\n muteUntil: new Date(\n Date.now() + (durationInHours || 24) * HOUR,\n ).toISOString(),\n // It's not likely to receive a mute event on a subject that does not already have a status row\n // but if it does happen, default to unnecessary\n reviewState: defaultReviewState,\n }\n case 'tools.ozone.moderation.defs#modEventComment':\n return {\n lastReviewedBy: createdBy,\n lastReviewedAt: createdAt,\n reviewState: defaultReviewState,\n }\n case 'tools.ozone.moderation.defs#modEventTag':\n return { tags: [], reviewState: defaultReviewState }\n case 'tools.ozone.moderation.defs#modEventResolveAppeal':\n return {\n appealed: false,\n }\n case 'tools.ozone.moderation.defs#ageAssuranceEvent':\n case 'tools.ozone.moderation.defs#ageAssuranceOverrideEvent':\n case 'tools.ozone.moderation.defs#ageAssurancePurgeEvent':\n return {\n reviewState: defaultReviewState,\n }\n default:\n return {}\n }\n}\n\nconst hostingEvents = [\n 'tools.ozone.moderation.defs#accountEvent',\n 'tools.ozone.moderation.defs#identityEvent',\n 'tools.ozone.moderation.defs#recordEvent',\n]\n\nconst getSubjectStatusForRecordEvent = ({\n event,\n currentStatus,\n}: {\n event: ModerationEventRow\n currentStatus?: ModerationSubjectStatusRow\n}): Partial<ModerationSubjectStatusRow> => {\n const timestamp =\n typeof event.meta?.timestamp === 'string'\n ? event.meta?.timestamp\n : event.createdAt\n\n if (event.action === 'tools.ozone.moderation.defs#recordEvent') {\n if (event.meta?.op === 'delete') {\n return {\n hostingStatus: 'deleted',\n hostingDeletedAt: timestamp,\n }\n } else if (event.meta?.op === 'update') {\n return {\n hostingStatus: 'active',\n hostingUpdatedAt: timestamp,\n }\n }\n return {}\n }\n\n if (event.action === 'tools.ozone.moderation.defs#accountEvent') {\n const status: Partial<ModerationSubjectStatusRow> = {\n hostingUpdatedAt: timestamp,\n }\n\n if (event.meta?.status) {\n status.hostingStatus = `${event.meta?.status}`\n }\n\n if (event.meta?.status === 'deleted') {\n status.hostingDeletedAt = timestamp\n } else if (event.meta?.status === 'deactivated') {\n status.hostingDeactivatedAt = timestamp\n } else {\n // When deactivated accounts are re-activated, we receive the event with just the active flag set to true\n // so we want to make sure that the hostingStatus is not set to an outdated value\n if (\n currentStatus?.hostingStatus === 'deactivated' &&\n event.meta?.active\n ) {\n status.hostingStatus = 'active'\n status.hostingReactivatedAt = timestamp\n }\n }\n\n return status\n }\n\n if (event.action === 'tools.ozone.moderation.defs#identityEvent') {\n const status: Partial<ModerationSubjectStatusRow> = {\n hostingUpdatedAt: timestamp,\n }\n\n if (event.meta?.tombstone) {\n status.hostingStatus = 'tombstoned'\n status.hostingDeletedAt = timestamp\n }\n\n return status\n }\n\n return {}\n}\n\nexport const moderationSubjectStatusQueryBuilder = (db: DatabaseSchema) => {\n // @NOTE: Using select() instead of selectAll() below because the materialized\n // views might be incomplete, and we don't want the null `did` columns to\n // interfere with the (never null) `did` column from the\n // `moderation_subject_status` table in the results\n return db\n .selectFrom('moderation_subject_status')\n .selectAll('moderation_subject_status')\n .leftJoin('account_events_stats', (join) =>\n join.onRef(\n 'moderation_subject_status.did',\n '=',\n 'account_events_stats.subjectDid',\n ),\n )\n .select([\n 'account_events_stats.takedownCount',\n 'account_events_stats.suspendCount',\n 'account_events_stats.escalateCount',\n 'account_events_stats.reportCount',\n 'account_events_stats.appealCount',\n ])\n .leftJoin('account_record_events_stats', (join) =>\n join.onRef(\n 'moderation_subject_status.did',\n '=',\n 'account_record_events_stats.subjectDid',\n ),\n )\n .select([\n 'account_record_events_stats.totalReports',\n 'account_record_events_stats.reportedCount',\n 'account_record_events_stats.escalatedCount',\n 'account_record_events_stats.appealedCount',\n ])\n .leftJoin('account_record_status_stats', (join) =>\n join.onRef(\n 'moderation_subject_status.did',\n '=',\n 'account_record_status_stats.did',\n ),\n )\n .select([\n 'account_record_status_stats.subjectCount',\n 'account_record_status_stats.pendingCount',\n 'account_record_status_stats.processedCount',\n 'account_record_status_stats.takendownCount',\n ])\n .leftJoin('account_strike', (join) =>\n join.onRef('moderation_subject_status.did', '=', 'account_strike.did'),\n )\n .select([\n 'account_strike.activeStrikeCount as strikeCount',\n 'account_strike.totalStrikeCount',\n 'account_strike.firstStrikeAt',\n 'account_strike.lastStrikeAt',\n ])\n}\n\n// Based on a given moderation action event, this function will update the moderation status of the subject\n// If there's no existing status, it will create one\n// If the action event does not affect the status, it will do nothing\nexport const adjustModerationSubjectStatus = async (\n db: Database,\n moderationEvent: ModerationEventRow,\n blobCids?: string[],\n): Promise<ModerationSubjectStatusRow | null> => {\n const {\n action,\n subjectDid,\n subjectUri,\n subjectCid,\n createdBy,\n meta,\n addedTags,\n removedTags,\n comment,\n createdAt,\n } = moderationEvent\n\n // If subjectUri exists, it's not a repoRef so pass along the uri to get identifier back\n const identifier = getStatusIdentifierFromSubject(subjectUri || subjectDid)\n\n db.assertTransaction()\n\n const now = new Date().toISOString()\n const currentStatus = await db.db\n .selectFrom('moderation_subject_status')\n .where('did', '=', identifier.did)\n .where('recordPath', '=', identifier.recordPath)\n // Make sure we respect other updates that may be happening at the same time\n .forUpdate()\n .selectAll()\n .executeTakeFirst()\n\n if (hostingEvents.includes(action)) {\n const newStatus = getSubjectStatusForRecordEvent({\n event: moderationEvent,\n currentStatus,\n })\n if (!Object.keys(newStatus).length) {\n return currentStatus || null\n }\n\n const status = await db.db\n .insertInto('moderation_subject_status')\n .values({\n ...identifier,\n ...newStatus,\n // newStatus doesn't contain a reviewState or takendown so in case this is a new entry\n // we need to set a default values so that the insert doesn't fail\n reviewState: currentStatus ? currentStatus.reviewState : REVIEWNONE,\n // @TODO: should we try to update this based on status property of account event?\n // For now we're the only one emitting takedowns so i don't think it makes too much of a difference\n takendown: currentStatus ? currentStatus.takendown : false,\n ageAssuranceState: currentStatus\n ? currentStatus.ageAssuranceState\n : 'unknown',\n createdAt: now,\n updatedAt: now,\n })\n .onConflict((oc) =>\n oc.constraint('moderation_status_unique_idx').doUpdateSet({\n ...newStatus,\n updatedAt: now,\n }),\n )\n .returningAll()\n .executeTakeFirst()\n\n return status || null\n }\n\n // If reporting is muted for this reporter, we don't want to update the subject status\n if (meta?.isReporterMuted) {\n return currentStatus || null\n }\n\n const isAppealEvent =\n action === 'tools.ozone.moderation.defs#modEventReport' &&\n meta?.reportType &&\n isAppealReport(`${meta.reportType}`)\n\n const subjectStatus = getSubjectStatusForModerationEvent({\n currentStatus,\n action,\n createdBy,\n createdAt,\n durationInHours: moderationEvent.durationInHours,\n })\n\n if (\n currentStatus?.reviewState === REVIEWESCALATED &&\n subjectStatus.reviewState !== REVIEWCLOSED\n ) {\n // If the current status is escalated only allow incoming events to move the state to\n // reviewClosed because escalated subjects should never move to any other state\n subjectStatus.reviewState = REVIEWESCALATED\n }\n\n if (currentStatus && subjectStatus.reviewState === REVIEWNONE) {\n // reviewNone is ONLY allowed when there is no current status\n // If there is a current status, it should not be allowed to move back to reviewNone\n subjectStatus.reviewState = currentStatus.reviewState\n }\n\n // Set these because we don't want to override them if they're already set\n const defaultData = {\n comment: null,\n // Defaulting reviewState to open for any event may not be the desired behavior.\n // For instance, if a subject never had any event and we just want to leave a comment to keep an eye on it\n // that shouldn't mean we want to review the subject\n reviewState: REVIEWNONE,\n recordCid: subjectCid || null,\n ageAssuranceState: currentStatus?.ageAssuranceState || 'unknown',\n }\n const newStatus = {\n ...defaultData,\n ...subjectStatus,\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventPriorityScore' &&\n typeof meta?.priorityScore === 'number'\n ) {\n newStatus.priorityScore = meta?.priorityScore\n subjectStatus.priorityScore = meta?.priorityScore\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventReverseTakedown' &&\n !subjectStatus.takendown\n ) {\n newStatus.takendown = false\n subjectStatus.takendown = false\n }\n\n if (isAppealEvent) {\n newStatus.appealed = true\n subjectStatus.appealed = true\n newStatus.lastAppealedAt = createdAt\n subjectStatus.lastAppealedAt = createdAt\n // Set reviewState to escalated when appeal events are emitted\n subjectStatus.reviewState = REVIEWESCALATED\n newStatus.reviewState = REVIEWESCALATED\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventResolveAppeal' &&\n subjectStatus.appealed\n ) {\n newStatus.appealed = false\n subjectStatus.appealed = false\n }\n\n if (\n action === 'tools.ozone.moderation.defs#modEventComment' &&\n meta?.sticky\n ) {\n newStatus.comment = comment\n subjectStatus.comment = comment\n }\n\n if (action === 'tools.ozone.moderation.defs#modEventTag') {\n let tags = currentStatus?.tags || []\n if (addedTags?.length) {\n tags = tags.concat(addedTags)\n }\n if (removedTags?.length) {\n tags = tags.filter((tag) => !removedTags.includes(tag))\n }\n newStatus.tags = jsonb([...new Set(tags)]) as unknown as string[]\n subjectStatus.tags = newStatus.tags\n }\n\n if (action === 'tools.ozone.moderation.defs#ageAssuranceEvent') {\n // Only when the last update was made by an admin AND state was set to reset user event can override final state\n if (\n currentStatus?.ageAssuranceUpdatedBy !== 'admin' ||\n currentStatus?.ageAssuranceState === 'reset'\n ) {\n if (typeof meta?.status === 'string') {\n newStatus.ageAssuranceState = meta.status\n subjectStatus.ageAssuranceState = meta.status\n newStatus.ageAssuranceUpdatedBy = 'user'\n subjectStatus.ageAssuranceUpdatedBy = 'user'\n }\n }\n }\n\n if (action === 'tools.ozone.moderation.defs#ageAssuranceOverrideEvent') {\n if (typeof meta?.status === 'string') {\n newStatus.ageAssuranceState = meta.status\n subjectStatus.ageAssuranceState = meta.status\n newStatus.ageAssuranceUpdatedBy = 'admin'\n subjectStatus.ageAssuranceUpdatedBy = 'admin'\n }\n }\n\n if (action === 'tools.ozone.moderation.defs#ageAssurancePurgeEvent') {\n newStatus.ageAssuranceState = 'unknown'\n subjectStatus.ageAssuranceState = 'unknown'\n newStatus.ageAssuranceUpdatedBy = null\n subjectStatus.ageAssuranceUpdatedBy = null\n }\n\n if (blobCids?.length) {\n const newBlobCids = jsonb(\n blobCids,\n ) as unknown as ModerationSubjectStatusRow['blobCids']\n newStatus.blobCids = newBlobCids\n subjectStatus.blobCids = newBlobCids\n }\n\n const insertQuery = db.db\n .insertInto('moderation_subject_status')\n .values({\n ...identifier,\n ...newStatus,\n createdAt: now,\n updatedAt: now,\n } as ModerationSubjectStatusRow)\n .onConflict((oc) =>\n oc.constraint('moderation_status_unique_idx').doUpdateSet({\n ...subjectStatus,\n updatedAt: now,\n }),\n )\n\n const status = await insertQuery.returningAll().executeTakeFirst()\n return status || null\n}\n\nexport const getStatusIdentifierFromSubject = (\n subject: string | AtUri,\n): { did: string; recordPath: string } => {\n const isSubjectString = typeof subject === 'string'\n if (isSubjectString && subject.startsWith('did:')) {\n return {\n did: subject,\n recordPath: '',\n }\n }\n\n if (isSubjectString && !subject.startsWith('at://')) {\n throw new Error('Subject is neither a did nor an at-uri')\n }\n\n const uri = isSubjectString ? new AtUri(subject) : subject\n return {\n did: uri.host,\n recordPath: `${uri.collection}/${uri.rkey}`,\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/ozone",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.167",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Backend service for moderating the Bluesky network.",
|
|
6
6
|
"keywords": [
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
"uint8arrays": "3.0.0",
|
|
36
36
|
"undici": "^6.14.1",
|
|
37
37
|
"ws": "^8.12.0",
|
|
38
|
-
"@atproto/api": "^0.19.
|
|
38
|
+
"@atproto/api": "^0.19.4",
|
|
39
39
|
"@atproto/common": "^0.5.14",
|
|
40
40
|
"@atproto/crypto": "^0.4.5",
|
|
41
41
|
"@atproto/identity": "^0.4.12",
|
|
42
42
|
"@atproto/lexicon": "^0.6.2",
|
|
43
|
-
"@atproto/syntax": "^0.5.
|
|
43
|
+
"@atproto/syntax": "^0.5.1",
|
|
44
44
|
"@atproto/ws-client": "^0.0.4",
|
|
45
45
|
"@atproto/xrpc": "^0.7.7",
|
|
46
|
-
"@atproto/xrpc-server": "^0.10.
|
|
46
|
+
"@atproto/xrpc-server": "^0.10.16"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@did-plc/server": "^0.0.1",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"jest": "^28.1.2",
|
|
56
56
|
"ts-node": "^10.8.2",
|
|
57
57
|
"typescript": "^5.6.3",
|
|
58
|
-
"@atproto/
|
|
59
|
-
"@atproto/
|
|
58
|
+
"@atproto/lex-cli": "^0.9.9",
|
|
59
|
+
"@atproto/pds": "^0.4.215"
|
|
60
60
|
},
|
|
61
61
|
"scripts": {
|
|
62
62
|
"codegen": "lex gen-server --yes ./src/lexicon ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* ../../lexicons/chat/bsky/*/* ../../lexicons/tools/ozone/*/*",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { isModEventDivert } from '@atproto/api/dist/client/types/tools/ozone/moderation/defs'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AuthRequiredError,
|
|
4
|
+
ForbiddenError,
|
|
5
|
+
InvalidRequestError,
|
|
6
|
+
} from '@atproto/xrpc-server'
|
|
3
7
|
import { AdminTokenOutput, ModeratorOutput } from '../../auth-verifier'
|
|
4
8
|
import { AppContext } from '../../context'
|
|
5
9
|
import { Server } from '../../lexicon'
|
|
@@ -8,6 +12,7 @@ import {
|
|
|
8
12
|
ModEventTag,
|
|
9
13
|
isAgeAssuranceEvent,
|
|
10
14
|
isAgeAssuranceOverrideEvent,
|
|
15
|
+
isAgeAssurancePurgeEvent,
|
|
11
16
|
isModEventAcknowledge,
|
|
12
17
|
isModEventEmail,
|
|
13
18
|
isModEventLabel,
|
|
@@ -71,6 +76,17 @@ const handleModerationEvent = async ({
|
|
|
71
76
|
}
|
|
72
77
|
}
|
|
73
78
|
|
|
79
|
+
if (isAgeAssurancePurgeEvent(event)) {
|
|
80
|
+
if (!subject.isRepo()) {
|
|
81
|
+
throw new InvalidRequestError('Invalid subject type')
|
|
82
|
+
}
|
|
83
|
+
if (!auth.credentials.isModerator) {
|
|
84
|
+
throw new ForbiddenError(
|
|
85
|
+
'Must be a moderator to purge age assurance events',
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
74
90
|
if (isRevokeAccountCredentialsEvent(event)) {
|
|
75
91
|
if (!subject.isRepo()) {
|
|
76
92
|
throw new InvalidRequestError('Invalid subject type')
|
package/src/api/util.ts
CHANGED
|
@@ -157,6 +157,7 @@ const eventTypes = new Set([
|
|
|
157
157
|
'tools.ozone.moderation.defs#modEventPriorityScore',
|
|
158
158
|
'tools.ozone.moderation.defs#ageAssuranceEvent',
|
|
159
159
|
'tools.ozone.moderation.defs#ageAssuranceOverrideEvent',
|
|
160
|
+
'tools.ozone.moderation.defs#ageAssurancePurgeEvent',
|
|
160
161
|
'tools.ozone.moderation.defs#revokeAccountCredentialsEvent',
|
|
161
162
|
'tools.ozone.moderation.defs#scheduleTakedownEvent',
|
|
162
163
|
'tools.ozone.moderation.defs#cancelScheduledTakedownEvent',
|
|
@@ -25,6 +25,7 @@ export interface ModerationEvent {
|
|
|
25
25
|
| 'tools.ozone.moderation.defs#modEventPriorityScore'
|
|
26
26
|
| 'tools.ozone.moderation.defs#ageAssuranceEvent'
|
|
27
27
|
| 'tools.ozone.moderation.defs#ageAssuranceOverrideEvent'
|
|
28
|
+
| 'tools.ozone.moderation.defs#ageAssurancePurgeEvent'
|
|
28
29
|
| 'tools.ozone.moderation.defs#revokeAccountCredentialsEvent'
|
|
29
30
|
subjectType:
|
|
30
31
|
| 'com.atproto.admin.defs#repoRef'
|
package/src/lexicon/lexicons.ts
CHANGED
|
@@ -15949,6 +15949,7 @@ export const schemaDict = {
|
|
|
15949
15949
|
'lex:tools.ozone.moderation.defs#modEventPriorityScore',
|
|
15950
15950
|
'lex:tools.ozone.moderation.defs#ageAssuranceEvent',
|
|
15951
15951
|
'lex:tools.ozone.moderation.defs#ageAssuranceOverrideEvent',
|
|
15952
|
+
'lex:tools.ozone.moderation.defs#ageAssurancePurgeEvent',
|
|
15952
15953
|
'lex:tools.ozone.moderation.defs#revokeAccountCredentialsEvent',
|
|
15953
15954
|
'lex:tools.ozone.moderation.defs#scheduleTakedownEvent',
|
|
15954
15955
|
'lex:tools.ozone.moderation.defs#cancelScheduledTakedownEvent',
|
|
@@ -16026,6 +16027,7 @@ export const schemaDict = {
|
|
|
16026
16027
|
'lex:tools.ozone.moderation.defs#modEventPriorityScore',
|
|
16027
16028
|
'lex:tools.ozone.moderation.defs#ageAssuranceEvent',
|
|
16028
16029
|
'lex:tools.ozone.moderation.defs#ageAssuranceOverrideEvent',
|
|
16030
|
+
'lex:tools.ozone.moderation.defs#ageAssurancePurgeEvent',
|
|
16029
16031
|
'lex:tools.ozone.moderation.defs#revokeAccountCredentialsEvent',
|
|
16030
16032
|
'lex:tools.ozone.moderation.defs#scheduleTakedownEvent',
|
|
16031
16033
|
'lex:tools.ozone.moderation.defs#cancelScheduledTakedownEvent',
|
|
@@ -16592,6 +16594,19 @@ export const schemaDict = {
|
|
|
16592
16594
|
},
|
|
16593
16595
|
},
|
|
16594
16596
|
},
|
|
16597
|
+
ageAssurancePurgeEvent: {
|
|
16598
|
+
type: 'object',
|
|
16599
|
+
description:
|
|
16600
|
+
'Purges all age assurance events for the subject. Only works on DID subjects. Moderator-only.',
|
|
16601
|
+
required: ['comment'],
|
|
16602
|
+
properties: {
|
|
16603
|
+
comment: {
|
|
16604
|
+
type: 'string',
|
|
16605
|
+
minLength: 1,
|
|
16606
|
+
description: 'Comment describing the reason for the purge.',
|
|
16607
|
+
},
|
|
16608
|
+
},
|
|
16609
|
+
},
|
|
16595
16610
|
revokeAccountCredentialsEvent: {
|
|
16596
16611
|
type: 'object',
|
|
16597
16612
|
description:
|
|
@@ -17465,6 +17480,7 @@ export const schemaDict = {
|
|
|
17465
17480
|
'lex:tools.ozone.moderation.defs#modEventPriorityScore',
|
|
17466
17481
|
'lex:tools.ozone.moderation.defs#ageAssuranceEvent',
|
|
17467
17482
|
'lex:tools.ozone.moderation.defs#ageAssuranceOverrideEvent',
|
|
17483
|
+
'lex:tools.ozone.moderation.defs#ageAssurancePurgeEvent',
|
|
17468
17484
|
'lex:tools.ozone.moderation.defs#revokeAccountCredentialsEvent',
|
|
17469
17485
|
'lex:tools.ozone.moderation.defs#scheduleTakedownEvent',
|
|
17470
17486
|
'lex:tools.ozone.moderation.defs#cancelScheduledTakedownEvent',
|
|
@@ -46,6 +46,7 @@ export interface ModEventView {
|
|
|
46
46
|
| $Typed<ModEventPriorityScore>
|
|
47
47
|
| $Typed<AgeAssuranceEvent>
|
|
48
48
|
| $Typed<AgeAssuranceOverrideEvent>
|
|
49
|
+
| $Typed<AgeAssurancePurgeEvent>
|
|
49
50
|
| $Typed<RevokeAccountCredentialsEvent>
|
|
50
51
|
| $Typed<ScheduleTakedownEvent>
|
|
51
52
|
| $Typed<CancelScheduledTakedownEvent>
|
|
@@ -98,6 +99,7 @@ export interface ModEventViewDetail {
|
|
|
98
99
|
| $Typed<ModEventPriorityScore>
|
|
99
100
|
| $Typed<AgeAssuranceEvent>
|
|
100
101
|
| $Typed<AgeAssuranceOverrideEvent>
|
|
102
|
+
| $Typed<AgeAssurancePurgeEvent>
|
|
101
103
|
| $Typed<RevokeAccountCredentialsEvent>
|
|
102
104
|
| $Typed<ScheduleTakedownEvent>
|
|
103
105
|
| $Typed<CancelScheduledTakedownEvent>
|
|
@@ -503,6 +505,23 @@ export function validateAgeAssuranceOverrideEvent<V>(v: V) {
|
|
|
503
505
|
)
|
|
504
506
|
}
|
|
505
507
|
|
|
508
|
+
/** Purges all age assurance events for the subject. Only works on DID subjects. Moderator-only. */
|
|
509
|
+
export interface AgeAssurancePurgeEvent {
|
|
510
|
+
$type?: 'tools.ozone.moderation.defs#ageAssurancePurgeEvent'
|
|
511
|
+
/** Comment describing the reason for the purge. */
|
|
512
|
+
comment: string
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const hashAgeAssurancePurgeEvent = 'ageAssurancePurgeEvent'
|
|
516
|
+
|
|
517
|
+
export function isAgeAssurancePurgeEvent<V>(v: V) {
|
|
518
|
+
return is$typed(v, id, hashAgeAssurancePurgeEvent)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
export function validateAgeAssurancePurgeEvent<V>(v: V) {
|
|
522
|
+
return validate<AgeAssurancePurgeEvent & V>(v, id, hashAgeAssurancePurgeEvent)
|
|
523
|
+
}
|
|
524
|
+
|
|
506
525
|
/** Account credentials revocation by moderators. Only works on DID subjects. */
|
|
507
526
|
export interface RevokeAccountCredentialsEvent {
|
|
508
527
|
$type?: 'tools.ozone.moderation.defs#revokeAccountCredentialsEvent'
|
|
@@ -42,6 +42,7 @@ export interface InputSchema {
|
|
|
42
42
|
| $Typed<ToolsOzoneModerationDefs.ModEventPriorityScore>
|
|
43
43
|
| $Typed<ToolsOzoneModerationDefs.AgeAssuranceEvent>
|
|
44
44
|
| $Typed<ToolsOzoneModerationDefs.AgeAssuranceOverrideEvent>
|
|
45
|
+
| $Typed<ToolsOzoneModerationDefs.AgeAssurancePurgeEvent>
|
|
45
46
|
| $Typed<ToolsOzoneModerationDefs.RevokeAccountCredentialsEvent>
|
|
46
47
|
| $Typed<ToolsOzoneModerationDefs.ScheduleTakedownEvent>
|
|
47
48
|
| $Typed<ToolsOzoneModerationDefs.CancelScheduledTakedownEvent>
|
package/src/mod-service/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
isAccountEvent,
|
|
29
29
|
isAgeAssuranceEvent,
|
|
30
30
|
isAgeAssuranceOverrideEvent,
|
|
31
|
+
isAgeAssurancePurgeEvent,
|
|
31
32
|
isIdentityEvent,
|
|
32
33
|
isModEventAcknowledge,
|
|
33
34
|
isModEventComment,
|
|
@@ -665,6 +666,10 @@ export class ModerationService {
|
|
|
665
666
|
subject.blobCids,
|
|
666
667
|
)
|
|
667
668
|
|
|
669
|
+
if (isAgeAssurancePurgeEvent(event)) {
|
|
670
|
+
await this.purgeAgeAssuranceEvents(subjectInfo.subjectDid)
|
|
671
|
+
}
|
|
672
|
+
|
|
668
673
|
// Updates are only needed if strikeCount is numeric (in some cases even 0)
|
|
669
674
|
if (modEvent.strikeCount !== null) {
|
|
670
675
|
try {
|
|
@@ -681,6 +686,15 @@ export class ModerationService {
|
|
|
681
686
|
return { event: modEvent, subjectStatus }
|
|
682
687
|
}
|
|
683
688
|
|
|
689
|
+
async purgeAgeAssuranceEvents(subjectDid: string) {
|
|
690
|
+
this.db.assertTransaction()
|
|
691
|
+
await this.db.db
|
|
692
|
+
.deleteFrom('moderation_event')
|
|
693
|
+
.where('subjectDid', '=', subjectDid)
|
|
694
|
+
.where('action', '=', 'tools.ozone.moderation.defs#ageAssuranceEvent')
|
|
695
|
+
.execute()
|
|
696
|
+
}
|
|
697
|
+
|
|
684
698
|
async getLastReversibleEventForSubject(subject: ReversalSubject) {
|
|
685
699
|
// If the subject is neither suspended nor muted don't bother finding the last reversible event
|
|
686
700
|
// Ideally, this should never happen because the caller of this method should only call this
|
|
@@ -125,6 +125,7 @@ const getSubjectStatusForModerationEvent = ({
|
|
|
125
125
|
}
|
|
126
126
|
case 'tools.ozone.moderation.defs#ageAssuranceEvent':
|
|
127
127
|
case 'tools.ozone.moderation.defs#ageAssuranceOverrideEvent':
|
|
128
|
+
case 'tools.ozone.moderation.defs#ageAssurancePurgeEvent':
|
|
128
129
|
return {
|
|
129
130
|
reviewState: defaultReviewState,
|
|
130
131
|
}
|
|
@@ -469,6 +470,13 @@ export const adjustModerationSubjectStatus = async (
|
|
|
469
470
|
}
|
|
470
471
|
}
|
|
471
472
|
|
|
473
|
+
if (action === 'tools.ozone.moderation.defs#ageAssurancePurgeEvent') {
|
|
474
|
+
newStatus.ageAssuranceState = 'unknown'
|
|
475
|
+
subjectStatus.ageAssuranceState = 'unknown'
|
|
476
|
+
newStatus.ageAssuranceUpdatedBy = null
|
|
477
|
+
subjectStatus.ageAssuranceUpdatedBy = null
|
|
478
|
+
}
|
|
479
|
+
|
|
472
480
|
if (blobCids?.length) {
|
|
473
481
|
const newBlobCids = jsonb(
|
|
474
482
|
blobCids,
|
|
@@ -10,7 +10,7 @@ Object {
|
|
|
10
10
|
"allowSubscriptions": "followers",
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)
|
|
13
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)",
|
|
14
14
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
15
15
|
"did": "user(0)",
|
|
16
16
|
"displayName": "ali",
|
|
@@ -45,7 +45,7 @@ Object {
|
|
|
45
45
|
"allowSubscriptions": "followers",
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)
|
|
48
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)",
|
|
49
49
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
50
50
|
"description": "its me!",
|
|
51
51
|
"did": "user(0)",
|
|
@@ -123,7 +123,7 @@ Object {
|
|
|
123
123
|
"allowSubscriptions": "followers",
|
|
124
124
|
},
|
|
125
125
|
},
|
|
126
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(4)/cids(1)
|
|
126
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(4)/cids(1)",
|
|
127
127
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
128
128
|
"description": "hi im bob label_me",
|
|
129
129
|
"did": "user(3)",
|
|
@@ -184,7 +184,7 @@ Object {
|
|
|
184
184
|
"allowSubscriptions": "followers",
|
|
185
185
|
},
|
|
186
186
|
},
|
|
187
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)
|
|
187
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)",
|
|
188
188
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
189
189
|
"did": "user(0)",
|
|
190
190
|
"displayName": "ali",
|
|
@@ -219,7 +219,7 @@ Object {
|
|
|
219
219
|
"allowSubscriptions": "followers",
|
|
220
220
|
},
|
|
221
221
|
},
|
|
222
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)
|
|
222
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)",
|
|
223
223
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
224
224
|
"description": "its me!",
|
|
225
225
|
"did": "user(0)",
|
|
@@ -299,7 +299,7 @@ Object {
|
|
|
299
299
|
"allowSubscriptions": "followers",
|
|
300
300
|
},
|
|
301
301
|
},
|
|
302
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(4)/cids(1)
|
|
302
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(4)/cids(1)",
|
|
303
303
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
304
304
|
"description": "hi im bob label_me",
|
|
305
305
|
"did": "user(3)",
|
|
@@ -362,7 +362,7 @@ Object {
|
|
|
362
362
|
"allowSubscriptions": "followers",
|
|
363
363
|
},
|
|
364
364
|
},
|
|
365
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)
|
|
365
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)",
|
|
366
366
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
367
367
|
"did": "user(0)",
|
|
368
368
|
"displayName": "ali",
|
|
@@ -397,7 +397,7 @@ Object {
|
|
|
397
397
|
"allowSubscriptions": "followers",
|
|
398
398
|
},
|
|
399
399
|
},
|
|
400
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)
|
|
400
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(1)/cids(1)",
|
|
401
401
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
402
402
|
"description": "its me!",
|
|
403
403
|
"did": "user(0)",
|
|
@@ -483,7 +483,7 @@ Object {
|
|
|
483
483
|
"allowSubscriptions": "followers",
|
|
484
484
|
},
|
|
485
485
|
},
|
|
486
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(5)/cids(1)
|
|
486
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(5)/cids(1)",
|
|
487
487
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
488
488
|
"description": "hi im bob label_me",
|
|
489
489
|
"did": "user(4)",
|
|
@@ -14,7 +14,7 @@ Array [
|
|
|
14
14
|
"lists": 0,
|
|
15
15
|
"starterPacks": 0,
|
|
16
16
|
},
|
|
17
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)
|
|
17
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)",
|
|
18
18
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
19
19
|
"description": "its me!",
|
|
20
20
|
"did": "user(0)",
|
|
@@ -199,7 +199,7 @@ Array [
|
|
|
199
199
|
"lists": 0,
|
|
200
200
|
"starterPacks": 0,
|
|
201
201
|
},
|
|
202
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)
|
|
202
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)",
|
|
203
203
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
204
204
|
"description": "its me!",
|
|
205
205
|
"did": "user(0)",
|
|
@@ -92,7 +92,7 @@ Array [
|
|
|
92
92
|
"lists": 0,
|
|
93
93
|
"starterPacks": 0,
|
|
94
94
|
},
|
|
95
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(6)/cids(0)
|
|
95
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(6)/cids(0)",
|
|
96
96
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
97
97
|
"description": "its me!",
|
|
98
98
|
"did": "user(5)",
|
|
@@ -141,7 +141,7 @@ Array [
|
|
|
141
141
|
"lists": 0,
|
|
142
142
|
"starterPacks": 0,
|
|
143
143
|
},
|
|
144
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(8)/cids(0)
|
|
144
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(8)/cids(0)",
|
|
145
145
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
146
146
|
"description": "hi im bob label_me",
|
|
147
147
|
"did": "user(7)",
|
|
@@ -273,7 +273,7 @@ Array [
|
|
|
273
273
|
"lists": 0,
|
|
274
274
|
"starterPacks": 0,
|
|
275
275
|
},
|
|
276
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(6)/cids(0)
|
|
276
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(6)/cids(0)",
|
|
277
277
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
278
278
|
"description": "its me!",
|
|
279
279
|
"did": "user(5)",
|
|
@@ -322,7 +322,7 @@ Array [
|
|
|
322
322
|
"lists": 0,
|
|
323
323
|
"starterPacks": 0,
|
|
324
324
|
},
|
|
325
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(8)/cids(0)
|
|
325
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(8)/cids(0)",
|
|
326
326
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
327
327
|
"description": "hi im bob label_me",
|
|
328
328
|
"did": "user(7)",
|
|
@@ -19,7 +19,7 @@ Array [
|
|
|
19
19
|
"lists": 0,
|
|
20
20
|
"starterPacks": 0,
|
|
21
21
|
},
|
|
22
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)
|
|
22
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)",
|
|
23
23
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
24
24
|
"description": "hi im bob label_me",
|
|
25
25
|
"did": "user(0)",
|
|
@@ -76,7 +76,7 @@ Array [
|
|
|
76
76
|
"lists": 0,
|
|
77
77
|
"starterPacks": 0,
|
|
78
78
|
},
|
|
79
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(2)/cids(0)
|
|
79
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(2)/cids(0)",
|
|
80
80
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
81
81
|
"description": "its me!",
|
|
82
82
|
"did": "user(1)",
|
|
@@ -18,7 +18,7 @@ Object {
|
|
|
18
18
|
"lists": 0,
|
|
19
19
|
"starterPacks": 0,
|
|
20
20
|
},
|
|
21
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)
|
|
21
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(3)/cids(0)",
|
|
22
22
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
23
23
|
"description": "its me!",
|
|
24
24
|
"did": "user(0)",
|
|
@@ -104,7 +104,7 @@ Object {
|
|
|
104
104
|
"lists": 0,
|
|
105
105
|
"starterPacks": 0,
|
|
106
106
|
},
|
|
107
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(2)/cids(0)
|
|
107
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(2)/cids(0)",
|
|
108
108
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
109
109
|
"description": "hi im bob label_me",
|
|
110
110
|
"did": "user(1)",
|
|
@@ -182,7 +182,7 @@ Object {
|
|
|
182
182
|
"lists": 0,
|
|
183
183
|
"starterPacks": 0,
|
|
184
184
|
},
|
|
185
|
-
"avatar": "https://bsky.public.url/img/avatar/plain/user(2)/cids(0)
|
|
185
|
+
"avatar": "https://bsky.public.url/img/avatar/plain/user(2)/cids(0)",
|
|
186
186
|
"createdAt": "1970-01-01T00:00:00.000Z",
|
|
187
187
|
"description": "its me!",
|
|
188
188
|
"did": "user(0)",
|
package/tests/_util.ts
CHANGED
|
@@ -64,14 +64,16 @@ export const forSnapshot = (obj: unknown) => {
|
|
|
64
64
|
if (str.match(/^\d+::bafy/)) {
|
|
65
65
|
return constantKeysetCursor
|
|
66
66
|
}
|
|
67
|
-
if (str.match(/\/img\/[^/]+\/.+\/did:plc:[^/]+\/[
|
|
68
|
-
// Match image urls
|
|
67
|
+
if (str.match(/\/img\/[^/]+\/.+\/did:plc:[^/]+\/[^/@]+(?:@[\w]+)?$/)) {
|
|
68
|
+
// Match image urls, stripping optional format suffix (e.g. @webp) for stable snapshots
|
|
69
69
|
const match = str.match(
|
|
70
|
-
/\/img\/[^/]+\/.+\/(did:plc:[^/]+)\/([
|
|
70
|
+
/\/img\/[^/]+\/.+\/(did:plc:[^/]+)\/([^/@]+)(?:@[\w]+)?$/,
|
|
71
71
|
)
|
|
72
72
|
if (!match) return str
|
|
73
73
|
const [, did, cid] = match
|
|
74
|
-
return str
|
|
74
|
+
return str
|
|
75
|
+
.replace(did, take(users, did))
|
|
76
|
+
.replace(new RegExp(`${cid}(?:@\\w+)?`), take(cids, cid))
|
|
75
77
|
}
|
|
76
78
|
// decent check for 64-byte base64 encoded signatures
|
|
77
79
|
if (str.length === 86 && !str.includes(' ')) {
|