mirror of https://gitlab.com/litecord/litecord.git
blueprints: split channels to channel.messages bp
This commit is contained in:
parent
8352a3cab4
commit
f2d5913672
|
|
@ -0,0 +1 @@
|
||||||
|
from .messages import bp as channel_messages
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
from quart import Blueprint, request, current_app as app, jsonify
|
||||||
|
|
||||||
|
from logbook import Logger
|
||||||
|
|
||||||
|
|
||||||
|
from litecord.blueprints.auth import token_check
|
||||||
|
from litecord.blueprints.checks import channel_check
|
||||||
|
from litecord.blueprints.dms import try_dm_state
|
||||||
|
from litecord.errors import MessageNotFound, Forbidden
|
||||||
|
from litecord.enums import MessageType, ChannelType, GUILD_CHANS
|
||||||
|
from litecord.snowflake import get_snowflake
|
||||||
|
from litecord.schemas import validate, MESSAGE_CREATE
|
||||||
|
|
||||||
|
|
||||||
|
log = Logger(__name__)
|
||||||
|
bp = Blueprint('channel_messages', __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:channel_id>/messages', methods=['GET'])
|
||||||
|
async def get_messages(channel_id):
|
||||||
|
user_id = await token_check()
|
||||||
|
await channel_check(user_id, channel_id)
|
||||||
|
|
||||||
|
# TODO: before, after, around keys
|
||||||
|
|
||||||
|
message_ids = await app.db.fetch(f"""
|
||||||
|
SELECT id
|
||||||
|
FROM messages
|
||||||
|
WHERE channel_id = $1
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT 100
|
||||||
|
""", channel_id)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for message_id in message_ids:
|
||||||
|
msg = await app.storage.get_message(message_id['id'])
|
||||||
|
|
||||||
|
if msg is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
result.append(msg)
|
||||||
|
|
||||||
|
log.info('Fetched {} messages', len(result))
|
||||||
|
return jsonify(result)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:channel_id>/messages/<int:message_id>', methods=['GET'])
|
||||||
|
async def get_single_message(channel_id, message_id):
|
||||||
|
user_id = await token_check()
|
||||||
|
await channel_check(user_id, channel_id)
|
||||||
|
|
||||||
|
# TODO: check READ_MESSAGE_HISTORY permissions
|
||||||
|
message = await app.storage.get_message(message_id)
|
||||||
|
|
||||||
|
if not message:
|
||||||
|
raise MessageNotFound()
|
||||||
|
|
||||||
|
return jsonify(message)
|
||||||
|
|
||||||
|
|
||||||
|
async def _dm_pre_dispatch(channel_id, peer_id):
|
||||||
|
"""Do some checks pre-MESSAGE_CREATE so we
|
||||||
|
make sure the receiving party will handle everything."""
|
||||||
|
|
||||||
|
# check the other party's dm_channel_state
|
||||||
|
|
||||||
|
dm_state = await app.db.fetchval("""
|
||||||
|
SELECT dm_id
|
||||||
|
FROM dm_channel_state
|
||||||
|
WHERE user_id = $1 AND dm_id = $2
|
||||||
|
""", peer_id, channel_id)
|
||||||
|
|
||||||
|
if dm_state:
|
||||||
|
# the peer already has the channel
|
||||||
|
# opened, so we don't need to do anything
|
||||||
|
return
|
||||||
|
|
||||||
|
dm_chan = await app.storage.get_channel(channel_id)
|
||||||
|
|
||||||
|
# dispatch CHANNEL_CREATE so the client knows which
|
||||||
|
# channel the future event is about
|
||||||
|
await app.dispatcher.dispatch_user(peer_id, 'CHANNEL_CREATE', dm_chan)
|
||||||
|
|
||||||
|
# subscribe the peer to the channel
|
||||||
|
await app.dispatcher.sub('channel', channel_id, peer_id)
|
||||||
|
|
||||||
|
# insert it on dm_channel_state so the client
|
||||||
|
# is subscribed on the future
|
||||||
|
await try_dm_state(peer_id, channel_id)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:channel_id>/messages', methods=['POST'])
|
||||||
|
async def create_message(channel_id):
|
||||||
|
user_id = await token_check()
|
||||||
|
ctype, guild_id = await channel_check(user_id, channel_id)
|
||||||
|
|
||||||
|
j = validate(await request.get_json(), MESSAGE_CREATE)
|
||||||
|
message_id = get_snowflake()
|
||||||
|
|
||||||
|
# TODO: check SEND_MESSAGES permission
|
||||||
|
# TODO: check connection to the gateway
|
||||||
|
|
||||||
|
await app.db.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO messages (id, channel_id, author_id, content, tts,
|
||||||
|
mention_everyone, nonce, message_type)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||||
|
""",
|
||||||
|
message_id,
|
||||||
|
channel_id,
|
||||||
|
user_id,
|
||||||
|
j['content'],
|
||||||
|
|
||||||
|
# TODO: check SEND_TTS_MESSAGES
|
||||||
|
j.get('tts', False),
|
||||||
|
|
||||||
|
# TODO: check MENTION_EVERYONE permissions
|
||||||
|
'@everyone' in j['content'],
|
||||||
|
int(j.get('nonce', 0)),
|
||||||
|
MessageType.DEFAULT.value
|
||||||
|
)
|
||||||
|
|
||||||
|
payload = await app.storage.get_message(message_id)
|
||||||
|
|
||||||
|
if ctype == ChannelType.DM:
|
||||||
|
# guild id here is the peer's ID.
|
||||||
|
await _dm_pre_dispatch(channel_id, guild_id)
|
||||||
|
|
||||||
|
await app.dispatcher.dispatch('channel', channel_id,
|
||||||
|
'MESSAGE_CREATE', payload)
|
||||||
|
|
||||||
|
# TODO: dispatch the MESSAGE_CREATE to any mentioning user.
|
||||||
|
|
||||||
|
if ctype == ChannelType.GUILD_TEXT:
|
||||||
|
for str_uid in payload['mentions']:
|
||||||
|
uid = int(str_uid)
|
||||||
|
|
||||||
|
await app.db.execute("""
|
||||||
|
UPDATE user_read_state
|
||||||
|
SET mention_count += 1
|
||||||
|
WHERE user_id = $1 AND channel_id = $2
|
||||||
|
""", uid, channel_id)
|
||||||
|
|
||||||
|
return jsonify(payload)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:channel_id>/messages/<int:message_id>', methods=['PATCH'])
|
||||||
|
async def edit_message(channel_id, message_id):
|
||||||
|
user_id = await token_check()
|
||||||
|
_ctype, guild_id = await channel_check(user_id, channel_id)
|
||||||
|
|
||||||
|
author_id = await app.db.fetchval("""
|
||||||
|
SELECT author_id FROM messages
|
||||||
|
WHERE messages.id = $1
|
||||||
|
""", message_id)
|
||||||
|
|
||||||
|
if not author_id == user_id:
|
||||||
|
raise Forbidden('You can not edit this message')
|
||||||
|
|
||||||
|
j = await request.get_json()
|
||||||
|
updated = 'content' in j or 'embed' in j
|
||||||
|
|
||||||
|
if 'content' in j:
|
||||||
|
await app.db.execute("""
|
||||||
|
UPDATE messages
|
||||||
|
SET content=$1
|
||||||
|
WHERE messages.id = $2
|
||||||
|
""", j['content'], message_id)
|
||||||
|
|
||||||
|
# TODO: update embed
|
||||||
|
|
||||||
|
message = await app.storage.get_message(message_id)
|
||||||
|
|
||||||
|
# only dispatch MESSAGE_UPDATE if we actually had any update to start with
|
||||||
|
if updated:
|
||||||
|
await app.dispatcher.dispatch('channel', channel_id,
|
||||||
|
'MESSAGE_UPDATE', message)
|
||||||
|
|
||||||
|
return jsonify(message)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/<int:channel_id>/messages/<int:message_id>', methods=['DELETE'])
|
||||||
|
async def delete_message(channel_id, message_id):
|
||||||
|
user_id = await token_check()
|
||||||
|
_ctype, guild_id = await channel_check(user_id, channel_id)
|
||||||
|
|
||||||
|
author_id = await app.db.fetchval("""
|
||||||
|
SELECT author_id FROM messages
|
||||||
|
WHERE messages.id = $1
|
||||||
|
""", message_id)
|
||||||
|
|
||||||
|
# TODO: MANAGE_MESSAGES permission check
|
||||||
|
if author_id != user_id:
|
||||||
|
raise Forbidden('You can not delete this message')
|
||||||
|
|
||||||
|
await app.db.execute("""
|
||||||
|
DELETE FROM messages
|
||||||
|
WHERE messages.id = $1
|
||||||
|
""", message_id)
|
||||||
|
|
||||||
|
await app.dispatcher.dispatch(
|
||||||
|
'channel', channel_id,
|
||||||
|
'MESSAGE_DELETE', {
|
||||||
|
'id': str(message_id),
|
||||||
|
'channel_id': str(channel_id),
|
||||||
|
|
||||||
|
# for lazy guilds
|
||||||
|
'guild_id': str(guild_id),
|
||||||
|
})
|
||||||
|
|
||||||
|
return '', 204
|
||||||
|
|
@ -4,13 +4,11 @@ from quart import Blueprint, request, current_app as app, jsonify
|
||||||
from logbook import Logger
|
from logbook import Logger
|
||||||
|
|
||||||
from ..auth import token_check
|
from ..auth import token_check
|
||||||
from ..snowflake import get_snowflake, snowflake_datetime
|
from ..snowflake import snowflake_datetime
|
||||||
from ..enums import ChannelType, MessageType, GUILD_CHANS
|
from ..enums import ChannelType, GUILD_CHANS
|
||||||
from ..errors import Forbidden, ChannelNotFound, MessageNotFound
|
from ..errors import ChannelNotFound
|
||||||
from ..schemas import validate, MESSAGE_CREATE
|
|
||||||
|
|
||||||
from .checks import channel_check, guild_check
|
from .checks import channel_check
|
||||||
from .dms import try_dm_state
|
|
||||||
|
|
||||||
log = Logger(__name__)
|
log = Logger(__name__)
|
||||||
bp = Blueprint('channels', __name__)
|
bp = Blueprint('channels', __name__)
|
||||||
|
|
@ -215,202 +213,6 @@ async def close_channel(channel_id):
|
||||||
return '', 404
|
return '', 404
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:channel_id>/messages', methods=['GET'])
|
|
||||||
async def get_messages(channel_id):
|
|
||||||
user_id = await token_check()
|
|
||||||
await channel_check(user_id, channel_id)
|
|
||||||
|
|
||||||
# TODO: before, after, around keys
|
|
||||||
|
|
||||||
message_ids = await app.db.fetch(f"""
|
|
||||||
SELECT id
|
|
||||||
FROM messages
|
|
||||||
WHERE channel_id = $1
|
|
||||||
ORDER BY id DESC
|
|
||||||
LIMIT 100
|
|
||||||
""", channel_id)
|
|
||||||
|
|
||||||
result = []
|
|
||||||
|
|
||||||
for message_id in message_ids:
|
|
||||||
msg = await app.storage.get_message(message_id['id'])
|
|
||||||
|
|
||||||
if msg is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
result.append(msg)
|
|
||||||
|
|
||||||
log.info('Fetched {} messages', len(result))
|
|
||||||
return jsonify(result)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:channel_id>/messages/<int:message_id>', methods=['GET'])
|
|
||||||
async def get_single_message(channel_id, message_id):
|
|
||||||
user_id = await token_check()
|
|
||||||
await channel_check(user_id, channel_id)
|
|
||||||
|
|
||||||
# TODO: check READ_MESSAGE_HISTORY permissions
|
|
||||||
message = await app.storage.get_message(message_id)
|
|
||||||
|
|
||||||
if not message:
|
|
||||||
raise MessageNotFound()
|
|
||||||
|
|
||||||
return jsonify(message)
|
|
||||||
|
|
||||||
|
|
||||||
async def _dm_pre_dispatch(channel_id, peer_id):
|
|
||||||
"""Do some checks pre-MESSAGE_CREATE so we
|
|
||||||
make sure the receiving party will handle everything."""
|
|
||||||
|
|
||||||
# check the other party's dm_channel_state
|
|
||||||
|
|
||||||
dm_state = await app.db.fetchval("""
|
|
||||||
SELECT dm_id
|
|
||||||
FROM dm_channel_state
|
|
||||||
WHERE user_id = $1 AND dm_id = $2
|
|
||||||
""", peer_id, channel_id)
|
|
||||||
|
|
||||||
if dm_state:
|
|
||||||
# the peer already has the channel
|
|
||||||
# opened, so we don't need to do anything
|
|
||||||
return
|
|
||||||
|
|
||||||
dm_chan = await app.storage.get_channel(channel_id)
|
|
||||||
|
|
||||||
# dispatch CHANNEL_CREATE so the client knows which
|
|
||||||
# channel the future event is about
|
|
||||||
await app.dispatcher.dispatch_user(peer_id, 'CHANNEL_CREATE', dm_chan)
|
|
||||||
|
|
||||||
# subscribe the peer to the channel
|
|
||||||
await app.dispatcher.sub('channel', channel_id, peer_id)
|
|
||||||
|
|
||||||
# insert it on dm_channel_state so the client
|
|
||||||
# is subscribed on the future
|
|
||||||
await try_dm_state(peer_id, channel_id)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:channel_id>/messages', methods=['POST'])
|
|
||||||
async def create_message(channel_id):
|
|
||||||
user_id = await token_check()
|
|
||||||
ctype, guild_id = await channel_check(user_id, channel_id)
|
|
||||||
|
|
||||||
j = validate(await request.get_json(), MESSAGE_CREATE)
|
|
||||||
message_id = get_snowflake()
|
|
||||||
|
|
||||||
# TODO: check SEND_MESSAGES permission
|
|
||||||
# TODO: check connection to the gateway
|
|
||||||
|
|
||||||
await app.db.execute(
|
|
||||||
"""
|
|
||||||
INSERT INTO messages (id, channel_id, author_id, content, tts,
|
|
||||||
mention_everyone, nonce, message_type)
|
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
||||||
""",
|
|
||||||
message_id,
|
|
||||||
channel_id,
|
|
||||||
user_id,
|
|
||||||
j['content'],
|
|
||||||
|
|
||||||
# TODO: check SEND_TTS_MESSAGES
|
|
||||||
j.get('tts', False),
|
|
||||||
|
|
||||||
# TODO: check MENTION_EVERYONE permissions
|
|
||||||
'@everyone' in j['content'],
|
|
||||||
int(j.get('nonce', 0)),
|
|
||||||
MessageType.DEFAULT.value
|
|
||||||
)
|
|
||||||
|
|
||||||
payload = await app.storage.get_message(message_id)
|
|
||||||
|
|
||||||
if ctype == ChannelType.DM:
|
|
||||||
# guild id here is the peer's ID.
|
|
||||||
await _dm_pre_dispatch(channel_id, guild_id)
|
|
||||||
|
|
||||||
await app.dispatcher.dispatch('channel', channel_id,
|
|
||||||
'MESSAGE_CREATE', payload)
|
|
||||||
|
|
||||||
# TODO: dispatch the MESSAGE_CREATE to any mentioning user.
|
|
||||||
|
|
||||||
if ctype == ChannelType.GUILD_TEXT:
|
|
||||||
for str_uid in payload['mentions']:
|
|
||||||
uid = int(str_uid)
|
|
||||||
|
|
||||||
await app.db.execute("""
|
|
||||||
UPDATE user_read_state
|
|
||||||
SET mention_count += 1
|
|
||||||
WHERE user_id = $1 AND channel_id = $2
|
|
||||||
""", uid, channel_id)
|
|
||||||
|
|
||||||
return jsonify(payload)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:channel_id>/messages/<int:message_id>', methods=['PATCH'])
|
|
||||||
async def edit_message(channel_id, message_id):
|
|
||||||
user_id = await token_check()
|
|
||||||
_ctype, guild_id = await channel_check(user_id, channel_id)
|
|
||||||
|
|
||||||
author_id = await app.db.fetchval("""
|
|
||||||
SELECT author_id FROM messages
|
|
||||||
WHERE messages.id = $1
|
|
||||||
""", message_id)
|
|
||||||
|
|
||||||
if not author_id == user_id:
|
|
||||||
raise Forbidden('You can not edit this message')
|
|
||||||
|
|
||||||
j = await request.get_json()
|
|
||||||
updated = 'content' in j or 'embed' in j
|
|
||||||
|
|
||||||
if 'content' in j:
|
|
||||||
await app.db.execute("""
|
|
||||||
UPDATE messages
|
|
||||||
SET content=$1
|
|
||||||
WHERE messages.id = $2
|
|
||||||
""", j['content'], message_id)
|
|
||||||
|
|
||||||
# TODO: update embed
|
|
||||||
|
|
||||||
message = await app.storage.get_message(message_id)
|
|
||||||
|
|
||||||
# only dispatch MESSAGE_UPDATE if we actually had any update to start with
|
|
||||||
if updated:
|
|
||||||
await app.dispatcher.dispatch('channel', channel_id,
|
|
||||||
'MESSAGE_UPDATE', message)
|
|
||||||
|
|
||||||
return jsonify(message)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:channel_id>/messages/<int:message_id>', methods=['DELETE'])
|
|
||||||
async def delete_message(channel_id, message_id):
|
|
||||||
user_id = await token_check()
|
|
||||||
_ctype, guild_id = await channel_check(user_id, channel_id)
|
|
||||||
|
|
||||||
author_id = await app.db.fetchval("""
|
|
||||||
SELECT author_id FROM messages
|
|
||||||
WHERE messages.id = $1
|
|
||||||
""", message_id)
|
|
||||||
|
|
||||||
# TODO: MANAGE_MESSAGES permission check
|
|
||||||
if author_id != user_id:
|
|
||||||
raise Forbidden('You can not delete this message')
|
|
||||||
|
|
||||||
await app.db.execute("""
|
|
||||||
DELETE FROM messages
|
|
||||||
WHERE messages.id = $1
|
|
||||||
""", message_id)
|
|
||||||
|
|
||||||
await app.dispatcher.dispatch(
|
|
||||||
'channel', channel_id,
|
|
||||||
'MESSAGE_DELETE', {
|
|
||||||
'id': str(message_id),
|
|
||||||
'channel_id': str(channel_id),
|
|
||||||
|
|
||||||
# for lazy guilds
|
|
||||||
'guild_id': str(guild_id),
|
|
||||||
})
|
|
||||||
|
|
||||||
return '', 204
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:channel_id>/pins', methods=['GET'])
|
@bp.route('/<int:channel_id>/pins', methods=['GET'])
|
||||||
async def get_pins(channel_id):
|
async def get_pins(channel_id):
|
||||||
user_id = await token_check()
|
user_id = await token_check()
|
||||||
|
|
|
||||||
|
|
@ -183,4 +183,3 @@ async def begin_guild_prune(guild_id):
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'pruned': len(member_ids)
|
'pruned': len(member_ids)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
6
run.py
6
run.py
|
|
@ -22,6 +22,10 @@ from litecord.blueprints.guild import (
|
||||||
guild_roles, guild_members, guild_channels, guild_mod
|
guild_roles, guild_members, guild_channels, guild_mod
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from litecord.blueprints.channel import (
|
||||||
|
channel_messages
|
||||||
|
)
|
||||||
|
|
||||||
from litecord.gateway import websocket_handler
|
from litecord.gateway import websocket_handler
|
||||||
from litecord.errors import LitecordError
|
from litecord.errors import LitecordError
|
||||||
from litecord.gateway.state_manager import StateManager
|
from litecord.gateway.state_manager import StateManager
|
||||||
|
|
@ -68,6 +72,8 @@ bps = {
|
||||||
guild_mod: '/guilds',
|
guild_mod: '/guilds',
|
||||||
|
|
||||||
channels: '/channels',
|
channels: '/channels',
|
||||||
|
channel_messages: '/channels',
|
||||||
|
|
||||||
webhooks: None,
|
webhooks: None,
|
||||||
science: None,
|
science: None,
|
||||||
voice: '/voice',
|
voice: '/voice',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue