mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
151 lines
10 KiB
Plaintext
151 lines
10 KiB
Plaintext
---
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
title: Bulk jobs
|
|
description: Administrative bulk mutations over an explicit user or guild set.
|
|
---
|
|
|
|
import RouteHeader from '@/components/RouteHeader.astro';
|
|
|
|
A bulk job applies one operation to an explicit set of users or guilds. The `task` field selects the request body and required [Admin ACL](/admin-api/#acl-registry).
|
|
|
|
Every target is a list of IDs. There is no search, role, tag, email, or IP selector, so the caller resolves its own target set first with [List users](/admin-api/users/#list-users) or [List guilds](/admin-api/guilds/#list-guilds).
|
|
|
|
[Queue bulk job](#queue-bulk-job) returns a job identifier immediately and applies nothing synchronously. The caller reads progress, terminal state, and failure text through [Get job](/admin-api/jobs/#get-job). [Cancel job](/admin-api/jobs/#cancel-job) stops a run.
|
|
|
|
## Bulk job creation object
|
|
|
|
A bulk job creation has the identifier of the queued job.
|
|
|
|
### Structure
|
|
|
|
| Field | Type | Description |
|
|
| --- | --- | --- |
|
|
| job_id<sup>1</sup> | snowflake | The job that applies the requested operation, readable through [Get job](/admin-api/jobs/#get-job) |
|
|
|
|
<sup>1</sup> The job is readable as soon as this response arrives
|
|
|
|
### Example
|
|
|
|
```json
|
|
{
|
|
"job_id": "1501314428688998182"
|
|
}
|
|
```
|
|
|
|
## Bulk task types
|
|
|
|
Each value is the exact `task` discriminator.
|
|
|
|
### `update_user_flags`
|
|
|
|
ACL `bulk:update:user_flags`. Adds and removes account flags on every targeted user. Runs as `bulkUpdateUserFlags`.
|
|
|
|
### `update_guild_features`
|
|
|
|
ACL `bulk:update:guild_features`. Adds and removes features on every targeted guild. Runs as `bulkUpdateGuildFeatures`.
|
|
|
|
### `add_guild_members`
|
|
|
|
ACL `bulk:add:guild_members`. Adds every targeted user to one guild. Runs as `bulkAddGuildMembers`.
|
|
|
|
### `schedule_user_deletion`
|
|
|
|
ACL `bulk:delete:users`. Schedules account deletion for every targeted user. Runs as `bulkScheduleUserDeletion`.
|
|
|
|
Each worker task is recorded as `task_type` on the job and listed under [background job task types](/admin-api/jobs/#background-job-task-types). Every bulk task runs in the `lifecycle` [processing lane](/admin-api/jobs/#processing-lanes).
|
|
|
|
## Queue bulk job
|
|
|
|
<RouteHeader method="POST" path="/v1/admin/bulk-jobs" auditReason />
|
|
|
|
Queues one bulk operation. Returns a [bulk job creation](#bulk-job-creation-object) object on success.
|
|
|
|
### Limitations
|
|
|
|
- The body matches exactly one `task` variant.
|
|
- The caller needs at least one of the [bulk ACLs](#bulk-task-types) and then the exact ACL that `task` selects.
|
|
|
|
:::caution[Authorisation depends on the validated body]
|
|
Body validation runs ahead of authentication and ACL evaluation, so a malformed body answers 400 even when the request has no credential.
|
|
:::
|
|
|
|
### JSON body
|
|
|
|
The `task` discriminator selects one of these structures. Every ID array has an upper bound and no lower bound, so an empty array queues a job that processes nothing and finishes with the status `succeeded`.
|
|
|
|
#### Update user flags structure
|
|
|
|
| Field | Type | Description |
|
|
| --- | --- | --- |
|
|
| task | string | The discriminator selecting this variant, `update_user_flags` |
|
|
| user_ids | array[snowflake] | The users to update (max 1000 entries) |
|
|
| add_flags?<sup>1</sup> | array[string] | [Account flag](/admin-api/users/#account-flags) values to add (max 64, default empty) |
|
|
| remove_flags?<sup>1</sup> | array[string] | [Account flag](/admin-api/users/#account-flags) values to remove (max 64, default empty) |
|
|
|
|
<sup>1</sup> Each entry is one 64-bit flag value written as an unsigned decimal string, such as `1024`. Body validation rejects a symbolic name. Additions are applied before removals, so a value named in both arrays ends up cleared
|
|
|
|
#### Update guild features structure
|
|
|
|
| Field | Type | Description |
|
|
| --- | --- | --- |
|
|
| task | string | The discriminator selecting this variant, `update_guild_features` |
|
|
| guild_ids | array[snowflake] | The guilds to update (max 1000 entries) |
|
|
| add_features?<sup>1</sup> | array[string] | [Guild features](/http-api/guilds/#guild-features) to add (max 100, default empty) |
|
|
| remove_features?<sup>1</sup> | array[string] | [Guild features](/http-api/guilds/#guild-features) to remove (max 100, default empty) |
|
|
|
|
<sup>1</sup> Body validation accepts any string, so a name outside the registry is written to the guild's feature set. Additions are applied before removals
|
|
|
|
#### Add guild members structure
|
|
|
|
| Field | Type | Description |
|
|
| --- | --- | --- |
|
|
| task | string | The discriminator selecting this variant, `add_guild_members` |
|
|
| guild_id | snowflake | The guild that receives the users |
|
|
| user_ids | array[snowflake] | The users to add as members (max 1000 entries) |
|
|
|
|
#### Schedule user deletion structure
|
|
|
|
| Field | Type | Description |
|
|
| --- | --- | --- |
|
|
| task | string | The discriminator selecting this variant, `schedule_user_deletion` |
|
|
| user_ids | array[snowflake] | The users to schedule for deletion (max 1000 entries) |
|
|
| reason_code | integer | [Deletion reason](/admin-api/users/#deletion-reasons) recorded against every targeted account |
|
|
| public_reason? | string | The reason shown to each account holder in the deletion notice (0-512 characters after normalisation) |
|
|
| days_until_deletion?<sup>1</sup> | integer | The delay before deletion in whole days (1-365, default 60) |
|
|
|
|
<sup>1</sup> Fluxer raises the value to the reason-specific minimum, 14 days for `USER_REQUESTED` and 60 days for every other code
|
|
|
|
### Response
|
|
|
|
| Status | Body | Condition |
|
|
| --- | --- | --- |
|
|
| 200 | [bulk job creation](#bulk-job-creation-object) object | The bulk job was queued |
|
|
| 403 | [error response](/admin-api/#error-response) | `MISSING_ACL` without the ACL selected by `task` |
|
|
| 500<sup>1</sup> | [error response](/admin-api/#error-response) | The job could not be queued |
|
|
|
|
<sup>1</sup> A full queue rejects the job and the request returns `INTERNAL_SERVER_ERROR`
|
|
|
|
### Side effects
|
|
|
|
The [job](/admin-api/jobs/) records the acting Admin and audit reason. Queueing records one [Admin audit entry](/admin-api/#admin-audit-entry-object) with action `queue_bulk_job`, target type `bulk_job`, target ID equal to the job identifier, and metadata keys `task` and `entity_count`. `entity_count` is the length of `guild_ids` for `update_guild_features` and of `user_ids` for every other task. An `add_guild_members` entry also has `guild_id`. Failure to create the job returns 500 `INTERNAL_SERVER_ERROR` without starting the operation or recording an entry.
|
|
|
|
Entities are processed in the submitted order. [Cancel job](/admin-api/jobs/#cancel-job) stops the run between entities and sets its status to `cancelled`. Completed changes remain in place. A failed or unknown entity counts as failed without stopping the remaining work.
|
|
|
|
Every task updates its progress before work starts and at completion. Every task except `schedule_user_deletion` also updates its progress after every 25 entities, and `schedule_user_deletion` updates its progress after every 10 accounts. The final `progress_message` has the successful and failed counts.
|
|
|
|
Every task writes one summary Admin audit entry when it finishes, with the action `bulk_update_user_flags`, `bulk_update_guild_features`, `bulk_add_guild_members`, `bulk_schedule_deletion`, `bulk_ban_file_shas`, or `bulk_delete_user_messages`. The summary has the audit reason, the entity count, the operation-specific parameters, the job identifier, and the processed, successful, and failed counts. Its `target_type` is `bulk_job` and its `target_id` is the job identifier, except for `add_guild_members`, which targets the guild. A failed job writes no summary entry. A cancelled job writes one, marked `cancelled`, covering the entities it processed before it stopped.
|
|
|
|
`update_user_flags` writes one `update_flags` entry for each account and dispatches [User Update](/gateway/events/#user-update) to the account's sessions. A change to a publicly visible flag also dispatches [Guild Member Update](/gateway/events/#guild-member-update) to every guild the account is in.
|
|
|
|
`update_guild_features` writes one `update_features` entry for each guild, dispatches [Guild Update](/gateway/events/#guild-update), and reindexes the guild for search. Fluxer reconciles a guild that already has a discovery application record against the new feature set, so gaining `DISCOVERABLE` approves the record and losing it marks the record removed. A guild with no discovery record is left alone.
|
|
|
|
`add_guild_members` bypasses the ban check that a normal join runs. The task suppresses the join system message, records the join source as an Admin force add, and dispatches [Guild Member Add](/gateway/events/#guild-member-add) to the guild and [Guild Create](/gateway/events/#guild-create) to the added account's sessions. The task still enforces the per-account guild cap and the guild member cap, so an account at either ceiling is counted as failed. An account that is already a member is left unchanged and counted as successful, with no second membership and no Dispatch. Adding a bot account also records a `BOT_ADD` guild audit log entry attributed to the acting Admin.
|
|
|
|
`delete_user_messages` deletes every message each account wrote, across every channel. It writes one `delete_all_user_messages` entry for each account, with the audit reason, the account, and the deleted message count, and reports progress after every account.
|
|
|
|
`schedule_user_deletion` marks each account deleted. The task runs the same steps as [Schedule user deletion](/admin-api/users/#schedule-user-deletion) for one account. It stores the reason code, public reason, and audit reason on the account, reschedules its pending deletion, terminates its sessions, cancels and refunds its Stripe subscription when one is on file, dispatches [User Update](/gateway/events/#user-update), writes one `schedule_deletion` entry for each account with the audit reason and the reason code, and emails the account holder when `notify_user` is true and an address is on file. A failed email is logged and does not fail the entity. The summary entry records `notify_user`. When the reason is not `USER_REQUESTED`, the task also bans the account's identifiers. When the reason is one that resolves reports under [Schedule user deletion](/admin-api/users/#schedule-user-deletion), the task also resolves the pending reports against the account, leaves the `child_safety`, `underage_user`, and `self_harm` categories pending, and sends each reporter of a resolved report the generic notice [Update report](/admin-api/reports/#update-report) describes. The skip cases of that notice apply.
|
|
|
|
### Rate limit
|
|
|
|
20 requests per minute for each authenticated user, on the `admin:bulk:operation` bucket.
|