mirror of https://gitlab.com/litecord/litecord.git
Merge branch 'impl/bulk-ack' into 'master'
Implement Bulk ACK endpoint Closes #52 See merge request litecord/litecord!73
This commit is contained in:
commit
16665e5692
|
|
@ -33,6 +33,7 @@ from .nodeinfo import bp as nodeinfo
|
||||||
from .static import bp as static
|
from .static import bp as static
|
||||||
from .attachments import bp as attachments
|
from .attachments import bp as attachments
|
||||||
from .dm_channels import bp as dm_channels
|
from .dm_channels import bp as dm_channels
|
||||||
|
from .read_states import bp as read_states
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"gateway",
|
"gateway",
|
||||||
|
|
@ -51,4 +52,5 @@ __all__ = [
|
||||||
"static",
|
"static",
|
||||||
"attachments",
|
"attachments",
|
||||||
"dm_channels",
|
"dm_channels",
|
||||||
|
"read_states",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,8 @@ from litecord.system_messages import send_sys_message
|
||||||
from litecord.blueprints.dm_channels import gdm_remove_recipient, gdm_destroy
|
from litecord.blueprints.dm_channels import gdm_remove_recipient, gdm_destroy
|
||||||
from litecord.utils import search_result_from_list
|
from litecord.utils import search_result_from_list
|
||||||
from litecord.embed.messages import process_url_embed, msg_update_embeds
|
from litecord.embed.messages import process_url_embed, msg_update_embeds
|
||||||
from litecord.common.channels import channel_ack
|
|
||||||
from litecord.pubsub.user import dispatch_user
|
from litecord.pubsub.user import dispatch_user
|
||||||
from litecord.permissions import get_permissions, Permissions
|
from litecord.permissions import get_permissions, Permissions
|
||||||
from litecord.errors import GuildNotFound
|
|
||||||
|
|
||||||
log = Logger(__name__)
|
log = Logger(__name__)
|
||||||
bp = Blueprint("channels", __name__)
|
bp = Blueprint("channels", __name__)
|
||||||
|
|
@ -653,50 +651,6 @@ async def trigger_typing(channel_id):
|
||||||
return "", 204
|
return "", 204
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<int:channel_id>/messages/<int:message_id>/ack", methods=["POST"])
|
|
||||||
async def ack_channel(channel_id, message_id):
|
|
||||||
"""Acknowledge a channel."""
|
|
||||||
user_id = await token_check()
|
|
||||||
ctype, guild_id = await channel_check(user_id, channel_id)
|
|
||||||
|
|
||||||
if ctype == ChannelType.DM:
|
|
||||||
guild_id = None
|
|
||||||
|
|
||||||
await channel_ack(user_id, guild_id, channel_id, message_id)
|
|
||||||
|
|
||||||
return jsonify(
|
|
||||||
{
|
|
||||||
# token seems to be used for
|
|
||||||
# data collection activities,
|
|
||||||
# so we never use it.
|
|
||||||
"token": None
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<int:channel_id>/messages/ack", methods=["DELETE"])
|
|
||||||
async def delete_read_state(channel_id):
|
|
||||||
"""Delete the read state of a channel."""
|
|
||||||
user_id = await token_check()
|
|
||||||
try:
|
|
||||||
await channel_check(user_id, channel_id)
|
|
||||||
except GuildNotFound:
|
|
||||||
# ignore when guild isn't found because we're deleting the
|
|
||||||
# read state regardless.
|
|
||||||
pass
|
|
||||||
|
|
||||||
await app.db.execute(
|
|
||||||
"""
|
|
||||||
DELETE FROM user_read_state
|
|
||||||
WHERE user_id = $1 AND channel_id = $2
|
|
||||||
""",
|
|
||||||
user_id,
|
|
||||||
channel_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
return "", 204
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<int:channel_id>/messages/search", methods=["GET"])
|
@bp.route("/<int:channel_id>/messages/search", methods=["GET"])
|
||||||
async def _search_channel(channel_id):
|
async def _search_channel(channel_id):
|
||||||
"""Search in DMs or group DMs"""
|
"""Search in DMs or group DMs"""
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ from ..schemas import (
|
||||||
VANITY_URL_PATCH,
|
VANITY_URL_PATCH,
|
||||||
)
|
)
|
||||||
from .checks import guild_check, guild_owner_check, guild_perm_check
|
from .checks import guild_check, guild_owner_check, guild_perm_check
|
||||||
from ..common.channels import channel_ack
|
|
||||||
from litecord.utils import to_update, search_result_from_list
|
from litecord.utils import to_update, search_result_from_list
|
||||||
from litecord.errors import BadRequest
|
from litecord.errors import BadRequest
|
||||||
from litecord.permissions import get_permissions
|
from litecord.permissions import get_permissions
|
||||||
|
|
@ -438,20 +437,6 @@ async def search_messages(guild_id):
|
||||||
return jsonify(await search_result_from_list(rows))
|
return jsonify(await search_result_from_list(rows))
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<int:guild_id>/ack", methods=["POST"])
|
|
||||||
async def ack_guild(guild_id):
|
|
||||||
"""ACKnowledge all messages in the guild."""
|
|
||||||
user_id = await token_check()
|
|
||||||
await guild_check(user_id, guild_id)
|
|
||||||
|
|
||||||
chan_ids = await app.storage.get_channel_ids(guild_id)
|
|
||||||
|
|
||||||
for chan_id in chan_ids:
|
|
||||||
await channel_ack(user_id, guild_id, chan_id)
|
|
||||||
|
|
||||||
return "", 204
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/<int:guild_id>/vanity-url", methods=["GET"])
|
@bp.route("/<int:guild_id>/vanity-url", methods=["GET"])
|
||||||
async def get_vanity_url(guild_id: int):
|
async def get_vanity_url(guild_id: int):
|
||||||
"""Get the vanity url of a guild."""
|
"""Get the vanity url of a guild."""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
"""
|
||||||
|
|
||||||
|
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/>.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from quart import Blueprint, current_app as app, jsonify, request
|
||||||
|
from litecord.auth import token_check
|
||||||
|
from litecord.common.channels import channel_ack
|
||||||
|
from litecord.errors import GuildNotFound
|
||||||
|
from litecord.blueprints.checks import channel_check, guild_check
|
||||||
|
from litecord.schemas import validate, BULK_ACK
|
||||||
|
from litecord.enums import GUILD_CHANS
|
||||||
|
|
||||||
|
|
||||||
|
bp = Blueprint("read_states", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/channels/<int:channel_id>/messages/<int:message_id>/ack", methods=["POST"])
|
||||||
|
async def ack_channel(channel_id, message_id):
|
||||||
|
"""Acknowledge a channel."""
|
||||||
|
user_id = await token_check()
|
||||||
|
ctype, guild_id = await channel_check(user_id, channel_id)
|
||||||
|
|
||||||
|
if ctype not in GUILD_CHANS:
|
||||||
|
guild_id = None
|
||||||
|
|
||||||
|
await channel_ack(user_id, channel_id, guild_id, message_id)
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
# token seems to be used for
|
||||||
|
# data collection activities,
|
||||||
|
# so we never use it.
|
||||||
|
"token": None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/read-states/ack-bulk", methods=["POST"])
|
||||||
|
async def bulk_ack():
|
||||||
|
"""Acknowledge multiple channels in a row"""
|
||||||
|
user_id = await token_check()
|
||||||
|
j = validate(await request.get_json(), BULK_ACK)
|
||||||
|
for ack_request in j:
|
||||||
|
channel_id, message_id = ack_request["channel_id"], ack_request["message_id"]
|
||||||
|
ctype, guild_id = await channel_check(user_id, channel_id)
|
||||||
|
if ctype not in GUILD_CHANS:
|
||||||
|
guild_id = None
|
||||||
|
|
||||||
|
await channel_ack(user_id, channel_id, guild_id, message_id)
|
||||||
|
|
||||||
|
# TODO: validate if this is the correct response
|
||||||
|
return "", 204
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/channels/<int:channel_id>/messages/ack", methods=["DELETE"])
|
||||||
|
async def delete_read_state(channel_id):
|
||||||
|
"""Delete the read state of a channel."""
|
||||||
|
user_id = await token_check()
|
||||||
|
try:
|
||||||
|
await channel_check(user_id, channel_id)
|
||||||
|
except GuildNotFound:
|
||||||
|
# ignore when guild isn't found because we're deleting the
|
||||||
|
# read state regardless.
|
||||||
|
pass
|
||||||
|
|
||||||
|
await app.db.execute(
|
||||||
|
"""
|
||||||
|
DELETE FROM user_read_state
|
||||||
|
WHERE user_id = $1 AND channel_id = $2
|
||||||
|
""",
|
||||||
|
user_id,
|
||||||
|
channel_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
return "", 204
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/guilds/<int:guild_id>/ack", methods=["POST"])
|
||||||
|
async def ack_guild(guild_id):
|
||||||
|
"""ACKnowledge all messages in the guild."""
|
||||||
|
user_id = await token_check()
|
||||||
|
await guild_check(user_id, guild_id)
|
||||||
|
|
||||||
|
chan_ids = await app.storage.get_channel_ids(guild_id)
|
||||||
|
|
||||||
|
for chan_id in chan_ids:
|
||||||
|
await channel_ack(user_id, chan_id, guild_id)
|
||||||
|
|
||||||
|
return "", 204
|
||||||
|
|
@ -27,7 +27,10 @@ from litecord.pubsub.user import dispatch_user
|
||||||
|
|
||||||
|
|
||||||
async def channel_ack(
|
async def channel_ack(
|
||||||
user_id: int, guild_id: int, channel_id: int, message_id: Optional[int] = None
|
user_id: int,
|
||||||
|
channel_id: int,
|
||||||
|
guild_id: Optional[int] = None,
|
||||||
|
message_id: Optional[int] = None,
|
||||||
):
|
):
|
||||||
"""ACK a channel."""
|
"""ACK a channel."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -619,3 +619,16 @@ BULK_DELETE = {
|
||||||
"schema": {"coerce": int},
|
"schema": {"coerce": int},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BULK_ACK = {
|
||||||
|
"read_states": {
|
||||||
|
"type": "list",
|
||||||
|
"required": True,
|
||||||
|
"minlength": 0,
|
||||||
|
"maxlength": 100,
|
||||||
|
"schema": {
|
||||||
|
"channel_id": {"coerce": int},
|
||||||
|
"message_id": {"coerce": int},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
2
run.py
2
run.py
|
|
@ -50,6 +50,7 @@ from litecord.blueprints import (
|
||||||
static,
|
static,
|
||||||
attachments,
|
attachments,
|
||||||
dm_channels,
|
dm_channels,
|
||||||
|
read_states,
|
||||||
)
|
)
|
||||||
|
|
||||||
# those blueprints are separated from the "main" ones
|
# those blueprints are separated from the "main" ones
|
||||||
|
|
@ -167,6 +168,7 @@ def set_blueprints(app_):
|
||||||
guilds_admin: "/admin/guilds",
|
guilds_admin: "/admin/guilds",
|
||||||
users_admin: "/admin/users",
|
users_admin: "/admin/users",
|
||||||
instance_invites: "/admin/instance/invites",
|
instance_invites: "/admin/instance/invites",
|
||||||
|
read_states: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
for bp, suffix in bps.items():
|
for bp, suffix in bps.items():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue