mirror of https://gitlab.com/litecord/litecord.git
make other blueprints use common, etc
This commit is contained in:
parent
1efc65511c
commit
a67b6580ba
|
|
@ -22,7 +22,7 @@ from quart import Blueprint, jsonify, current_app as app, request
|
|||
from litecord.auth import admin_check
|
||||
from litecord.schemas import validate
|
||||
from litecord.admin_schemas import GUILD_UPDATE
|
||||
from litecord.blueprints.guilds import delete_guild
|
||||
from litecord.common.guilds import delete_guild
|
||||
from litecord.errors import GuildNotFound
|
||||
|
||||
bp = Blueprint("guilds_admin", __name__)
|
||||
|
|
|
|||
|
|
@ -23,10 +23,9 @@ from quart import Blueprint, request, current_app as app, jsonify
|
|||
from logbook import Logger
|
||||
|
||||
|
||||
from litecord.utils import async_map
|
||||
from litecord.utils import async_map, query_tuple_from_args, extract_limit
|
||||
from litecord.blueprints.auth import token_check
|
||||
from litecord.blueprints.checks import channel_check, channel_perm_check
|
||||
from litecord.blueprints.channel.messages import query_tuple_from_args, extract_limit
|
||||
|
||||
from litecord.enums import GUILD_CHANS
|
||||
|
||||
|
|
@ -165,7 +164,8 @@ def _emoji_sql_simple(emoji: str, param=4):
|
|||
return emoji_sql(emoji_type, emoji_id, emoji_name, param)
|
||||
|
||||
|
||||
async def remove_reaction(channel_id: int, message_id: int, user_id: int, emoji: str):
|
||||
async def _remove_reaction(channel_id: int, message_id: int, user_id: int, emoji: str):
|
||||
"""Remove given reaction from a message."""
|
||||
ctype, guild_id = await channel_check(user_id, channel_id)
|
||||
|
||||
emoji_type, emoji_id, emoji_name = emoji_info_from_str(emoji)
|
||||
|
|
@ -201,8 +201,7 @@ async def remove_own_reaction(channel_id, message_id, emoji):
|
|||
"""Remove a reaction."""
|
||||
user_id = await token_check()
|
||||
|
||||
await remove_reaction(channel_id, message_id, user_id, emoji)
|
||||
|
||||
await _remove_reaction(channel_id, message_id, user_id, emoji)
|
||||
return "", 204
|
||||
|
||||
|
||||
|
|
@ -212,7 +211,7 @@ async def remove_user_reaction(channel_id, message_id, emoji, other_id):
|
|||
user_id = await token_check()
|
||||
await channel_perm_check(user_id, channel_id, "manage_messages")
|
||||
|
||||
await remove_reaction(channel_id, message_id, other_id, emoji)
|
||||
await _remove_reaction(channel_id, message_id, other_id, emoji)
|
||||
return "", 204
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ from litecord.blueprints.dm_channels import gdm_remove_recipient, gdm_destroy
|
|||
from litecord.utils import search_result_from_list
|
||||
from litecord.embed.messages import process_url_embed, msg_update_embeds
|
||||
from litecord.snowflake import snowflake_datetime
|
||||
from litecord.common.channels import channel_ack
|
||||
|
||||
log = Logger(__name__)
|
||||
bp = Blueprint("channels", __name__)
|
||||
|
|
@ -136,7 +137,7 @@ async def _update_guild_chan_cat(guild_id: int, channel_id: int):
|
|||
await app.dispatcher.dispatch_guild(guild_id, "CHANNEL_UPDATE", child)
|
||||
|
||||
|
||||
async def delete_messages(channel_id):
|
||||
async def _delete_messages(channel_id):
|
||||
await app.db.execute(
|
||||
"""
|
||||
DELETE FROM channel_pins
|
||||
|
|
@ -162,7 +163,7 @@ async def delete_messages(channel_id):
|
|||
)
|
||||
|
||||
|
||||
async def guild_cleanup(channel_id):
|
||||
async def _guild_cleanup(channel_id):
|
||||
await app.db.execute(
|
||||
"""
|
||||
DELETE FROM channel_overwrites
|
||||
|
|
@ -220,8 +221,8 @@ async def close_channel(channel_id):
|
|||
# didn't work on my setup, so I delete
|
||||
# everything before moving to the main
|
||||
# channel table deletes
|
||||
await delete_messages(channel_id)
|
||||
await guild_cleanup(channel_id)
|
||||
await _delete_messages(channel_id)
|
||||
await _guild_cleanup(channel_id)
|
||||
|
||||
await app.db.execute(
|
||||
f"""
|
||||
|
|
@ -595,48 +596,6 @@ async def trigger_typing(channel_id):
|
|||
return "", 204
|
||||
|
||||
|
||||
async def channel_ack(user_id, guild_id, channel_id, message_id: int = None):
|
||||
"""ACK a channel."""
|
||||
|
||||
if not message_id:
|
||||
message_id = await app.storage.chan_last_message(channel_id)
|
||||
|
||||
await app.db.execute(
|
||||
"""
|
||||
INSERT INTO user_read_state
|
||||
(user_id, channel_id, last_message_id, mention_count)
|
||||
VALUES
|
||||
($1, $2, $3, 0)
|
||||
ON CONFLICT ON CONSTRAINT user_read_state_pkey
|
||||
DO
|
||||
UPDATE
|
||||
SET last_message_id = $3, mention_count = 0
|
||||
WHERE user_read_state.user_id = $1
|
||||
AND user_read_state.channel_id = $2
|
||||
""",
|
||||
user_id,
|
||||
channel_id,
|
||||
message_id,
|
||||
)
|
||||
|
||||
if guild_id:
|
||||
await app.dispatcher.dispatch_user_guild(
|
||||
user_id,
|
||||
guild_id,
|
||||
"MESSAGE_ACK",
|
||||
{"message_id": str(message_id), "channel_id": str(channel_id)},
|
||||
)
|
||||
else:
|
||||
# we don't use ChannelDispatcher here because since
|
||||
# guild_id is None, all user devices are already subscribed
|
||||
# to the given channel (a dm or a group dm)
|
||||
await app.dispatcher.dispatch_user(
|
||||
user_id,
|
||||
"MESSAGE_ACK",
|
||||
{"message_id": str(message_id), "channel_id": str(channel_id)},
|
||||
)
|
||||
|
||||
|
||||
@bp.route("/<int:channel_id>/messages/<int:message_id>/ack", methods=["POST"])
|
||||
async def ack_channel(channel_id, message_id):
|
||||
"""Acknowledge a channel."""
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ from ..snowflake import get_snowflake
|
|||
from .auth import token_check
|
||||
|
||||
from litecord.blueprints.dm_channels import gdm_create, gdm_add_recipient
|
||||
from litecord.common.channels import try_dm_state
|
||||
|
||||
log = Logger(__name__)
|
||||
bp = Blueprint("dms", __name__)
|
||||
|
|
@ -44,24 +45,6 @@ async def get_dms():
|
|||
return jsonify(dms)
|
||||
|
||||
|
||||
async def try_dm_state(user_id: int, dm_id: int):
|
||||
"""Try inserting the user into the dm state
|
||||
for the given DM.
|
||||
|
||||
Does not do anything if the user is already
|
||||
in the dm state.
|
||||
"""
|
||||
await app.db.execute(
|
||||
"""
|
||||
INSERT INTO dm_channel_state (user_id, dm_id)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT DO NOTHING
|
||||
""",
|
||||
user_id,
|
||||
dm_id,
|
||||
)
|
||||
|
||||
|
||||
async def jsonify_dm(dm_id: int, user_id: int):
|
||||
dm_chan = await app.storage.get_dm(dm_id, user_id)
|
||||
return jsonify(dm_chan)
|
||||
|
|
|
|||
|
|
@ -27,77 +27,11 @@ from litecord.blueprints.guild.roles import gen_pairs
|
|||
|
||||
from litecord.schemas import validate, ROLE_UPDATE_POSITION, CHAN_CREATE
|
||||
from litecord.blueprints.checks import guild_check, guild_owner_check, guild_perm_check
|
||||
|
||||
from litecord.common.guilds import create_guild_channel
|
||||
|
||||
bp = Blueprint("guild_channels", __name__)
|
||||
|
||||
|
||||
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, $2)
|
||||
""",
|
||||
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,
|
||||
)
|
||||
|
||||
# account for the first channel in a guild too
|
||||
max_pos = max_pos or 0
|
||||
|
||||
# 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)
|
||||
|
||||
|
||||
@bp.route("/<int:guild_id>/channels", methods=["GET"])
|
||||
async def get_guild_channels(guild_id):
|
||||
"""Get the list of channels in a guild."""
|
||||
|
|
|
|||
|
|
@ -23,47 +23,11 @@ from litecord.blueprints.auth import token_check
|
|||
from litecord.blueprints.checks import guild_perm_check
|
||||
|
||||
from litecord.schemas import validate, GUILD_PRUNE
|
||||
from litecord.common.guilds import remove_member, remove_member_multi
|
||||
|
||||
bp = Blueprint("guild_moderation", __name__)
|
||||
|
||||
|
||||
async def remove_member(guild_id: int, member_id: int):
|
||||
"""Do common tasks related to deleting a member from the guild,
|
||||
such as dispatching GUILD_DELETE and GUILD_MEMBER_REMOVE."""
|
||||
|
||||
await app.db.execute(
|
||||
"""
|
||||
DELETE FROM members
|
||||
WHERE guild_id = $1 AND user_id = $2
|
||||
""",
|
||||
guild_id,
|
||||
member_id,
|
||||
)
|
||||
|
||||
await app.dispatcher.dispatch_user_guild(
|
||||
member_id,
|
||||
guild_id,
|
||||
"GUILD_DELETE",
|
||||
{"guild_id": str(guild_id), "unavailable": False},
|
||||
)
|
||||
|
||||
await app.dispatcher.unsub("guild", guild_id, member_id)
|
||||
|
||||
await app.dispatcher.dispatch("lazy_guild", guild_id, "remove_member", member_id)
|
||||
|
||||
await app.dispatcher.dispatch_guild(
|
||||
guild_id,
|
||||
"GUILD_MEMBER_REMOVE",
|
||||
{"guild_id": str(guild_id), "user": await app.storage.get_user(member_id)},
|
||||
)
|
||||
|
||||
|
||||
async def remove_member_multi(guild_id: int, members: list):
|
||||
"""Remove multiple members."""
|
||||
for member_id in members:
|
||||
await remove_member(guild_id, member_id)
|
||||
|
||||
|
||||
@bp.route("/<int:guild_id>/members/<int:member_id>", methods=["DELETE"])
|
||||
async def kick_guild_member(guild_id, member_id):
|
||||
"""Remove a member from a guild."""
|
||||
|
|
@ -221,6 +185,5 @@ async def begin_guild_prune(guild_id):
|
|||
days = j["days"]
|
||||
member_ids = await get_prune(guild_id, days)
|
||||
|
||||
app.loop.create_task(remove_member_multi(guild_id, member_ids))
|
||||
|
||||
app.sched.spawn(remove_member_multi(guild_id, member_ids))
|
||||
return jsonify({"pruned": len(member_ids)})
|
||||
|
|
|
|||
|
|
@ -27,11 +27,9 @@ from litecord.auth import token_check
|
|||
from litecord.blueprints.checks import guild_check, guild_perm_check
|
||||
from litecord.schemas import validate, ROLE_CREATE, ROLE_UPDATE, ROLE_UPDATE_POSITION
|
||||
|
||||
from litecord.snowflake import get_snowflake
|
||||
from litecord.utils import dict_get
|
||||
from litecord.permissions import get_role_perms
|
||||
from litecord.utils import maybe_lazy_guild_dispatch
|
||||
from litecord.common.guilds import create_role
|
||||
|
||||
DEFAULT_EVERYONE_PERMS = 104324161
|
||||
log = Logger(__name__)
|
||||
bp = Blueprint("guild_roles", __name__)
|
||||
|
||||
|
|
@ -45,71 +43,6 @@ async def get_guild_roles(guild_id):
|
|||
return jsonify(await app.storage.get_role_data(guild_id))
|
||||
|
||||
|
||||
async def _maybe_lg(guild_id: int, event: str, role, force: bool = False):
|
||||
# sometimes we want to dispatch an event
|
||||
# even if the role isn't hoisted
|
||||
|
||||
# an example of such a case is when a role loses
|
||||
# its hoist status.
|
||||
|
||||
# check if is a dict first because role_delete
|
||||
# only receives the role id.
|
||||
if isinstance(role, dict) and not role["hoist"] and not force:
|
||||
return
|
||||
|
||||
await app.dispatcher.dispatch("lazy_guild", guild_id, event, role)
|
||||
|
||||
|
||||
async def create_role(guild_id, name: str, **kwargs):
|
||||
"""Create a role in a guild."""
|
||||
new_role_id = get_snowflake()
|
||||
|
||||
everyone_perms = await get_role_perms(guild_id, guild_id)
|
||||
default_perms = dict_get(kwargs, "default_perms", everyone_perms.binary)
|
||||
|
||||
# update all roles so that we have space for pos 1, but without
|
||||
# sending GUILD_ROLE_UPDATE for everyone
|
||||
await app.db.execute(
|
||||
"""
|
||||
UPDATE roles
|
||||
SET
|
||||
position = position + 1
|
||||
WHERE guild_id = $1
|
||||
AND NOT (position = 0)
|
||||
""",
|
||||
guild_id,
|
||||
)
|
||||
|
||||
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,
|
||||
name,
|
||||
dict_get(kwargs, "color", 0),
|
||||
dict_get(kwargs, "hoist", False),
|
||||
# always set ourselves on position 1
|
||||
1,
|
||||
int(dict_get(kwargs, "permissions", default_perms)),
|
||||
False,
|
||||
dict_get(kwargs, "mentionable", False),
|
||||
)
|
||||
|
||||
role = await app.storage.get_role(new_role_id, guild_id)
|
||||
|
||||
# we need to update the lazy guild handlers for the newly created group
|
||||
await _maybe_lg(guild_id, "new_role", role)
|
||||
|
||||
await app.dispatcher.dispatch_guild(
|
||||
guild_id, "GUILD_ROLE_CREATE", {"guild_id": str(guild_id), "role": role}
|
||||
)
|
||||
|
||||
return role
|
||||
|
||||
|
||||
@bp.route("/<int:guild_id>/roles", methods=["POST"])
|
||||
async def create_guild_role(guild_id: int):
|
||||
"""Add a role to a guild"""
|
||||
|
|
@ -132,7 +65,7 @@ async def _role_update_dispatch(role_id: int, guild_id: int):
|
|||
"""Dispatch a GUILD_ROLE_UPDATE with updated information on a role."""
|
||||
role = await app.storage.get_role(role_id, guild_id)
|
||||
|
||||
await _maybe_lg(guild_id, "role_pos_upd", role)
|
||||
await maybe_lazy_guild_dispatch(guild_id, "role_pos_upd", role)
|
||||
|
||||
await app.dispatcher.dispatch_guild(
|
||||
guild_id, "GUILD_ROLE_UPDATE", {"guild_id": str(guild_id), "role": role}
|
||||
|
|
@ -343,7 +276,7 @@ async def update_guild_role(guild_id, role_id):
|
|||
)
|
||||
|
||||
role = await _role_update_dispatch(role_id, guild_id)
|
||||
await _maybe_lg(guild_id, "role_update", role, True)
|
||||
await maybe_lazy_guild_dispatch(guild_id, "role_update", role, True)
|
||||
return jsonify(role)
|
||||
|
||||
|
||||
|
|
@ -369,7 +302,7 @@ async def delete_guild_role(guild_id, role_id):
|
|||
if res == "DELETE 0":
|
||||
return "", 204
|
||||
|
||||
await _maybe_lg(guild_id, "role_delete", role_id, True)
|
||||
await maybe_lazy_guild_dispatch(guild_id, "role_delete", role_id, True)
|
||||
|
||||
await app.dispatcher.dispatch_guild(
|
||||
guild_id,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ from ..schemas import validate, USER_UPDATE, GET_MENTIONS
|
|||
|
||||
from .guilds import guild_check
|
||||
from litecord.auth import token_check, hash_data, check_username_usage, roll_discrim
|
||||
from litecord.blueprints.guild.mod import remove_member
|
||||
from litecord.common.guilds import remove_member
|
||||
|
||||
from litecord.enums import PremiumType
|
||||
from litecord.images import parse_data_uri
|
||||
|
|
@ -319,7 +319,6 @@ async def leave_guild(guild_id: int):
|
|||
await guild_check(user_id, guild_id)
|
||||
|
||||
await remove_member(guild_id, user_id)
|
||||
|
||||
return "", 204
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ from litecord.snowflake import get_snowflake
|
|||
from litecord.utils import async_map
|
||||
from litecord.errors import WebhookNotFound, Unauthorized, ChannelNotFound, BadRequest
|
||||
|
||||
from litecord.blueprints.channel.messages import (
|
||||
from litecord.common.messages import (
|
||||
msg_create_request,
|
||||
msg_create_check_content,
|
||||
msg_add_attachment,
|
||||
|
|
|
|||
|
|
@ -116,6 +116,10 @@ class Forbidden(LitecordError):
|
|||
status_code = 403
|
||||
|
||||
|
||||
class ForbiddenDM(Forbidden):
|
||||
error_code = 50007
|
||||
|
||||
|
||||
class NotFound(LitecordError):
|
||||
status_code = 404
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ from typing import Any, Iterable, Optional, Sequence, List, Dict, Union
|
|||
|
||||
from logbook import Logger
|
||||
from quart.json import JSONEncoder
|
||||
from quart import current_app as app
|
||||
from quart import current_app as app, request
|
||||
|
||||
from .errors import BadRequest
|
||||
|
||||
log = Logger(__name__)
|
||||
|
||||
|
|
@ -233,3 +235,52 @@ def maybe_int(val: Any) -> Union[int, Any]:
|
|||
return int(val)
|
||||
except (ValueError, TypeError):
|
||||
return val
|
||||
|
||||
|
||||
async def maybe_lazy_guild_dispatch(
|
||||
guild_id: int, event: str, role, force: bool = False
|
||||
):
|
||||
# sometimes we want to dispatch an event
|
||||
# even if the role isn't hoisted
|
||||
|
||||
# an example of such a case is when a role loses
|
||||
# its hoist status.
|
||||
|
||||
# check if is a dict first because role_delete
|
||||
# only receives the role id.
|
||||
if isinstance(role, dict) and not role["hoist"] and not force:
|
||||
return
|
||||
|
||||
await app.dispatcher.dispatch("lazy_guild", guild_id, event, role)
|
||||
|
||||
|
||||
def extract_limit(request_, default: int = 50, max_val: int = 100):
|
||||
"""Extract a limit kwarg."""
|
||||
try:
|
||||
limit = int(request_.args.get("limit", default))
|
||||
|
||||
if limit not in range(0, max_val + 1):
|
||||
raise ValueError()
|
||||
except (TypeError, ValueError):
|
||||
raise BadRequest("limit not int")
|
||||
|
||||
return limit
|
||||
|
||||
|
||||
def query_tuple_from_args(args: dict, limit: int) -> tuple:
|
||||
"""Extract a 2-tuple out of request arguments."""
|
||||
before, after = None, None
|
||||
|
||||
if "around" in request.args:
|
||||
average = int(limit / 2)
|
||||
around = int(args["around"])
|
||||
|
||||
after = around - average
|
||||
before = around + average
|
||||
|
||||
elif "before" in args:
|
||||
before = int(args["before"])
|
||||
elif "after" in args:
|
||||
before = int(args["after"])
|
||||
|
||||
return before, after
|
||||
|
|
|
|||
Loading…
Reference in New Issue