chore(admin): remove user type toggles (#3161)

This commit is contained in:
Hampus
2026-10-03 14:22:13 +02:00
committed by GitHub
parent 81d69c41f5
commit 7fa00c0e89
90 changed files with 67 additions and 627 deletions
@@ -83,7 +83,7 @@ Only [Create Admin API key](#create-admin-api-key) returns this object. It has t
<sup>2</sup> Derived from `expires_in_days` at the instant the key is created, and null when that field is omitted
<sup>3</sup> Reflects the stored set, so a value repeated in the request appears once
<sup>3</sup> Reflects the stored set, so a value repeated in the request appears once and a value outside the [ACL registry](/admin-api/#acl-registry) is left out
:::caution[The secret is returned once]
The secret cannot be retrieved or rotated later. If it is lost, revoke the key and create a replacement.
@@ -140,7 +140,7 @@ The acting credential must already have every value in `acls`, unless it has `*`
| --- | --- | --- |
| name<sup>1</sup> | string | The name given to the key (1-100 characters) |
| expires_in_days?<sup>2</sup> | integer | The number of days until the key expires (1-365) |
| acls<sup>3</sup> | array[string] | The [ACLs](/admin-api/#acl-registry) stored on the key, each a registry value (at most 107) |
| acls<sup>3</sup> | array[string] | The [ACLs](/admin-api/#acl-registry) stored on the key, each a registry value (at most 103) |
<sup>1</sup> A value that is empty after trimming is rejected, so whitespace alone is not a name
@@ -218,7 +218,7 @@ An update never rotates the credential, and no field on this route changes the e
| Field | Type | Description |
| --- | --- | --- |
| name?<sup>1</sup> | string | The replacement name for the key (1-100 characters) |
| acls?<sup>2</sup> | array[string] | The complete replacement set of [ACLs](/admin-api/#acl-registry), each a registry value (at most 107) |
| acls?<sup>2</sup> | array[string] | The complete replacement set of [ACLs](/admin-api/#acl-registry), each a registry value (at most 103) |
<sup>1</sup> A value that is empty after trimming is rejected
@@ -61,7 +61,7 @@ A body with none of those fields resolves to no ACL at all and applies no change
Fluxer checks each ACL an Admin grants against the ACLs that Admin holds. [Set user ACLs](/admin-api/users/#set-user-acls) and [Create Admin API key](/admin-api/api-keys/#create-admin-api-key) both refuse to write an ACL the acting Admin does not itself hold, with 403 `MISSING_ACL`. A wildcard holder is exempt. Set user ACLs also refuses the acting Admin's own account with 403 `ACCESS_DENIED`, and it looks up the target account before it checks the granted ACLs, so an unknown ID fails first with 404 `UNKNOWN_USER`.
[Set user ACLs](/admin-api/users/#set-user-acls), [Create Admin API key](/admin-api/api-keys/#create-admin-api-key), and [Update Admin API key](/admin-api/api-keys/#update-admin-api-key) each accept at most 107 ACLs and validate every entry against the registry, so a value outside it returns 400 `INVALID_FORM_BODY`.
[Set user ACLs](/admin-api/users/#set-user-acls), [Create Admin API key](/admin-api/api-keys/#create-admin-api-key), and [Update Admin API key](/admin-api/api-keys/#update-admin-api-key) each accept at most 103 ACLs and validate every entry against the registry, so a value outside it returns 400 `INVALID_FORM_BODY`.
:::caution[`*` satisfies every present and future ACL]
A key whose owning account holds `*` skips the owner check. An Admin holding `*` can grant any ACL.
@@ -373,8 +373,6 @@ An entry with any other action has `access` set to `write`.
| schedule_deletion | Account deletion was scheduled |
| send_password_reset | A password reset message was requested for an account |
| set_acls | The Admin ACL set of an account was replaced |
| set_bot_status | The bot flag of an account was changed |
| set_system_status | The system flag of an account was changed |
| set_traits | Account traits were replaced |
| shutdown_guild | One guild was stopped on the main Gateway |
| system_dm.send | A system DM broadcast was created |
@@ -476,7 +474,7 @@ Returns every Admin permission string the instance recognises, in [ACL registry]
| Field | Type | Description |
| --- | --- | --- |
| acls<sup>1</sup> | array[string] | The permission strings the Admin API recognises (at most 107 entries) |
| acls<sup>1</sup> | array[string] | The permission strings the Admin API recognises (at most 103 entries) |
<sup>1</sup> The response is the registry itself and does not vary with the caller's own ACL set
@@ -589,7 +587,6 @@ The registry is returned in this order by [List ACLs](#list-acls). A value outsi
| user:view:email<sup>6</sup> | Unredacts user email addresses and email verification state |
| user:view:ip<sup>6</sup> | Unredacts the last active IP address and the location derived from it |
| user:temp_ban | Applies and removes an account ban |
| user:update:bot_status | Updates bot and system account state |
| user:update:dob | Updates dates of birth |
| user:update:email | Updates the email address, marks the address verified, resends verification, and sends a password reset |
| user:update:flags | Updates account flags and premium flags, refreshes in-app purchases, and ends every login session of an account |
@@ -57,7 +57,7 @@ When the caller lacks `user:view:email`, `user:view:dob`, or `user:view:ip`, Flu
| deletion_audit_log_reason | ?string | The private reason stored with the pending deletion, and null without `audit_log:view` |
| deletion_scheduled_by | ?snowflake | The ID of the account that scheduled the pending deletion, or null when it was not recorded |
| deletion_scheduled_at | ?ISO8601 timestamp | The time the pending deletion was scheduled, or null when it was not recorded |
| acls<sup>7</sup> | array[string] | Effective [Admin ACLs](/admin-api/#acl-registry), with at most 107 entries |
| acls<sup>7</sup> | array[string] | Effective [Admin ACLs](/admin-api/#acl-registry), with at most 103 entries |
| traits<sup>8</sup> | array[string] | The free-form operator labels set on the account, with at most 100 entries |
| has_totp<sup>9</sup> | boolean | Whether a TOTP authenticator is registered |
| authenticator_types<sup>9</sup> <sup>12</sup> | array[integer] | Registered [authenticator types](/http-api/users/#authenticator-types), with at most 10 entries |
@@ -78,7 +78,7 @@ When the caller lacks `user:view:email`, `user:view:dob`, or `user:view:ip`, Flu
<sup>6</sup> Written when the account holder schedules its own bulk message deletion, and cleared by [Cancel scheduled message deletion](#cancel-scheduled-message-deletion)
<sup>7</sup> The set written by [Set user ACLs](#set-user-acls), returned in stored order. This set alone decides whether the account can reach the Admin API, and the `STAFF` [account flag](#account-flags) plays no part in that
<sup>7</sup> The set written by [Set user ACLs](#set-user-acls), returned in stored order with any value outside the [ACL registry](/admin-api/#acl-registry) left out. This set alone decides whether the account can reach the Admin API, and the `STAFF` [account flag](#account-flags) plays no part in that
<sup>8</sup> Sorted in ascending order, unlike `acls`
@@ -945,95 +945,6 @@ The operation records one [Admin audit entry](/admin-api/#admin-audit-entry-obje
100 requests per minute for each authenticated user, on the `admin:user:modify` bucket.
## Set user bot status
<RouteHeader method="PUT" path="/v1/admin/users/{user_id}/bot-status" auditReason />
Marks the account as a bot or as an ordinary account, and returns the resulting account. Requires `user:update:bot_status`.
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| user_id | snowflake | The ID of the target account |
### JSON body
| Field | Type | Description |
| --- | --- | --- |
| bot<sup>1</sup> | boolean | Whether the account is a bot |
<sup>1</sup> Required. Setting it to false also clears `system` in the same write
### Response body
| Field | Type | Description |
| --- | --- | --- |
| user | [Admin user](#admin-user-object) object | The resulting account |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 200 | response body | Bot status was set |
| 403<sup>1</sup> | [error response](/admin-api/#error-response) | Credential type or ACL evaluation denies the request. `ACCESS_DENIED` when the target holds an Admin ACL and `bot` is true |
| 404 | [error response](/admin-api/#error-response) | `UNKNOWN_USER`, because the account does not exist |
<sup>1</sup> A staff account cannot be converted into a bot. Clear its ACL set with [Set user ACLs](#set-user-acls) first
### Side effects
[User Update](/gateway/events/#user-update) is emitted to the account's own sessions, and each guild the account is a member of receives [Guild Member Update](/gateway/events/#guild-member-update) when the write changes `bot` or `system`.
The operation records one [Admin audit entry](/admin-api/#admin-audit-entry-object) with action `set_bot_status`, target type `user`, and a metadata key `bot`. Clearing `system` as a side effect records no second entry.
### Rate limit
100 requests per minute for each authenticated user, on the `admin:user:modify` bucket.
## Set user system status
<RouteHeader method="PUT" path="/v1/admin/users/{user_id}/system-status" auditReason />
Marks the account as an official system account or removes that marker, and returns the resulting account. Requires `user:update:bot_status`, the same ACL as [Set user bot status](#set-user-bot-status).
### Path parameters
| Field | Type | Description |
| --- | --- | --- |
| user_id | snowflake | The ID of the target account |
### JSON body
| Field | Type | Description |
| --- | --- | --- |
| system<sup>1</sup> | boolean | Whether the account is a system account |
<sup>1</sup> Required. Setting it to true on an account that is not already a bot fails validation
### Response body
| Field | Type | Description |
| --- | --- | --- |
| user | [Admin user](#admin-user-object) object | The resulting account |
### Response
| Status | Body | Condition |
| --- | --- | --- |
| 200 | response body | System status was set |
| 404 | [error response](/admin-api/#error-response) | `UNKNOWN_USER`, because the account does not exist |
<sup>1</sup> The non-bot case is `INVALID_FORM_BODY` with the validation code `USER_MUST_BE_A_BOT_TO_BE_MARKED_AS_A_SYSTEM_USER` on the `system` path
### Side effects
[User Update](/gateway/events/#user-update) is emitted to the account's own sessions. The operation records one [Admin audit entry](/admin-api/#admin-audit-entry-object) with action `set_system_status`, target type `user`, and a metadata key `system`.
### Rate limit
100 requests per minute for each authenticated user, on the `admin:user:modify` bucket.
## Set user ACLs
<RouteHeader method="PUT" path="/v1/admin/users/{user_id}/acls" auditReason />
@@ -1060,7 +971,7 @@ A path naming the acting account fails with 403 `ACCESS_DENIED` before the accou
| Field | Type | Description |
| --- | --- | --- |
| acls<sup>1</sup> | array[string] | Replacement [Admin ACLs](/admin-api/#acl-registry), with at most 107 values |
| acls<sup>1</sup> | array[string] | Replacement [Admin ACLs](/admin-api/#acl-registry), with at most 103 values |
<sup>1</sup> Required. A value outside the [ACL registry](/admin-api/#acl-registry) fails body validation, and a repeated value is collapsed
@@ -2045,10 +2045,6 @@ This user doesn't have an email address
This user isn't banned
### `USER_MUST_BE_A_BOT_TO_BE_MARKED_AS_A_SYSTEM_USER`
User must be a bot to be marked as a system user
### `USER_NOT_IN_CHANNEL`
This user isn't in the channel