pull/133/head
stijndcl 2022-09-22 01:11:24 +02:00
parent 87caeec47b
commit 72415aeed0
5 changed files with 103 additions and 9 deletions

View File

@ -16,9 +16,10 @@ from didier.exceptions import expect
from didier.menus.bookmarks import BookmarkSource from didier.menus.bookmarks import BookmarkSource
from didier.menus.common import Menu from didier.menus.common import Menu
from didier.utils.discord import colours from didier.utils.discord import colours
from didier.utils.discord.assets import get_author_avatar from didier.utils.discord.assets import get_author_avatar, get_user_avatar
from didier.utils.discord.constants import Limits
from didier.utils.types.datetime import str_to_date from didier.utils.types.datetime import str_to_date
from didier.utils.types.string import leading from didier.utils.types.string import abbreviate, leading
from didier.views.modals import CreateBookmark from didier.views.modals import CreateBookmark
@ -204,9 +205,7 @@ class Discord(commands.Cog):
user = user or ctx.author user = user or ctx.author
embed = discord.Embed(colour=colours.github_white(), title="GitHub Links") embed = discord.Embed(colour=colours.github_white(), title="GitHub Links")
embed.set_author( embed.set_author(name=user.display_name, icon_url=get_user_avatar(user))
name=user.display_name, icon_url=user.avatar.url if user.avatar is not None else user.default_avatar.url
)
embed.set_footer(text="Links can be added using didier github add <link>.") embed.set_footer(text="Links can be added using didier github add <link>.")
@ -323,6 +322,39 @@ class Discord(commands.Cog):
await message.add_reaction("📌") await message.add_reaction("📌")
return await interaction.response.send_message("📌", ephemeral=True) return await interaction.response.send_message("📌", ephemeral=True)
@commands.hybrid_command(name="snipe")
async def snipe(self, ctx: commands.Context):
"""Publicly shame people when they edit or delete one of their messages.
Note that uncached messages will not be sniped.
"""
if ctx.guild is None:
return await ctx.reply("Snipe only works in servers.", mention_author=False, ephemeral=True)
sniped_data = self.client.sniped.get(ctx.channel.id, None)
if sniped_data is None:
return await ctx.reply(
"There's no one to make fun of in this channel.", mention_author=False, ephemeral=True
)
embed = discord.Embed(colour=discord.Colour.blue())
embed.set_author(name=sniped_data[0].author.display_name, icon_url=get_user_avatar(sniped_data[0].author))
if sniped_data[1] is not None:
embed.title = "Edit Snipe"
embed.add_field(
name="Before", value=abbreviate(sniped_data[0].content, Limits.EMBED_FIELD_VALUE_LENGTH), inline=False
)
embed.add_field(
name="After", value=abbreviate(sniped_data[1].content, Limits.EMBED_FIELD_VALUE_LENGTH), inline=False
)
else:
embed.title = "Delete Snipe"
embed.add_field(name="Message", value=sniped_data[0].content)
return await ctx.reply(embed=embed, mention_author=False)
async def setup(client: Didier): async def setup(client: Didier):
"""Load the cog""" """Load the cog"""

View File

@ -3,7 +3,7 @@ import os
import pathlib import pathlib
import re import re
from functools import cached_property from functools import cached_property
from typing import Union from typing import Union, Optional
import discord import discord
from aiohttp import ClientSession from aiohttp import ClientSession
@ -20,6 +20,7 @@ from didier.data.embeds.schedules import Schedule, parse_schedule
from didier.exceptions import HTTPException, NoMatch from didier.exceptions import HTTPException, NoMatch
from didier.utils.discord.prefix import get_prefix from didier.utils.discord.prefix import get_prefix
from didier.utils.easter_eggs import detect_easter_egg from didier.utils.easter_eggs import detect_easter_egg
from didier.utils.discord.snipe import should_snipe
from didier.utils.types.datetime import tz_aware_now from didier.utils.types.datetime import tz_aware_now
__all__ = ["Didier"] __all__ = ["Didier"]
@ -36,6 +37,7 @@ class Didier(commands.Bot):
initial_extensions: tuple[str, ...] = () initial_extensions: tuple[str, ...] = ()
http_session: ClientSession http_session: ClientSession
schedules: dict[settings.ScheduleType, Schedule] = {} schedules: dict[settings.ScheduleType, Schedule] = {}
sniped: dict[int, tuple[discord.Message, Optional[discord.Message]]] = {}
wordle_words: set[str] = set() wordle_words: set[str] = set()
def __init__(self): def __init__(self):
@ -335,6 +337,20 @@ class Didier(commands.Bot):
if easter_egg is not None: if easter_egg is not None:
await message.reply(easter_egg, mention_author=False) await message.reply(easter_egg, mention_author=False)
async def on_message_delete(self, message: discord.Message):
"""Event triggered when a message is deleted"""
if not should_snipe(message):
return
self.sniped[message.channel.id] = (message, None,)
async def on_message_edit(self, before: discord.Message, after: discord.Message):
"""Event triggered when a message is edited"""
if not should_snipe(before):
return
self.sniped[before.channel.id] = (before, after,)
async def on_ready(self): async def on_ready(self):
"""Event triggered when the bot is ready""" """Event triggered when the bot is ready"""
print(settings.DISCORD_READY_MESSAGE) print(settings.DISCORD_READY_MESSAGE)

View File

@ -3,10 +3,18 @@ from typing import Union
import discord import discord
from discord.ext import commands from discord.ext import commands
__all__ = ["get_author_avatar"] __all__ = ["get_author_avatar", "get_user_avatar"]
def get_user_avatar(user: Union[discord.User, discord.Member]) -> discord.Asset:
"""Get a user's avatar asset"""
if isinstance(user, discord.Member):
return user.display_avatar or user.default_avatar
return user.avatar or user.default_avatar
def get_author_avatar(ctx: Union[commands.Context, discord.Interaction]) -> discord.Asset: def get_author_avatar(ctx: Union[commands.Context, discord.Interaction]) -> discord.Asset:
"""Get a user's avatar asset""" """Get the avatar asset of a command author"""
author = ctx.author if isinstance(ctx, commands.Context) else ctx.user author = ctx.author if isinstance(ctx, commands.Context) else ctx.user
return author.avatar or author.default_avatar return get_user_avatar(author)

View File

@ -0,0 +1,19 @@
import discord
from didier.utils.regexes import STEAM_CODE
__all__ = ["should_snipe"]
def should_snipe(message: discord.Message) -> bool:
"""Check if a message should be sniped or not"""
# Don't snipe DM's
if message.guild is None:
return False
# Don't snipe bots
if message.author.bot:
return False
return not STEAM_CODE.is_in(message.content)

View File

@ -0,0 +1,19 @@
from typing import Union
from dataclasses import dataclass
import re
__all__ = ["STEAM_CODE"]
@dataclass
class Regex:
"""Dataclass for a type of pattern"""
pattern: str
flags: Union[int, re.RegexFlag] = 0
def is_in(self, text: str) -> bool:
"""Check if a match for a pattern can be found within a string"""
return re.search(self.pattern, text, self.flags) is not None
STEAM_CODE = Regex(pattern="[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}", flags=re.IGNORECASE)