Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/target
Cargo.lock
*.lock
.env
.st*
.st*
.DS_Store
.idea
52 changes: 52 additions & 0 deletions interactions/src/commands/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ async def message_plural_debug(
)
)])

@message_command(
name='/plu/ral delete',
contexts=InteractionContextType.ALL(),
integration_types=ApplicationIntegrationType.ALL())
async def message_plural_delete(
interaction: Interaction,
message: Message
) -> None:
await PAGES['delete'](interaction, message)

@message_command(
name='/plu/ral edit',
Expand Down Expand Up @@ -569,6 +578,49 @@ async def slash_delete_all_data(
await PAGES['delete_all_data'](interaction)


@slash_command(
name='delete',
description='Delete your most recent message',
contexts=InteractionContextType.ALL(),
integration_types=ApplicationIntegrationType.ALL()
)
async def slash_delete(
interaction: Interaction
) -> None:
db_message = await DBMessage.find_one(
{'user': (await interaction.get_usergroup()).id,
'channel_id': interaction.channel_id},
sort=[('ts', -1)]
)

if db_message is None:
raise InteractionError('No messages found to delete')

if db_message.interaction_token and db_message.expired:
raise InteractionError(
'No message found\n\n'
'Messages older than 15 minutes cannot be deleted'
)

try:
message = await (
Webhook.from_db_message(
db_message
).fetch_message(
db_message.proxy_id)
if db_message.interaction_token else
Message.fetch(
interaction.channel_id,
db_message.proxy_id))
except Forbidden as e:
raise InteractionError(
'Unable to read messages in this channel, please use the /plu/ral delete message command'
'\n\n(right-click on the message -> Apps -> /plu/ral delete)'
) from e

await PAGES['delete'](interaction, message)


@slash_command(
name='edit',
description='Edit your most recent message',
Expand Down
121 changes: 100 additions & 21 deletions interactions/src/commands/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import timedelta
from asyncio import gather
from typing import Any
from typing import Any, Never

from beanie import PydanticObjectId
from regex import (
Expand Down Expand Up @@ -271,10 +271,98 @@ async def edit_message(
)]
)

async def forbidden_error(
action: str,
*reasons: str,
src: Exception | None = None,
) -> Never:
if len(reasons) == 0:
reasons = (
'it is either not a /plu/ral message, older than 7 days, ',
'or you are not the author of the message',
)
if src is None:
raise InteractionError(
f"You cannot {action} this message, ",
*reasons
)
raise InteractionError(
f"You cannot {action} this message, ",
*reasons
) from src


async def can_delete(
interaction: Interaction,
message: Message,
) -> None:
db_message = await DBMessage.find_one({
'user': (await interaction.get_usergroup()).id,
'channel_id': interaction.channel_id,
'$or': [
{'original_id': message.id},
{'proxy_id': message.id}
]
})

if db_message is None:
await forbidden_error('delete')

match db_message.reason:
case 'Userproxy /proxy command' | 'Userproxy Reply command':
userproxy = await ProxyMember.find_one({
'userproxy.bot_id': message.author.id
})

if userproxy is None:
raise InteractionError('Userproxy not found')

usergroup = await interaction.get_usergroup()

group = await userproxy.get_group()

if not (
usergroup.id == group.account or
interaction.author_id in group.users
):
await forbidden_error(
'delete'
)

if not db_message.expired:
return

try:
await Channel.fetch(
message.channel_id,
userproxy.userproxy.token)
except HTTPException as e:
await forbidden_error(
'delete',
'Userproxy messages can be deleted normally',
src=e
)
case '/say command' if (
message.interaction_metadata and
message.interaction_metadata.user.id == interaction.author_id
):
return
case _ if message.webhook_id:
if message.webhook_id != db_message.webhook_id:
await forbidden_error(
'delete'
)
case _ if message.author.bot:
pass
case _:
await forbidden_error(
'delete'
)


async def can_edit(
interaction: Interaction,
message: Message
message: Message,
) -> None:
db_message = await DBMessage.find_one({
'user': (await interaction.get_usergroup()).id,
Expand All @@ -286,11 +374,7 @@ async def can_edit(
})

if db_message is None:
raise InteractionError(
'You cannot edit this message, '
'it is either not a /plu/ral message, older than 7 days, '
'or you are not the author of the message'
)
await forbidden_error('edit')

match db_message.reason:
case 'Userproxy /proxy command' | 'Userproxy Reply command':
Expand All @@ -309,10 +393,8 @@ async def can_edit(
usergroup.id == group.account or
interaction.author_id in group.users
):
raise InteractionError(
'You cannot edit this message, '
'it is either not a /plu/ral message, older than 7 days, '
'or you are not the author of the message'
await forbidden_error(
'edit'
)

if not db_message.expired:
Expand All @@ -323,11 +405,12 @@ async def can_edit(
message.channel_id,
userproxy.userproxy.token)
except HTTPException as e:
raise InteractionError(
'You cannot edit this message, '
await forbidden_error(
'edit',
'Userproxy messages can only be edited within 15 minutes'
' of sending them unless the userproxy bot is in the server'
) from e
' of sending them unless the userproxy bot is in the server',
src=e
)
case '/say command' if (
message.interaction_metadata and
message.interaction_metadata.user.id == interaction.author_id
Expand All @@ -337,16 +420,12 @@ async def can_edit(
if message.webhook_id != db_message.webhook_id:
raise InteractionError(
'You cannot edit this message, '
'it is either not a /plu/ral message, older than 7 days, '
'or you are not the author of the message'
)
case _ if message.author.bot:
pass
case _:
raise InteractionError(
'You cannot edit this message, '
'it is either not a /plu/ral message, older than 7 days, '
'or you are not the author of the message'
await forbidden_error(
'edit'
)


Expand Down
2 changes: 2 additions & 0 deletions interactions/src/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from .proxy import PAGES as PROXY_PAGES
from .help import PAGES as HELP_PAGES
from .base import PAGES as BASE_PAGES
from .delete import PAGES as DELETE_PAGES
from .edit import PAGES as EDIT_PAGES
from .api import PAGES as API_PAGES
from .bio import PAGES as BIO_PAGES
Expand All @@ -23,6 +24,7 @@
PROXY_PAGES |
HELP_PAGES |
BASE_PAGES |
DELETE_PAGES |
EDIT_PAGES |
API_PAGES |
BIO_PAGES |
Expand Down
50 changes: 50 additions & 0 deletions interactions/src/components/delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from plural.db import Message as DBMessage, redis

from src.commands.helpers import make_json_safe

from src.discord import (
Message,
Interaction
)


PAGES = {
'delete': lambda interaction, message: _delete(interaction, message)
}

async def _delete(
interaction: Interaction,
message: Message
) -> None:
from src.commands.helpers import can_delete

await can_delete(interaction, message)

db_message = await DBMessage.find_one({
'user': (await interaction.get_usergroup()).id,
'channel_id': interaction.channel_id,
'$or': [
{'original_id': message.id},
{'proxy_id': message.id}
]
})

if db_message is None:
raise RuntimeError(
'DBMessage not found but delete check passed.\n\n'
'this should never happen'
)

pipeline = redis.pipeline()
pipeline.json().set(
f'discord:pending_delete:{message.id}', '$',
make_json_safe(
message.model_dump(
mode='json',
exclude_defaults=True)))
pipeline.expire(f'discord:pending_delete:{message.id}', 900)
await pipeline.execute()

await message.delete()

await interaction.response.ack()