mirror of https://gitlab.com/litecord/litecord.git
748 lines
21 KiB
Python
748 lines
21 KiB
Python
"""
|
|
|
|
Litecord
|
|
Copyright (C) 2018-2019 Luna Mendes
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, version 3 of the License.
|
|
|
|
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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
"""
|
|
|
|
import re
|
|
from typing import Union, Dict, List
|
|
|
|
from cerberus import Validator
|
|
from logbook import Logger
|
|
from quart import current_app as app
|
|
|
|
from .errors import BadRequest
|
|
from .permissions import Permissions
|
|
from .types import Color
|
|
from .enums import (
|
|
ActivityType, StatusType, ExplicitFilter, RelationshipType,
|
|
MessageNotifications, ChannelType, VerificationLevel
|
|
)
|
|
|
|
from litecord.embed.schemas import EMBED_OBJECT, EmbedURL
|
|
|
|
log = Logger(__name__)
|
|
|
|
USERNAME_REGEX = re.compile(r'^[a-zA-Z0-9_ ]{2,30}$', re.A)
|
|
EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$',
|
|
re.A)
|
|
DATA_REGEX = re.compile(r'data\:image/(png|jpeg|gif);base64,(.+)', re.A)
|
|
|
|
|
|
# collection of regexes
|
|
USER_MENTION = re.compile(r'<@!?(\d+)>', re.A | re.M)
|
|
CHAN_MENTION = re.compile(r'<#(\d+)>', re.A | re.M)
|
|
ROLE_MENTION = re.compile(r'<@&(\d+)>', re.A | re.M)
|
|
EMOJO_MENTION = re.compile(r'<:(\.+):(\d+)>', re.A | re.M)
|
|
ANIMOJI_MENTION = re.compile(r'<a:(\.+):(\d+)>', re.A | re.M)
|
|
|
|
|
|
def _in_enum(enum, value) -> bool:
|
|
"""Return if a given value is in the enum."""
|
|
try:
|
|
enum(value)
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
|
|
class LitecordValidator(Validator):
|
|
"""Main validator class for Litecord, containing custom types."""
|
|
def _validate_type_username(self, value: str) -> bool:
|
|
"""Validate against the username regex."""
|
|
return bool(USERNAME_REGEX.match(value))
|
|
|
|
def _validate_type_password(self, value: str) -> bool:
|
|
"""Validate a password. Max 1024 chars.
|
|
|
|
The valid password length on Discord's client might be different.
|
|
"""
|
|
return 8 <= len(value) <= 1024
|
|
|
|
def _validate_type_email(self, value: str) -> bool:
|
|
"""Validate against the email regex."""
|
|
return bool(EMAIL_REGEX.match(value)) and len(value) < 256
|
|
|
|
def _validate_type_b64_icon(self, value: str) -> bool:
|
|
return bool(DATA_REGEX.match(value))
|
|
|
|
def _validate_type_discriminator(self, value: str) -> bool:
|
|
"""Discriminators are numbers in the API
|
|
that can go from 0 to 9999.
|
|
"""
|
|
try:
|
|
discrim = int(value)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
|
|
return 0 < discrim <= 9999
|
|
|
|
def _validate_type_snowflake(self, value: str) -> bool:
|
|
try:
|
|
int(value)
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
def _validate_type_voice_region(self, value: str) -> bool:
|
|
# NOTE: when this code is being ran, there is a small chance the
|
|
# app context injected by quart still exists
|
|
return value.lower() in app.voice.lvsp.regions.keys()
|
|
|
|
def _validate_type_verification_level(self, value: int) -> bool:
|
|
return _in_enum(VerificationLevel, value)
|
|
|
|
def _validate_type_activity_type(self, value: int) -> bool:
|
|
return value in ActivityType.values()
|
|
|
|
def _validate_type_channel_type(self, value: int) -> bool:
|
|
return value in ChannelType.values()
|
|
|
|
def _validate_type_status_external(self, value: str) -> bool:
|
|
statuses = StatusType.values()
|
|
return value in statuses
|
|
|
|
def _validate_type_explicit(self, value: str) -> bool:
|
|
try:
|
|
val = int(value)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
|
|
return val in ExplicitFilter.values()
|
|
|
|
def _validate_type_rel_type(self, value: str) -> bool:
|
|
try:
|
|
val = int(value)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
|
|
# nobody is allowed to use the INCOMING and OUTGOING rel types
|
|
return val in (RelationshipType.FRIEND.value,
|
|
RelationshipType.BLOCK.value)
|
|
|
|
def _validate_type_msg_notifications(self, value: str):
|
|
try:
|
|
val = int(value)
|
|
except (TypeError, ValueError):
|
|
return False
|
|
|
|
return val in MessageNotifications.values()
|
|
|
|
def _validate_type_guild_name(self, value: str) -> bool:
|
|
return 2 <= len(value) <= 100
|
|
|
|
def _validate_type_role_name(self, value: str) -> bool:
|
|
return 1 <= len(value) <= 100
|
|
|
|
def _validate_type_channel_name(self, value: str) -> bool:
|
|
# for now, we'll use the same validation for guild_name
|
|
return self._validate_type_guild_name(value)
|
|
|
|
def _validate_type_theme(self, value: str) -> bool:
|
|
return value in ['light', 'dark']
|
|
|
|
def _validate_type_nickname(self, value: str) -> bool:
|
|
return isinstance(value, str) and (len(value) < 32)
|
|
|
|
|
|
def validate(reqjson: Union[Dict, List], schema: Dict,
|
|
raise_err: bool = True) -> Dict:
|
|
"""Validate the given user-given data against a schema, giving the
|
|
"correct" version of the document, with all defaults applied.
|
|
|
|
Parameters
|
|
----------
|
|
reqjson:
|
|
The input data
|
|
schema:
|
|
The schema to validate reqjson against
|
|
raise_err:
|
|
If we should raise a BadRequest error when the validation
|
|
fails. Default is true.
|
|
"""
|
|
validator = LitecordValidator(schema)
|
|
|
|
try:
|
|
valid = validator.validate(reqjson)
|
|
except Exception:
|
|
log.exception('Error while validating')
|
|
raise Exception(f'Error while validating: {reqjson}')
|
|
|
|
if not valid:
|
|
errs = validator.errors
|
|
log.warning('Error validating doc {!r}: {!r}', reqjson, errs)
|
|
|
|
if raise_err:
|
|
raise BadRequest('bad payload', errs)
|
|
|
|
return None
|
|
|
|
return validator.document
|
|
|
|
|
|
REGISTER = {
|
|
'username': {'type': 'username', 'required': True},
|
|
'email': {'type': 'email', 'required': False},
|
|
'password': {'type': 'password', 'required': False},
|
|
|
|
# invite stands for a guild invite, not an instance invite (that's on
|
|
# the register_with_invite handler).
|
|
'invite': {'type': 'string', 'required': False, 'nullable': True},
|
|
|
|
# following fields only sent by official client, unused by us
|
|
'fingerprint': {'type': 'string', 'required': False, 'nullable': True},
|
|
'captcha_key': {'type': 'string', 'required': False, 'nullable': True},
|
|
'gift_code_sku_id': {'type': 'string', 'required': False, 'nullable': True},
|
|
'consent': {'type': 'boolean', 'required': False},
|
|
}
|
|
|
|
# only used by us, not discord, hence 'invcode' (to separate from discord)
|
|
REGISTER_WITH_INVITE = {**REGISTER, **{
|
|
'invcode': {'type': 'string', 'required': True}
|
|
}}
|
|
|
|
|
|
USER_UPDATE = {
|
|
'username': {
|
|
'type': 'username', 'minlength': 2,
|
|
'maxlength': 30, 'required': False},
|
|
|
|
'discriminator': {
|
|
'type': 'discriminator',
|
|
'required': False,
|
|
'nullable': True,
|
|
},
|
|
|
|
'password': {
|
|
'type': 'password', 'required': False,
|
|
},
|
|
|
|
'new_password': {
|
|
'type': 'password', 'required': False,
|
|
'dependencies': 'password', 'nullable': True
|
|
},
|
|
|
|
'email': {
|
|
'type': 'email', 'required': False, 'dependencies': 'password',
|
|
},
|
|
|
|
'avatar': {
|
|
# can be both b64_icon or string (just the hash)
|
|
'type': 'string', 'required': False,
|
|
'nullable': True
|
|
},
|
|
|
|
}
|
|
|
|
PARTIAL_ROLE_GUILD_CREATE = {
|
|
'type': 'dict',
|
|
'schema': {
|
|
'name': {'type': 'role_name'},
|
|
'color': {'type': 'number', 'default': 0},
|
|
'hoist': {'type': 'boolean', 'default': False},
|
|
|
|
# NOTE: no position on partial role (on guild create)
|
|
|
|
'permissions': {'coerce': Permissions, 'required': False},
|
|
'mentionable': {'type': 'boolean', 'default': False},
|
|
}
|
|
}
|
|
|
|
PARTIAL_CHANNEL_GUILD_CREATE = {
|
|
'type': 'dict',
|
|
'schema': {
|
|
'name': {'type': 'channel_name'},
|
|
'type': {'type': 'channel_type'},
|
|
}
|
|
}
|
|
|
|
GUILD_CREATE = {
|
|
'name': {'type': 'guild_name'},
|
|
'region': {'type': 'voice_region', 'nullable': True},
|
|
'icon': {'type': 'b64_icon', 'required': False, 'nullable': True},
|
|
|
|
'verification_level': {
|
|
'type': 'verification_level', 'default': 0},
|
|
'default_message_notifications': {
|
|
'type': 'msg_notifications', 'default': 0},
|
|
'explicit_content_filter': {
|
|
'type': 'explicit', 'default': 0},
|
|
|
|
'roles': {
|
|
'type': 'list', 'required': False,
|
|
'schema': PARTIAL_ROLE_GUILD_CREATE},
|
|
'channels': {
|
|
'type': 'list', 'default': [], 'schema': PARTIAL_CHANNEL_GUILD_CREATE},
|
|
}
|
|
|
|
|
|
GUILD_UPDATE = {
|
|
'name': {
|
|
'type': 'guild_name',
|
|
'required': False
|
|
},
|
|
'region': {'type': 'voice_region', 'required': False, 'nullable': True},
|
|
|
|
# all three can have hashes
|
|
'icon': {'type': 'string', 'required': False, 'nullable': True},
|
|
'banner': {'type': 'string', 'required': False, 'nullable': True},
|
|
'splash': {'type': 'string', 'required': False, 'nullable': True},
|
|
|
|
'description': {
|
|
'type': 'string', 'required': False,
|
|
'minlength': 1, 'maxlength': 120,
|
|
'nullable': True
|
|
},
|
|
|
|
'verification_level': {
|
|
'type': 'verification_level', 'required': False},
|
|
'default_message_notifications': {
|
|
'type': 'msg_notifications', 'required': False},
|
|
'explicit_content_filter': {'type': 'explicit', 'required': False},
|
|
|
|
'afk_channel_id': {
|
|
'type': 'snowflake', 'required': False, 'nullable': True},
|
|
'afk_timeout': {'type': 'number', 'required': False},
|
|
|
|
'owner_id': {'type': 'snowflake', 'required': False},
|
|
|
|
'system_channel_id': {
|
|
'type': 'snowflake', 'required': False, 'nullable': True},
|
|
}
|
|
|
|
|
|
CHAN_OVERWRITE = {
|
|
'id': {'coerce': int},
|
|
'type': {'type': 'string', 'allowed': ['role', 'member']},
|
|
'allow': {'coerce': Permissions},
|
|
'deny': {'coerce': Permissions}
|
|
}
|
|
|
|
|
|
CHAN_CREATE = {
|
|
'name': {
|
|
'type': 'string', 'minlength': 2,
|
|
'maxlength': 100, 'required': True
|
|
},
|
|
|
|
'type': {'type': 'channel_type',
|
|
'default': ChannelType.GUILD_TEXT.value},
|
|
|
|
'position': {'coerce': int, 'required': False},
|
|
|
|
'topic': {
|
|
'type': 'string', 'minlength': 0,
|
|
'maxlength': 1024, 'required': False},
|
|
|
|
'nsfw': {'type': 'boolean', 'required': False},
|
|
'rate_limit_per_user': {
|
|
'coerce': int, 'min': 0,
|
|
'max': 120, 'required': False},
|
|
|
|
'bitrate': {
|
|
'coerce': int, 'min': 8000,
|
|
|
|
# NOTE: 'max' is 96000 for non-vip guilds
|
|
'max': 128000, 'required': False},
|
|
|
|
'user_limit': {
|
|
# user_limit being 0 means infinite.
|
|
'coerce': int, 'min': 0,
|
|
'max': 99, 'required': False
|
|
},
|
|
|
|
'permission_overwrites': {
|
|
'type': 'list',
|
|
'schema': {'type': 'dict', 'schema': CHAN_OVERWRITE},
|
|
'required': False
|
|
},
|
|
|
|
'parent_id': {'coerce': int, 'required': False, 'nullable': True}
|
|
}
|
|
|
|
|
|
CHAN_UPDATE = {**CHAN_CREATE, **{
|
|
'name': {
|
|
'type': 'string', 'minlength': 2,
|
|
'maxlength': 100, 'required': False},
|
|
|
|
}}
|
|
|
|
|
|
ROLE_CREATE = {
|
|
'name': {'type': 'string', 'default': 'new role'},
|
|
'permissions': {'coerce': Permissions, 'nullable': True},
|
|
'color': {'coerce': Color, 'default': 0},
|
|
'hoist': {'type': 'boolean', 'default': False},
|
|
'mentionable': {'type': 'boolean', 'default': False},
|
|
}
|
|
|
|
ROLE_UPDATE = {
|
|
'name': {'type': 'string', 'required': False},
|
|
'permissions': {'coerce': Permissions, 'required': False},
|
|
'color': {'coerce': Color, 'required': False},
|
|
'hoist': {'type': 'boolean', 'required': False},
|
|
'mentionable': {'type': 'boolean', 'required': False},
|
|
}
|
|
|
|
|
|
ROLE_UPDATE_POSITION = {
|
|
'roles': {
|
|
'type': 'list',
|
|
'schema': {
|
|
'type': 'dict',
|
|
'schema': {
|
|
'id': {'coerce': int},
|
|
'position': {'coerce': int},
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
MEMBER_UPDATE = {
|
|
'nick': {
|
|
'type': 'nickname', 'required': False},
|
|
'roles': {'type': 'list', 'required': False,
|
|
'schema': {'coerce': int}},
|
|
'mute': {'type': 'boolean', 'required': False},
|
|
'deaf': {'type': 'boolean', 'required': False},
|
|
'channel_id': {'type': 'snowflake', 'required': False},
|
|
}
|
|
|
|
|
|
# NOTE: things such as payload_json are parsed at the handler
|
|
# for creating a message.
|
|
MESSAGE_CREATE = {
|
|
'content': {'type': 'string', 'minlength': 0, 'maxlength': 2000},
|
|
'nonce': {'type': 'snowflake', 'required': False},
|
|
'tts': {'type': 'boolean', 'required': False},
|
|
|
|
'embed': {
|
|
'type': 'dict',
|
|
'schema': EMBED_OBJECT,
|
|
'required': False,
|
|
'nullable': True
|
|
}
|
|
}
|
|
|
|
|
|
GW_ACTIVITY = {
|
|
'name': {'type': 'string', 'required': True},
|
|
'type': {'type': 'activity_type', 'required': True},
|
|
|
|
'url': {'type': 'string', 'required': False, 'nullable': True},
|
|
|
|
'timestamps': {
|
|
'type': 'dict',
|
|
'required': False,
|
|
'schema': {
|
|
'start': {'type': 'number', 'required': False},
|
|
'end': {'type': 'number', 'required': False},
|
|
},
|
|
},
|
|
|
|
'application_id': {'type': 'snowflake', 'required': False,
|
|
'nullable': False},
|
|
'details': {'type': 'string', 'required': False, 'nullable': True},
|
|
'state': {'type': 'string', 'required': False, 'nullable': True},
|
|
|
|
'party': {
|
|
'type': 'dict',
|
|
'required': False,
|
|
'schema': {
|
|
'id': {'type': 'snowflake', 'required': False},
|
|
'size': {'type': 'list', 'required': False},
|
|
}
|
|
},
|
|
|
|
'assets': {
|
|
'type': 'dict',
|
|
'required': False,
|
|
'schema': {
|
|
'large_image': {'type': 'snowflake', 'required': False},
|
|
'large_text': {'type': 'string', 'required': False},
|
|
'small_image': {'type': 'snowflake', 'required': False},
|
|
'small_text': {'type': 'string', 'required': False},
|
|
}
|
|
},
|
|
|
|
'secrets': {
|
|
'type': 'dict',
|
|
'required': False,
|
|
'schema': {
|
|
'join': {'type': 'string', 'required': False},
|
|
'spectate': {'type': 'string', 'required': False},
|
|
'match': {'type': 'string', 'required': False},
|
|
}
|
|
},
|
|
|
|
'instance': {'type': 'boolean', 'required': False},
|
|
'flags': {'type': 'number', 'required': False},
|
|
}
|
|
|
|
GW_STATUS_UPDATE = {
|
|
'status': {'type': 'status_external', 'required': False,
|
|
'default': 'online'},
|
|
'activities': {
|
|
'type': 'list', 'required': False,
|
|
'schema': {'type': 'dict', 'schema': GW_ACTIVITY}
|
|
},
|
|
'afk': {'type': 'boolean', 'required': False},
|
|
|
|
'since': {'type': 'number', 'required': False, 'nullable': True},
|
|
'game': {
|
|
'type': 'dict',
|
|
'required': False,
|
|
'nullable': True,
|
|
'schema': GW_ACTIVITY,
|
|
},
|
|
}
|
|
|
|
INVITE = {
|
|
# max_age in seconds
|
|
# 0 for infinite
|
|
'max_age': {
|
|
'type': 'number',
|
|
'min': 0,
|
|
'max': 86400,
|
|
|
|
# a day
|
|
'default': 86400
|
|
},
|
|
|
|
# max invite uses
|
|
'max_uses': {
|
|
'type': 'number',
|
|
'min': 0,
|
|
|
|
# idk
|
|
'max': 1000,
|
|
|
|
# default infinite
|
|
'default': 0
|
|
},
|
|
|
|
'temporary': {'type': 'boolean', 'required': False, 'default': False},
|
|
'unique': {'type': 'boolean', 'required': False, 'default': True},
|
|
'validate': {'type': 'string', 'required': False, 'nullable': True} # discord client sends invite code there
|
|
}
|
|
|
|
USER_SETTINGS = {
|
|
'afk_timeout': {
|
|
'type': 'number', 'required': False, 'min': 0, 'max': 3000},
|
|
|
|
'animate_emoji': {'type': 'boolean', 'required': False},
|
|
'convert_emoticons': {'type': 'boolean', 'required': False},
|
|
'default_guilds_restricted': {'type': 'boolean', 'required': False},
|
|
'detect_platform_accounts': {'type': 'boolean', 'required': False},
|
|
'developer_mode': {'type': 'boolean', 'required': False},
|
|
'disable_games_tab': {'type': 'boolean', 'required': False},
|
|
'enable_tts_command': {'type': 'boolean', 'required': False},
|
|
|
|
'explicit_content_filter': {'type': 'explicit', 'required': False},
|
|
|
|
'friend_source': {
|
|
'type': 'dict',
|
|
'required': False,
|
|
'schema': {
|
|
'all': {'type': 'boolean', 'required': False},
|
|
'mutual_guilds': {'type': 'boolean', 'required': False},
|
|
'mutual_friends': {'type': 'boolean', 'required': False},
|
|
}
|
|
},
|
|
'guild_positions': {
|
|
'type': 'list',
|
|
'required': False,
|
|
'schema': {'type': 'snowflake'}
|
|
},
|
|
'restricted_guilds': {
|
|
'type': 'list',
|
|
'required': False,
|
|
'schema': {'type': 'snowflake'}
|
|
},
|
|
|
|
'gif_auto_play': {'type': 'boolean', 'required': False},
|
|
'inline_attachment_media': {'type': 'boolean', 'required': False},
|
|
'inline_embed_media': {'type': 'boolean', 'required': False},
|
|
'message_display_compact': {'type': 'boolean', 'required': False},
|
|
'render_embeds': {'type': 'boolean', 'required': False},
|
|
'render_reactions': {'type': 'boolean', 'required': False},
|
|
'show_current_game': {'type': 'boolean', 'required': False},
|
|
|
|
'timezone_offset': {'type': 'number', 'required': False},
|
|
|
|
'status': {'type': 'status_external', 'required': False},
|
|
'theme': {'type': 'theme', 'required': False}
|
|
}
|
|
|
|
RELATIONSHIP = {
|
|
'type': {
|
|
'type': 'rel_type',
|
|
'required': False,
|
|
'default': RelationshipType.FRIEND.value
|
|
}
|
|
}
|
|
|
|
CREATE_DM = {
|
|
'recipient_id': {
|
|
'type': 'snowflake',
|
|
'required': True
|
|
}
|
|
}
|
|
|
|
CREATE_GROUP_DM = {
|
|
'recipients': {
|
|
'type': 'list',
|
|
'required': True,
|
|
'schema': {'type': 'snowflake'}
|
|
},
|
|
}
|
|
|
|
GROUP_DM_UPDATE = {
|
|
'name': {
|
|
'type': 'guild_name',
|
|
'required': False
|
|
},
|
|
'icon': {'type': 'b64_icon', 'required': False, 'nullable': True},
|
|
}
|
|
|
|
SPECIFIC_FRIEND = {
|
|
'username': {'type': 'username'},
|
|
'discriminator': {'type': 'discriminator'}
|
|
}
|
|
|
|
GUILD_SETTINGS_CHAN_OVERRIDE = {
|
|
'type': 'dict',
|
|
'schema': {
|
|
'muted': {
|
|
'type': 'boolean', 'required': False},
|
|
'message_notifications': {
|
|
'type': 'msg_notifications',
|
|
'required': False,
|
|
}
|
|
}
|
|
}
|
|
|
|
GUILD_SETTINGS = {
|
|
'channel_overrides': {
|
|
'type': 'dict',
|
|
'valueschema': GUILD_SETTINGS_CHAN_OVERRIDE,
|
|
'keyschema': {'type': 'snowflake'},
|
|
'required': False,
|
|
},
|
|
'suppress_everyone': {
|
|
'type': 'boolean', 'required': False},
|
|
'muted': {
|
|
'type': 'boolean', 'required': False},
|
|
'mobile_push': {
|
|
'type': 'boolean', 'required': False},
|
|
'message_notifications': {
|
|
'type': 'msg_notifications',
|
|
'required': False,
|
|
}
|
|
}
|
|
|
|
GUILD_PRUNE = {
|
|
'days': {'type': 'number', 'coerce': int, 'min': 1, 'max': 30, 'default': 7},
|
|
'compute_prune_count': {'type': 'string', 'default': 'true'}
|
|
}
|
|
|
|
NEW_EMOJI = {
|
|
'name': {
|
|
'type': 'string', 'minlength': 1, 'maxlength': 256, 'required': True},
|
|
'image': {'type': 'b64_icon', 'required': True},
|
|
'roles': {'type': 'list', 'schema': {'coerce': int}}
|
|
}
|
|
|
|
PATCH_EMOJI = {
|
|
'name': {
|
|
'type': 'string', 'minlength': 1, 'maxlength': 256, 'required': True},
|
|
'roles': {'type': 'list', 'schema': {'coerce': int}}
|
|
}
|
|
|
|
|
|
SEARCH_CHANNEL = {
|
|
'content': {'type': 'string', 'minlength': 1, 'required': True},
|
|
'include_nsfw': {'coerce': bool, 'default': False},
|
|
'offset': {'coerce': int, 'default': 0}
|
|
}
|
|
|
|
|
|
GET_MENTIONS = {
|
|
'limit': {'coerce': int, 'default': 25},
|
|
'roles': {'coerce': bool, 'default': True},
|
|
'everyone': {'coerce': bool, 'default': True},
|
|
'guild_id': {'coerce': int, 'required': False}
|
|
}
|
|
|
|
|
|
VANITY_URL_PATCH = {
|
|
# TODO: put proper values in maybe an invite data type
|
|
'code': {'type': 'string', 'minlength': 5, 'maxlength': 30}
|
|
}
|
|
|
|
WEBHOOK_CREATE = {
|
|
'name': {
|
|
'type': 'string', 'minlength': 2, 'maxlength': 32,
|
|
'required': True
|
|
},
|
|
'avatar': {'type': 'b64_icon', 'required': False, 'nullable': False}
|
|
}
|
|
|
|
WEBHOOK_UPDATE = {
|
|
'name': {
|
|
'type': 'string', 'minlength': 2, 'maxlength': 32,
|
|
'required': False
|
|
},
|
|
|
|
# TODO: check if its b64_icon or string since the client
|
|
# could pass an icon hash instead.
|
|
'avatar': {'type': 'b64_icon', 'required': False, 'nullable': False},
|
|
'channel_id': {'coerce': int, 'required': False, 'nullable': False}
|
|
}
|
|
|
|
WEBHOOK_MESSAGE_CREATE = {
|
|
'content': {
|
|
'type': 'string',
|
|
'minlength': 0, 'maxlength': 2000, 'required': False
|
|
},
|
|
'tts': {'type': 'boolean', 'required': False},
|
|
|
|
'username': {
|
|
'type': 'string',
|
|
'minlength': 2, 'maxlength': 32, 'required': False
|
|
},
|
|
|
|
'avatar_url': {
|
|
'coerce': EmbedURL, 'required': False
|
|
},
|
|
|
|
'embeds': {
|
|
'type': 'list',
|
|
'required': False,
|
|
'schema': {'type': 'dict', 'schema': EMBED_OBJECT}
|
|
}
|
|
}
|
|
|
|
BULK_DELETE = {
|
|
'messages': {
|
|
'type': 'list', 'required': True,
|
|
'minlength': 2, 'maxlength': 100,
|
|
'schema': {'coerce': int}
|
|
}
|
|
}
|