mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
refactor: simplify account standing and verification levels (#3130)
This commit is contained in:
+17
-349
@@ -1683,7 +1683,7 @@
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
}
|
||||
},
|
||||
"description": "Enqueue one background administrative job. The `task` discriminator selects both the body variant and the ACL evaluated for the request: `update_user_flags` needs bulk:update:user_flags, `update_suspicious_activity_flags` needs bulk:update:suspicious_activity, `update_guild_features` needs bulk:update:guild_features, `add_guild_members` needs bulk:add:guild_members, `schedule_user_deletion` needs bulk:delete:users, and `delete_user_messages` needs bulk:delete:user_messages. Returns a job_id immediately; observe progress at /admin/jobs/:job_id.",
|
||||
"description": "Enqueue one background administrative job. The `task` discriminator selects both the body variant and the ACL evaluated for the request: `update_user_flags` needs bulk:update:user_flags, `update_guild_features` needs bulk:update:guild_features, `add_guild_members` needs bulk:add:guild_members, `schedule_user_deletion` needs bulk:delete:users, and `delete_user_messages` needs bulk:delete:user_messages. Returns a job_id immediately; observe progress at /admin/jobs/:job_id.",
|
||||
"security": [{"adminApiKey": []}],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
@@ -7190,74 +7190,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/admin/users/{user_id}/phone-verification": {
|
||||
"put": {
|
||||
"operationId": "update_admin_user_phone_verification",
|
||||
"summary": "Update user phone verification flag",
|
||||
"tags": ["Admin"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserMutationResponse"}}}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request - The request was malformed or contained invalid data",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized - Authentication is required or the token is invalid",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden - You do not have permission to perform this action",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"429": {
|
||||
"description": "Too Many Requests - You are being rate limited",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}},
|
||||
"headers": {
|
||||
"Retry-After": {
|
||||
"description": "Number of seconds to wait before retrying (only on 429)",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Limit": {
|
||||
"description": "The number of requests that can be made in the current window",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Remaining": {
|
||||
"description": "The number of remaining requests that can be made",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Reset": {
|
||||
"description": "Unix timestamp when the rate limit resets",
|
||||
"schema": {"type": "integer"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error - An unexpected error occurred",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
}
|
||||
},
|
||||
"description": "Set whether a user is treated as having completed phone verification. This is the only supported path for clearing the irreversible user-facing phone verification flag. Requires USER_UPDATE_PHONE permission.",
|
||||
"security": [{"adminApiKey": []}],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "user_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]},
|
||||
"description": "The ID of the user"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {"schema": {"$ref": "#/components/schemas/AdminUserPhoneVerificationRequest"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/users/{user_id}/premium-flags": {
|
||||
"patch": {
|
||||
"operationId": "update_admin_user_premium_flags",
|
||||
@@ -7851,142 +7783,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/admin/users/{user_id}/suspicious-activity-disablement": {
|
||||
"put": {
|
||||
"operationId": "disable_admin_user_suspicious",
|
||||
"summary": "Disable user for suspicious activity",
|
||||
"tags": ["Admin"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserMutationResponse"}}}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request - The request was malformed or contained invalid data",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized - Authentication is required or the token is invalid",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden - You do not have permission to perform this action",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"429": {
|
||||
"description": "Too Many Requests - You are being rate limited",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}},
|
||||
"headers": {
|
||||
"Retry-After": {
|
||||
"description": "Number of seconds to wait before retrying (only on 429)",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Limit": {
|
||||
"description": "The number of requests that can be made in the current window",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Remaining": {
|
||||
"description": "The number of remaining requests that can be made",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Reset": {
|
||||
"description": "Unix timestamp when the rate limit resets",
|
||||
"schema": {"type": "integer"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error - An unexpected error occurred",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
}
|
||||
},
|
||||
"description": "Disable user account due to suspicious activity or abuse. Account is locked pending review. User cannot access services. Emails the user unless notify_user is false. Creates audit log entry. Requires USER_DISABLE_SUSPICIOUS permission.",
|
||||
"security": [{"adminApiKey": []}],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "user_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]},
|
||||
"description": "The ID of the user"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {"schema": {"$ref": "#/components/schemas/AdminUserSuspiciousDisableRequest"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/users/{user_id}/suspicious-activity-flags": {
|
||||
"put": {
|
||||
"operationId": "update_admin_user_suspicious_activity_flags",
|
||||
"summary": "Update suspicious activity flags",
|
||||
"tags": ["Admin"],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserMutationResponse"}}}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request - The request was malformed or contained invalid data",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized - Authentication is required or the token is invalid",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"403": {
|
||||
"description": "Forbidden - You do not have permission to perform this action",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
},
|
||||
"429": {
|
||||
"description": "Too Many Requests - You are being rate limited",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ThrottledError"}}},
|
||||
"headers": {
|
||||
"Retry-After": {
|
||||
"description": "Number of seconds to wait before retrying (only on 429)",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Limit": {
|
||||
"description": "The number of requests that can be made in the current window",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Remaining": {
|
||||
"description": "The number of remaining requests that can be made",
|
||||
"schema": {"type": "integer"}
|
||||
},
|
||||
"X-RateLimit-Reset": {
|
||||
"description": "Unix timestamp when the rate limit resets",
|
||||
"schema": {"type": "integer"}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error - An unexpected error occurred",
|
||||
"content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}
|
||||
}
|
||||
},
|
||||
"description": "Flag user as suspicious for account abuse, fraud, or policy violations. Enables enforcement actions and rate limiting. Creates audit log entry. Requires USER_UPDATE_SUSPICIOUS_ACTIVITY permission.",
|
||||
"security": [{"adminApiKey": []}],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "user_id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {"description": "The ID of the user", "allOf": [{"$ref": "#/components/schemas/SnowflakeType"}]},
|
||||
"description": "The ID of the user"
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {"schema": {"$ref": "#/components/schemas/AdminUserSuspiciousActivityFlagsRequest"}}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/admin/users/{user_id}/system-status": {
|
||||
"put": {
|
||||
"operationId": "set_admin_user_system_status",
|
||||
@@ -9506,31 +9302,6 @@
|
||||
},
|
||||
"required": ["system"]
|
||||
},
|
||||
"AdminUserSuspiciousActivityFlagsRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flags": {
|
||||
"description": "Bitmask of suspicious activity flags",
|
||||
"allOf": [{"$ref": "#/components/schemas/SuspiciousActivityFlags"}]
|
||||
}
|
||||
},
|
||||
"required": ["flags"]
|
||||
},
|
||||
"AdminUserSuspiciousDisableRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"flags": {
|
||||
"description": "Bitmask of suspicious activity flags that triggered the disable",
|
||||
"allOf": [{"$ref": "#/components/schemas/SuspiciousActivityFlags"}]
|
||||
},
|
||||
"notify_user": {
|
||||
"default": true,
|
||||
"description": "Whether to email the user that the account was disabled",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["flags"]
|
||||
},
|
||||
"AdminStorePurchaseListResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -9685,16 +9456,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"AdminUserPhoneVerificationRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"has_verified_phone": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the user should be treated as having completed phone verification"
|
||||
}
|
||||
},
|
||||
"required": ["has_verified_phone"]
|
||||
},
|
||||
"DeleteAllUserMessagesResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -10110,7 +9871,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"acls": {
|
||||
"maxItems": 108,
|
||||
"maxItems": 104,
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/AdminAclType"},
|
||||
"description": "List of access control permissions to assign"
|
||||
@@ -12436,37 +12197,6 @@
|
||||
},
|
||||
"required": ["user_ids", "task"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user_ids": {
|
||||
"maxItems": 1000,
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/SnowflakeType"},
|
||||
"description": "List of user IDs to update"
|
||||
},
|
||||
"add_flags": {
|
||||
"default": [],
|
||||
"description": "Suspicious activity flag names to add to all specified users",
|
||||
"maxItems": 32,
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"remove_flags": {
|
||||
"default": [],
|
||||
"description": "Suspicious activity flag names to remove from all specified users",
|
||||
"maxItems": 32,
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"task": {
|
||||
"type": "string",
|
||||
"enum": ["update_suspicious_activity_flags"],
|
||||
"description": "Adds and removes verification requirements on every targeted user"
|
||||
}
|
||||
},
|
||||
"required": ["user_ids", "task"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -12999,7 +12729,7 @@
|
||||
},
|
||||
"acls": {
|
||||
"description": "Replacement list of access control permissions for the key",
|
||||
"maxItems": 108,
|
||||
"maxItems": 104,
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/AdminAclType"}
|
||||
}
|
||||
@@ -13017,7 +12747,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"acls": {
|
||||
"maxItems": 108,
|
||||
"maxItems": 104,
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "List of access control permissions for the key"
|
||||
@@ -13047,7 +12777,7 @@
|
||||
"maximum": 365
|
||||
},
|
||||
"acls": {
|
||||
"maxItems": 108,
|
||||
"maxItems": 104,
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/AdminAclType"},
|
||||
"description": "List of access control permissions for the key"
|
||||
@@ -13068,7 +12798,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"acls": {
|
||||
"maxItems": 108,
|
||||
"maxItems": 104,
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "List of access control permissions for the key"
|
||||
@@ -13081,7 +12811,7 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"acls": {
|
||||
"maxItems": 108,
|
||||
"maxItems": 104,
|
||||
"type": "array",
|
||||
"items": {"type": "string", "minLength": 1, "maxLength": 64},
|
||||
"description": "Every admin access control permission the admin API recognises"
|
||||
@@ -13135,7 +12865,6 @@
|
||||
"bulk:delete:users",
|
||||
"bulk:delete:user_messages",
|
||||
"bulk:update:guild_features",
|
||||
"bulk:update:suspicious_activity",
|
||||
"bulk:update:user_flags",
|
||||
"csam:submit_ncmec",
|
||||
"discovery:remove",
|
||||
@@ -13171,7 +12900,6 @@
|
||||
"system_dm:send",
|
||||
"user:cancel:bulk_message_deletion",
|
||||
"user:delete",
|
||||
"user:disable:suspicious",
|
||||
"user:list:dm_channels",
|
||||
"user:list:guilds",
|
||||
"user:list:relationships",
|
||||
@@ -13188,9 +12916,7 @@
|
||||
"user:update:email",
|
||||
"user:update:flags",
|
||||
"user:update:mfa",
|
||||
"user:update:phone",
|
||||
"user:update:profile",
|
||||
"user:update:suspicious_activity",
|
||||
"user:update:traits",
|
||||
"user:update:username",
|
||||
"voice:region:create",
|
||||
@@ -13637,11 +13363,6 @@
|
||||
},
|
||||
{"name": "SPAMMER", "value": "64", "description": "User is flagged as a spammer"},
|
||||
{"name": "DELETED", "value": "17179869184", "description": "User account has been deleted"},
|
||||
{
|
||||
"name": "DISABLED_SUSPICIOUS_ACTIVITY",
|
||||
"value": "34359738368",
|
||||
"description": "User account disabled due to suspicious activity"
|
||||
},
|
||||
{"name": "SELF_DELETED", "value": "68719476736", "description": "User account was self-deleted"},
|
||||
{"name": "DISABLED", "value": "274877906944", "description": "User account is disabled"},
|
||||
{"name": "HAS_SESSION_STARTED", "value": "549755813888", "description": "User has started a session"},
|
||||
@@ -13652,6 +13373,7 @@
|
||||
"value": "562949953421312",
|
||||
"description": "User is verified as not underage"
|
||||
},
|
||||
{"name": "ACCOUNT_LIMITED", "value": "1125899906842624", "description": "User account is limited"},
|
||||
{
|
||||
"name": "HAS_DISMISSED_PREMIUM_ONBOARDING",
|
||||
"value": "2251799813685248",
|
||||
@@ -13669,14 +13391,9 @@
|
||||
"description": "User has verified their age as an adult via credit card verification"
|
||||
},
|
||||
{
|
||||
"name": "FORCE_INBOUND_PHONE_VERIFICATION",
|
||||
"value": "2305843009213693952",
|
||||
"description": "User is forced through inbound phone verification, for debugging"
|
||||
},
|
||||
{
|
||||
"name": "NOT_SUSPICIOUS",
|
||||
"name": "LIMIT_EXEMPT",
|
||||
"value": "4611686018427387904",
|
||||
"description": "User is permanently exempt from automatic suspicious-activity flagging"
|
||||
"description": "User is permanently exempt from account limitation"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -15019,15 +14736,14 @@
|
||||
"GuildVerificationLevel": {
|
||||
"description": "Required verification level for members",
|
||||
"type": "integer",
|
||||
"enum": [0, 1, 2, 3, 4],
|
||||
"enum": [0, 1, 2, 3],
|
||||
"format": "int32",
|
||||
"x-enumNames": ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"],
|
||||
"x-enumNames": ["NONE", "LOW", "MEDIUM", "HIGH"],
|
||||
"x-enumDescriptions": [
|
||||
"Unrestricted",
|
||||
"Must have verified email",
|
||||
"Registered for more than 5 minutes",
|
||||
"Member of the server for more than 10 minutes",
|
||||
"Must have a verified phone number"
|
||||
"Member of the server for more than 10 minutes"
|
||||
]
|
||||
},
|
||||
"GuildOperations": {
|
||||
@@ -15109,15 +14825,14 @@
|
||||
"minimum": 0,
|
||||
"maximum": 2147483647,
|
||||
"format": "int32",
|
||||
"x-enumNames": ["NONE", "LOW", "MEDIUM", "HIGH", "VERY_HIGH"],
|
||||
"x-enumNames": ["NONE", "LOW", "MEDIUM", "HIGH"],
|
||||
"x-enumDescriptions": [
|
||||
"Unrestricted",
|
||||
"Must have verified email",
|
||||
"Registered for more than 5 minutes",
|
||||
"Member of the server for more than 10 minutes",
|
||||
"Must have a verified phone number"
|
||||
"Member of the server for more than 10 minutes"
|
||||
],
|
||||
"enum": [0, 1, 2, 3, 4]
|
||||
"enum": [0, 1, 2, 3]
|
||||
},
|
||||
"PurgeGuildAssetErrorSchema": {
|
||||
"type": "object",
|
||||
@@ -15887,7 +15602,6 @@
|
||||
"email": {"nullable": true, "type": "string"},
|
||||
"email_verified": {"type": "boolean"},
|
||||
"email_bounced": {"type": "boolean"},
|
||||
"has_verified_phone": {"type": "boolean"},
|
||||
"date_of_birth": {"nullable": true, "type": "string"},
|
||||
"locale": {"nullable": true, "type": "string"},
|
||||
"premium_type": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]},
|
||||
@@ -15895,11 +15609,6 @@
|
||||
"premium_until": {"nullable": true, "type": "string"},
|
||||
"premium_grace_ends_at": {"nullable": true, "type": "string"},
|
||||
"premium_lifetime_sequence": {"nullable": true, "allOf": [{"$ref": "#/components/schemas/Int32Type"}]},
|
||||
"suspicious_activity_flags": {"allOf": [{"$ref": "#/components/schemas/SuspiciousActivityFlags"}]},
|
||||
"phone_verification_deferred": {
|
||||
"type": "boolean",
|
||||
"description": "Whether a stored phone requirement is deferred and not enforced"
|
||||
},
|
||||
"temp_banned_until": {"nullable": true, "type": "string"},
|
||||
"pending_deletion_at": {"nullable": true, "type": "string"},
|
||||
"pending_bulk_message_deletion_at": {"nullable": true, "type": "string"},
|
||||
@@ -15920,7 +15629,7 @@
|
||||
"description": "ISO 8601 timestamp when the pending deletion was scheduled",
|
||||
"type": "string"
|
||||
},
|
||||
"acls": {"maxItems": 108, "type": "array", "items": {"type": "string"}},
|
||||
"acls": {"maxItems": 104, "type": "array", "items": {"type": "string"}},
|
||||
"traits": {"maxItems": 100, "type": "array", "items": {"type": "string"}},
|
||||
"has_totp": {"type": "boolean"},
|
||||
"authenticator_types": {"maxItems": 10, "type": "array", "items": {"$ref": "#/components/schemas/Int32Type"}},
|
||||
@@ -15946,7 +15655,6 @@
|
||||
"email",
|
||||
"email_verified",
|
||||
"email_bounced",
|
||||
"has_verified_phone",
|
||||
"date_of_birth",
|
||||
"locale",
|
||||
"premium_type",
|
||||
@@ -15954,8 +15662,6 @@
|
||||
"premium_until",
|
||||
"premium_grace_ends_at",
|
||||
"premium_lifetime_sequence",
|
||||
"suspicious_activity_flags",
|
||||
"phone_verification_deferred",
|
||||
"temp_banned_until",
|
||||
"pending_deletion_at",
|
||||
"pending_bulk_message_deletion_at",
|
||||
@@ -15975,44 +15681,6 @@
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"SuspiciousActivityFlags": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 2147483647,
|
||||
"description": "Suspicious activity indicators",
|
||||
"format": "int32",
|
||||
"x-bitflagValues": [
|
||||
{"name": "REQUIRE_VERIFIED_EMAIL", "value": "1", "description": "Requires verified email address"},
|
||||
{"name": "REQUIRE_REVERIFIED_EMAIL", "value": "2", "description": "Requires re-verified email address"},
|
||||
{"name": "REQUIRE_VERIFIED_PHONE", "value": "4", "description": "Requires verified phone number"},
|
||||
{"name": "REQUIRE_REVERIFIED_PHONE", "value": "8", "description": "Requires re-verified phone number"},
|
||||
{
|
||||
"name": "REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE",
|
||||
"value": "16",
|
||||
"description": "Requires verified email or verified phone"
|
||||
},
|
||||
{
|
||||
"name": "REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE",
|
||||
"value": "32",
|
||||
"description": "Requires re-verified email or re-verified phone"
|
||||
},
|
||||
{
|
||||
"name": "REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE",
|
||||
"value": "64",
|
||||
"description": "Requires verified email or re-verified phone"
|
||||
},
|
||||
{
|
||||
"name": "REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE",
|
||||
"value": "128",
|
||||
"description": "Requires re-verified email or re-verified phone"
|
||||
},
|
||||
{
|
||||
"name": "REQUIRE_INBOUND_PHONE_VERIFICATION",
|
||||
"value": "256",
|
||||
"description": "Requires inbound SMS verification (user must text code to platform number)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"PremiumFlags": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
|
||||
@@ -42,7 +42,6 @@ pub const BULK_ADD_GUILD_MEMBERS: &str = "bulk:add:guild_members";
|
||||
pub const BULK_DELETE_USERS: &str = "bulk:delete:users";
|
||||
pub const BULK_DELETE_USER_MESSAGES: &str = "bulk:delete:user_messages";
|
||||
pub const BULK_UPDATE_GUILD_FEATURES: &str = "bulk:update:guild_features";
|
||||
pub const BULK_UPDATE_SUSPICIOUS_ACTIVITY: &str = "bulk:update:suspicious_activity";
|
||||
pub const BULK_UPDATE_USER_FLAGS: &str = "bulk:update:user_flags";
|
||||
pub const CSAM_SUBMIT_NCMEC: &str = "csam:submit_ncmec";
|
||||
pub const DISCOVERY_REMOVE: &str = "discovery:remove";
|
||||
@@ -78,7 +77,6 @@ pub const REPORT_VIEW_REPORTER_PII: &str = "report:view:reporter_pii";
|
||||
pub const SYSTEM_DM_SEND: &str = "system_dm:send";
|
||||
pub const USER_CANCEL_BULK_MESSAGE_DELETION: &str = "user:cancel:bulk_message_deletion";
|
||||
pub const USER_DELETE: &str = "user:delete";
|
||||
pub const USER_DISABLE_SUSPICIOUS: &str = "user:disable:suspicious";
|
||||
pub const USER_LIST_DM_CHANNELS: &str = "user:list:dm_channels";
|
||||
pub const USER_LIST_GUILDS: &str = "user:list:guilds";
|
||||
pub const USER_LIST_RELATIONSHIPS: &str = "user:list:relationships";
|
||||
@@ -95,9 +93,7 @@ pub const USER_UPDATE_DOB: &str = "user:update:dob";
|
||||
pub const USER_UPDATE_EMAIL: &str = "user:update:email";
|
||||
pub const USER_UPDATE_FLAGS: &str = "user:update:flags";
|
||||
pub const USER_UPDATE_MFA: &str = "user:update:mfa";
|
||||
pub const USER_UPDATE_PHONE: &str = "user:update:phone";
|
||||
pub const USER_UPDATE_PROFILE: &str = "user:update:profile";
|
||||
pub const USER_UPDATE_SUSPICIOUS_ACTIVITY: &str = "user:update:suspicious_activity";
|
||||
pub const USER_UPDATE_TRAITS: &str = "user:update:traits";
|
||||
pub const USER_UPDATE_USERNAME: &str = "user:update:username";
|
||||
pub const VOICE_REGION_CREATE: &str = "voice:region:create";
|
||||
@@ -151,7 +147,6 @@ pub const ALL_ACLS: &[&str] = &[
|
||||
BULK_DELETE_USERS,
|
||||
BULK_DELETE_USER_MESSAGES,
|
||||
BULK_UPDATE_GUILD_FEATURES,
|
||||
BULK_UPDATE_SUSPICIOUS_ACTIVITY,
|
||||
BULK_UPDATE_USER_FLAGS,
|
||||
CSAM_SUBMIT_NCMEC,
|
||||
DISCOVERY_REMOVE,
|
||||
@@ -187,7 +182,6 @@ pub const ALL_ACLS: &[&str] = &[
|
||||
SYSTEM_DM_SEND,
|
||||
USER_CANCEL_BULK_MESSAGE_DELETION,
|
||||
USER_DELETE,
|
||||
USER_DISABLE_SUSPICIOUS,
|
||||
USER_LIST_DM_CHANNELS,
|
||||
USER_LIST_GUILDS,
|
||||
USER_LIST_RELATIONSHIPS,
|
||||
@@ -204,9 +198,7 @@ pub const ALL_ACLS: &[&str] = &[
|
||||
USER_UPDATE_EMAIL,
|
||||
USER_UPDATE_FLAGS,
|
||||
USER_UPDATE_MFA,
|
||||
USER_UPDATE_PHONE,
|
||||
USER_UPDATE_PROFILE,
|
||||
USER_UPDATE_SUSPICIOUS_ACTIVITY,
|
||||
USER_UPDATE_TRAITS,
|
||||
USER_UPDATE_USERNAME,
|
||||
VOICE_REGION_CREATE,
|
||||
|
||||
@@ -19,19 +19,18 @@ pub mod user_flag_bits {
|
||||
pub const SPAMMER: u64 = 1 << 6;
|
||||
pub const HIGH_GLOBAL_RATE_LIMIT: u64 = 1 << 33;
|
||||
pub const DELETED: u64 = 1 << 34;
|
||||
pub const DISABLED_SUSPICIOUS_ACTIVITY: u64 = 1 << 35;
|
||||
pub const SELF_DELETED: u64 = 1 << 36;
|
||||
pub const DISABLED: u64 = 1 << 38;
|
||||
pub const HAS_SESSION_STARTED: u64 = 1 << 39;
|
||||
pub const RATE_LIMIT_BYPASS: u64 = 1 << 47;
|
||||
pub const REPORT_BANNED: u64 = 1 << 48;
|
||||
pub const VERIFIED_NOT_UNDERAGE: u64 = 1 << 49;
|
||||
pub const ACCOUNT_LIMITED: u64 = 1 << 50;
|
||||
pub const HAS_DISMISSED_PREMIUM_ONBOARDING: u64 = 1 << 51;
|
||||
pub const APP_STORE_REVIEWER: u64 = 1 << 53;
|
||||
pub const STAFF_HIDDEN: u64 = 1 << 57;
|
||||
pub const AGE_VERIFIED_ADULT: u64 = 1 << 60;
|
||||
pub const FORCE_INBOUND_PHONE_VERIFICATION: u64 = 1 << 61;
|
||||
pub const NOT_SUSPICIOUS: u64 = 1 << 62;
|
||||
pub const LIMIT_EXEMPT: u64 = 1 << 62;
|
||||
}
|
||||
|
||||
pub const USER_FLAGS: &[U64Flag] = &[
|
||||
@@ -67,10 +66,6 @@ pub const USER_FLAGS: &[U64Flag] = &[
|
||||
name: "DELETED",
|
||||
value: user_flag_bits::DELETED,
|
||||
},
|
||||
U64Flag {
|
||||
name: "DISABLED_SUSPICIOUS_ACTIVITY",
|
||||
value: user_flag_bits::DISABLED_SUSPICIOUS_ACTIVITY,
|
||||
},
|
||||
U64Flag {
|
||||
name: "SELF_DELETED",
|
||||
value: user_flag_bits::SELF_DELETED,
|
||||
@@ -95,6 +90,10 @@ pub const USER_FLAGS: &[U64Flag] = &[
|
||||
name: "VERIFIED_NOT_UNDERAGE",
|
||||
value: user_flag_bits::VERIFIED_NOT_UNDERAGE,
|
||||
},
|
||||
U64Flag {
|
||||
name: "ACCOUNT_LIMITED",
|
||||
value: user_flag_bits::ACCOUNT_LIMITED,
|
||||
},
|
||||
U64Flag {
|
||||
name: "HAS_DISMISSED_PREMIUM_ONBOARDING",
|
||||
value: user_flag_bits::HAS_DISMISSED_PREMIUM_ONBOARDING,
|
||||
@@ -112,12 +111,8 @@ pub const USER_FLAGS: &[U64Flag] = &[
|
||||
value: user_flag_bits::AGE_VERIFIED_ADULT,
|
||||
},
|
||||
U64Flag {
|
||||
name: "FORCE_INBOUND_PHONE_VERIFICATION",
|
||||
value: user_flag_bits::FORCE_INBOUND_PHONE_VERIFICATION,
|
||||
},
|
||||
U64Flag {
|
||||
name: "NOT_SUSPICIOUS",
|
||||
value: user_flag_bits::NOT_SUSPICIOUS,
|
||||
name: "LIMIT_EXEMPT",
|
||||
value: user_flag_bits::LIMIT_EXEMPT,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -159,42 +154,3 @@ pub const PREMIUM_FLAGS: &[I32Flag] = &[
|
||||
value: 1 << 8,
|
||||
},
|
||||
];
|
||||
|
||||
pub const SUSPICIOUS_ACTIVITY_FLAGS: &[I32Flag] = &[
|
||||
I32Flag {
|
||||
name: "REQUIRE_VERIFIED_EMAIL",
|
||||
value: 1 << 0,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_REVERIFIED_EMAIL",
|
||||
value: 1 << 1,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_VERIFIED_PHONE",
|
||||
value: 1 << 2,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_REVERIFIED_PHONE",
|
||||
value: 1 << 3,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE",
|
||||
value: 1 << 4,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE",
|
||||
value: 1 << 5,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE",
|
||||
value: 1 << 6,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE",
|
||||
value: 1 << 7,
|
||||
},
|
||||
I32Flag {
|
||||
name: "REQUIRE_INBOUND_PHONE_VERIFICATION",
|
||||
value: 1 << 8,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -12,7 +12,7 @@ impl AdminApiClient {
|
||||
acls: &[String],
|
||||
) -> ApiResult<CreateAdminApiKeyResponse> {
|
||||
let body = generated_types::CreateAdminApiKeyRequest {
|
||||
acls: parse_acls(acls)?,
|
||||
acls: parse_acls(acls),
|
||||
expires_in_days: None,
|
||||
name: generated_types::CreateAdminApiKeyRequestName::try_from(name)
|
||||
.map_err(|e| ApiError::Parse(e.to_string()))?,
|
||||
@@ -44,11 +44,8 @@ impl AdminApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse_acls(acls: &[String]) -> ApiResult<Vec<generated_types::AdminAclType>> {
|
||||
pub(super) fn parse_acls(acls: &[String]) -> Vec<generated_types::AdminAclType> {
|
||||
acls.iter()
|
||||
.map(|acl| {
|
||||
generated_types::AdminAclType::try_from(acl.as_str())
|
||||
.map_err(|e| ApiError::Parse(e.to_string()))
|
||||
})
|
||||
.filter_map(|acl| generated_types::AdminAclType::try_from(acl.as_str()).ok())
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -22,22 +22,6 @@ impl AdminApiClient {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn bulk_update_suspicious_activity_flags(
|
||||
&self,
|
||||
user_ids: &[String],
|
||||
add_flags: &[String],
|
||||
remove_flags: &[String],
|
||||
audit_log_reason: Option<&str>,
|
||||
) -> ApiResult<BulkJobResponse> {
|
||||
let body = generated_types::AdminBulkJobCreateRequest::UpdateSuspiciousActivityFlags {
|
||||
add_flags: add_flags.to_vec(),
|
||||
remove_flags: remove_flags.to_vec(),
|
||||
user_ids: snowflakes(user_ids),
|
||||
};
|
||||
self.post_typed_with_reason("/admin/bulk-jobs", &body, audit_log_reason)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn bulk_update_guild_features(
|
||||
&self,
|
||||
guild_ids: &[String],
|
||||
|
||||
@@ -85,7 +85,6 @@ mod tests {
|
||||
"email": "[email protected]",
|
||||
"email_verified": true,
|
||||
"email_bounced": false,
|
||||
"has_verified_phone": false,
|
||||
"date_of_birth": "2000-01-15",
|
||||
"locale": "en-US",
|
||||
"premium_type": 2,
|
||||
@@ -93,8 +92,6 @@ mod tests {
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
@@ -108,15 +108,9 @@ pub struct AdminUser {
|
||||
pub premium_grace_ends_at: Option<String>,
|
||||
pub premium_lifetime_sequence: Option<i32>,
|
||||
#[serde(default)]
|
||||
pub suspicious_activity_flags: i32,
|
||||
#[serde(default)]
|
||||
pub phone_verification_deferred: bool,
|
||||
#[serde(default)]
|
||||
pub has_totp: bool,
|
||||
#[serde(default)]
|
||||
pub authenticator_types: Vec<i32>,
|
||||
#[serde(default)]
|
||||
pub has_verified_phone: bool,
|
||||
pub temp_banned_until: Option<String>,
|
||||
pub pending_deletion_at: Option<String>,
|
||||
pub pending_bulk_message_deletion_at: Option<String>,
|
||||
|
||||
@@ -231,22 +231,9 @@ impl AdminApiClient {
|
||||
Ok(resp.user)
|
||||
}
|
||||
|
||||
pub async fn update_suspicious_flags(&self, user_id: &str, flags: i32) -> ApiResult<AdminUser> {
|
||||
let body = generated_types::AdminUserSuspiciousActivityFlagsRequest {
|
||||
flags: generated_types::SuspiciousActivityFlags::from(flags),
|
||||
};
|
||||
let response = self
|
||||
.generated()
|
||||
.update_admin_user_suspicious_activity_flags(&snowflake(user_id), &body)
|
||||
.await
|
||||
.map_err(|e| self.generated_error(e))?;
|
||||
let resp: UserMutationResponse = self.generated_value(response.into_inner())?;
|
||||
Ok(resp.user)
|
||||
}
|
||||
|
||||
pub async fn set_user_acls(&self, user_id: &str, acls: &[String]) -> ApiResult<AdminUser> {
|
||||
let body = generated_types::AdminUserAclsRequest {
|
||||
acls: super::admin_api_keys::parse_acls(acls)?,
|
||||
acls: super::admin_api_keys::parse_acls(acls),
|
||||
};
|
||||
let response = self
|
||||
.generated()
|
||||
@@ -296,21 +283,6 @@ impl AdminApiClient {
|
||||
Ok(resp.user)
|
||||
}
|
||||
|
||||
pub async fn update_has_verified_phone(
|
||||
&self,
|
||||
user_id: &str,
|
||||
has_verified_phone: bool,
|
||||
) -> ApiResult<AdminUser> {
|
||||
let body = generated_types::AdminUserPhoneVerificationRequest { has_verified_phone };
|
||||
let response = self
|
||||
.generated()
|
||||
.update_admin_user_phone_verification(&snowflake(user_id), &body)
|
||||
.await
|
||||
.map_err(|e| self.generated_error(e))?;
|
||||
let resp: UserMutationResponse = self.generated_value(response.into_inner())?;
|
||||
Ok(resp.user)
|
||||
}
|
||||
|
||||
pub async fn clear_user_fields(
|
||||
&self,
|
||||
user_id: &str,
|
||||
|
||||
@@ -219,19 +219,6 @@ pub(crate) async fn bulk_actions_post(
|
||||
.bulk_update_user_flags(&user_ids, &add, &remove, audit_log_reason.as_deref())
|
||||
.await
|
||||
}
|
||||
"bulk-update-suspicious-activity-flags" => {
|
||||
let user_ids = form.list_values_any(&["user_ids[]", "user_ids"]);
|
||||
let add = form.list_values_any(&["add_flags[]", "add_flags"]);
|
||||
let remove = form.list_values_any(&["remove_flags[]", "remove_flags"]);
|
||||
client
|
||||
.bulk_update_suspicious_activity_flags(
|
||||
&user_ids,
|
||||
&add,
|
||||
&remove,
|
||||
audit_log_reason.as_deref(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
"bulk-update-guild-features" => {
|
||||
let guild_ids = form.list_values_any(&["guild_ids[]", "guild_ids"]);
|
||||
let mut add = form.list_values_any(&["add_features[]", "add_features"]);
|
||||
|
||||
@@ -134,19 +134,6 @@ pub async fn dispatch(
|
||||
"Failed to update premium flags",
|
||||
)
|
||||
}
|
||||
"update_suspicious_flags" => {
|
||||
let Ok(submitted) =
|
||||
form.parse_list_values::<i32>(&["suspicious_flags[]", "suspicious_flags"])
|
||||
else {
|
||||
return DispatchOutcome::error("Invalid suspicious activity flag value");
|
||||
};
|
||||
let flags = submitted.into_iter().fold(0, |acc, flag| acc | flag);
|
||||
DispatchOutcome::from_result(
|
||||
client.update_suspicious_flags(user_id, flags).await,
|
||||
"Suspicious activity flags updated successfully",
|
||||
"Failed to update suspicious activity flags",
|
||||
)
|
||||
}
|
||||
"update_acls" => {
|
||||
let acls = form.list_values_any(&["acls[]", "acls"]);
|
||||
DispatchOutcome::from_result(
|
||||
@@ -178,14 +165,6 @@ pub async fn dispatch(
|
||||
"Email verified successfully",
|
||||
"Failed to verify email",
|
||||
),
|
||||
"update_has_verified_phone" => {
|
||||
let val = form.bool_value("has_verified_phone");
|
||||
DispatchOutcome::from_result(
|
||||
client.update_has_verified_phone(user_id, val).await,
|
||||
"Phone verification status updated successfully",
|
||||
"Failed to update phone verification status",
|
||||
)
|
||||
}
|
||||
"terminate_sessions" => DispatchOutcome::from_result(
|
||||
client.terminate_user_sessions(user_id).await,
|
||||
"User sessions terminated successfully",
|
||||
|
||||
@@ -54,7 +54,6 @@ pub const NAV_SECTIONS: &[NavSection] = &[
|
||||
"bulk-actions",
|
||||
[
|
||||
acl::BULK_UPDATE_USER_FLAGS,
|
||||
acl::BULK_UPDATE_SUSPICIOUS_ACTIVITY,
|
||||
acl::BULK_UPDATE_GUILD_FEATURES,
|
||||
acl::BULK_ADD_GUILD_MEMBERS,
|
||||
acl::BULK_DELETE_USERS,
|
||||
@@ -268,7 +267,6 @@ mod tests {
|
||||
.expect("bulk actions nav item");
|
||||
for required in [
|
||||
acl::BULK_UPDATE_USER_FLAGS,
|
||||
acl::BULK_UPDATE_SUSPICIOUS_ACTIVITY,
|
||||
acl::BULK_UPDATE_GUILD_FEATURES,
|
||||
acl::BULK_ADD_GUILD_MEMBERS,
|
||||
acl::BULK_DELETE_USERS,
|
||||
|
||||
@@ -19,11 +19,7 @@ pub fn format_action(action: &str) -> String {
|
||||
|
||||
pub fn action_badge_variant(action: &str) -> BadgeVariant {
|
||||
match action {
|
||||
"temp_ban"
|
||||
| "disable_suspicious_activity"
|
||||
| "schedule_deletion"
|
||||
| "ban_ip"
|
||||
| "ban_email" => BadgeVariant::Danger,
|
||||
"temp_ban" | "schedule_deletion" | "ban_ip" | "ban_email" => BadgeVariant::Danger,
|
||||
"unban" | "cancel_deletion" | "unban_ip" | "unban_email" => BadgeVariant::Success,
|
||||
"update_flags" | "update_features" | "set_acls" | "update_settings" | "annotate_ban" => {
|
||||
BadgeVariant::Info
|
||||
@@ -361,4 +357,12 @@ mod tests {
|
||||
assert!(!markup.contains("<a "));
|
||||
assert!(markup.contains("Email domain"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retired_action_names_still_render() {
|
||||
let mut retired = entry("user", "1500000000000000002");
|
||||
retired.action = "update_retired_toggle".to_string();
|
||||
let markup = audit_log_table_body("/admin", &[retired]).into_string();
|
||||
assert!(markup.contains("Update retired toggle"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,10 +80,6 @@ const PATCHABLE_USER_FLAGS: &[UserFlag] = &[
|
||||
name: "DELETED",
|
||||
value: 1 << 34,
|
||||
},
|
||||
UserFlag {
|
||||
name: "DISABLED_SUSPICIOUS_ACTIVITY",
|
||||
value: 1 << 35,
|
||||
},
|
||||
UserFlag {
|
||||
name: "SELF_DELETED",
|
||||
value: 1 << 36,
|
||||
@@ -108,6 +104,10 @@ const PATCHABLE_USER_FLAGS: &[UserFlag] = &[
|
||||
name: "VERIFIED_NOT_UNDERAGE",
|
||||
value: 1 << 49,
|
||||
},
|
||||
UserFlag {
|
||||
name: "ACCOUNT_LIMITED",
|
||||
value: 1 << 50,
|
||||
},
|
||||
UserFlag {
|
||||
name: "HAS_DISMISSED_PREMIUM_ONBOARDING",
|
||||
value: 1 << 51,
|
||||
@@ -125,26 +125,11 @@ const PATCHABLE_USER_FLAGS: &[UserFlag] = &[
|
||||
value: 1 << 60,
|
||||
},
|
||||
UserFlag {
|
||||
name: "FORCE_INBOUND_PHONE_VERIFICATION",
|
||||
value: 1 << 61,
|
||||
},
|
||||
UserFlag {
|
||||
name: "NOT_SUSPICIOUS",
|
||||
name: "LIMIT_EXEMPT",
|
||||
value: 1 << 62,
|
||||
},
|
||||
];
|
||||
|
||||
const SUSPICIOUS_ACTIVITY_FLAGS: &[&str] = &[
|
||||
"REQUIRE_VERIFIED_EMAIL",
|
||||
"REQUIRE_REVERIFIED_EMAIL",
|
||||
"REQUIRE_VERIFIED_PHONE",
|
||||
"REQUIRE_REVERIFIED_PHONE",
|
||||
"REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE",
|
||||
"REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE",
|
||||
"REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE",
|
||||
"REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE",
|
||||
"REQUIRE_INBOUND_PHONE_VERIFICATION",
|
||||
];
|
||||
const GUILD_FEATURES: &[&str] = &[
|
||||
"ANIMATED_ICON",
|
||||
"ANIMATED_BANNER",
|
||||
@@ -206,9 +191,6 @@ pub fn bulk_actions_page(config: &AdminConfig, auth: &AuthContext, csrf_token: &
|
||||
@if acl::has_permission(admin_acls, acl::BULK_UPDATE_USER_FLAGS) {
|
||||
(bulk_update_user_flags_section(base, csrf_token))
|
||||
}
|
||||
@if acl::has_permission(admin_acls, acl::BULK_UPDATE_SUSPICIOUS_ACTIVITY) {
|
||||
(bulk_update_suspicious_activity_section(base, csrf_token))
|
||||
}
|
||||
@if acl::has_permission(admin_acls, acl::BULK_UPDATE_GUILD_FEATURES) {
|
||||
(bulk_update_guild_features_section(base, csrf_token))
|
||||
}
|
||||
@@ -226,16 +208,6 @@ pub fn bulk_actions_page(config: &AdminConfig, auth: &AuthContext, csrf_token: &
|
||||
admin_layout(config, auth, "Bulk Actions", "bulk-actions", None, content)
|
||||
}
|
||||
|
||||
fn flag_checkbox_grid(prefix: &str, flags: &[&str]) -> Markup {
|
||||
html! {
|
||||
div class="grid grid-cols-1 gap-3 sm:grid-cols-2" {
|
||||
@for flag in flags {
|
||||
(checkbox(prefix, flag, flag, false, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn guild_feature_checkbox_grid(prefix: &str, include_deprecated: bool) -> Markup {
|
||||
html! {
|
||||
div class="grid grid-cols-1 gap-3 sm:grid-cols-2" {
|
||||
@@ -288,36 +260,6 @@ fn bulk_update_user_flags_section(base: &str, csrf_token: &str) -> Markup {
|
||||
)
|
||||
}
|
||||
|
||||
fn bulk_update_suspicious_activity_section(base: &str, csrf_token: &str) -> Markup {
|
||||
section_card_simple(
|
||||
"Bulk Update Suspicious Activity Flags",
|
||||
html! {
|
||||
form method="post" action={(base) "/bulk-actions?action=bulk-update-suspicious-activity-flags"} {
|
||||
(csrf_input(csrf_token))
|
||||
div class="space-y-4" {
|
||||
(textarea_input("user_ids", "User IDs (one per line)", "123456789\n987654321", "", 5, true))
|
||||
div {
|
||||
p class="font-semibold text-neutral-500 text-xs uppercase tracking-wide mb-2" {
|
||||
"Flags to Add"
|
||||
}
|
||||
(flag_checkbox_grid("add_flags[]", SUSPICIOUS_ACTIVITY_FLAGS))
|
||||
}
|
||||
div {
|
||||
p class="font-semibold text-neutral-500 text-xs uppercase tracking-wide mb-2" {
|
||||
"Flags to Remove"
|
||||
}
|
||||
(flag_checkbox_grid("remove_flags[]", SUSPICIOUS_ACTIVITY_FLAGS))
|
||||
}
|
||||
(text_input("audit_log_reason", "Audit Log Reason (optional)", "", "Reason for this bulk operation"))
|
||||
(form_actions(html! {
|
||||
(submit_button("Update Suspicious Activity Flags"))
|
||||
}))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn bulk_update_guild_features_section(base: &str, csrf_token: &str) -> Markup {
|
||||
section_card_simple(
|
||||
"Bulk Update Guild Features",
|
||||
|
||||
@@ -52,13 +52,12 @@ pub fn settings_tab(
|
||||
"guild-verification-level",
|
||||
"verification_level",
|
||||
"Verification Level",
|
||||
guild.verification_level.unwrap_or(0),
|
||||
guild.verification_level.unwrap_or(0).min(3),
|
||||
&[
|
||||
(0, "None"),
|
||||
(1, "Low (verified email)"),
|
||||
(2, "Medium (5+ minutes)"),
|
||||
(3, "High (10+ minutes)"),
|
||||
(4, "Very High (verified phone)"),
|
||||
],
|
||||
))
|
||||
(select_field(
|
||||
@@ -225,12 +224,11 @@ fn select_field(
|
||||
}
|
||||
|
||||
fn settings_tab_readonly(guild: &GuildDetailInfo) -> Markup {
|
||||
let verification_label = match guild.verification_level.unwrap_or(0) {
|
||||
let verification_label = match guild.verification_level.unwrap_or(0).min(3) {
|
||||
0 => "None",
|
||||
1 => "Low (verified email)",
|
||||
2 => "Medium (5+ minutes)",
|
||||
3 => "High (10+ minutes)",
|
||||
4 => "Very High (verified phone)",
|
||||
_ => "Unknown",
|
||||
};
|
||||
let mfa_label = match guild.mfa_level.unwrap_or(0) {
|
||||
|
||||
@@ -1403,7 +1403,7 @@ fn captcha_section(base: &str, csrf_token: &str, captcha: &CaptchaConfigResponse
|
||||
))
|
||||
p class="text-sm text-neutral-700" {
|
||||
(format!(
|
||||
"Average solve: about {estimate:.1} s on a low-end Android phone, \
|
||||
"Average solve: about {estimate:.1} s on a low-end Android device, \
|
||||
well under a second in desktop browsers."
|
||||
))
|
||||
}
|
||||
|
||||
@@ -154,10 +154,6 @@ fn session_entry(base: &str, s: &UserSession, is_tombstone: bool) -> Markup {
|
||||
}
|
||||
|
||||
fn quick_actions_card(base: &str, user: &AdminUser, csrf_token: &str) -> Markup {
|
||||
let phone_action = format!(
|
||||
"{base}/users/{}?action=update_has_verified_phone&tab=account",
|
||||
user.id
|
||||
);
|
||||
html! {
|
||||
(card_with_header("Quick Actions", html! {
|
||||
div class="flex flex-wrap gap-3" {
|
||||
@@ -165,20 +161,6 @@ fn quick_actions_card(base: &str, user: &AdminUser, csrf_token: &str) -> Markup
|
||||
(action_form(base, &user.id, "verify_email", "account", None,
|
||||
"Verify Email", csrf_token))
|
||||
}
|
||||
form method="post"
|
||||
action=(&phone_action)
|
||||
hx-post=(&phone_action)
|
||||
hx-target="#flash-container"
|
||||
hx-swap="none"
|
||||
hx-push-url="false" {
|
||||
(csrf_input(csrf_token))
|
||||
input type="hidden" name="has_verified_phone"
|
||||
value=@if user.has_verified_phone { "false" } @else { "true" };
|
||||
button type="submit" class=(BTN_CLS) {
|
||||
@if user.has_verified_phone { "Clear Phone Verified" }
|
||||
@else { "Mark Phone Verified" }
|
||||
}
|
||||
}
|
||||
(action_form(base, &user.id, "send_password_reset", "account", None,
|
||||
"Send Password Reset", csrf_token))
|
||||
}
|
||||
|
||||
@@ -139,13 +139,6 @@ fn render_overview_tab(
|
||||
}
|
||||
}))
|
||||
}
|
||||
(detail_row("Phone", html! {
|
||||
@if user.has_verified_phone {
|
||||
span class="text-green-700" { "Verified" }
|
||||
} @else {
|
||||
span class="text-neutral-400" { "Not verified" }
|
||||
}
|
||||
}))
|
||||
@if acl::has_permission(admin_acls, acl::USER_VIEW_DOB) {
|
||||
(detail_row("Date of Birth", html! {
|
||||
(user.date_of_birth.as_deref().unwrap_or("Not set"))
|
||||
@@ -270,8 +263,6 @@ fn flags_card(
|
||||
csrf_token: &str,
|
||||
) -> Markup {
|
||||
let can_update_flags = acl::has_permission(admin_acls, acl::USER_UPDATE_FLAGS);
|
||||
let can_update_suspicious =
|
||||
acl::has_permission(admin_acls, acl::USER_UPDATE_SUSPICIOUS_ACTIVITY);
|
||||
html! {
|
||||
div class="space-y-6" {
|
||||
(u64_flag_form(
|
||||
@@ -298,23 +289,6 @@ fn flags_card(
|
||||
can_update_flags,
|
||||
Some(acl::USER_UPDATE_FLAGS),
|
||||
))
|
||||
(i32_flag_form(
|
||||
config,
|
||||
&user.id,
|
||||
"Suspicious Activity Flags",
|
||||
"update_suspicious_flags",
|
||||
"suspicious_flags[]",
|
||||
user.suspicious_activity_flags,
|
||||
admin_flags::SUSPICIOUS_ACTIVITY_FLAGS,
|
||||
csrf_token,
|
||||
can_update_suspicious,
|
||||
Some(acl::USER_UPDATE_SUSPICIOUS_ACTIVITY),
|
||||
))
|
||||
@if user.phone_verification_deferred {
|
||||
p class="text-sm text-amber-700 dark:text-amber-400" {
|
||||
"Phone verification is deferred: the requirement above is stored but not enforced."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ fn deserialize_admin_users_me_response() {
|
||||
"email": "[email protected]",
|
||||
"email_verified": true,
|
||||
"email_bounced": false,
|
||||
"has_verified_phone": true,
|
||||
"date_of_birth": "2003-02-25",
|
||||
"locale": "en-US",
|
||||
"premium_type": 2,
|
||||
@@ -31,7 +30,6 @@ fn deserialize_admin_users_me_response() {
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": 1,
|
||||
"suspicious_activity_flags": 0,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
@@ -64,9 +62,7 @@ fn deserialize_admin_users_me_response() {
|
||||
assert_eq!(user.acls, vec!["super_admin"]);
|
||||
assert_eq!(user.traits, vec!["beta_tester"]);
|
||||
assert_eq!(user.premium_type, Some(2));
|
||||
assert_eq!(user.suspicious_activity_flags, 0);
|
||||
assert!(user.has_totp);
|
||||
assert!(user.has_verified_phone);
|
||||
assert_eq!(user.last_active_ip.as_deref(), Some("1.2.3.4"));
|
||||
}
|
||||
|
||||
@@ -79,10 +75,10 @@ fn deserialize_flags_as_string_and_number() {
|
||||
"premium_flags": 0, "avatar": null, "banner": null, "bio": null,
|
||||
"pronouns": null, "accent_color": null, "email": null,
|
||||
"email_verified": false, "email_bounced": false,
|
||||
"has_verified_phone": false, "date_of_birth": null, "locale": null,
|
||||
"date_of_birth": null, "locale": null,
|
||||
"premium_type": null, "premium_since": null, "premium_until": null,
|
||||
"premium_grace_ends_at": null, "premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0, "temp_banned_until": null,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null, "pending_bulk_message_deletion_at": null,
|
||||
"deletion_reason_code": null, "deletion_public_reason": null, "deletion_audit_log_reason": null,
|
||||
"deletion_scheduled_by": null, "deletion_scheduled_at": null,
|
||||
@@ -111,10 +107,10 @@ fn deserialize_discriminator_int_and_string() {
|
||||
"bot": true, "system": false, "flags": "0", "premium_flags": 0,
|
||||
"avatar": null, "banner": null, "bio": null, "pronouns": null,
|
||||
"accent_color": null, "email": null, "email_verified": false,
|
||||
"email_bounced": false, "has_verified_phone": false, "date_of_birth": null,
|
||||
"email_bounced": false, "date_of_birth": null,
|
||||
"locale": null, "premium_type": null, "premium_since": null,
|
||||
"premium_until": null, "premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null, "suspicious_activity_flags": 0,
|
||||
"premium_lifetime_sequence": null,
|
||||
"temp_banned_until": null, "pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null, "deletion_reason_code": null,
|
||||
"deletion_public_reason": null, "deletion_audit_log_reason": null,
|
||||
@@ -161,7 +157,6 @@ fn deserialize_search_users_response() {
|
||||
"email": null,
|
||||
"email_verified": false,
|
||||
"email_bounced": false,
|
||||
"has_verified_phone": false,
|
||||
"date_of_birth": null,
|
||||
"locale": null,
|
||||
"premium_type": null,
|
||||
@@ -169,7 +164,6 @@ fn deserialize_search_users_response() {
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
@@ -881,10 +875,10 @@ fn deserialize_user_mutation_response() {
|
||||
"flags": "1", "premium_flags": 0, "avatar": null, "banner": null,
|
||||
"bio": null, "pronouns": null, "accent_color": null, "email": null,
|
||||
"email_verified": false, "email_bounced": false,
|
||||
"has_verified_phone": false, "date_of_birth": null, "locale": null,
|
||||
"date_of_birth": null, "locale": null,
|
||||
"premium_type": null, "premium_since": null, "premium_until": null,
|
||||
"premium_grace_ends_at": null, "premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0, "temp_banned_until": null,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null, "pending_bulk_message_deletion_at": null,
|
||||
"deletion_reason_code": null, "deletion_public_reason": null, "deletion_audit_log_reason": null,
|
||||
"deletion_scheduled_by": null, "deletion_scheduled_at": null,
|
||||
|
||||
@@ -263,11 +263,8 @@ fn admin_user() -> Value {
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"has_totp": false,
|
||||
"authenticator_types": [],
|
||||
"has_verified_phone": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
@@ -363,7 +363,9 @@ async fn user_account_actions_use_no_swap_htmx_toasts() {
|
||||
assert!(body.contains("__fluxerAdminActionForms"), "{body}");
|
||||
assert!(!body.contains(&native_confirm), "{body}");
|
||||
assert!(
|
||||
body.contains(r#"hx-post="/users/1500000000000000001?action=update_has_verified_phone&tab=account""#),
|
||||
body.contains(
|
||||
r#"hx-post="/users/1500000000000000001?action=send_password_reset&tab=account""#
|
||||
),
|
||||
"{body}"
|
||||
);
|
||||
assert!(body.contains(r##"hx-target="#flash-container""##), "{body}");
|
||||
@@ -374,7 +376,7 @@ async fn user_account_actions_use_no_swap_htmx_toasts() {
|
||||
.unwrap_or_else(|| panic!("account page did not set csrf_token cookie\n{body}"));
|
||||
let (status, response_headers, response_body) = post_form_with_headers(
|
||||
&app,
|
||||
"/users/1500000000000000001?action=update_has_verified_phone&tab=account",
|
||||
"/users/1500000000000000001?action=send_password_reset&tab=account",
|
||||
&[
|
||||
("HX-Request", "true"),
|
||||
("HX-Target", "flash-container"),
|
||||
@@ -383,7 +385,7 @@ async fn user_account_actions_use_no_swap_htmx_toasts() {
|
||||
&format!("{}; csrf_token={}", app.session_cookie, csrf_token),
|
||||
),
|
||||
],
|
||||
&format!("_csrf={csrf_token}&has_verified_phone=true"),
|
||||
&format!("_csrf={csrf_token}"),
|
||||
)
|
||||
.await;
|
||||
assert_eq!(status, StatusCode::NO_CONTENT, "{response_body}");
|
||||
@@ -399,7 +401,7 @@ async fn user_account_actions_use_no_swap_htmx_toasts() {
|
||||
.unwrap_or_else(|| panic!("missing toast header\n{response_body}"));
|
||||
assert!(toast.contains("success"), "{toast}");
|
||||
assert!(
|
||||
toast.contains("Phone verification status updated successfully"),
|
||||
toast.contains("Password reset sent successfully"),
|
||||
"{toast}"
|
||||
);
|
||||
}
|
||||
@@ -839,8 +841,8 @@ async fn mock_api(method: Method, uri: Uri) -> Response {
|
||||
(Method::GET, "/admin/users/1500000000000000001") => {
|
||||
json_response(json!({ "users": [searched_user()] }))
|
||||
}
|
||||
(Method::PUT, "/admin/users/1500000000000000001/phone-verification") => {
|
||||
json_response(json!({ "user": searched_user() }))
|
||||
(Method::POST, "/admin/users/1500000000000000001/password-reset") => {
|
||||
StatusCode::NO_CONTENT.into_response()
|
||||
}
|
||||
(Method::GET, "/admin/guilds") => {
|
||||
json_response(json!({ "guilds": [searched_guild()], "total": 1 }))
|
||||
@@ -947,11 +949,8 @@ fn user(id: &str, username: &str) -> Value {
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"has_totp": false,
|
||||
"authenticator_types": [],
|
||||
"has_verified_phone": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
@@ -322,11 +322,8 @@ fn admin_user() -> Value {
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"has_totp": false,
|
||||
"authenticator_types": [],
|
||||
"has_verified_phone": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
"email": "[email protected]",
|
||||
"email_verified": true,
|
||||
"email_bounced": false,
|
||||
"has_verified_phone": true,
|
||||
"date_of_birth": "2000-01-01",
|
||||
"locale": "en-US",
|
||||
"premium_type": null,
|
||||
@@ -24,8 +23,6 @@
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"email": "[email protected]",
|
||||
"email_verified": true,
|
||||
"email_bounced": false,
|
||||
"has_verified_phone": false,
|
||||
"date_of_birth": null,
|
||||
"locale": "en-US",
|
||||
"premium_type": null,
|
||||
@@ -25,8 +24,6 @@
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"email": "[email protected]",
|
||||
"email_verified": true,
|
||||
"email_bounced": false,
|
||||
"has_verified_phone": false,
|
||||
"date_of_birth": null,
|
||||
"locale": "en-US",
|
||||
"premium_type": null,
|
||||
@@ -25,8 +24,6 @@
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
@@ -294,11 +294,8 @@ fn admin_user() -> Value {
|
||||
"premium_until": null,
|
||||
"premium_grace_ends_at": null,
|
||||
"premium_lifetime_sequence": null,
|
||||
"suspicious_activity_flags": 0,
|
||||
"phone_verification_deferred": false,
|
||||
"has_totp": false,
|
||||
"authenticator_types": [],
|
||||
"has_verified_phone": false,
|
||||
"temp_banned_until": null,
|
||||
"pending_deletion_at": null,
|
||||
"pending_bulk_message_deletion_at": null,
|
||||
|
||||
Reference in New Issue
Block a user