Skip to content

Commit 591de19

Browse files
authored
Ozone delayed action (#4241)
* ✨ Add delayed takedown feature to ozone * ✨ Apply tag auth check and add takedown event push * ✅ Add tests for takedown restrictions * 🐛 Remove only test block * 🐛 Add service forwarding * ✨ Copy event properties into scheduled takedown event * 🧹 Cleanup * 🐛 Make statuses required in listScheduledActions * 🐛 Define required field in lexicon * ✨ Add tag when scheduling and cancelling scheduled takedown
1 parent 09439d7 commit 591de19

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+4813
-89
lines changed

.changeset/seven-mirrors-double.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@atproto/ozone": patch
3+
"@atproto/api": patch
4+
"@atproto/pds": patch
5+
---
6+
7+
Add scheduled action api to ozone
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"lexicon": 1,
3+
"id": "tools.ozone.moderation.cancelScheduledActions",
4+
"defs": {
5+
"main": {
6+
"type": "procedure",
7+
"description": "Cancel all pending scheduled moderation actions for specified subjects",
8+
"input": {
9+
"encoding": "application/json",
10+
"schema": {
11+
"type": "object",
12+
"required": ["subjects"],
13+
"properties": {
14+
"subjects": {
15+
"type": "array",
16+
"maxLength": 100,
17+
"items": {
18+
"type": "string",
19+
"format": "did"
20+
},
21+
"description": "Array of DID subjects to cancel scheduled actions for"
22+
},
23+
"comment": {
24+
"type": "string",
25+
"description": "Optional comment describing the reason for cancellation"
26+
}
27+
}
28+
}
29+
},
30+
"output": {
31+
"encoding": "application/json",
32+
"schema": {
33+
"type": "ref",
34+
"ref": "#cancellationResults"
35+
}
36+
}
37+
},
38+
"cancellationResults": {
39+
"type": "object",
40+
"required": ["succeeded", "failed"],
41+
"properties": {
42+
"succeeded": {
43+
"type": "array",
44+
"items": { "type": "string", "format": "did" },
45+
"description": "DIDs for which all pending scheduled actions were successfully cancelled"
46+
},
47+
"failed": {
48+
"type": "array",
49+
"items": { "type": "ref", "ref": "#failedCancellation" },
50+
"description": "DIDs for which cancellation failed with error details"
51+
}
52+
}
53+
},
54+
"failedCancellation": {
55+
"type": "object",
56+
"required": ["did", "error"],
57+
"properties": {
58+
"did": { "type": "string", "format": "did" },
59+
"error": { "type": "string" },
60+
"errorCode": { "type": "string" }
61+
}
62+
}
63+
}
64+
}

lexicons/tools/ozone/moderation/defs.json

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
"#modEventPriorityScore",
3939
"#ageAssuranceEvent",
4040
"#ageAssuranceOverrideEvent",
41-
"#revokeAccountCredentialsEvent"
41+
"#revokeAccountCredentialsEvent",
42+
"#scheduleTakedownEvent",
43+
"#cancelScheduledTakedownEvent"
4244
]
4345
},
4446
"subject": {
@@ -93,7 +95,9 @@
9395
"#modEventPriorityScore",
9496
"#ageAssuranceEvent",
9597
"#ageAssuranceOverrideEvent",
96-
"#revokeAccountCredentialsEvent"
98+
"#revokeAccountCredentialsEvent",
99+
"#scheduleTakedownEvent",
100+
"#cancelScheduledTakedownEvent"
97101
]
98102
},
99103
"subject": {
@@ -678,6 +682,23 @@
678682
"timestamp": { "type": "string", "format": "datetime" }
679683
}
680684
},
685+
"scheduleTakedownEvent": {
686+
"type": "object",
687+
"description": "Logs a scheduled takedown action for an account.",
688+
"properties": {
689+
"comment": { "type": "string" },
690+
"executeAt": { "type": "string", "format": "datetime" },
691+
"executeAfter": { "type": "string", "format": "datetime" },
692+
"executeUntil": { "type": "string", "format": "datetime" }
693+
}
694+
},
695+
"cancelScheduledTakedownEvent": {
696+
"type": "object",
697+
"description": "Logs cancellation of a scheduled takedown action for an account.",
698+
"properties": {
699+
"comment": { "type": "string" }
700+
}
701+
},
681702
"repoView": {
682703
"type": "object",
683704
"required": [
@@ -1003,6 +1024,83 @@
10031024
"timelineEventPlcTombstone": {
10041025
"type": "token",
10051026
"description": "Moderation event timeline event for a PLC tombstone operation"
1027+
},
1028+
"scheduledActionView": {
1029+
"type": "object",
1030+
"description": "View of a scheduled moderation action",
1031+
"required": ["id", "action", "did", "createdBy", "createdAt", "status"],
1032+
"properties": {
1033+
"id": {
1034+
"type": "integer",
1035+
"description": "Auto-incrementing row ID"
1036+
},
1037+
"action": {
1038+
"type": "string",
1039+
"knownValues": ["takedown"],
1040+
"description": "Type of action to be executed"
1041+
},
1042+
"eventData": {
1043+
"type": "unknown",
1044+
"description": "Serialized event object that will be propagated to the event when performed"
1045+
},
1046+
"did": {
1047+
"type": "string",
1048+
"format": "did",
1049+
"description": "Subject DID for the action"
1050+
},
1051+
"executeAt": {
1052+
"type": "string",
1053+
"format": "datetime",
1054+
"description": "Exact time to execute the action"
1055+
},
1056+
"executeAfter": {
1057+
"type": "string",
1058+
"format": "datetime",
1059+
"description": "Earliest time to execute the action (for randomized scheduling)"
1060+
},
1061+
"executeUntil": {
1062+
"type": "string",
1063+
"format": "datetime",
1064+
"description": "Latest time to execute the action (for randomized scheduling)"
1065+
},
1066+
"randomizeExecution": {
1067+
"type": "boolean",
1068+
"description": "Whether execution time should be randomized within the specified range"
1069+
},
1070+
"createdBy": {
1071+
"type": "string",
1072+
"format": "did",
1073+
"description": "DID of the user who created this scheduled action"
1074+
},
1075+
"createdAt": {
1076+
"type": "string",
1077+
"format": "datetime",
1078+
"description": "When the scheduled action was created"
1079+
},
1080+
"updatedAt": {
1081+
"type": "string",
1082+
"format": "datetime",
1083+
"description": "When the scheduled action was last updated"
1084+
},
1085+
"status": {
1086+
"type": "string",
1087+
"knownValues": ["pending", "executed", "cancelled", "failed"],
1088+
"description": "Current status of the scheduled action"
1089+
},
1090+
"lastExecutedAt": {
1091+
"type": "string",
1092+
"format": "datetime",
1093+
"description": "When the action was last attempted to be executed"
1094+
},
1095+
"lastFailureReason": {
1096+
"type": "string",
1097+
"description": "Reason for the last execution failure"
1098+
},
1099+
"executionEventId": {
1100+
"type": "integer",
1101+
"description": "ID of the moderation event created when action was successfully executed"
1102+
}
1103+
}
10061104
}
10071105
}
10081106
}

lexicons/tools/ozone/moderation/emitEvent.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
"tools.ozone.moderation.defs#modEventPriorityScore",
3636
"tools.ozone.moderation.defs#ageAssuranceEvent",
3737
"tools.ozone.moderation.defs#ageAssuranceOverrideEvent",
38-
"tools.ozone.moderation.defs#revokeAccountCredentialsEvent"
38+
"tools.ozone.moderation.defs#revokeAccountCredentialsEvent",
39+
"tools.ozone.moderation.defs#scheduleTakedownEvent",
40+
"tools.ozone.moderation.defs#cancelScheduledTakedownEvent"
3941
]
4042
},
4143
"subject": {

lexicons/tools/ozone/moderation/getAccountTimeline.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@
9292
"tools.ozone.hosting.getAccountHistory#accountCreated",
9393
"tools.ozone.hosting.getAccountHistory#emailConfirmed",
9494
"tools.ozone.hosting.getAccountHistory#passwordUpdated",
95-
"tools.ozone.hosting.getAccountHistory#handleUpdated"
95+
"tools.ozone.hosting.getAccountHistory#handleUpdated",
96+
"tools.ozone.moderation.defs#scheduleTakedownEvent",
97+
"tools.ozone.moderation.defs#cancelScheduledTakedownEvent"
9698
]
9799
},
98100
"count": {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"lexicon": 1,
3+
"id": "tools.ozone.moderation.listScheduledActions",
4+
"defs": {
5+
"main": {
6+
"type": "procedure",
7+
"description": "List scheduled moderation actions with optional filtering",
8+
"input": {
9+
"encoding": "application/json",
10+
"schema": {
11+
"type": "object",
12+
"required": ["statuses"],
13+
"properties": {
14+
"startsAfter": {
15+
"type": "string",
16+
"format": "datetime",
17+
"description": "Filter actions scheduled to execute after this time"
18+
},
19+
"endsBefore": {
20+
"type": "string",
21+
"format": "datetime",
22+
"description": "Filter actions scheduled to execute before this time"
23+
},
24+
"subjects": {
25+
"type": "array",
26+
"maxLength": 100,
27+
"items": {
28+
"type": "string",
29+
"format": "did"
30+
},
31+
"description": "Filter actions for specific DID subjects"
32+
},
33+
"statuses": {
34+
"type": "array",
35+
"minLength": 1,
36+
"items": {
37+
"type": "string",
38+
"knownValues": ["pending", "executed", "cancelled", "failed"]
39+
},
40+
"description": "Filter actions by status"
41+
},
42+
"limit": {
43+
"type": "integer",
44+
"minimum": 1,
45+
"maximum": 100,
46+
"default": 50,
47+
"description": "Maximum number of results to return"
48+
},
49+
"cursor": {
50+
"type": "string",
51+
"description": "Cursor for pagination"
52+
}
53+
}
54+
}
55+
},
56+
"output": {
57+
"encoding": "application/json",
58+
"schema": {
59+
"type": "object",
60+
"required": ["actions"],
61+
"properties": {
62+
"actions": {
63+
"type": "array",
64+
"items": {
65+
"type": "ref",
66+
"ref": "tools.ozone.moderation.defs#scheduledActionView"
67+
}
68+
},
69+
"cursor": {
70+
"type": "string",
71+
"description": "Cursor for next page of results"
72+
}
73+
}
74+
}
75+
}
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)