mirror of https://gitlab.com/litecord/litecord.git
blueprints.guilds: add auto-role and auto-channel creation
also simplify a lot of repeated code on the blueprint.
- litecord: add permissions module
for future role code
- schemas: add channel_type, guild_name, channel_name types
- schemas: add GUILD_CREATE schema
This commit is contained in:
parent
75a8e77a21
commit
aaa11be258
|
|
@ -9,6 +9,7 @@ from .channels import channel_ack
|
||||||
from .checks import guild_check
|
from .checks import guild_check
|
||||||
|
|
||||||
bp = Blueprint('guilds', __name__)
|
bp = Blueprint('guilds', __name__)
|
||||||
|
DEFAULT_EVERYONE_PERMS = 104324161
|
||||||
|
|
||||||
|
|
||||||
async def guild_owner_check(user_id: int, guild_id: int):
|
async def guild_owner_check(user_id: int, guild_id: int):
|
||||||
|
|
@ -48,8 +49,116 @@ async def create_guild_settings(guild_id: int, user_id: int):
|
||||||
""", m_notifs, user_id, guild_id)
|
""", m_notifs, user_id, guild_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def add_member(guild_id: int, user_id: int):
|
||||||
|
"""Add a user to a guild."""
|
||||||
|
await app.db.execute("""
|
||||||
|
INSERT INTO members (user_id, guild_id)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
""", user_id, guild_id)
|
||||||
|
|
||||||
|
await create_guild_settings(guild_id, user_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def guild_create_roles_prep(guild_id: int, roles: list):
|
||||||
|
"""Create roles in preparation in guild create."""
|
||||||
|
# by reaching this point in the code that means
|
||||||
|
# roles is not nullable, which means
|
||||||
|
# roles has at least one element, so we can access safely.
|
||||||
|
|
||||||
|
# the first member in the roles array
|
||||||
|
# are patches to the @everyone role
|
||||||
|
everyone_patches = roles[0]
|
||||||
|
for field in everyone_patches:
|
||||||
|
await app.db.execute(f"""
|
||||||
|
UPDATE roles
|
||||||
|
SET {field}={everyone_patches[field]}
|
||||||
|
WHERE roles.id = $1
|
||||||
|
""", guild_id)
|
||||||
|
|
||||||
|
default_perms = (everyone_patches.get('permissions')
|
||||||
|
or DEFAULT_EVERYONE_PERMS)
|
||||||
|
|
||||||
|
# from the 2nd and forward,
|
||||||
|
# should be treated as new roles
|
||||||
|
for role in roles[1:]:
|
||||||
|
new_role_id = get_snowflake()
|
||||||
|
|
||||||
|
await app.db.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO roles (id, guild_id, name, color,
|
||||||
|
hoist, position, permissions, managed, mentionable)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||||
|
""",
|
||||||
|
new_role_id,
|
||||||
|
guild_id,
|
||||||
|
role['name'],
|
||||||
|
role.get('color', 0),
|
||||||
|
role.get('hoist', False),
|
||||||
|
role.get('permissions', default_perms),
|
||||||
|
False,
|
||||||
|
role.get('mentionable', False)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def _specific_chan_create(channel_id, ctype, **kwargs):
|
||||||
|
if ctype == ChannelType.GUILD_TEXT:
|
||||||
|
await app.db.execute("""
|
||||||
|
INSERT INTO guild_text_channels (id, topic)
|
||||||
|
VALUES ($1)
|
||||||
|
""", channel_id, kwargs.get('topic', ''))
|
||||||
|
elif ctype == ChannelType.GUILD_VOICE:
|
||||||
|
await app.db.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO guild_voice_channels (id, bitrate, user_limit)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
""",
|
||||||
|
channel_id,
|
||||||
|
kwargs.get('bitrate', 64),
|
||||||
|
kwargs.get('user_limit', 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def create_guild_channel(guild_id: int, channel_id: int,
|
||||||
|
ctype: ChannelType, **kwargs):
|
||||||
|
"""Create a channel in a guild."""
|
||||||
|
await app.db.execute("""
|
||||||
|
INSERT INTO channels (id, channel_type)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
""", channel_id, ctype.value)
|
||||||
|
|
||||||
|
# calc new pos
|
||||||
|
max_pos = await app.db.fetchval("""
|
||||||
|
SELECT MAX(position)
|
||||||
|
FROM guild_channels
|
||||||
|
WHERE guild_id = $1
|
||||||
|
""", guild_id)
|
||||||
|
|
||||||
|
# all channels go to guild_channels
|
||||||
|
await app.db.execute("""
|
||||||
|
INSERT INTO guild_channels (id, guild_id, name, position)
|
||||||
|
VALUES ($1, $2, $3, $4)
|
||||||
|
""", channel_id, guild_id, kwargs['name'], max_pos + 1)
|
||||||
|
|
||||||
|
# the rest of sql magic is dependant on the channel
|
||||||
|
# we're creating (a text or voice or category),
|
||||||
|
# so we use this function.
|
||||||
|
await _specific_chan_create(channel_id, ctype, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
async def guild_create_channels_prep(guild_id: int, channels: list):
|
||||||
|
"""Create channels pre-guild create"""
|
||||||
|
for channel_raw in channels:
|
||||||
|
channel_id = get_snowflake()
|
||||||
|
ctype = ChannelType(channel_raw['type'])
|
||||||
|
|
||||||
|
await create_guild_channel(guild_id, channel_id, ctype)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('', methods=['POST'])
|
@bp.route('', methods=['POST'])
|
||||||
async def create_guild():
|
async def create_guild():
|
||||||
|
"""Create a new guild, assigning
|
||||||
|
the user creating it as the owner and
|
||||||
|
making them join."""
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
j = await request.get_json()
|
j = await request.get_json()
|
||||||
|
|
||||||
|
|
@ -66,36 +175,27 @@ async def create_guild():
|
||||||
j.get('default_message_notifications', 0),
|
j.get('default_message_notifications', 0),
|
||||||
j.get('explicit_content_filter', 0))
|
j.get('explicit_content_filter', 0))
|
||||||
|
|
||||||
await app.db.execute("""
|
await add_member(guild_id, user_id)
|
||||||
INSERT INTO members (user_id, guild_id)
|
|
||||||
VALUES ($1, $2)
|
|
||||||
""", user_id, guild_id)
|
|
||||||
|
|
||||||
await create_guild_settings(guild_id, user_id)
|
|
||||||
|
|
||||||
|
# create the default @everyone role (everyone has it by default,
|
||||||
|
# so we don't insert that in the table)
|
||||||
await app.db.execute("""
|
await app.db.execute("""
|
||||||
INSERT INTO roles (id, guild_id, name, position, permissions)
|
INSERT INTO roles (id, guild_id, name, position, permissions)
|
||||||
VALUES ($1, $2, $3, $4, $5)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
""", guild_id, guild_id, '@everyone', 0, 104324161)
|
""", guild_id, guild_id, '@everyone', 0, DEFAULT_EVERYONE_PERMS)
|
||||||
|
|
||||||
|
# create a single #general channel.
|
||||||
general_id = get_snowflake()
|
general_id = get_snowflake()
|
||||||
|
|
||||||
await app.db.execute("""
|
await create_guild_channel(
|
||||||
INSERT INTO channels (id, channel_type)
|
guild_id, general_id, ChannelType.GUILD_TEXT,
|
||||||
VALUES ($1, $2)
|
name='general')
|
||||||
""", general_id, ChannelType.GUILD_TEXT.value)
|
|
||||||
|
|
||||||
await app.db.execute("""
|
if j.get('roles'):
|
||||||
INSERT INTO guild_channels (id, guild_id, name, position)
|
await guild_create_roles_prep(guild_id, j['roles'])
|
||||||
VALUES ($1, $2, $3, $4)
|
|
||||||
""", general_id, guild_id, 'general', 0)
|
|
||||||
|
|
||||||
await app.db.execute("""
|
if j.get('channels'):
|
||||||
INSERT INTO guild_text_channels (id)
|
await guild_create_channels_prep(guild_id, j['channels'])
|
||||||
VALUES ($1)
|
|
||||||
""", general_id)
|
|
||||||
|
|
||||||
# TODO: j['roles'] and j['channels']
|
|
||||||
|
|
||||||
guild_total = await app.storage.get_guild_full(guild_id, user_id, 250)
|
guild_total = await app.storage.get_guild_full(guild_id, user_id, 250)
|
||||||
|
|
||||||
|
|
@ -106,12 +206,13 @@ async def create_guild():
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>', methods=['GET'])
|
@bp.route('/<int:guild_id>', methods=['GET'])
|
||||||
async def get_guild(guild_id):
|
async def get_guild(guild_id):
|
||||||
|
"""Get a single guilds' information."""
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
gj = await app.storage.get_guild(guild_id, user_id)
|
return jsonify(
|
||||||
gj_extra = await app.storage.get_guild_extra(guild_id, user_id, 250)
|
await app.storage.get_guild_full(guild_id, user_id, 250)
|
||||||
|
)
|
||||||
return jsonify({**gj, **gj_extra})
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>', methods=['UPDATE'])
|
@bp.route('/<int:guild_id>', methods=['UPDATE'])
|
||||||
|
|
@ -139,8 +240,6 @@ async def update_guild(guild_id):
|
||||||
""", j['name'], guild_id)
|
""", j['name'], guild_id)
|
||||||
|
|
||||||
if 'region' in j:
|
if 'region' in j:
|
||||||
# TODO: check region value
|
|
||||||
|
|
||||||
await app.db.execute("""
|
await app.db.execute("""
|
||||||
UPDATE guilds
|
UPDATE guilds
|
||||||
SET region = $1
|
SET region = $1
|
||||||
|
|
@ -167,15 +266,14 @@ async def update_guild(guild_id):
|
||||||
WHERE guild_id = $2
|
WHERE guild_id = $2
|
||||||
""", j[field], guild_id)
|
""", j[field], guild_id)
|
||||||
|
|
||||||
# return guild object
|
guild = await app.storage.get_guild_full(
|
||||||
gj = await app.storage.get_guild(guild_id, user_id)
|
guild_id, user_id
|
||||||
gj_extra = await app.storage.get_guild_extra(guild_id, user_id, 250)
|
)
|
||||||
|
|
||||||
gj_total = {**gj, **gj_extra}
|
await app.dispatcher.dispatch_guild(
|
||||||
|
guild_id, 'GUILD_UPDATE', guild)
|
||||||
|
|
||||||
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_UPDATE', gj_total)
|
return jsonify(guild)
|
||||||
|
|
||||||
return jsonify({**gj, **gj_extra})
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>', methods=['DELETE'])
|
@bp.route('/<int:guild_id>', methods=['DELETE'])
|
||||||
|
|
@ -185,7 +283,7 @@ async def delete_guild(guild_id):
|
||||||
await guild_owner_check(user_id, guild_id)
|
await guild_owner_check(user_id, guild_id)
|
||||||
|
|
||||||
await app.db.execute("""
|
await app.db.execute("""
|
||||||
DELETE FROM guild
|
DELETE FROM guilds
|
||||||
WHERE guilds.id = $1
|
WHERE guilds.id = $1
|
||||||
""", guild_id)
|
""", guild_id)
|
||||||
|
|
||||||
|
|
@ -219,42 +317,19 @@ async def create_channel(guild_id):
|
||||||
# TODO: check permissions for MANAGE_CHANNELS
|
# TODO: check permissions for MANAGE_CHANNELS
|
||||||
await guild_check(user_id, guild_id)
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
new_channel_id = get_snowflake()
|
|
||||||
channel_type = j.get('type', ChannelType.GUILD_TEXT)
|
channel_type = j.get('type', ChannelType.GUILD_TEXT)
|
||||||
|
|
||||||
channel_type = ChannelType(channel_type)
|
channel_type = ChannelType(channel_type)
|
||||||
|
|
||||||
if channel_type not in (ChannelType.GUILD_TEXT,
|
if channel_type not in (ChannelType.GUILD_TEXT,
|
||||||
ChannelType.GUILD_VOICE):
|
ChannelType.GUILD_VOICE):
|
||||||
raise BadRequest('Invalid channel type')
|
raise BadRequest('Invalid channel type')
|
||||||
|
|
||||||
await app.db.execute("""
|
new_channel_id = get_snowflake()
|
||||||
INSERT INTO channels (id, channel_type)
|
await create_guild_channel(guild_id, new_channel_id, channel_type,)
|
||||||
VALUES ($1, $2)
|
|
||||||
""", new_channel_id, channel_type.value)
|
|
||||||
|
|
||||||
max_pos = await app.db.fetchval("""
|
|
||||||
SELECT MAX(position)
|
|
||||||
FROM guild_channels
|
|
||||||
WHERE guild_id = $1
|
|
||||||
""", guild_id)
|
|
||||||
|
|
||||||
if channel_type == ChannelType.GUILD_TEXT:
|
|
||||||
await app.db.execute("""
|
|
||||||
INSERT INTO guild_channels (id, guild_id, name, position)
|
|
||||||
VALUES ($1, $2, $3, $4)
|
|
||||||
""", new_channel_id, guild_id, j['name'], max_pos + 1)
|
|
||||||
|
|
||||||
await app.db.execute("""
|
|
||||||
INSERT INTO guild_text_channels (id)
|
|
||||||
VALUES ($1)
|
|
||||||
""", new_channel_id)
|
|
||||||
|
|
||||||
elif channel_type == ChannelType.GUILD_VOICE:
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
chan = await app.storage.get_channel(new_channel_id)
|
chan = await app.storage.get_channel(new_channel_id)
|
||||||
await app.dispatcher.dispatch_guild(guild_id, 'CHANNEL_CREATE', chan)
|
await app.dispatcher.dispatch_guild(
|
||||||
|
guild_id, 'CHANNEL_CREATE', chan)
|
||||||
return jsonify(chan)
|
return jsonify(chan)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -271,15 +346,16 @@ async def modify_channel_pos(guild_id):
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/members/<int:member_id>', methods=['GET'])
|
@bp.route('/<int:guild_id>/members/<int:member_id>', methods=['GET'])
|
||||||
async def get_guild_member(guild_id, member_id):
|
async def get_guild_member(guild_id, member_id):
|
||||||
|
"""Get a member's information in a guild."""
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
await guild_check(user_id, guild_id)
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
member = await app.storage.get_single_member(guild_id, member_id)
|
member = await app.storage.get_single_member(guild_id, member_id)
|
||||||
return jsonify(member)
|
return jsonify(member)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/members', methods=['GET'])
|
@bp.route('/<int:guild_id>/members', methods=['GET'])
|
||||||
async def get_members(guild_id):
|
async def get_members(guild_id):
|
||||||
|
"""Get members inside a guild."""
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
await guild_check(user_id, guild_id)
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
|
|
@ -304,6 +380,7 @@ async def get_members(guild_id):
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/members/<int:member_id>', methods=['PATCH'])
|
@bp.route('/<int:guild_id>/members/<int:member_id>', methods=['PATCH'])
|
||||||
async def modify_guild_member(guild_id, member_id):
|
async def modify_guild_member(guild_id, member_id):
|
||||||
|
"""Modify a members' information in a guild."""
|
||||||
j = await request.get_json()
|
j = await request.get_json()
|
||||||
|
|
||||||
if 'nick' in j:
|
if 'nick' in j:
|
||||||
|
|
@ -350,6 +427,7 @@ async def modify_guild_member(guild_id, member_id):
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/members/@me/nick', methods=['PATCH'])
|
@bp.route('/<int:guild_id>/members/@me/nick', methods=['PATCH'])
|
||||||
async def update_nickname(guild_id):
|
async def update_nickname(guild_id):
|
||||||
|
"""Update a member's nickname in a guild."""
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
await guild_check(user_id, guild_id)
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
|
|
@ -371,28 +449,36 @@ async def update_nickname(guild_id):
|
||||||
return j['nick']
|
return j['nick']
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/members/<int:member_id>', methods=['DELETE'])
|
async def remove_member(guild_id: int, member_id: int):
|
||||||
async def kick_member(guild_id, member_id):
|
"""Do common tasks related to deleting a member from the guild,
|
||||||
user_id = await token_check()
|
such as dispatching GUILD_DELETE and GUILD_MEMBER_REMOVE."""
|
||||||
|
|
||||||
# TODO: check KICK_MEMBERS permission
|
|
||||||
await guild_owner_check(user_id, guild_id)
|
|
||||||
|
|
||||||
await app.db.execute("""
|
await app.db.execute("""
|
||||||
DELETE FROM members
|
DELETE FROM members
|
||||||
WHERE guild_id = $1 AND user_id = $2
|
WHERE guild_id = $1 AND user_id = $2
|
||||||
""", guild_id, member_id)
|
""", guild_id, member_id)
|
||||||
|
|
||||||
await app.dispatcher.dispatch_user(user_id, 'GUILD_DELETE', {
|
await app.dispatcher.dispatch_user(member_id, 'GUILD_DELETE', {
|
||||||
'guild_id': guild_id,
|
'guild_id': guild_id,
|
||||||
'unavailable': False,
|
'unavailable': False,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await app.dispatcher.unsub('guild', guild_id, member_id)
|
||||||
|
|
||||||
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_REMOVE', {
|
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_REMOVE', {
|
||||||
'guild': guild_id,
|
'guild': guild_id,
|
||||||
'user': await app.storage.get_user(member_id),
|
'user': await app.storage.get_user(member_id),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:guild_id>/members/<int:member_id>', methods=['DELETE'])
|
||||||
|
async def kick_member(guild_id, member_id):
|
||||||
|
"""Remove a member from a guild."""
|
||||||
|
user_id = await token_check()
|
||||||
|
|
||||||
|
# TODO: check KICK_MEMBERS permission
|
||||||
|
await guild_owner_check(user_id, guild_id)
|
||||||
|
await remove_member(guild_id, member_id)
|
||||||
return '', 204
|
return '', 204
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -434,22 +520,7 @@ async def create_ban(guild_id, member_id):
|
||||||
VALUES ($1, $2, $3)
|
VALUES ($1, $2, $3)
|
||||||
""", guild_id, member_id, j.get('reason', ''))
|
""", guild_id, member_id, j.get('reason', ''))
|
||||||
|
|
||||||
await app.db.execute("""
|
await remove_member(guild_id, member_id)
|
||||||
DELETE FROM members
|
|
||||||
WHERE guild_id = $1 AND user_id = $2
|
|
||||||
""", guild_id, user_id)
|
|
||||||
|
|
||||||
await app.dispatcher.dispatch_user(member_id, 'GUILD_DELETE', {
|
|
||||||
'guild_id': guild_id,
|
|
||||||
'unavailable': False,
|
|
||||||
})
|
|
||||||
|
|
||||||
await app.dispatcher.unsub('guild', guild_id, member_id)
|
|
||||||
|
|
||||||
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_MEMBER_REMOVE', {
|
|
||||||
'guild': guild_id,
|
|
||||||
'user': await app.storage.get_user(member_id),
|
|
||||||
})
|
|
||||||
|
|
||||||
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_BAN_ADD', {**{
|
await app.dispatcher.dispatch_guild(guild_id, 'GUILD_BAN_ADD', {**{
|
||||||
'guild': guild_id,
|
'guild': guild_id,
|
||||||
|
|
@ -460,6 +531,10 @@ async def create_ban(guild_id, member_id):
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/messages/search')
|
@bp.route('/<int:guild_id>/messages/search')
|
||||||
async def search_messages(guild_id):
|
async def search_messages(guild_id):
|
||||||
|
"""Search messages in a guild.
|
||||||
|
|
||||||
|
This is an undocumented route.
|
||||||
|
"""
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
await guild_check(user_id, guild_id)
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
|
|
@ -474,6 +549,7 @@ async def search_messages(guild_id):
|
||||||
|
|
||||||
@bp.route('/<int:guild_id>/ack', methods=['POST'])
|
@bp.route('/<int:guild_id>/ack', methods=['POST'])
|
||||||
async def ack_guild(guild_id):
|
async def ack_guild(guild_id):
|
||||||
|
"""ACKnowledge all messages in the guild."""
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
await guild_check(user_id, guild_id)
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
# so we don't keep repeating the same
|
||||||
|
# type for all the fields
|
||||||
|
_i = ctypes.c_uint8
|
||||||
|
|
||||||
|
class _RawPermsBits(ctypes.LittleEndianStructure):
|
||||||
|
"""raw bitfield for discord's permission number."""
|
||||||
|
_fields_ = [
|
||||||
|
('create_invites', _i, 1),
|
||||||
|
('kick_members', _i, 1),
|
||||||
|
('ban_members', _i, 1),
|
||||||
|
('administrator', _i, 1),
|
||||||
|
('manage_channels', _i, 1),
|
||||||
|
('manage_guild', _i, 1),
|
||||||
|
('add_reactions', _i, 1),
|
||||||
|
('view_audit_log', _i, 1),
|
||||||
|
('priority_speaker', _i, 1),
|
||||||
|
('_unused1', _i, 1),
|
||||||
|
('read_messages', _i, 1),
|
||||||
|
('send_messages', _i, 1),
|
||||||
|
('send_tts', _i, 1),
|
||||||
|
('manage_messages', _i, 1),
|
||||||
|
('embed_links', _i, 1),
|
||||||
|
('attach_files', _i, 1),
|
||||||
|
('read_history', _i, 1),
|
||||||
|
('mention_everyone', _i, 1),
|
||||||
|
('external_emojis', _i, 1),
|
||||||
|
('_unused2', _i, 1),
|
||||||
|
('connect', _i, 1),
|
||||||
|
('speak', _i, 1),
|
||||||
|
('mute_members', _i, 1),
|
||||||
|
('deafen_members', _i, 1),
|
||||||
|
('move_members', _i, 1),
|
||||||
|
('use_voice_activation', _i, 1),
|
||||||
|
('change_nickname', _i, 1),
|
||||||
|
('manage_nicknames', _i, 1),
|
||||||
|
('manage_roles', _i, 1),
|
||||||
|
('manage_webhooks', _i, 1),
|
||||||
|
('manage_emojis', _i, 1),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Permissions(ctypes.Union):
|
||||||
|
_fields_ = [
|
||||||
|
('bits', _RawPermsBits),
|
||||||
|
('binary', ctypes.c_uint64),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, val: int):
|
||||||
|
self.binary = val
|
||||||
|
|
||||||
|
def numby(self):
|
||||||
|
return self.binary
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import re
|
import re
|
||||||
|
from typing import Union, Dict, List, Any
|
||||||
|
|
||||||
from cerberus import Validator
|
from cerberus import Validator
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
|
|
||||||
from .errors import BadRequest
|
from .errors import BadRequest
|
||||||
|
from .permissions import Permissions
|
||||||
from .enums import ActivityType, StatusType, ExplicitFilter, \
|
from .enums import ActivityType, StatusType, ExplicitFilter, \
|
||||||
RelationshipType, MessageNotifications
|
RelationshipType, MessageNotifications, ChannelType
|
||||||
|
|
||||||
|
|
||||||
log = Logger(__name__)
|
log = Logger(__name__)
|
||||||
|
|
@ -61,6 +63,9 @@ class LitecordValidator(Validator):
|
||||||
def _validate_type_activity_type(self, value: int) -> bool:
|
def _validate_type_activity_type(self, value: int) -> bool:
|
||||||
return value in ActivityType.values()
|
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:
|
def _validate_type_status_external(self, value: str) -> bool:
|
||||||
statuses = StatusType.values()
|
statuses = StatusType.values()
|
||||||
|
|
||||||
|
|
@ -94,8 +99,19 @@ class LitecordValidator(Validator):
|
||||||
|
|
||||||
return val in MessageNotifications.values()
|
return val in MessageNotifications.values()
|
||||||
|
|
||||||
|
def _validate_type_guild_name(self, value: str) -> bool:
|
||||||
|
return 2 <= len(value) <= 100
|
||||||
|
|
||||||
def validate(reqjson, schema, raise_err: bool = True):
|
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(reqjson: Union[Dict, List], schema: Dict,
|
||||||
|
raise_err: bool = True) -> Union[Dict, List]:
|
||||||
|
"""Validate a given document (user-input) and give
|
||||||
|
the correct document as a result.
|
||||||
|
"""
|
||||||
validator = LitecordValidator(schema)
|
validator = LitecordValidator(schema)
|
||||||
|
|
||||||
if not validator.validate(reqjson):
|
if not validator.validate(reqjson):
|
||||||
|
|
@ -146,12 +162,44 @@ USER_UPDATE = {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PARTIAL_ROLE_GUILD_CREATE = {
|
||||||
|
'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 = {
|
||||||
|
'name': {'type': 'channel_name'},
|
||||||
|
'type': {'type': 'channel_type'}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILD_CREATE = {
|
||||||
|
'name': {'type': 'guild_name'},
|
||||||
|
'region': {'type': 'voice_region'},
|
||||||
|
'icon': {'type': '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 = {
|
GUILD_UPDATE = {
|
||||||
'name': {
|
'name': {
|
||||||
'type': 'string',
|
'type': 'guild_name',
|
||||||
'minlength': 2,
|
|
||||||
'maxlength': 100,
|
|
||||||
'required': False
|
'required': False
|
||||||
},
|
},
|
||||||
'region': {'type': 'voice_region', 'required': False},
|
'region': {'type': 'voice_region', 'required': False},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue