diff options
author | Puyodead1 <puyodead@proton.me> | 2023-12-20 03:33:28 -0500 |
---|---|---|
committer | Puyodead1 <puyodead@proton.me> | 2023-12-20 03:33:28 -0500 |
commit | e34887261f8d86aa4e98f4b8ccd6e57ce72c6620 (patch) | |
tree | b7cb601c7e818349b3000eaf20bc75e44c22ff87 | |
parent | add missing license headers (diff) | |
download | server-e34887261f8d86aa4e98f4b8ccd6e57ce72c6620.tar.xz |
initial progress for admin api feat/admin-api
22 files changed, 4525 insertions, 91 deletions
diff --git a/assets/schemas.json b/assets/schemas.json index a0ab1697..dd4e8922 100644 --- a/assets/schemas.json +++ b/assets/schemas.json @@ -46780,6 +46780,9 @@ }, "rules_channel_id": { "type": "string" + }, + "owner_id": { + "type": "string" } }, "additionalProperties": false, @@ -55255,6 +55258,9 @@ "string" ] }, + "owner_id": { + "type": "string" + }, "region": { "type": "string" }, @@ -245731,6 +245737,4207 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, + "AdminGuildsResponse": { + "type": "array", + "items": { + "$ref": "#/definitions/Guild" + }, + "definitions": { + "ChannelPermissionOverwriteType": { + "enum": [ + 0, + 1, + 2 + ], + "type": "number" + }, + "ConnectedAccountTokenData": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "token_type": { + "type": "string" + }, + "scope": { + "type": "string" + }, + "refresh_token": { + "type": "string" + }, + "expires_in": { + "type": "integer" + }, + "expires_at": { + "type": "integer" + }, + "fetched_at": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "fetched_at" + ] + }, + "ChannelModifySchema": { + "type": "object", + "properties": { + "name": { + "maxLength": 100, + "type": "string" + }, + "type": { + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 14, + 15, + 2, + 255, + 3, + 33, + 34, + 35, + 4, + 5, + 6, + 64, + 7, + 8, + 9 + ], + "type": "number" + }, + "topic": { + "type": "string" + }, + "icon": { + "type": [ + "null", + "string" + ] + }, + "bitrate": { + "type": "integer" + }, + "user_limit": { + "type": "integer" + }, + "rate_limit_per_user": { + "type": "integer" + }, + "position": { + "type": "integer" + }, + "permission_overwrites": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ChannelPermissionOverwriteType" + }, + "allow": { + "type": "string" + }, + "deny": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "allow", + "deny", + "id", + "type" + ] + } + }, + "parent_id": { + "type": "string" + }, + "id": { + "type": "string" + }, + "nsfw": { + "type": "boolean" + }, + "rtc_region": { + "type": "string" + }, + "default_auto_archive_duration": { + "type": "integer" + }, + "default_reaction_emoji": { + "type": [ + "null", + "string" + ] + }, + "flags": { + "type": "integer" + }, + "default_thread_rate_limit_per_user": { + "type": "integer" + }, + "video_quality_mode": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "ActivitySchema": { + "type": "object", + "properties": { + "afk": { + "type": "boolean" + }, + "status": { + "$ref": "#/definitions/Status" + }, + "activities": { + "type": "array", + "items": { + "$ref": "#/definitions/Activity" + } + }, + "since": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "status" + ] + }, + "Status": { + "enum": [ + "dnd", + "idle", + "invisible", + "offline", + "online" + ], + "type": "string" + }, + "Activity": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ActivityType" + }, + "url": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "timestamps": { + "type": "object", + "properties": { + "start": { + "type": "integer" + }, + "end": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end", + "start" + ] + }, + "application_id": { + "type": "string" + }, + "details": { + "type": "string" + }, + "state": { + "type": "string" + }, + "emoji": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "id": { + "type": "string" + }, + "animated": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "animated", + "name" + ] + }, + "party": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "size": { + "type": "array", + "items": { + "type": "integer" + } + } + }, + "additionalProperties": false + }, + "assets": { + "type": "object", + "properties": { + "large_image": { + "type": "string" + }, + "large_text": { + "type": "string" + }, + "small_image": { + "type": "string" + }, + "small_text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "secrets": { + "type": "object", + "properties": { + "join": { + "type": "string" + }, + "spectate": { + "type": "string" + }, + "match": { + "type": "string" + } + }, + "additionalProperties": false + }, + "instance": { + "type": "boolean" + }, + "flags": { + "type": "string" + }, + "id": { + "type": "string" + }, + "sync_id": { + "type": "string" + }, + "metadata": { + "type": "object", + "properties": { + "context_uri": { + "type": "string" + }, + "album_id": { + "type": "string" + }, + "artist_ids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "album_id", + "artist_ids" + ] + }, + "session_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "flags", + "name", + "session_id", + "type" + ] + }, + "ActivityType": { + "enum": [ + 0, + 1, + 2, + 4, + 5 + ], + "type": "number" + }, + "Embed": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "type": { + "enum": [ + "article", + "gifv", + "image", + "link", + "rich", + "video" + ], + "type": "string" + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "color": { + "type": "integer" + }, + "footer": { + "type": "object", + "properties": { + "text": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "text" + ] + }, + "image": { + "$ref": "#/definitions/EmbedImage" + }, + "thumbnail": { + "$ref": "#/definitions/EmbedImage" + }, + "video": { + "$ref": "#/definitions/EmbedImage" + }, + "provider": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "author": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "icon_url": { + "type": "string" + }, + "proxy_icon_url": { + "type": "string" + } + }, + "additionalProperties": false + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "inline": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "name", + "value" + ] + } + } + }, + "additionalProperties": false + }, + "EmbedImage": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "height": { + "type": "integer" + }, + "width": { + "type": "integer" + } + }, + "additionalProperties": false + }, + "ChannelOverride": { + "type": "object", + "properties": { + "message_notifications": { + "type": "integer" + }, + "mute_config": { + "$ref": "#/definitions/MuteConfig" + }, + "muted": { + "type": "boolean" + }, + "channel_id": { + "type": [ + "null", + "string" + ] + } + }, + "additionalProperties": false, + "required": [ + "channel_id", + "message_notifications", + "mute_config", + "muted" + ] + }, + "MuteConfig": { + "type": "object", + "properties": { + "end_time": { + "type": "integer" + }, + "selected_time_window": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "end_time", + "selected_time_window" + ] + }, + "CustomStatus": { + "type": "object", + "properties": { + "emoji_id": { + "type": "string" + }, + "emoji_name": { + "type": "string" + }, + "expires_at": { + "type": "integer" + }, + "text": { + "type": "string" + } + }, + "additionalProperties": false + }, + "FriendSourceFlags": { + "type": "object", + "properties": { + "all": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "all" + ] + }, + "GuildFolder": { + "type": "object", + "properties": { + "color": { + "type": "integer" + }, + "guild_ids": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "color", + "guild_ids", + "id", + "name" + ] + }, + "GenerateWebAuthnCredentialsSchema": { + "type": "object", + "properties": { + "password": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "password" + ] + }, + "CreateWebAuthnCredentialSchema": { + "type": "object", + "properties": { + "credential": { + "type": "string" + }, + "name": { + "type": "string" + }, + "ticket": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "credential", + "name", + "ticket" + ] + }, + "APIErrorResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "errors": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "_errors": { + "type": "array", + "items": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "code", + "message" + ] + } + } + }, + "additionalProperties": false, + "required": [ + "_errors" + ] + } + } + }, + "additionalProperties": false, + "required": [ + "code", + "errors", + "message" + ] + }, + "CaptchaRequiredResponse": { + "type": "object", + "properties": { + "captcha_key": { + "type": "string" + }, + "captcha_sitekey": { + "type": "string" + }, + "captcha_service": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "captcha_key", + "captcha_service", + "captcha_sitekey" + ] + }, + "Guild": { + "type": "object", + "properties": { + "afk_channel_id": { + "type": "string" + }, + "afk_channel": { + "$ref": "#/definitions/Channel" + }, + "afk_timeout": { + "type": "integer" + }, + "bans": { + "type": "array", + "items": { + "$ref": "#/definitions/Ban" + } + }, + "banner": { + "type": "string" + }, + "default_message_notifications": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "discovery_splash": { + "type": "string" + }, + "explicit_content_filter": { + "type": "integer" + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "primary_category_id": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "large": { + "type": "boolean", + "default": false + }, + "max_members": { + "type": "integer" + }, + "max_presences": { + "type": "integer" + }, + "max_video_channel_users": { + "type": "integer" + }, + "member_count": { + "type": "integer" + }, + "presence_count": { + "type": "integer" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/definitions/Member" + } + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/definitions/Role" + } + }, + "channels": { + "type": "array", + "items": { + "$ref": "#/definitions/Channel" + } + }, + "template_id": { + "type": "string" + }, + "template": { + "$ref": "#/definitions/Template" + }, + "emojis": { + "type": "array", + "items": { + "$ref": "#/definitions/Emoji" + } + }, + "stickers": { + "type": "array", + "items": { + "$ref": "#/definitions/Sticker" + } + }, + "invites": { + "type": "array", + "items": { + "$ref": "#/definitions/Invite" + } + }, + "voice_states": { + "type": "array", + "items": { + "$ref": "#/definitions/VoiceState" + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/Webhook" + } + }, + "mfa_level": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "owner_id": { + "type": "string" + }, + "owner": { + "$ref": "#/definitions/User" + }, + "preferred_locale": { + "type": "string" + }, + "premium_subscription_count": { + "type": "integer" + }, + "premium_tier": { + "type": "integer" + }, + "public_updates_channel_id": { + "type": "string" + }, + "public_updates_channel": { + "$ref": "#/definitions/Channel" + }, + "rules_channel_id": { + "type": "string" + }, + "rules_channel": { + "type": "string" + }, + "region": { + "type": "string" + }, + "splash": { + "type": "string" + }, + "system_channel_id": { + "type": "string" + }, + "system_channel": { + "$ref": "#/definitions/Channel" + }, + "system_channel_flags": { + "type": "integer" + }, + "unavailable": { + "type": "boolean", + "default": false + }, + "verification_level": { + "type": "integer" + }, + "welcome_screen": { + "$ref": "#/definitions/GuildWelcomeScreen" + }, + "widget_channel_id": { + "type": "string" + }, + "widget_channel": { + "$ref": "#/definitions/Channel" + }, + "widget_enabled": { + "type": "boolean", + "default": true + }, + "nsfw_level": { + "type": "integer" + }, + "nsfw": { + "type": "boolean", + "default": false + }, + "parent": { + "type": "string" + }, + "permissions": { + "type": "integer" + }, + "premium_progress_bar_enabled": { + "type": "boolean", + "default": false + }, + "channel_ordering": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "bans", + "channel_ordering", + "channels", + "emojis", + "features", + "id", + "invites", + "members", + "name", + "nsfw", + "premium_progress_bar_enabled", + "public_updates_channel_id", + "roles", + "stickers", + "template", + "unavailable", + "voice_states", + "webhooks", + "welcome_screen", + "widget_enabled" + ] + }, + "Channel": { + "type": "object", + "properties": { + "created_at": { + "type": "string", + "format": "date-time" + }, + "name": { + "type": "string" + }, + "icon": { + "type": [ + "null", + "string" + ] + }, + "type": { + "$ref": "#/definitions/ChannelType" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/definitions/Recipient" + } + }, + "last_message_id": { + "type": "string" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "parent_id": { + "type": "string" + }, + "parent": { + "$ref": "#/definitions/Channel" + }, + "owner_id": { + "type": "string" + }, + "owner": { + "$ref": "#/definitions/User" + }, + "last_pin_timestamp": { + "type": "integer" + }, + "default_auto_archive_duration": { + "type": "integer" + }, + "permission_overwrites": { + "type": "array", + "items": { + "$ref": "#/definitions/ChannelPermissionOverwrite" + } + }, + "video_quality_mode": { + "type": "integer" + }, + "bitrate": { + "type": "integer" + }, + "user_limit": { + "type": "integer" + }, + "nsfw": { + "type": "boolean", + "default": false + }, + "rate_limit_per_user": { + "type": "integer" + }, + "topic": { + "type": "string" + }, + "invites": { + "type": "array", + "items": { + "$ref": "#/definitions/Invite" + } + }, + "retention_policy_id": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/Message" + } + }, + "voice_states": { + "type": "array", + "items": { + "$ref": "#/definitions/VoiceState" + } + }, + "read_states": { + "type": "array", + "items": { + "$ref": "#/definitions/ReadState" + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/Webhook" + } + }, + "flags": { + "type": "integer", + "default": 0 + }, + "default_thread_rate_limit_per_user": { + "type": "integer", + "default": 0 + }, + "position": { + "description": "Must be calculated Channel.calculatePosition", + "type": "integer" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "created_at", + "default_thread_rate_limit_per_user", + "flags", + "id", + "nsfw", + "owner", + "parent_id", + "position", + "type" + ] + }, + "ChannelType": { + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 14, + 15, + 2, + 255, + 3, + 33, + 34, + 35, + 4, + 5, + 6, + 64, + 7, + 8, + 9 + ], + "type": "number" + }, + "Recipient": { + "type": "object", + "properties": { + "channel_id": { + "type": "string" + }, + "channel": { + "$ref": "#/definitions/Channel" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "closed": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "channel", + "channel_id", + "closed", + "id", + "user", + "user_id" + ] + }, + "User": { + "type": "object", + "properties": { + "username": { + "type": "string" + }, + "discriminator": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "accent_color": { + "type": "integer" + }, + "banner": { + "type": "string" + }, + "theme_colors": { + "type": "array", + "items": { + "type": "integer" + } + }, + "pronouns": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "desktop": { + "type": "boolean", + "default": false + }, + "mobile": { + "type": "boolean", + "default": false + }, + "premium": { + "type": "boolean" + }, + "premium_type": { + "type": "integer" + }, + "bot": { + "type": "boolean", + "default": false + }, + "bio": { + "type": "string", + "default": "" + }, + "system": { + "type": "boolean", + "default": false + }, + "nsfw_allowed": { + "type": "boolean", + "default": true + }, + "mfa_enabled": { + "type": "boolean", + "default": false + }, + "webauthn_enabled": { + "type": "boolean", + "default": false + }, + "totp_secret": { + "type": "string", + "default": "" + }, + "totp_last_ticket": { + "type": "string", + "default": "" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "premium_since": { + "type": "string", + "format": "date-time" + }, + "verified": { + "type": "boolean" + }, + "disabled": { + "type": "boolean", + "default": false + }, + "deleted": { + "type": "boolean", + "default": false + }, + "email": { + "type": "string" + }, + "flags": { + "type": "integer", + "default": 0 + }, + "public_flags": { + "type": "integer", + "default": 0 + }, + "purchased_flags": { + "type": "integer", + "default": 0 + }, + "premium_usage_flags": { + "type": "integer", + "default": 0 + }, + "rights": { + "type": "string" + }, + "sessions": { + "type": "array", + "items": { + "$ref": "#/definitions/Session" + } + }, + "relationships": { + "type": "array", + "items": { + "$ref": "#/definitions/Relationship" + } + }, + "connected_accounts": { + "type": "array", + "items": { + "$ref": "#/definitions/ConnectedAccount" + } + }, + "data": { + "type": "object", + "properties": { + "valid_tokens_since": { + "type": "string", + "format": "date-time" + }, + "hash": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "valid_tokens_since" + ] + }, + "fingerprints": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "settings": { + "$ref": "#/definitions/UserSettings" + }, + "extended_settings": { + "type": "string", + "default": "{}" + }, + "security_keys": { + "type": "array", + "items": { + "$ref": "#/definitions/SecurityKey" + } + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "bio", + "bot", + "connected_accounts", + "created_at", + "data", + "deleted", + "desktop", + "disabled", + "discriminator", + "extended_settings", + "fingerprints", + "flags", + "id", + "mfa_enabled", + "mobile", + "nsfw_allowed", + "premium", + "premium_since", + "premium_type", + "premium_usage_flags", + "public_flags", + "purchased_flags", + "relationships", + "rights", + "security_keys", + "sessions", + "settings", + "system", + "username", + "verified", + "webauthn_enabled" + ] + }, + "Session": { + "type": "object", + "properties": { + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "session_id": { + "type": "string" + }, + "activities": { + "type": "array", + "items": { + "$ref": "#/definitions/Activity" + } + }, + "client_info": { + "type": "object", + "properties": { + "client": { + "type": "string" + }, + "os": { + "type": "string" + }, + "version": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "client", + "os", + "version" + ] + }, + "status": { + "$ref": "#/definitions/Status" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "activities", + "client_info", + "id", + "session_id", + "status", + "user", + "user_id" + ] + }, + "Relationship": { + "type": "object", + "properties": { + "from_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/User" + }, + "to_id": { + "type": "string" + }, + "to": { + "$ref": "#/definitions/User" + }, + "nickname": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/RelationshipType" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "from", + "from_id", + "id", + "to", + "to_id", + "type" + ] + }, + "RelationshipType": { + "enum": [ + 1, + 2, + 3, + 4 + ], + "type": "number" + }, + "ConnectedAccount": { + "type": "object", + "properties": { + "external_id": { + "type": "string" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "friend_sync": { + "type": "boolean", + "default": false + }, + "name": { + "type": "string" + }, + "revoked": { + "type": "boolean", + "default": false + }, + "show_activity": { + "type": "integer", + "default": 0 + }, + "type": { + "type": "string" + }, + "verified": { + "type": "boolean", + "default": true + }, + "visibility": { + "type": "integer", + "default": 0 + }, + "integrations": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "metadata_": {}, + "metadata_visibility": { + "type": "integer", + "default": 0 + }, + "two_way_link": { + "type": "boolean", + "default": false + }, + "token_data": { + "anyOf": [ + { + "$ref": "#/definitions/ConnectedAccountTokenData" + }, + { + "type": "null" + } + ] + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "external_id", + "id", + "name", + "type", + "user", + "user_id" + ] + }, + "UserSettings": { + "type": "object", + "properties": { + "index": { + "type": "string" + }, + "afk_timeout": { + "type": "integer", + "default": 3600 + }, + "allow_accessibility_detection": { + "type": "boolean", + "default": true + }, + "animate_emoji": { + "type": "boolean", + "default": true + }, + "animate_stickers": { + "type": "integer", + "default": 0 + }, + "contact_sync_enabled": { + "type": "boolean", + "default": false + }, + "convert_emoticons": { + "type": "boolean", + "default": false + }, + "custom_status": { + "anyOf": [ + { + "$ref": "#/definitions/CustomStatus" + }, + { + "type": "null" + } + ], + "default": null + }, + "default_guilds_restricted": { + "type": "boolean", + "default": false + }, + "detect_platform_accounts": { + "type": "boolean", + "default": false + }, + "developer_mode": { + "type": "boolean", + "default": true + }, + "disable_games_tab": { + "type": "boolean", + "default": true + }, + "enable_tts_command": { + "type": "boolean", + "default": false + }, + "explicit_content_filter": { + "type": "integer", + "default": 0 + }, + "friend_source_flags": { + "$ref": "#/definitions/FriendSourceFlags" + }, + "gateway_connected": { + "type": "boolean", + "default": false + }, + "gif_auto_play": { + "type": "boolean", + "default": false + }, + "guild_folders": { + "type": "array", + "items": { + "$ref": "#/definitions/GuildFolder" + }, + "default": [] + }, + "guild_positions": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "inline_attachment_media": { + "type": "boolean", + "default": true + }, + "inline_embed_media": { + "type": "boolean", + "default": true + }, + "locale": { + "type": "string", + "default": "en-US" + }, + "message_display_compact": { + "type": "boolean", + "default": false + }, + "native_phone_integration_enabled": { + "type": "boolean", + "default": true + }, + "render_embeds": { + "type": "boolean", + "default": true + }, + "render_reactions": { + "type": "boolean", + "default": true + }, + "restricted_guilds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "show_current_game": { + "type": "boolean", + "default": true + }, + "status": { + "enum": [ + "dnd", + "idle", + "invisible", + "offline", + "online" + ], + "type": "string", + "default": "online" + }, + "stream_notifications_enabled": { + "type": "boolean", + "default": false + }, + "theme": { + "enum": [ + "dark", + "light" + ], + "type": "string", + "default": "dark" + }, + "timezone_offset": { + "type": "integer", + "default": 0 + } + }, + "additionalProperties": false, + "required": [ + "afk_timeout", + "allow_accessibility_detection", + "animate_emoji", + "animate_stickers", + "contact_sync_enabled", + "convert_emoticons", + "custom_status", + "default_guilds_restricted", + "detect_platform_accounts", + "developer_mode", + "disable_games_tab", + "enable_tts_command", + "explicit_content_filter", + "friend_source_flags", + "gateway_connected", + "gif_auto_play", + "guild_folders", + "guild_positions", + "index", + "inline_attachment_media", + "inline_embed_media", + "locale", + "message_display_compact", + "native_phone_integration_enabled", + "render_embeds", + "render_reactions", + "restricted_guilds", + "show_current_game", + "status", + "stream_notifications_enabled", + "theme", + "timezone_offset" + ] + }, + "SecurityKey": { + "type": "object", + "properties": { + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "key_id": { + "type": "string" + }, + "public_key": { + "type": "string" + }, + "counter": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "counter", + "id", + "key_id", + "name", + "public_key", + "user", + "user_id" + ] + }, + "ChannelPermissionOverwrite": { + "type": "object", + "properties": { + "allow": { + "type": "string" + }, + "deny": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/ChannelPermissionOverwriteType" + } + }, + "additionalProperties": false, + "required": [ + "allow", + "deny", + "id", + "type" + ] + }, + "Invite": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "temporary": { + "type": "boolean" + }, + "uses": { + "type": "integer" + }, + "max_uses": { + "type": "integer" + }, + "max_age": { + "type": "integer" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "expires_at": { + "type": "string", + "format": "date-time" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "channel_id": { + "type": "string" + }, + "channel": { + "$ref": "#/definitions/Channel" + }, + "inviter_id": { + "type": "string" + }, + "inviter": { + "$ref": "#/definitions/User" + }, + "target_user_id": { + "type": "string" + }, + "target_user": { + "type": "string" + }, + "target_user_type": { + "type": "integer" + }, + "vanity_url": { + "type": "boolean" + }, + "flags": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "channel", + "channel_id", + "code", + "created_at", + "flags", + "guild", + "guild_id", + "inviter", + "max_age", + "max_uses", + "target_user_id", + "temporary", + "uses" + ] + }, + "Message": { + "type": "object", + "properties": { + "channel_id": { + "type": "string" + }, + "channel": { + "$ref": "#/definitions/Channel" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "author_id": { + "type": "string" + }, + "author": { + "$ref": "#/definitions/User" + }, + "member_id": { + "type": "string" + }, + "member": { + "$ref": "#/definitions/Member" + }, + "webhook_id": { + "type": "string" + }, + "webhook": { + "$ref": "#/definitions/Webhook" + }, + "application_id": { + "type": "string" + }, + "application": { + "$ref": "#/definitions/Application" + }, + "content": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "edited_timestamp": { + "type": "string", + "format": "date-time" + }, + "tts": { + "type": "boolean" + }, + "mention_everyone": { + "type": "boolean" + }, + "mentions": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + }, + "mention_roles": { + "type": "array", + "items": { + "$ref": "#/definitions/Role" + } + }, + "mention_channels": { + "type": "array", + "items": { + "$ref": "#/definitions/Channel" + } + }, + "sticker_items": { + "type": "array", + "items": { + "$ref": "#/definitions/Sticker" + } + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/definitions/Attachment_1" + } + }, + "embeds": { + "type": "array", + "items": { + "$ref": "#/definitions/Embed" + } + }, + "reactions": { + "type": "array", + "items": { + "$ref": "#/definitions/Reaction" + } + }, + "nonce": { + "type": "string" + }, + "pinned": { + "type": "boolean" + }, + "type": { + "$ref": "#/definitions/MessageType" + }, + "activity": { + "type": "object", + "properties": { + "type": { + "type": "integer" + }, + "party_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "party_id", + "type" + ] + }, + "flags": { + "type": "integer" + }, + "message_reference": { + "type": "object", + "properties": { + "message_id": { + "type": "string" + }, + "channel_id": { + "type": "string" + }, + "guild_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "message_id" + ] + }, + "referenced_message": { + "$ref": "#/definitions/Message" + }, + "interaction": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/InteractionType" + }, + "name": { + "type": "string" + }, + "user_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "id", + "name", + "type", + "user_id" + ] + }, + "components": { + "type": "array", + "items": { + "$ref": "#/definitions/MessageComponent" + } + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "channel", + "embeds", + "id", + "mention_channels", + "mention_roles", + "mentions", + "reactions", + "timestamp", + "type" + ] + }, + "Member": { + "type": "object", + "properties": { + "index": { + "type": "string" + }, + "id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "nick": { + "type": "string" + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/definitions/Role" + } + }, + "joined_at": { + "type": "string", + "format": "date-time" + }, + "premium_since": { + "type": "integer" + }, + "deaf": { + "type": "boolean" + }, + "mute": { + "type": "boolean" + }, + "pending": { + "type": "boolean" + }, + "settings": { + "$ref": "#/definitions/UserGuildSettings" + }, + "last_message_id": { + "type": "string" + }, + "joined_by": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "banner": { + "type": "string" + }, + "bio": { + "type": "string" + }, + "theme_colors": { + "type": "array", + "items": { + "type": "integer" + } + }, + "pronouns": { + "type": "string" + }, + "communication_disabled_until": { + "type": "string", + "format": "date-time" + } + }, + "additionalProperties": false, + "required": [ + "banner", + "bio", + "communication_disabled_until", + "deaf", + "guild", + "guild_id", + "id", + "index", + "joined_at", + "joined_by", + "mute", + "pending", + "roles", + "settings", + "user" + ] + }, + "Role": { + "type": "object", + "properties": { + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "color": { + "type": "integer" + }, + "hoist": { + "type": "boolean" + }, + "managed": { + "type": "boolean" + }, + "mentionable": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "permissions": { + "type": "string" + }, + "position": { + "type": "integer" + }, + "icon": { + "type": "string" + }, + "unicode_emoji": { + "type": "string" + }, + "tags": { + "type": "object", + "properties": { + "bot_id": { + "type": "string" + }, + "integration_id": { + "type": "string" + }, + "premium_subscriber": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "flags": { + "type": "integer" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "color", + "flags", + "guild", + "guild_id", + "hoist", + "id", + "managed", + "mentionable", + "name", + "permissions", + "position" + ] + }, + "UserGuildSettings": { + "type": "object", + "properties": { + "channel_overrides": { + "anyOf": [ + { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ChannelOverride" + } + }, + { + "type": "null" + } + ] + }, + "message_notifications": { + "type": "integer" + }, + "mobile_push": { + "type": "boolean" + }, + "mute_config": { + "anyOf": [ + { + "$ref": "#/definitions/MuteConfig" + }, + { + "type": "null" + } + ] + }, + "muted": { + "type": "boolean" + }, + "suppress_everyone": { + "type": "boolean" + }, + "suppress_roles": { + "type": "boolean" + }, + "version": { + "type": "integer" + }, + "guild_id": { + "type": [ + "null", + "string" + ] + }, + "flags": { + "type": "integer" + }, + "mute_scheduled_events": { + "type": "boolean" + }, + "hide_muted_channels": { + "type": "boolean" + }, + "notify_highlights": { + "type": "number", + "enum": [ + 0 + ] + } + }, + "additionalProperties": false, + "required": [ + "channel_overrides", + "flags", + "guild_id", + "hide_muted_channels", + "message_notifications", + "mobile_push", + "mute_config", + "mute_scheduled_events", + "muted", + "notify_highlights", + "suppress_everyone", + "suppress_roles", + "version" + ] + }, + "Webhook": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/WebhookType" + }, + "name": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "token": { + "type": "string" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "channel_id": { + "type": "string" + }, + "channel": { + "$ref": "#/definitions/Channel" + }, + "application_id": { + "type": "string" + }, + "application": { + "$ref": "#/definitions/Application" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "source_guild_id": { + "type": "string" + }, + "source_guild": { + "$ref": "#/definitions/Guild" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "application", + "application_id", + "channel", + "channel_id", + "guild", + "guild_id", + "id", + "source_guild", + "source_guild_id", + "type", + "user", + "user_id" + ] + }, + "WebhookType": { + "enum": [ + 1, + 2, + 3 + ], + "type": "number" + }, + "Application": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "description": { + "type": "string" + }, + "summary": { + "type": "string", + "default": "" + }, + "type": { + "type": "object", + "properties": {}, + "additionalProperties": true + }, + "hook": { + "type": "boolean", + "default": true + }, + "bot_public": { + "type": "boolean", + "default": true + }, + "bot_require_code_grant": { + "type": "boolean", + "default": false + }, + "verify_key": { + "type": "string" + }, + "owner": { + "$ref": "#/definitions/User" + }, + "flags": { + "type": "integer", + "default": 0 + }, + "redirect_uris": { + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "rpc_application_state": { + "type": "integer", + "default": 0 + }, + "store_application_state": { + "type": "integer", + "default": 1 + }, + "verification_state": { + "type": "integer", + "default": 1 + }, + "interactions_endpoint_url": { + "type": "string" + }, + "integration_public": { + "type": "boolean", + "default": true + }, + "integration_require_code_grant": { + "type": "boolean", + "default": false + }, + "discoverability_state": { + "type": "integer", + "default": 1 + }, + "discovery_eligibility_flags": { + "type": "integer", + "default": 2240 + }, + "bot": { + "$ref": "#/definitions/User" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "cover_image": { + "type": "string" + }, + "install_params": { + "type": "object", + "properties": { + "scopes": { + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "permissions", + "scopes" + ] + }, + "terms_of_service_url": { + "type": "string" + }, + "privacy_policy_url": { + "type": "string" + }, + "team": { + "$ref": "#/definitions/Team" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "description", + "discoverability_state", + "discovery_eligibility_flags", + "flags", + "hook", + "id", + "integration_public", + "integration_require_code_grant", + "name", + "owner", + "redirect_uris", + "rpc_application_state", + "store_application_state", + "summary", + "verification_state", + "verify_key" + ] + }, + "Team": { + "type": "object", + "properties": { + "icon": { + "type": "string" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/definitions/TeamMember" + } + }, + "name": { + "type": "string" + }, + "owner_user_id": { + "type": "string" + }, + "owner_user": { + "$ref": "#/definitions/User" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "id", + "members", + "name", + "owner_user", + "owner_user_id" + ] + }, + "TeamMember": { + "type": "object", + "properties": { + "membership_state": { + "$ref": "#/definitions/TeamMemberState" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + } + }, + "team_id": { + "type": "string" + }, + "team": { + "$ref": "#/definitions/Team" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "id", + "membership_state", + "permissions", + "team", + "team_id", + "user", + "user_id" + ] + }, + "TeamMemberState": { + "enum": [ + 1, + 2 + ], + "type": "number" + }, + "Sticker": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "available": { + "type": "boolean" + }, + "tags": { + "type": "string" + }, + "pack_id": { + "type": "string" + }, + "pack": { + "$ref": "#/definitions/StickerPack" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "type": { + "$ref": "#/definitions/StickerType" + }, + "format_type": { + "$ref": "#/definitions/StickerFormatType" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "format_type", + "id", + "name", + "pack", + "type" + ] + }, + "StickerPack": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "banner_asset_id": { + "type": "string" + }, + "stickers": { + "type": "array", + "items": { + "$ref": "#/definitions/Sticker" + } + }, + "cover_sticker_id": { + "type": "string" + }, + "cover_sticker": { + "$ref": "#/definitions/Sticker" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "id", + "name", + "stickers" + ] + }, + "StickerType": { + "enum": [ + 1, + 2 + ], + "type": "number" + }, + "StickerFormatType": { + "enum": [ + 0, + 1, + 2, + 3 + ], + "type": "number" + }, + "Attachment_1": { + "type": "object", + "properties": { + "filename": { + "type": "string" + }, + "size": { + "type": "integer" + }, + "url": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "height": { + "type": "integer" + }, + "width": { + "type": "integer" + }, + "content_type": { + "type": "string" + }, + "message_id": { + "type": "string" + }, + "message": { + "$ref": "#/definitions/Message" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "filename", + "id", + "message", + "message_id", + "proxy_url", + "size", + "url" + ] + }, + "Reaction": { + "type": "object", + "properties": { + "count": { + "type": "integer" + }, + "emoji": { + "$ref": "#/definitions/PartialEmoji" + }, + "user_ids": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "count", + "emoji", + "user_ids" + ] + }, + "PartialEmoji": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "animated": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "name" + ] + }, + "MessageType": { + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 19, + 2, + 20, + 255, + 3, + 4, + 41, + 42, + 43, + 5, + 50, + 6, + 63, + 7, + 8, + 9 + ], + "type": "number" + }, + "InteractionType": { + "enum": [ + 0, + 1, + 2 + ], + "type": "number" + }, + "MessageComponent": { + "type": "object", + "properties": { + "type": { + "type": "integer" + }, + "style": { + "type": "integer" + }, + "label": { + "type": "string" + }, + "emoji": { + "$ref": "#/definitions/PartialEmoji" + }, + "custom_id": { + "type": "string" + }, + "url": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "components": { + "type": "array", + "items": { + "$ref": "#/definitions/MessageComponent" + } + } + }, + "additionalProperties": false, + "required": [ + "components", + "type" + ] + }, + "VoiceState": { + "type": "object", + "properties": { + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "channel_id": { + "type": "string" + }, + "channel": { + "$ref": "#/definitions/Channel" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "member": { + "$ref": "#/definitions/Member" + }, + "session_id": { + "type": "string" + }, + "token": { + "type": "string" + }, + "deaf": { + "type": "boolean" + }, + "mute": { + "type": "boolean" + }, + "self_deaf": { + "type": "boolean" + }, + "self_mute": { + "type": "boolean" + }, + "self_stream": { + "type": "boolean" + }, + "self_video": { + "type": "boolean" + }, + "suppress": { + "type": "boolean" + }, + "request_to_speak_timestamp": { + "type": "string", + "format": "date-time" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "channel", + "channel_id", + "deaf", + "guild_id", + "id", + "member", + "mute", + "self_deaf", + "self_mute", + "self_video", + "session_id", + "suppress", + "token", + "user", + "user_id" + ] + }, + "ReadState": { + "type": "object", + "properties": { + "channel_id": { + "type": "string" + }, + "channel": { + "$ref": "#/definitions/Channel" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "last_message_id": { + "type": "string" + }, + "public_ack": { + "type": "string" + }, + "notifications_cursor": { + "type": "string" + }, + "last_pin_timestamp": { + "type": "string", + "format": "date-time" + }, + "mention_count": { + "type": "integer" + }, + "manual": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "channel", + "channel_id", + "id", + "last_message_id", + "manual", + "mention_count", + "notifications_cursor", + "public_ack", + "user", + "user_id" + ] + }, + "Ban": { + "type": "object", + "properties": { + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "executor_id": { + "type": "string" + }, + "executor": { + "$ref": "#/definitions/User" + }, + "ip": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "executor", + "executor_id", + "guild", + "guild_id", + "id", + "ip", + "user", + "user_id" + ] + }, + "Template": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "usage_count": { + "type": "integer" + }, + "creator_id": { + "type": "string" + }, + "creator": { + "$ref": "#/definitions/User" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "source_guild_id": { + "type": "string" + }, + "source_guild": { + "$ref": "#/definitions/Guild" + }, + "serialized_source_guild": { + "$ref": "#/definitions/Guild" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "code", + "created_at", + "creator", + "creator_id", + "id", + "name", + "serialized_source_guild", + "source_guild", + "source_guild_id", + "updated_at" + ] + }, + "Emoji": { + "type": "object", + "properties": { + "animated": { + "type": "boolean" + }, + "available": { + "type": "boolean" + }, + "guild_id": { + "type": "string" + }, + "guild": { + "$ref": "#/definitions/Guild" + }, + "user_id": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/User" + }, + "managed": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "require_colons": { + "type": "boolean" + }, + "roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "groups": { + "type": "array", + "items": { + "type": "string" + } + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "animated", + "available", + "groups", + "guild", + "guild_id", + "id", + "managed", + "name", + "require_colons", + "roles", + "user", + "user_id" + ] + }, + "GuildWelcomeScreen": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "description": { + "type": "string" + }, + "welcome_channels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "emoji_id": { + "type": "string" + }, + "emoji_name": { + "type": "string" + }, + "channel_id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "channel_id", + "description" + ] + } + } + }, + "additionalProperties": false, + "required": [ + "description", + "enabled", + "welcome_channels" + ] + }, + "GuildMessagesSearchMessage": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/MessageType" + }, + "content": { + "type": "string" + }, + "channel_id": { + "type": "string" + }, + "author": { + "$ref": "#/definitions/PublicUser" + }, + "attachments": { + "type": "array", + "items": { + "$ref": "#/definitions/Attachment_1" + } + }, + "embeds": { + "type": "array", + "items": { + "$ref": "#/definitions/Embed" + } + }, + "mentions": { + "type": "array", + "items": { + "$ref": "#/definitions/PublicUser" + } + }, + "mention_roles": { + "type": "array", + "items": { + "$ref": "#/definitions/Role" + } + }, + "pinned": { + "type": "boolean" + }, + "mention_everyone": { + "type": "boolean" + }, + "tts": { + "type": "boolean" + }, + "timestamp": { + "type": "string" + }, + "edited_timestamp": { + "type": [ + "null", + "string" + ] + }, + "flags": { + "type": "integer" + }, + "components": { + "type": "array", + "items": {} + }, + "hit": { + "type": "boolean", + "enum": [ + true + ] + } + }, + "additionalProperties": false, + "required": [ + "attachments", + "author", + "channel_id", + "components", + "edited_timestamp", + "embeds", + "flags", + "hit", + "id", + "mention_roles", + "mentions", + "pinned", + "timestamp", + "tts", + "type" + ] + }, + "PublicUser": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "premium_since": { + "type": "string", + "format": "date-time" + }, + "avatar": { + "type": "string" + }, + "username": { + "type": "string" + }, + "discriminator": { + "type": "string" + }, + "public_flags": { + "type": "integer" + }, + "accent_color": { + "type": "integer" + }, + "banner": { + "type": "string" + }, + "bio": { + "type": "string" + }, + "bot": { + "type": "boolean" + }, + "premium_type": { + "type": "integer" + }, + "theme_colors": { + "type": "array", + "items": { + "type": "integer" + } + }, + "pronouns": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "bio", + "bot", + "discriminator", + "id", + "premium_since", + "premium_type", + "public_flags", + "username" + ] + }, + "GuildVanityUrl": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "uses": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "code", + "uses" + ] + }, + "GuildVanityUrlNoInvite": { + "type": "object", + "properties": { + "code": { + "type": "null" + } + }, + "additionalProperties": false, + "required": [ + "code" + ] + }, + "ClientStatus": { + "type": "object", + "properties": { + "desktop": { + "type": "string" + }, + "mobile": { + "type": "string" + }, + "web": { + "type": "string" + } + }, + "additionalProperties": false + }, + "Snowflake": { + "description": "A container for useful snowflake-related methods.", + "type": "object", + "additionalProperties": false + }, + "TenorGifResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + }, + "src": { + "type": "string" + }, + "gif_src": { + "type": "string" + }, + "width": { + "type": "integer" + }, + "height": { + "type": "integer" + }, + "preview": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "gif_src", + "height", + "id", + "preview", + "src", + "title", + "url", + "width" + ] + }, + "BackupCode": { + "type": "object", + "properties": { + "user": { + "$ref": "#/definitions/User" + }, + "code": { + "type": "string" + }, + "consumed": { + "type": "boolean" + }, + "expired": { + "type": "boolean" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "code", + "consumed", + "expired", + "id", + "user" + ] + }, + "APIGuild": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "reload": { + "description": "Reloads entity data from the database.", + "type": "object", + "additionalProperties": false + }, + "id": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "parent": { + "type": "string" + }, + "owner_id": { + "type": "string" + }, + "nsfw": { + "type": "boolean" + }, + "invites": { + "type": "array", + "items": { + "$ref": "#/definitions/Invite" + } + }, + "voice_states": { + "type": "array", + "items": { + "$ref": "#/definitions/VoiceState" + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/Webhook" + } + }, + "toJSON": { + "type": "object", + "additionalProperties": false + }, + "_do_validate": { + "type": "object", + "additionalProperties": false + }, + "assign": { + "type": "object", + "additionalProperties": false + }, + "hasId": { + "description": "Checks if entity has an id.\nIf entity composite compose ids, it will check them all.", + "type": "object", + "additionalProperties": false + }, + "save": { + "description": "Saves current entity in the database.\nIf entity does not exist in the database then inserts, otherwise updates.", + "type": "object", + "additionalProperties": false + }, + "remove": { + "description": "Removes current entity from the database.", + "type": "object", + "additionalProperties": false + }, + "softRemove": { + "description": "Records the delete date of current entity.", + "type": "object", + "additionalProperties": false + }, + "recover": { + "description": "Recovers a given entity in the database.", + "type": "object", + "additionalProperties": false + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/definitions/Role" + } + }, + "banner": { + "type": "string" + }, + "description": { + "type": "string" + }, + "unavailable": { + "type": "boolean" + }, + "channels": { + "type": "array", + "items": { + "$ref": "#/definitions/Channel" + } + }, + "region": { + "type": "string" + }, + "system_channel_id": { + "type": "string" + }, + "rules_channel_id": { + "type": "string" + }, + "afk_timeout": { + "type": "integer" + }, + "explicit_content_filter": { + "type": "integer" + }, + "afk_channel_id": { + "type": "string" + }, + "bans": { + "type": "array", + "items": { + "$ref": "#/definitions/Ban" + } + }, + "default_message_notifications": { + "type": "integer" + }, + "discovery_splash": { + "type": "string" + }, + "features": { + "type": "array", + "items": { + "type": "string" + } + }, + "primary_category_id": { + "type": "string" + }, + "large": { + "type": "boolean" + }, + "max_members": { + "type": "integer" + }, + "max_presences": { + "type": "integer" + }, + "max_video_channel_users": { + "type": "integer" + }, + "member_count": { + "type": "integer" + }, + "presence_count": { + "type": "integer" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/definitions/Member" + } + }, + "template_id": { + "type": "string" + }, + "emojis": { + "type": "array", + "items": { + "$ref": "#/definitions/Emoji" + } + }, + "stickers": { + "type": "array", + "items": { + "$ref": "#/definitions/Sticker" + } + }, + "mfa_level": { + "type": "integer" + }, + "preferred_locale": { + "type": "string" + }, + "premium_subscription_count": { + "type": "integer" + }, + "premium_tier": { + "type": "integer" + }, + "public_updates_channel_id": { + "type": "string" + }, + "splash": { + "type": "string" + }, + "system_channel_flags": { + "type": "integer" + }, + "verification_level": { + "type": "integer" + }, + "welcome_screen": { + "$ref": "#/definitions/GuildWelcomeScreen" + }, + "widget_channel_id": { + "type": "string" + }, + "widget_enabled": { + "type": "boolean" + }, + "nsfw_level": { + "type": "integer" + }, + "permissions": { + "type": "integer" + }, + "premium_progress_bar_enabled": { + "type": "boolean" + }, + "channel_ordering": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "_do_validate", + "assign", + "bans", + "channel_ordering", + "channels", + "emojis", + "features", + "hasId", + "id", + "invites", + "members", + "name", + "nsfw", + "premium_progress_bar_enabled", + "public_updates_channel_id", + "recover", + "reload", + "remove", + "roles", + "save", + "softRemove", + "stickers", + "toJSON", + "unavailable", + "voice_states", + "webhooks", + "welcome_screen", + "widget_enabled" + ] + }, + "DmChannelDTO": { + "type": "object", + "properties": { + "icon": { + "type": [ + "null", + "string" + ] + }, + "id": { + "type": "string" + }, + "last_message_id": { + "type": [ + "null", + "string" + ] + }, + "name": { + "type": [ + "null", + "string" + ] + }, + "origin_channel_id": { + "type": [ + "null", + "string" + ] + }, + "owner_id": { + "type": "string" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/definitions/MinimalPublicUserDTO" + } + }, + "type": { + "type": "integer" + } + }, + "additionalProperties": false, + "required": [ + "icon", + "id", + "last_message_id", + "name", + "origin_channel_id", + "recipients", + "type" + ] + }, + "MinimalPublicUserDTO": { + "type": "object", + "properties": { + "avatar": { + "type": [ + "null", + "string" + ] + }, + "discriminator": { + "type": "string" + }, + "id": { + "type": "string" + }, + "public_flags": { + "type": "integer" + }, + "username": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "discriminator", + "id", + "public_flags", + "username" + ] + }, + "Categories": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "localizations": { + "type": "string" + }, + "is_primary": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "id", + "is_primary", + "localizations", + "name" + ] + }, + "GuildVoiceRegion": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "custom": { + "type": "boolean" + }, + "deprecated": { + "type": "boolean" + }, + "optimal": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "custom", + "deprecated", + "id", + "name", + "optimal" + ] + }, + "UserLimits": { + "type": "object", + "properties": { + "maxGuilds": { + "type": "integer", + "default": 1048576 + }, + "maxUsername": { + "type": "integer", + "default": 32 + }, + "maxFriends": { + "type": "integer", + "default": 5000 + } + }, + "additionalProperties": false, + "required": [ + "maxFriends", + "maxGuilds", + "maxUsername" + ] + }, + "GuildLimits": { + "type": "object", + "properties": { + "maxRoles": { + "type": "integer", + "default": 1000 + }, + "maxEmojis": { + "type": "integer", + "default": 2000 + }, + "maxMembers": { + "type": "integer", + "default": 25000000 + }, + "maxChannels": { + "type": "integer", + "default": 65535 + }, + "maxChannelsInCategory": { + "type": "integer", + "default": 65535 + } + }, + "additionalProperties": false, + "required": [ + "maxChannels", + "maxChannelsInCategory", + "maxEmojis", + "maxMembers", + "maxRoles" + ] + }, + "MessageLimits": { + "type": "object", + "properties": { + "maxCharacters": { + "type": "integer", + "default": 1048576 + }, + "maxTTSCharacters": { + "type": "integer", + "default": 160 + }, + "maxReactions": { + "type": "integer", + "default": 2048 + }, + "maxAttachmentSize": { + "type": "integer", + "default": 1073741824 + }, + "maxBulkDelete": { + "type": "integer", + "default": 1000 + }, + "maxEmbedDownloadSize": { + "type": "integer", + "default": 5242880 + } + }, + "additionalProperties": false, + "required": [ + "maxAttachmentSize", + "maxBulkDelete", + "maxCharacters", + "maxEmbedDownloadSize", + "maxReactions", + "maxTTSCharacters" + ] + }, + "ChannelLimits": { + "type": "object", + "properties": { + "maxPins": { + "type": "integer", + "default": 500 + }, + "maxTopic": { + "type": "integer", + "default": 1024 + }, + "maxWebhooks": { + "type": "integer", + "default": 100 + } + }, + "additionalProperties": false, + "required": [ + "maxPins", + "maxTopic", + "maxWebhooks" + ] + }, + "RateLimits": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "default": false + }, + "ip": { + "$ref": "#/definitions/RateLimitOptions" + }, + "global": { + "$ref": "#/definitions/RateLimitOptions" + }, + "error": { + "$ref": "#/definitions/RateLimitOptions" + }, + "routes": { + "$ref": "#/definitions/RouteRateLimit" + } + }, + "additionalProperties": false, + "required": [ + "enabled", + "error", + "global", + "ip", + "routes" + ] + }, + "RateLimitOptions": { + "type": "object", + "properties": { + "bot": { + "type": "integer" + }, + "count": { + "type": "integer" + }, + "window": { + "type": "integer" + }, + "onyIp": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "count", + "window" + ] + }, + "RouteRateLimit": { + "type": "object", + "properties": { + "guild": { + "$ref": "#/definitions/RateLimitOptions" + }, + "webhook": { + "$ref": "#/definitions/RateLimitOptions" + }, + "channel": { + "$ref": "#/definitions/RateLimitOptions" + }, + "auth": {} + }, + "additionalProperties": false, + "required": [ + "auth", + "channel", + "guild", + "webhook" + ] + }, + "GlobalRateLimits": { + "type": "object", + "properties": { + "register": { + "$ref": "#/definitions/GlobalRateLimit" + }, + "sendMessage": { + "$ref": "#/definitions/GlobalRateLimit" + } + }, + "additionalProperties": false, + "required": [ + "register", + "sendMessage" + ] + }, + "GlobalRateLimit": { + "type": "object", + "properties": { + "limit": { + "type": "integer", + "default": 100 + }, + "window": { + "type": "integer", + "default": 3600000 + }, + "enabled": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false, + "required": [ + "enabled", + "limit", + "window" + ] + }, + "PublicConnectedAccount": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "verified": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "name", + "type" + ] + }, + "UserProfile": { + "type": "object", + "properties": { + "accent_color": { + "type": "integer" + }, + "banner": { + "type": "string" + }, + "bio": { + "type": "string" + }, + "theme_colors": { + "type": "array", + "items": { + "type": "integer" + } + }, + "pronouns": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "bio" + ] + }, + "TokenResponse": { + "type": "object", + "properties": { + "token": { + "type": "string" + }, + "settings": { + "$ref": "#/definitions/UserSettings" + } + }, + "additionalProperties": false, + "required": [ + "settings", + "token" + ] + }, + "MFAResponse": { + "type": "object", + "properties": { + "ticket": { + "type": "string" + }, + "mfa": { + "type": "boolean", + "enum": [ + true + ] + }, + "sms": { + "type": "boolean", + "enum": [ + false + ] + }, + "token": { + "type": "null" + } + }, + "additionalProperties": false, + "required": [ + "mfa", + "sms", + "ticket", + "token" + ] + }, + "WebAuthnResponse": { + "type": "object", + "properties": { + "webauthn": { + "type": "string" + }, + "ticket": { + "type": "string" + }, + "mfa": { + "type": "boolean", + "enum": [ + true + ] + }, + "sms": { + "type": "boolean", + "enum": [ + false + ] + }, + "token": { + "type": "null" + } + }, + "additionalProperties": false, + "required": [ + "mfa", + "sms", + "ticket", + "token", + "webauthn" + ] + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" + }, "BackupCodesChallengeResponse": { "type": "object", "properties": { @@ -372700,6 +376907,9 @@ }, "disabled": { "type": "boolean" + }, + "rights": { + "type": "string" } }, "additionalProperties": false, @@ -372718,6 +376928,7 @@ "premium_usage_flags", "public_flags", "purchased_flags", + "rights", "username", "verified" ], @@ -389598,6 +393809,9 @@ }, "disabled": { "type": "boolean" + }, + "rights": { + "type": "string" } }, "additionalProperties": false, @@ -389616,6 +393830,7 @@ "premium_usage_flags", "public_flags", "purchased_flags", + "rights", "username", "verified" ], @@ -490966,29 +495181,35 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, - "UserRelationshipsResponse": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/RelationshipType" - }, - "nickname": { - "type": "null" + "UserRelationsResponse": { + "type": "array", + "items": { + "additionalProperties": false, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "username": { + "type": "string" + }, + "discriminator": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "public_flags": { + "type": "integer" + } }, - "user": { - "$ref": "#/definitions/PublicUser" - } + "required": [ + "discriminator", + "id", + "public_flags", + "username" + ] }, - "additionalProperties": false, - "required": [ - "id", - "nickname", - "type", - "user" - ], "definitions": { "ChannelPermissionOverwriteType": { "enum": [ @@ -495185,35 +499406,29 @@ }, "$schema": "http://json-schema.org/draft-07/schema#" }, - "UserRelationsResponse": { - "type": "array", - "items": { - "additionalProperties": false, - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "username": { - "type": "string" - }, - "discriminator": { - "type": "string" - }, - "avatar": { - "type": "string" - }, - "public_flags": { - "type": "integer" - } + "UserRelationshipsResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "required": [ - "discriminator", - "id", - "public_flags", - "username" - ] + "type": { + "$ref": "#/definitions/RelationshipType" + }, + "nickname": { + "type": "null" + }, + "user": { + "$ref": "#/definitions/PublicUser" + } }, + "additionalProperties": false, + "required": [ + "id", + "nickname", + "type", + "user" + ], "definitions": { "ChannelPermissionOverwriteType": { "enum": [ diff --git a/src/api/middlewares/Authentication.ts b/src/api/middlewares/Authentication.ts index 9e41b453..7b8898dc 100644 --- a/src/api/middlewares/Authentication.ts +++ b/src/api/middlewares/Authentication.ts @@ -16,8 +16,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { checkToken, Rights } from "@spacebar/util"; import * as Sentry from "@sentry/node"; +import { checkToken, Rights } from "@spacebar/util"; import { NextFunction, Request, Response } from "express"; import { HTTPError } from "lambert-server"; @@ -67,6 +67,8 @@ declare global { user_bot: boolean; token: { id: string; iat: number }; rights: Rights; + has_permission?: boolean; + has_right?: boolean; } } } diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts index 9aeb27f0..93018ee5 100644 --- a/src/api/routes/guilds/#guild_id/bans.ts +++ b/src/api/routes/guilds/#guild_id/bans.ts @@ -39,6 +39,7 @@ router.get( "/", route({ permission: "BAN_MEMBERS", + right: "OPERATOR", responses: { 200: { body: "GuildBansResponse", @@ -85,6 +86,7 @@ router.get( "/:user", route({ permission: "BAN_MEMBERS", + right: "OPERATOR", responses: { 200: { body: "BanModeratorSchema", @@ -123,6 +125,7 @@ router.put( route({ requestBody: "BanCreateSchema", permission: "BAN_MEMBERS", + right: "OPERATOR", responses: { 200: { body: "Ban", @@ -182,6 +185,7 @@ router.delete( "/:user_id", route({ permission: "BAN_MEMBERS", + right: "OPERATOR", responses: { 204: {}, 403: { @@ -195,13 +199,12 @@ router.delete( async (req: Request, res: Response) => { const { guild_id, user_id } = req.params; - const ban = await Ban.findOneOrFail({ - where: { guild_id: guild_id, user_id: user_id }, - }); - const banned_user = await User.getPublicUser(user_id); await Promise.all([ + Ban.findOneOrFail({ + where: { guild_id: guild_id, user_id: user_id }, + }), Ban.delete({ user_id: user_id, guild_id, diff --git a/src/api/routes/guilds/#guild_id/channels.ts b/src/api/routes/guilds/#guild_id/channels.ts index 68208fee..fc5d5271 100644 --- a/src/api/routes/guilds/#guild_id/channels.ts +++ b/src/api/routes/guilds/#guild_id/channels.ts @@ -50,6 +50,7 @@ router.post( route({ requestBody: "ChannelModifySchema", permission: "MANAGE_CHANNELS", + right: "OPERATOR", responses: { 201: { body: "Channel", @@ -81,6 +82,7 @@ router.patch( route({ requestBody: "ChannelReorderSchema", permission: "MANAGE_CHANNELS", + right: "OPERATOR", responses: { 204: {}, 400: { diff --git a/src/api/routes/guilds/#guild_id/delete.ts b/src/api/routes/guilds/#guild_id/delete.ts index dee52c81..364faa4f 100644 --- a/src/api/routes/guilds/#guild_id/delete.ts +++ b/src/api/routes/guilds/#guild_id/delete.ts @@ -17,7 +17,7 @@ */ import { route } from "@spacebar/api"; -import { Guild, GuildDeleteEvent, emitEvent } from "@spacebar/util"; +import { Guild, GuildDeleteEvent, emitEvent, getRights } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; @@ -40,12 +40,13 @@ router.post( }), async (req: Request, res: Response) => { const { guild_id } = req.params; + const rights = await getRights(req.user_id); const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: ["owner_id"], }); - if (guild.owner_id !== req.user_id) + if (!rights.has("OPERATOR") || guild.owner_id !== req.user_id) throw new HTTPError("You are not the owner of this guild", 401); await Promise.all([ diff --git a/src/api/routes/guilds/#guild_id/index.ts b/src/api/routes/guilds/#guild_id/index.ts index 839ec363..86a75d40 100644 --- a/src/api/routes/guilds/#guild_id/index.ts +++ b/src/api/routes/guilds/#guild_id/index.ts @@ -19,7 +19,6 @@ import { route } from "@spacebar/api"; import { Channel, - DiscordApiErrors, Guild, GuildUpdateEvent, GuildUpdateSchema, @@ -27,7 +26,6 @@ import { Permissions, SpacebarApiErrors, emitEvent, - getPermission, getRights, handleFile, } from "@spacebar/util"; @@ -53,12 +51,13 @@ router.get( }), async (req: Request, res: Response) => { const { guild_id } = req.params; + const rights = await getRights(req.user_id); const [guild, member] = await Promise.all([ Guild.findOneOrFail({ where: { id: guild_id } }), Member.findOne({ where: { guild_id: guild_id, id: req.user_id } }), ]); - if (!member) + if (!rights.has("OPERATOR") || !member) throw new HTTPError( "You are not a member of the guild you are trying to access", 401, @@ -76,6 +75,7 @@ router.patch( route({ requestBody: "GuildUpdateSchema", permission: "MANAGE_GUILD", + right: "OPERATOR", responses: { "200": { body: "GuildUpdateSchema", @@ -95,14 +95,6 @@ router.patch( const body = req.body as GuildUpdateSchema; const { guild_id } = req.params; - const rights = await getRights(req.user_id); - const permission = await getPermission(req.user_id, guild_id); - - if (!rights.has("MANAGE_GUILDS") && !permission.has("MANAGE_GUILD")) - throw DiscordApiErrors.MISSING_PERMISSIONS.withParams( - "MANAGE_GUILDS", - ); - const guild = await Guild.findOneOrFail({ where: { id: guild_id }, relations: ["emojis", "roles", "stickers"], diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts index 7b8e44d3..decc7bba 100644 --- a/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts +++ b/src/api/routes/guilds/#guild_id/members/#member_id/nick.ts @@ -17,7 +17,12 @@ */ import { route } from "@spacebar/api"; -import { getPermission, Member, PermissionResolvable } from "@spacebar/util"; +import { + getPermission, + getRights, + Member, + PermissionResolvable, +} from "@spacebar/util"; import { Request, Response, Router } from "express"; const router = Router(); @@ -38,14 +43,18 @@ router.patch( }), async (req: Request, res: Response) => { const { guild_id } = req.params; + const rights = await getRights(req.user_id); let permissionString: PermissionResolvable = "MANAGE_NICKNAMES"; const member_id = req.params.member_id === "@me" ? ((permissionString = "CHANGE_NICKNAME"), req.user_id) : req.params.member_id; - const perms = await getPermission(req.user_id, guild_id); - perms.hasThrow(permissionString); + // admins dont need to be in the guild + if (member_id !== "@me" && !rights.has("OPERATOR")) { + const perms = await getPermission(req.user_id, guild_id); + perms.hasThrow(permissionString); + } await Member.changeNickname(member_id, guild_id, req.body.nick); res.status(200).send(); diff --git a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts index 46dd70bb..f6da0ffb 100644 --- a/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts +++ b/src/api/routes/guilds/#guild_id/members/#member_id/roles/#role_id/index.ts @@ -26,6 +26,7 @@ router.delete( "/", route({ permission: "MANAGE_ROLES", + right: "OPERATOR", responses: { 204: {}, 403: { @@ -45,6 +46,7 @@ router.put( "/", route({ permission: "MANAGE_ROLES", + right: "OPERATOR", responses: { 204: {}, 403: {}, diff --git a/src/api/routes/guilds/#guild_id/members/index.ts b/src/api/routes/guilds/#guild_id/members/index.ts index 9260308d..07ed3acf 100644 --- a/src/api/routes/guilds/#guild_id/members/index.ts +++ b/src/api/routes/guilds/#guild_id/members/index.ts @@ -17,7 +17,7 @@ */ import { route } from "@spacebar/api"; -import { Member, PublicMemberProjection } from "@spacebar/util"; +import { Member, PublicMemberProjection, getRights } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; import { MoreThan } from "typeorm"; @@ -51,13 +51,15 @@ router.get( }), async (req: Request, res: Response) => { const { guild_id } = req.params; + const rights = await getRights(req.user_id); const limit = Number(req.query.limit) || 1; if (limit > 1000 || limit < 1) throw new HTTPError("Limit must be between 1 and 1000"); const after = `${req.query.after}`; const query = after ? { id: MoreThan(after) } : {}; - await Member.IsInGuildOrFail(req.user_id, guild_id); + if (!rights.has("OPERATOR")) + await Member.IsInGuildOrFail(req.user_id, guild_id); const members = await Member.find({ where: { guild_id, ...query }, diff --git a/src/api/routes/guilds/#guild_id/messages/search.ts b/src/api/routes/guilds/#guild_id/messages/search.ts index 637d1e43..f1111050 100644 --- a/src/api/routes/guilds/#guild_id/messages/search.ts +++ b/src/api/routes/guilds/#guild_id/messages/search.ts @@ -19,7 +19,13 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { route } from "@spacebar/api"; -import { Channel, FieldErrors, Message, getPermission } from "@spacebar/util"; +import { + Channel, + FieldErrors, + Message, + getPermission, + getRights, +} from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; import { FindManyOptions, In, Like } from "typeorm"; @@ -53,6 +59,7 @@ router.get( author_id, } = req.query; + const rights = await getRights(req.user_id); const parsedLimit = Number(limit) || 50; if (parsedLimit < 1 || parsedLimit > 100) throw new HTTPError("limit must be between 1 and 100", 422); @@ -75,7 +82,7 @@ router.get( req.params.guild_id, channel_id as string | undefined, ); - permissions.hasThrow("VIEW_CHANNEL"); + if (!rights.has("OPERATOR")) permissions.hasThrow("VIEW_CHANNEL"); if (!permissions.has("READ_MESSAGE_HISTORY")) return res.json({ messages: [], total_results: 0 }); @@ -120,6 +127,7 @@ router.get( channel.id, ); if ( + !rights.has("OPERATOR") || !perm.has("VIEW_CHANNEL") || !perm.has("READ_MESSAGE_HISTORY") ) diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts index ea1a782a..d854c1f1 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/index.ts @@ -19,6 +19,7 @@ import { route } from "@spacebar/api"; import { emitEvent, + getRights, GuildRoleDeleteEvent, GuildRoleUpdateEvent, handleFile, @@ -48,7 +49,10 @@ router.get( }), async (req: Request, res: Response) => { const { guild_id, role_id } = req.params; - await Member.IsInGuildOrFail(req.user_id, guild_id); + const rights = await getRights(req.user_id); + // admins dont need to be in the guild + if (!rights.has("OPERATOR")) + await Member.IsInGuildOrFail(req.user_id, guild_id); const role = await Role.findOneOrFail({ where: { guild_id, id: role_id }, }); @@ -59,6 +63,7 @@ router.get( router.delete( "/", route({ + right: "OPERATOR", permission: "MANAGE_ROLES", responses: { 204: {}, @@ -103,6 +108,7 @@ router.patch( "/", route({ requestBody: "RoleModifySchema", + right: "OPERATOR", permission: "MANAGE_ROLES", responses: { 200: { diff --git a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts index 539cd5d8..22744abe 100644 --- a/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts +++ b/src/api/routes/guilds/#guild_id/roles/#role_id/members.ts @@ -16,15 +16,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Router, Request, Response } from "express"; -import { DiscordApiErrors, Member, partition } from "@spacebar/util"; import { route } from "@spacebar/api"; +import { DiscordApiErrors, Member, partition } from "@spacebar/util"; +import { Request, Response, Router } from "express"; const router = Router(); router.patch( "/", - route({ permission: "MANAGE_ROLES" }), + route({ permission: "MANAGE_ROLES", right: "OPERATOR" }), async (req: Request, res: Response) => { // Payload is JSON containing a list of member_ids, the new list of members to have the role const { guild_id, role_id } = req.params; diff --git a/src/api/routes/guilds/#guild_id/roles/index.ts b/src/api/routes/guilds/#guild_id/roles/index.ts index e2c34e7f..4f56232d 100644 --- a/src/api/routes/guilds/#guild_id/roles/index.ts +++ b/src/api/routes/guilds/#guild_id/roles/index.ts @@ -49,6 +49,7 @@ router.post( route({ requestBody: "RoleModifySchema", permission: "MANAGE_ROLES", + right: "OPERATOR", responses: { 200: { body: "Role", @@ -65,11 +66,14 @@ router.post( const guild_id = req.params.guild_id; const body = req.body as RoleModifySchema; - const role_count = await Role.count({ where: { guild_id } }); - const { maxRoles } = Config.get().limits.guild; + // admins can bypass this + if (!req.has_right) { + const role_count = await Role.count({ where: { guild_id } }); + const { maxRoles } = Config.get().limits.guild; - if (role_count > maxRoles) - throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles); + if (role_count > maxRoles) + throw DiscordApiErrors.MAXIMUM_ROLES.withParams(maxRoles); + } const role = Role.create({ // values before ...body are default and can be overriden diff --git a/src/api/routes/guilds/#guild_id/roles/member-counts.ts b/src/api/routes/guilds/#guild_id/roles/member-counts.ts index 88243b42..8b098dcf 100644 --- a/src/api/routes/guilds/#guild_id/roles/member-counts.ts +++ b/src/api/routes/guilds/#guild_id/roles/member-counts.ts @@ -16,16 +16,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Request, Response, Router } from "express"; -import { Role, Member } from "@spacebar/util"; import { route } from "@spacebar/api"; +import { Member, Role, getRights } from "@spacebar/util"; +import { Request, Response, Router } from "express"; import {} from "typeorm"; const router: Router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { const { guild_id } = req.params; - await Member.IsInGuildOrFail(req.user_id, guild_id); + const rights = await getRights(req.user_id); + // admins dont need to be in the guild + if (!rights.has("OPERATOR")) + await Member.IsInGuildOrFail(req.user_id, guild_id); const role_ids = await Role.find({ where: { guild_id }, select: ["id"] }); const counts: { [id: string]: number } = {}; diff --git a/src/api/routes/guilds/index.ts b/src/api/routes/guilds/index.ts index 545beb18..242d49a0 100644 --- a/src/api/routes/guilds/index.ts +++ b/src/api/routes/guilds/index.ts @@ -26,16 +26,71 @@ import { getRights, } from "@spacebar/util"; import { Request, Response, Router } from "express"; +import { HTTPError } from "lambert-server"; +import { ILike, MoreThan } from "typeorm"; const router: Router = Router(); +router.get( + "/", + route({ + description: "Get a list of guilds", + right: "OPERATOR", + query: { + limit: { + description: + "max number of guilds to return (1-1000). default 100", + type: "number", + required: false, + }, + after: { + description: "The amount of guilds to skip", + type: "number", + required: false, + }, + query: { + description: "The search query", + type: "string", + required: false, + }, + }, + responses: { + 200: { + body: "AdminGuildsResponse", + }, + 400: { + body: "APIErrorResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const { after, query } = req.query as { + after?: number; + query?: string; + }; + + const limit = Number(req.query.limit) || 100; + if (limit > 1000 || limit < 1) + throw new HTTPError("Limit must be between 1 and 1000"); + + const guilds = await Guild.find({ + where: { + ...(after ? { id: MoreThan(`${after}`) } : {}), + ...(query ? { name: ILike(`%${query}%`) } : {}), + }, + take: limit, + }); + + res.send(guilds); + }, +); + //TODO: create default channel router.post( "/", route({ requestBody: "GuildCreateSchema", - right: "CREATE_GUILDS", responses: { 201: { body: "GuildCreateResponse", @@ -50,17 +105,31 @@ router.post( }), async (req: Request, res: Response) => { const body = req.body as GuildCreateSchema; + const rights = await getRights(req.user_id); + if (!rights.has("CREATE_GUILDS") && !rights.has("OPERATOR")) { + throw new HTTPError( + `You are missing the following rights CREATE_GUILDS or OPERATOR`, + 403, + ); + } const { maxGuilds } = Config.get().limits.user; const guild_count = await Member.count({ where: { id: req.user_id } }); - const rights = await getRights(req.user_id); - if (guild_count >= maxGuilds && !rights.has("MANAGE_GUILDS")) { + // allow admins to bypass guild limits + if (guild_count >= maxGuilds && !rights.has("OPERATOR")) { throw DiscordApiErrors.MAXIMUM_GUILDS.withParams(maxGuilds); } + let owner_id = req.user_id; + + // only admins can do this, is ignored otherwise + if (body.owner_id && rights.has("OPERATOR")) { + owner_id = body.owner_id; + } + const guild = await Guild.createGuild({ ...body, - owner_id: req.user_id, + owner_id, }); const { autoJoin } = Config.get().guild; diff --git a/src/api/routes/users/#id/index.ts b/src/api/routes/users/#id/index.ts index 1bd413d3..dd47a0cd 100644 --- a/src/api/routes/users/#id/index.ts +++ b/src/api/routes/users/#id/index.ts @@ -17,7 +17,7 @@ */ import { route } from "@spacebar/api"; -import { User } from "@spacebar/util"; +import { User, getRights } from "@spacebar/util"; import { Request, Response, Router } from "express"; const router: Router = Router(); @@ -33,8 +33,15 @@ router.get( }), async (req: Request, res: Response) => { const { id } = req.params; + const rights = await getRights(req.user_id); - res.json(await User.getPublicUser(id)); + const user = await User.findOneOrFail({ where: { id } }); + + res.json( + rights.has("OPERATOR") + ? await user.toPrivateUser() + : await user.toPublicUser(), + ); }, ); diff --git a/src/api/routes/users/index.ts b/src/api/routes/users/index.ts new file mode 100644 index 00000000..a8373fd0 --- /dev/null +++ b/src/api/routes/users/index.ts @@ -0,0 +1,82 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +import { route } from "@spacebar/api"; +import { PrivateUserProjection, User } from "@spacebar/util"; +import { Request, Response, Router } from "express"; +import { HTTPError } from "lambert-server"; +import { ILike, MoreThan } from "typeorm"; +const router = Router(); + +router.get( + "/", + route({ + right: "OPERATOR", + description: "Get a list of users", + query: { + limit: { + description: + "max number of users to return (1-1000). default 100", + type: "number", + required: false, + }, + after: { + description: "The amount of users to skip", + type: "number", + required: false, + }, + query: { + description: "The search query", + type: "string", + required: false, + }, + }, + responses: { + 200: { + body: "AdminUsersResponse", + }, + 400: { + body: "APIErrorResponse", + }, + }, + }), + async (req: Request, res: Response) => { + const { after, query } = req.query as { + after?: number; + query?: string; + }; + + const limit = Number(req.query.limit) || 100; + if (limit > 1000 || limit < 1) + throw new HTTPError("Limit must be between 1 and 1000"); + + const users = await User.find({ + where: { + ...(after ? { id: MoreThan(`${after}`) } : {}), + ...(query ? { username: ILike(`%${query}%`) } : {}), + }, + take: limit, + select: PrivateUserProjection, + order: { id: "ASC" }, + }); + + res.send(users); + }, +); + +export default router; diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts index 5a0b48e6..eef6c526 100644 --- a/src/api/util/handlers/route.ts +++ b/src/api/util/handlers/route.ts @@ -89,7 +89,7 @@ export function route(opts: RouteOptions) { } return async (req: Request, res: Response, next: NextFunction) => { - if (opts.permission) { + if (opts.permission && !opts.right) { const required = new Permissions(opts.permission); req.permission = await getPermission( req.user_id, @@ -103,6 +103,8 @@ export function route(opts: RouteOptions) { opts.permission as string, ); } + + req.has_permission = true; } if (opts.right) { @@ -114,6 +116,7 @@ export function route(opts: RouteOptions) { opts.right as string, ); } + req.has_right = true; } if (validate) { diff --git a/src/util/entities/User.ts b/src/util/entities/User.ts index c6582b00..aa552ee4 100644 --- a/src/util/entities/User.ts +++ b/src/util/entities/User.ts @@ -64,6 +64,7 @@ export enum PrivateUserEnum { purchased_flags, premium_usage_flags, disabled, + rights, // settings, // now a relation // locale } diff --git a/src/util/schemas/GuildCreateSchema.ts b/src/util/schemas/GuildCreateSchema.ts index f7138991..eb775b26 100644 --- a/src/util/schemas/GuildCreateSchema.ts +++ b/src/util/schemas/GuildCreateSchema.ts @@ -29,4 +29,5 @@ export interface GuildCreateSchema { guild_template_code?: string; system_channel_id?: string; rules_channel_id?: string; + owner_id?: string; // used by admins to create a guild for someone else } diff --git a/src/util/schemas/responses/AdminGuildsResponse.ts b/src/util/schemas/responses/AdminGuildsResponse.ts new file mode 100644 index 00000000..2f9d6bc3 --- /dev/null +++ b/src/util/schemas/responses/AdminGuildsResponse.ts @@ -0,0 +1,21 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2023 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +import { Guild } from "../../entities"; + +export type AdminGuildsResponse = Guild[]; diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts index accb26f5..e0619a93 100644 --- a/src/util/schemas/responses/index.ts +++ b/src/util/schemas/responses/index.ts @@ -18,6 +18,7 @@ export * from "./APIErrorOrCaptchaResponse"; export * from "./APIErrorResponse"; +export * from "./AdminGuildsResponse"; export * from "./BackupCodesChallengeResponse"; export * from "./CaptchaRequiredResponse"; export * from "./DiscoverableGuildsResponse"; |