From a9e808d15e3be5791acd0adadb0277f57cca20be Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Tue, 21 Jan 2020 02:45:09 +0200 Subject: [PATCH 01/17] Add birthday cog --- __init__.py | 6 ++ birthday.py | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++ info.json | 26 ++++-- 3 files changed, 286 insertions(+), 6 deletions(-) create mode 100644 __init__.py create mode 100644 birthday.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..c3a667d --- /dev/null +++ b/__init__.py @@ -0,0 +1,6 @@ + +from .birthday import Birthdays + + +def setup(bot): + bot.add_cog(Birthdays(bot)) diff --git a/birthday.py b/birthday.py new file mode 100644 index 0000000..a78a8f3 --- /dev/null +++ b/birthday.py @@ -0,0 +1,260 @@ +import logging +import hashlib +import asyncio +import contextlib +import datetime +import discord +import itertools + +from redbot.core import commands, Config, checks +from redbot.core.bot import Red +from redbot.core.config import Group +from redbot.core.i18n import Translator, cog_i18n +from redbot.core.commands import Context, Cog + +T_ = Translator("Birthdays", __file__) + +def _(s): + def func(*args, **kwargs): + real_args = list(args) + real_args.pop(0) + return T_(s).format(*real_args, **kwargs) + return func + +@cog_i18n(T_) +class Birthdays(Cog): + """Announces people's birthdays and gives them a birthday role for the whole day""" + __author__ = "PancakeSparkle#8243" + + # Just some constants + DATE_GROUP = "DATE" + GUILD_DATE_GROUP = "GUILD_DATE" + + # More constants + BDAY_LIST_TITLE = _("Birthday List") + + # Even more constants + BDAY_WITH_YEAR = _("<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>") + BDAY_WITHOUT_YEAR = _("Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>") + ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") + BDAY_INVALID = _(":x: The birthday date you entered is invalid. It must be `MM-DD`.") + BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") + CHANNEL_SET = _("<:aureliaagree:616091883013144586> " + "The channel for announcing birthdays on **{g}** has been set to: **{c}**.") + BDAY_REMOVED = _(":put_litter_in_its_place: Your birthday has been removed.") + + + def __init__(self, bot): + super().__init__() + self.bot = bot + self.logger = logging.getLogger("aurelia.cogs.birthdays") + unique_id = int(hashlib.sha512((self.__author__ + "@" + self.__class__.__name__).encode()).hexdigest(), 16) + self.config = Config.get_conf(self, identifier=unique_id) + self.config.init_custom(self.DATE_GROUP, 1) + self.config.init_custom(self.GUILD_DATE_GROUP, 2) + self.config.register_guild(channel=None, role=None, yesterdays=[]) + self.bday_loop = asyncio.ensure_future(self.initialise()) + asyncio.ensure_future(self.check_breaking_change()) + + # Events + async def initialise(self): + await self.bot.wait_until_ready() + with contextlib.suppress(RuntimeError): + while self == self.bot.get_cog(self.__class__.__name__): + now = datetime.datetime.utcnow() + tomorrow = (now + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0) + await asyncio.sleep((tomorrow - now).total_seconds()) + await self.clean_yesterday_bdays() + await self.do_today_bdays() + + def cog_unload(self): + self.bday_loop.cancel() + + # Commands + @commands.group() + @commands.guild_only() + async def bday(self, ctx: Context): + """Birthday settings""" + pass + + @bday.command(name="channel") + @checks.mod_or_permissions(manage_roles=True) + async def bday_channel(self, ctx: Context, channel: discord.TextChannel): + """Sets the birthday announcement channel""" + message = ctx.message + guild = message.guild + await self.config.guild(channel.guild).channel.set(channel.id) + await message.channel.send(self.CHANNEL_SET(g=guild.name, c=channel.name)) + + @bday.command(name="role") + @checks.mod_or_permissions(manage_roles=True) + async def bday_role(self, ctx: Context, role: discord.Role): + """Sets the birthday role""" + message = ctx.message + guild = message.guild + await self.config.guild(role.guild).role.set(role.id) + await message.channel.send(self.ROLE_SET(g=guild.name, r=role.name)) + + @bday.command(name="remove", aliases=["del", "clear", "rm"]) + async def bday_remove(self, ctx: Context): + """Unsets your birthday date""" + message = ctx.message + await self.remove_user_bday(message.guild.id, message.author.id) + await message.channel.send(self.BDAY_REMOVED()) + + @bday.command(name="set") + async def bday_set(self, ctx: Context, date, year: int=None): + """Sets your birthday date + + The given date must be given as: MM-DD + Year is optional. If not given, the age won't be displayed.""" + message = ctx.message + channel = message.channel + author = message.author + birthday = self.parse_date(date) + if birthday is None: + print(self.BDAY_INVALID()) + await channel.send(self.BDAY_INVALID()) + + else: + await self.remove_user_bday(message.guild.id, author.id) + await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) + bday_month_str = birthday.strftime("%B") + bday_day_str = birthday.strftime("%d").lstrip("0") + await channel.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) + + @bday.command(name="list") + async def bday_list(self, ctx: Context): + """Lists birthdays + + If a user has their year set, it will display the age they'll get after their birthday this year""" + message = ctx.message + await self.clean_bdays() + bdays = await self.get_guild_date_configs(message.guild.id) + this_year = datetime.date.today().year + embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) + for k, g in itertools.groupby(sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), + lambda i: i.month): + + value = "\n".join(date.strftime("%d").lstrip("0") + ": " + + ", ".join("<@!{}>".format(u_id) + + ("" if year is None else " ({})".format(this_year - int(year))) + for u_id, year in bdays.get(str(date.toordinal()), {}).items()) + for date in g if len(bdays.get(str(date.toordinal()))) > 0) + if not value.isspace(): + embed.add_field(name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value) + await message.channel.send(embed=embed) + + async def clean_bday(self, guild_id: int, guild_config: dict, user_id: int): + guild = self.bot.get_guild(guild_id) + if guild is not None: + role = discord.utils.get(guild.roles, id=guild_config.get("role")) + + await self.maybe_update_guild(guild) + member = guild.get_member(user_id) + if member is not None and role is not None and role in member.roles: + + await member.remove_roles(role) + + async def handle_bday(self, user_id: int, year: str): + embed = discord.Embed(color=discord.Colour.gold()) + if year is not None: + age = datetime.date.today().year - int(year) + embed.description = self.BDAY_WITH_YEAR(user_id, age) + else: + embed.description = self.BDAY_WITHOUT_YEAR(user_id) + all_guild_configs = await self.config.all_guilds() + for guild_id, guild_config in all_guild_configs.items(): + guild = self.bot.get_guild(guild_id) + if guild is not None: + member = guild.get_member(user_id) + if member is not None: + role_id = guild_config.get("role") + if role_id is not None: + role = discord.utils.get(guild.roles, id=role_id) + if role is not None: + try: + await member.add_roles(role) + except (discord.Forbidden, discord.HTTPException): + pass + else: + async with self.config.guild(guild).yesterdays() as yesterdays: + yesterdays.append(member.id) + channel = guild.get_channel(guild_config.get("channel")) + if channel is not None: + await channel.send(embed=embed) + + async def clean_bdays(self): + birthdays = await self.get_all_date_configs() + for guild_id, guild_bdays in birthdays.items(): + for date, bdays in guild_bdays.items(): + for user_id, year in bdays.items(): + if not any(g.get_member(int(user_id)) is not None for g in self.bot.guilds): + async with self.get_date_config(guild_id, date)() as config_bdays: + del config_bdays[user_id] + config_bdays = await self.get_date_config(guild_id, date)() + if len(config_bdays) == 0: + await self.get_date_config(guild_id, date).clear() + + async def remove_user_bday(self, guild_id: int, user_id: int): + user_id = str(user_id) + birthdays = await self.get_guild_date_configs(guild_id) + for date, user_ids in birthdays.items(): + if user_id in user_ids: + await self.get_date_config(guild_id, date).get_attr(user_id).clear() + + + async def clean_yesterday_bdays(self): + all_guild_configs = await self.config.all_guilds() + for guild_id, guild_config in all_guild_configs.items(): + for user_id in guild_config.get("yesterdays", []): + asyncio.ensure_future(self.clean_bday(guild_id, guild_config, user_id)) + await self.config.guild(discord.Guild(data={"id": guild_id}, state=None)).yesterdays.clear() + + async def do_today_bdays(self): + guild_configs = await self.get_all_date_configs() + for guild_id, guild_config in guild_configs.items(): + this_date = datetime.datetime.utcnow().date().replace(year=1) + todays_bday_config = guild_config.get(str(this_date.toordinal()), {}) + for user_id, year in todays_bday_config.items(): + asyncio.ensure_future(self.handle_bday(int(user_id), year)) + + async def maybe_update_guild(self, guild: discord.Guild): + if not guild.unavailable and guild.large: + if not guild.chunked or any(m.joined_at is None for m in guild.members): + await self.bot.request_offline_members(guild) + + def parse_date(self, date_str: str): + result = None + try: + result = datetime.datetime.strptime(date_str, "%m-%d").date().replace(year=1) + except ValueError: + pass + return result + + async def check_breaking_change(self): + await self.bot.wait_until_ready() + previous = await self.config.custom(self.DATE_GROUP).all() + if len(previous) > 0: + await self.config.custom(self.DATE_GROUP).clear() + owner = self.bot.get_user(self.bot.owner_id) + if len(self.bot.guilds) == 1: + await self.get_guild_date_config(self.bot.guilds[0].id).set_raw(value=previous) + self.logger.info("Birthdays are now per-guild. Previous birthdays have been copied.") + else: + await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw(value=previous) + self.logger.info("Previous birthdays have been backed up in the config file.") + + + + def get_date_config(self, guild_id: int, date: int) -> Group: + return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id), str(date)) + + def get_guild_date_config(self, guild_id: int) -> Group: + return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id)) + + async def get_guild_date_configs(self, guild_id: int) -> dict: + return await self.get_guild_date_config(guild_id).all() + + async def get_all_date_configs(self) -> dict: + return await self.config.custom(self.GUILD_DATE_GROUP).all() diff --git a/info.json b/info.json index 7373ee6..7702487 100644 --- a/info.json +++ b/info.json @@ -1,7 +1,21 @@ { - "AUTHOR": "Brandons209", - "INSTALL_MSG": "Thank you for using my cogs! Have fun!", - "NAME": "Brandon-V3", - "SHORT": "Cogs by Brandons209", - "DESCRIPTION": "Cogs for Red-Discord Bot by Brandons209" -} + "author": [ + "PancakeSparkle" + + ], + "bot_version": [ + 3, + 0, + 0 + ], + "description": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", + "hidden": false, + "install_msg": "Use [p]bday to bring up the help menu", + "requirements": [], + "short": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", + "tags": [ + "brandons209", + "pancakesparkle", + "punish" + ] + } \ No newline at end of file From 2385c7886feee80eb689901a12152bbf35dc0a83 Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Tue, 21 Jan 2020 03:11:51 +0200 Subject: [PATCH 02/17] Add files via upload --- birthday/__init__.py | 6 + birthday/birthday.py | 260 +++++++++++++++++++++++++++++++++++++++++++ birthday/info.json | 21 ++++ 3 files changed, 287 insertions(+) create mode 100644 birthday/__init__.py create mode 100644 birthday/birthday.py create mode 100644 birthday/info.json diff --git a/birthday/__init__.py b/birthday/__init__.py new file mode 100644 index 0000000..c3a667d --- /dev/null +++ b/birthday/__init__.py @@ -0,0 +1,6 @@ + +from .birthday import Birthdays + + +def setup(bot): + bot.add_cog(Birthdays(bot)) diff --git a/birthday/birthday.py b/birthday/birthday.py new file mode 100644 index 0000000..a78a8f3 --- /dev/null +++ b/birthday/birthday.py @@ -0,0 +1,260 @@ +import logging +import hashlib +import asyncio +import contextlib +import datetime +import discord +import itertools + +from redbot.core import commands, Config, checks +from redbot.core.bot import Red +from redbot.core.config import Group +from redbot.core.i18n import Translator, cog_i18n +from redbot.core.commands import Context, Cog + +T_ = Translator("Birthdays", __file__) + +def _(s): + def func(*args, **kwargs): + real_args = list(args) + real_args.pop(0) + return T_(s).format(*real_args, **kwargs) + return func + +@cog_i18n(T_) +class Birthdays(Cog): + """Announces people's birthdays and gives them a birthday role for the whole day""" + __author__ = "PancakeSparkle#8243" + + # Just some constants + DATE_GROUP = "DATE" + GUILD_DATE_GROUP = "GUILD_DATE" + + # More constants + BDAY_LIST_TITLE = _("Birthday List") + + # Even more constants + BDAY_WITH_YEAR = _("<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>") + BDAY_WITHOUT_YEAR = _("Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>") + ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") + BDAY_INVALID = _(":x: The birthday date you entered is invalid. It must be `MM-DD`.") + BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") + CHANNEL_SET = _("<:aureliaagree:616091883013144586> " + "The channel for announcing birthdays on **{g}** has been set to: **{c}**.") + BDAY_REMOVED = _(":put_litter_in_its_place: Your birthday has been removed.") + + + def __init__(self, bot): + super().__init__() + self.bot = bot + self.logger = logging.getLogger("aurelia.cogs.birthdays") + unique_id = int(hashlib.sha512((self.__author__ + "@" + self.__class__.__name__).encode()).hexdigest(), 16) + self.config = Config.get_conf(self, identifier=unique_id) + self.config.init_custom(self.DATE_GROUP, 1) + self.config.init_custom(self.GUILD_DATE_GROUP, 2) + self.config.register_guild(channel=None, role=None, yesterdays=[]) + self.bday_loop = asyncio.ensure_future(self.initialise()) + asyncio.ensure_future(self.check_breaking_change()) + + # Events + async def initialise(self): + await self.bot.wait_until_ready() + with contextlib.suppress(RuntimeError): + while self == self.bot.get_cog(self.__class__.__name__): + now = datetime.datetime.utcnow() + tomorrow = (now + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0) + await asyncio.sleep((tomorrow - now).total_seconds()) + await self.clean_yesterday_bdays() + await self.do_today_bdays() + + def cog_unload(self): + self.bday_loop.cancel() + + # Commands + @commands.group() + @commands.guild_only() + async def bday(self, ctx: Context): + """Birthday settings""" + pass + + @bday.command(name="channel") + @checks.mod_or_permissions(manage_roles=True) + async def bday_channel(self, ctx: Context, channel: discord.TextChannel): + """Sets the birthday announcement channel""" + message = ctx.message + guild = message.guild + await self.config.guild(channel.guild).channel.set(channel.id) + await message.channel.send(self.CHANNEL_SET(g=guild.name, c=channel.name)) + + @bday.command(name="role") + @checks.mod_or_permissions(manage_roles=True) + async def bday_role(self, ctx: Context, role: discord.Role): + """Sets the birthday role""" + message = ctx.message + guild = message.guild + await self.config.guild(role.guild).role.set(role.id) + await message.channel.send(self.ROLE_SET(g=guild.name, r=role.name)) + + @bday.command(name="remove", aliases=["del", "clear", "rm"]) + async def bday_remove(self, ctx: Context): + """Unsets your birthday date""" + message = ctx.message + await self.remove_user_bday(message.guild.id, message.author.id) + await message.channel.send(self.BDAY_REMOVED()) + + @bday.command(name="set") + async def bday_set(self, ctx: Context, date, year: int=None): + """Sets your birthday date + + The given date must be given as: MM-DD + Year is optional. If not given, the age won't be displayed.""" + message = ctx.message + channel = message.channel + author = message.author + birthday = self.parse_date(date) + if birthday is None: + print(self.BDAY_INVALID()) + await channel.send(self.BDAY_INVALID()) + + else: + await self.remove_user_bday(message.guild.id, author.id) + await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) + bday_month_str = birthday.strftime("%B") + bday_day_str = birthday.strftime("%d").lstrip("0") + await channel.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) + + @bday.command(name="list") + async def bday_list(self, ctx: Context): + """Lists birthdays + + If a user has their year set, it will display the age they'll get after their birthday this year""" + message = ctx.message + await self.clean_bdays() + bdays = await self.get_guild_date_configs(message.guild.id) + this_year = datetime.date.today().year + embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) + for k, g in itertools.groupby(sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), + lambda i: i.month): + + value = "\n".join(date.strftime("%d").lstrip("0") + ": " + + ", ".join("<@!{}>".format(u_id) + + ("" if year is None else " ({})".format(this_year - int(year))) + for u_id, year in bdays.get(str(date.toordinal()), {}).items()) + for date in g if len(bdays.get(str(date.toordinal()))) > 0) + if not value.isspace(): + embed.add_field(name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value) + await message.channel.send(embed=embed) + + async def clean_bday(self, guild_id: int, guild_config: dict, user_id: int): + guild = self.bot.get_guild(guild_id) + if guild is not None: + role = discord.utils.get(guild.roles, id=guild_config.get("role")) + + await self.maybe_update_guild(guild) + member = guild.get_member(user_id) + if member is not None and role is not None and role in member.roles: + + await member.remove_roles(role) + + async def handle_bday(self, user_id: int, year: str): + embed = discord.Embed(color=discord.Colour.gold()) + if year is not None: + age = datetime.date.today().year - int(year) + embed.description = self.BDAY_WITH_YEAR(user_id, age) + else: + embed.description = self.BDAY_WITHOUT_YEAR(user_id) + all_guild_configs = await self.config.all_guilds() + for guild_id, guild_config in all_guild_configs.items(): + guild = self.bot.get_guild(guild_id) + if guild is not None: + member = guild.get_member(user_id) + if member is not None: + role_id = guild_config.get("role") + if role_id is not None: + role = discord.utils.get(guild.roles, id=role_id) + if role is not None: + try: + await member.add_roles(role) + except (discord.Forbidden, discord.HTTPException): + pass + else: + async with self.config.guild(guild).yesterdays() as yesterdays: + yesterdays.append(member.id) + channel = guild.get_channel(guild_config.get("channel")) + if channel is not None: + await channel.send(embed=embed) + + async def clean_bdays(self): + birthdays = await self.get_all_date_configs() + for guild_id, guild_bdays in birthdays.items(): + for date, bdays in guild_bdays.items(): + for user_id, year in bdays.items(): + if not any(g.get_member(int(user_id)) is not None for g in self.bot.guilds): + async with self.get_date_config(guild_id, date)() as config_bdays: + del config_bdays[user_id] + config_bdays = await self.get_date_config(guild_id, date)() + if len(config_bdays) == 0: + await self.get_date_config(guild_id, date).clear() + + async def remove_user_bday(self, guild_id: int, user_id: int): + user_id = str(user_id) + birthdays = await self.get_guild_date_configs(guild_id) + for date, user_ids in birthdays.items(): + if user_id in user_ids: + await self.get_date_config(guild_id, date).get_attr(user_id).clear() + + + async def clean_yesterday_bdays(self): + all_guild_configs = await self.config.all_guilds() + for guild_id, guild_config in all_guild_configs.items(): + for user_id in guild_config.get("yesterdays", []): + asyncio.ensure_future(self.clean_bday(guild_id, guild_config, user_id)) + await self.config.guild(discord.Guild(data={"id": guild_id}, state=None)).yesterdays.clear() + + async def do_today_bdays(self): + guild_configs = await self.get_all_date_configs() + for guild_id, guild_config in guild_configs.items(): + this_date = datetime.datetime.utcnow().date().replace(year=1) + todays_bday_config = guild_config.get(str(this_date.toordinal()), {}) + for user_id, year in todays_bday_config.items(): + asyncio.ensure_future(self.handle_bday(int(user_id), year)) + + async def maybe_update_guild(self, guild: discord.Guild): + if not guild.unavailable and guild.large: + if not guild.chunked or any(m.joined_at is None for m in guild.members): + await self.bot.request_offline_members(guild) + + def parse_date(self, date_str: str): + result = None + try: + result = datetime.datetime.strptime(date_str, "%m-%d").date().replace(year=1) + except ValueError: + pass + return result + + async def check_breaking_change(self): + await self.bot.wait_until_ready() + previous = await self.config.custom(self.DATE_GROUP).all() + if len(previous) > 0: + await self.config.custom(self.DATE_GROUP).clear() + owner = self.bot.get_user(self.bot.owner_id) + if len(self.bot.guilds) == 1: + await self.get_guild_date_config(self.bot.guilds[0].id).set_raw(value=previous) + self.logger.info("Birthdays are now per-guild. Previous birthdays have been copied.") + else: + await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw(value=previous) + self.logger.info("Previous birthdays have been backed up in the config file.") + + + + def get_date_config(self, guild_id: int, date: int) -> Group: + return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id), str(date)) + + def get_guild_date_config(self, guild_id: int) -> Group: + return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id)) + + async def get_guild_date_configs(self, guild_id: int) -> dict: + return await self.get_guild_date_config(guild_id).all() + + async def get_all_date_configs(self) -> dict: + return await self.config.custom(self.GUILD_DATE_GROUP).all() diff --git a/birthday/info.json b/birthday/info.json new file mode 100644 index 0000000..7702487 --- /dev/null +++ b/birthday/info.json @@ -0,0 +1,21 @@ +{ + "author": [ + "PancakeSparkle" + + ], + "bot_version": [ + 3, + 0, + 0 + ], + "description": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", + "hidden": false, + "install_msg": "Use [p]bday to bring up the help menu", + "requirements": [], + "short": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", + "tags": [ + "brandons209", + "pancakesparkle", + "punish" + ] + } \ No newline at end of file From 282d14e33a5dd570ca886c530e5415534745e597 Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Tue, 21 Jan 2020 03:13:09 +0200 Subject: [PATCH 03/17] Delete __init__.py --- __init__.py | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 __init__.py diff --git a/__init__.py b/__init__.py deleted file mode 100644 index c3a667d..0000000 --- a/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ - -from .birthday import Birthdays - - -def setup(bot): - bot.add_cog(Birthdays(bot)) From 1835dd968e749eec5de7ce7dde2190edee997d3b Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Tue, 21 Jan 2020 03:13:33 +0200 Subject: [PATCH 04/17] Delete birthday.py --- birthday.py | 260 ---------------------------------------------------- 1 file changed, 260 deletions(-) delete mode 100644 birthday.py diff --git a/birthday.py b/birthday.py deleted file mode 100644 index a78a8f3..0000000 --- a/birthday.py +++ /dev/null @@ -1,260 +0,0 @@ -import logging -import hashlib -import asyncio -import contextlib -import datetime -import discord -import itertools - -from redbot.core import commands, Config, checks -from redbot.core.bot import Red -from redbot.core.config import Group -from redbot.core.i18n import Translator, cog_i18n -from redbot.core.commands import Context, Cog - -T_ = Translator("Birthdays", __file__) - -def _(s): - def func(*args, **kwargs): - real_args = list(args) - real_args.pop(0) - return T_(s).format(*real_args, **kwargs) - return func - -@cog_i18n(T_) -class Birthdays(Cog): - """Announces people's birthdays and gives them a birthday role for the whole day""" - __author__ = "PancakeSparkle#8243" - - # Just some constants - DATE_GROUP = "DATE" - GUILD_DATE_GROUP = "GUILD_DATE" - - # More constants - BDAY_LIST_TITLE = _("Birthday List") - - # Even more constants - BDAY_WITH_YEAR = _("<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>") - BDAY_WITHOUT_YEAR = _("Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>") - ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") - BDAY_INVALID = _(":x: The birthday date you entered is invalid. It must be `MM-DD`.") - BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") - CHANNEL_SET = _("<:aureliaagree:616091883013144586> " - "The channel for announcing birthdays on **{g}** has been set to: **{c}**.") - BDAY_REMOVED = _(":put_litter_in_its_place: Your birthday has been removed.") - - - def __init__(self, bot): - super().__init__() - self.bot = bot - self.logger = logging.getLogger("aurelia.cogs.birthdays") - unique_id = int(hashlib.sha512((self.__author__ + "@" + self.__class__.__name__).encode()).hexdigest(), 16) - self.config = Config.get_conf(self, identifier=unique_id) - self.config.init_custom(self.DATE_GROUP, 1) - self.config.init_custom(self.GUILD_DATE_GROUP, 2) - self.config.register_guild(channel=None, role=None, yesterdays=[]) - self.bday_loop = asyncio.ensure_future(self.initialise()) - asyncio.ensure_future(self.check_breaking_change()) - - # Events - async def initialise(self): - await self.bot.wait_until_ready() - with contextlib.suppress(RuntimeError): - while self == self.bot.get_cog(self.__class__.__name__): - now = datetime.datetime.utcnow() - tomorrow = (now + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0) - await asyncio.sleep((tomorrow - now).total_seconds()) - await self.clean_yesterday_bdays() - await self.do_today_bdays() - - def cog_unload(self): - self.bday_loop.cancel() - - # Commands - @commands.group() - @commands.guild_only() - async def bday(self, ctx: Context): - """Birthday settings""" - pass - - @bday.command(name="channel") - @checks.mod_or_permissions(manage_roles=True) - async def bday_channel(self, ctx: Context, channel: discord.TextChannel): - """Sets the birthday announcement channel""" - message = ctx.message - guild = message.guild - await self.config.guild(channel.guild).channel.set(channel.id) - await message.channel.send(self.CHANNEL_SET(g=guild.name, c=channel.name)) - - @bday.command(name="role") - @checks.mod_or_permissions(manage_roles=True) - async def bday_role(self, ctx: Context, role: discord.Role): - """Sets the birthday role""" - message = ctx.message - guild = message.guild - await self.config.guild(role.guild).role.set(role.id) - await message.channel.send(self.ROLE_SET(g=guild.name, r=role.name)) - - @bday.command(name="remove", aliases=["del", "clear", "rm"]) - async def bday_remove(self, ctx: Context): - """Unsets your birthday date""" - message = ctx.message - await self.remove_user_bday(message.guild.id, message.author.id) - await message.channel.send(self.BDAY_REMOVED()) - - @bday.command(name="set") - async def bday_set(self, ctx: Context, date, year: int=None): - """Sets your birthday date - - The given date must be given as: MM-DD - Year is optional. If not given, the age won't be displayed.""" - message = ctx.message - channel = message.channel - author = message.author - birthday = self.parse_date(date) - if birthday is None: - print(self.BDAY_INVALID()) - await channel.send(self.BDAY_INVALID()) - - else: - await self.remove_user_bday(message.guild.id, author.id) - await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) - bday_month_str = birthday.strftime("%B") - bday_day_str = birthday.strftime("%d").lstrip("0") - await channel.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) - - @bday.command(name="list") - async def bday_list(self, ctx: Context): - """Lists birthdays - - If a user has their year set, it will display the age they'll get after their birthday this year""" - message = ctx.message - await self.clean_bdays() - bdays = await self.get_guild_date_configs(message.guild.id) - this_year = datetime.date.today().year - embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) - for k, g in itertools.groupby(sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), - lambda i: i.month): - - value = "\n".join(date.strftime("%d").lstrip("0") + ": " - + ", ".join("<@!{}>".format(u_id) - + ("" if year is None else " ({})".format(this_year - int(year))) - for u_id, year in bdays.get(str(date.toordinal()), {}).items()) - for date in g if len(bdays.get(str(date.toordinal()))) > 0) - if not value.isspace(): - embed.add_field(name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value) - await message.channel.send(embed=embed) - - async def clean_bday(self, guild_id: int, guild_config: dict, user_id: int): - guild = self.bot.get_guild(guild_id) - if guild is not None: - role = discord.utils.get(guild.roles, id=guild_config.get("role")) - - await self.maybe_update_guild(guild) - member = guild.get_member(user_id) - if member is not None and role is not None and role in member.roles: - - await member.remove_roles(role) - - async def handle_bday(self, user_id: int, year: str): - embed = discord.Embed(color=discord.Colour.gold()) - if year is not None: - age = datetime.date.today().year - int(year) - embed.description = self.BDAY_WITH_YEAR(user_id, age) - else: - embed.description = self.BDAY_WITHOUT_YEAR(user_id) - all_guild_configs = await self.config.all_guilds() - for guild_id, guild_config in all_guild_configs.items(): - guild = self.bot.get_guild(guild_id) - if guild is not None: - member = guild.get_member(user_id) - if member is not None: - role_id = guild_config.get("role") - if role_id is not None: - role = discord.utils.get(guild.roles, id=role_id) - if role is not None: - try: - await member.add_roles(role) - except (discord.Forbidden, discord.HTTPException): - pass - else: - async with self.config.guild(guild).yesterdays() as yesterdays: - yesterdays.append(member.id) - channel = guild.get_channel(guild_config.get("channel")) - if channel is not None: - await channel.send(embed=embed) - - async def clean_bdays(self): - birthdays = await self.get_all_date_configs() - for guild_id, guild_bdays in birthdays.items(): - for date, bdays in guild_bdays.items(): - for user_id, year in bdays.items(): - if not any(g.get_member(int(user_id)) is not None for g in self.bot.guilds): - async with self.get_date_config(guild_id, date)() as config_bdays: - del config_bdays[user_id] - config_bdays = await self.get_date_config(guild_id, date)() - if len(config_bdays) == 0: - await self.get_date_config(guild_id, date).clear() - - async def remove_user_bday(self, guild_id: int, user_id: int): - user_id = str(user_id) - birthdays = await self.get_guild_date_configs(guild_id) - for date, user_ids in birthdays.items(): - if user_id in user_ids: - await self.get_date_config(guild_id, date).get_attr(user_id).clear() - - - async def clean_yesterday_bdays(self): - all_guild_configs = await self.config.all_guilds() - for guild_id, guild_config in all_guild_configs.items(): - for user_id in guild_config.get("yesterdays", []): - asyncio.ensure_future(self.clean_bday(guild_id, guild_config, user_id)) - await self.config.guild(discord.Guild(data={"id": guild_id}, state=None)).yesterdays.clear() - - async def do_today_bdays(self): - guild_configs = await self.get_all_date_configs() - for guild_id, guild_config in guild_configs.items(): - this_date = datetime.datetime.utcnow().date().replace(year=1) - todays_bday_config = guild_config.get(str(this_date.toordinal()), {}) - for user_id, year in todays_bday_config.items(): - asyncio.ensure_future(self.handle_bday(int(user_id), year)) - - async def maybe_update_guild(self, guild: discord.Guild): - if not guild.unavailable and guild.large: - if not guild.chunked or any(m.joined_at is None for m in guild.members): - await self.bot.request_offline_members(guild) - - def parse_date(self, date_str: str): - result = None - try: - result = datetime.datetime.strptime(date_str, "%m-%d").date().replace(year=1) - except ValueError: - pass - return result - - async def check_breaking_change(self): - await self.bot.wait_until_ready() - previous = await self.config.custom(self.DATE_GROUP).all() - if len(previous) > 0: - await self.config.custom(self.DATE_GROUP).clear() - owner = self.bot.get_user(self.bot.owner_id) - if len(self.bot.guilds) == 1: - await self.get_guild_date_config(self.bot.guilds[0].id).set_raw(value=previous) - self.logger.info("Birthdays are now per-guild. Previous birthdays have been copied.") - else: - await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw(value=previous) - self.logger.info("Previous birthdays have been backed up in the config file.") - - - - def get_date_config(self, guild_id: int, date: int) -> Group: - return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id), str(date)) - - def get_guild_date_config(self, guild_id: int) -> Group: - return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id)) - - async def get_guild_date_configs(self, guild_id: int) -> dict: - return await self.get_guild_date_config(guild_id).all() - - async def get_all_date_configs(self) -> dict: - return await self.config.custom(self.GUILD_DATE_GROUP).all() From 5bd5c7bb0ab4bdd4c85d75ba5cc8d2bb1f099b46 Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Tue, 21 Jan 2020 03:13:46 +0200 Subject: [PATCH 05/17] Delete info.json --- info.json | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 info.json diff --git a/info.json b/info.json deleted file mode 100644 index 7702487..0000000 --- a/info.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "author": [ - "PancakeSparkle" - - ], - "bot_version": [ - 3, - 0, - 0 - ], - "description": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", - "hidden": false, - "install_msg": "Use [p]bday to bring up the help menu", - "requirements": [], - "short": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", - "tags": [ - "brandons209", - "pancakesparkle", - "punish" - ] - } \ No newline at end of file From 14309cd5c5c76a2693999efadcfef97f1f5163e8 Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Tue, 21 Jan 2020 03:15:06 +0200 Subject: [PATCH 06/17] Add files via upload --- info.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 info.json diff --git a/info.json b/info.json new file mode 100644 index 0000000..7373ee6 --- /dev/null +++ b/info.json @@ -0,0 +1,7 @@ +{ + "AUTHOR": "Brandons209", + "INSTALL_MSG": "Thank you for using my cogs! Have fun!", + "NAME": "Brandon-V3", + "SHORT": "Cogs by Brandons209", + "DESCRIPTION": "Cogs for Red-Discord Bot by Brandons209" +} From 58c1f67186861e12bc62340381652c6dfade3427 Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Tue, 21 Jan 2020 06:03:58 +0200 Subject: [PATCH 07/17] Add files via upload --- birthday/info.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/birthday/info.json b/birthday/info.json index 7702487..c940915 100644 --- a/birthday/info.json +++ b/birthday/info.json @@ -15,7 +15,7 @@ "short": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", "tags": [ "brandons209", - "pancakesparkle", - "punish" + "pancakesparkle" + ] - } \ No newline at end of file + } From 3ae6922070215c8c1109943f16ce2aa477a3ce5b Mon Sep 17 00:00:00 2001 From: brandons209 Date: Wed, 22 Jan 2020 13:45:24 -0500 Subject: [PATCH 08/17] cleaned up some stuff, fixed adding roles with spaces --- birthday/__init__.py | 2 -- birthday/birthday.py | 3 +-- birthday/info.json | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/birthday/__init__.py b/birthday/__init__.py index c3a667d..311a728 100644 --- a/birthday/__init__.py +++ b/birthday/__init__.py @@ -1,6 +1,4 @@ - from .birthday import Birthdays - def setup(bot): bot.add_cog(Birthdays(bot)) diff --git a/birthday/birthday.py b/birthday/birthday.py index a78a8f3..1dfdd1e 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -88,7 +88,7 @@ class Birthdays(Cog): @bday.command(name="role") @checks.mod_or_permissions(manage_roles=True) - async def bday_role(self, ctx: Context, role: discord.Role): + async def bday_role(self, ctx: Context, *, role: discord.Role): """Sets the birthday role""" message = ctx.message guild = message.guild @@ -115,7 +115,6 @@ class Birthdays(Cog): if birthday is None: print(self.BDAY_INVALID()) await channel.send(self.BDAY_INVALID()) - else: await self.remove_user_bday(message.guild.id, author.id) await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) diff --git a/birthday/info.json b/birthday/info.json index c940915..40b4468 100644 --- a/birthday/info.json +++ b/birthday/info.json @@ -1,7 +1,7 @@ { "author": [ "PancakeSparkle" - + ], "bot_version": [ 3, @@ -16,6 +16,5 @@ "tags": [ "brandons209", "pancakesparkle" - ] } From 79509db4e8ce3d49fae8b515730b9c773b867593 Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Sat, 8 Feb 2020 00:20:10 +0200 Subject: [PATCH 09/17] edited some files with new,changed formatting --- birthday/__init__.py | 1 + birthday/birthday.py | 43 +++++++++++++++++++++++++++---------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/birthday/__init__.py b/birthday/__init__.py index 311a728..3c30a9c 100644 --- a/birthday/__init__.py +++ b/birthday/__init__.py @@ -1,4 +1,5 @@ from .birthday import Birthdays + def setup(bot): bot.add_cog(Birthdays(bot)) diff --git a/birthday/birthday.py b/birthday/birthday.py index 1dfdd1e..7b79f7c 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -6,6 +6,7 @@ import datetime import discord import itertools + from redbot.core import commands, Config, checks from redbot.core.bot import Red from redbot.core.config import Group @@ -14,16 +15,20 @@ from redbot.core.commands import Context, Cog T_ = Translator("Birthdays", __file__) + def _(s): def func(*args, **kwargs): real_args = list(args) real_args.pop(0) return T_(s).format(*real_args, **kwargs) + return func + @cog_i18n(T_) class Birthdays(Cog): """Announces people's birthdays and gives them a birthday role for the whole day""" + __author__ = "PancakeSparkle#8243" # Just some constants @@ -39,10 +44,12 @@ class Birthdays(Cog): ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") BDAY_INVALID = _(":x: The birthday date you entered is invalid. It must be `MM-DD`.") BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") - CHANNEL_SET = _("<:aureliaagree:616091883013144586> " - "The channel for announcing birthdays on **{g}** has been set to: **{c}**.") + CHANNEL_SET = _( + "<:aureliaagree:616091883013144586> " + "The channel for announcing birthdays on **{g}** has been set to: **{c}**." + ) BDAY_REMOVED = _(":put_litter_in_its_place: Your birthday has been removed.") - + BDAY_DM = _(":tada: Aurelia wishes you a very happy birthday! :tada:") def __init__(self, bot): super().__init__() @@ -63,9 +70,9 @@ class Birthdays(Cog): while self == self.bot.get_cog(self.__class__.__name__): now = datetime.datetime.utcnow() tomorrow = (now + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0) - await asyncio.sleep((tomorrow - now).total_seconds()) await self.clean_yesterday_bdays() await self.do_today_bdays() + await asyncio.sleep((tomorrow - now).total_seconds()) def cog_unload(self): self.bday_loop.cancel() @@ -103,7 +110,7 @@ class Birthdays(Cog): await message.channel.send(self.BDAY_REMOVED()) @bday.command(name="set") - async def bday_set(self, ctx: Context, date, year: int=None): + async def bday_set(self, ctx: Context, date, year: int = None): """Sets your birthday date The given date must be given as: MM-DD @@ -117,7 +124,7 @@ class Birthdays(Cog): await channel.send(self.BDAY_INVALID()) else: await self.remove_user_bday(message.guild.id, author.id) - await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) + await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id) bday_month_str = birthday.strftime("%B") bday_day_str = birthday.strftime("%d").lstrip("0") await channel.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) @@ -132,14 +139,20 @@ class Birthdays(Cog): bdays = await self.get_guild_date_configs(message.guild.id) this_year = datetime.date.today().year embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) - for k, g in itertools.groupby(sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), - lambda i: i.month): + for k, g in itertools.groupby( + sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), lambda i: i.month + ): - value = "\n".join(date.strftime("%d").lstrip("0") + ": " - + ", ".join("<@!{}>".format(u_id) - + ("" if year is None else " ({})".format(this_year - int(year))) - for u_id, year in bdays.get(str(date.toordinal()), {}).items()) - for date in g if len(bdays.get(str(date.toordinal()))) > 0) + value = "\n".join( + date.strftime("%d").lstrip("0") + + ": " + + ", ".join( + "<@!{}>".format(u_id) + ("" if year is None else " ({})".format(this_year - int(year))) + for u_id, year in bdays.get(str(date.toordinal()), {}).items() + ) + for date in g + if len(bdays.get(str(date.toordinal()))) > 0 + ) if not value.isspace(): embed.add_field(name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value) await message.channel.send(embed=embed) @@ -182,6 +195,7 @@ class Birthdays(Cog): channel = guild.get_channel(guild_config.get("channel")) if channel is not None: await channel.send(embed=embed) + await member.send(self.BDAY_DM()) async def clean_bdays(self): birthdays = await self.get_all_date_configs() @@ -202,7 +216,6 @@ class Birthdays(Cog): if user_id in user_ids: await self.get_date_config(guild_id, date).get_attr(user_id).clear() - async def clean_yesterday_bdays(self): all_guild_configs = await self.config.all_guilds() for guild_id, guild_config in all_guild_configs.items(): @@ -244,8 +257,6 @@ class Birthdays(Cog): await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw(value=previous) self.logger.info("Previous birthdays have been backed up in the config file.") - - def get_date_config(self, guild_id: int, date: int) -> Group: return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id), str(date)) From 3bef65a7f331bce235b5338961d2e54d59fb64a1 Mon Sep 17 00:00:00 2001 From: Sydney Date: Sun, 9 Feb 2020 23:15:05 -0500 Subject: [PATCH 10/17] Fix broken async and await calls --- birthday/birthday.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/birthday/birthday.py b/birthday/birthday.py index 7b79f7c..970e465 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -5,11 +5,15 @@ import contextlib import datetime import discord import itertools +from typing import ( + Any, + Dict, +) from redbot.core import commands, Config, checks from redbot.core.bot import Red -from redbot.core.config import Group +from redbot.core.config import _ValueCtxManager, Group, Value from redbot.core.i18n import Translator, cog_i18n from redbot.core.commands import Context, Cog @@ -124,9 +128,10 @@ class Birthdays(Cog): await channel.send(self.BDAY_INVALID()) else: await self.remove_user_bday(message.guild.id, author.id) - await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id) + self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id) bday_month_str = birthday.strftime("%B") bday_day_str = birthday.strftime("%d").lstrip("0") + await channel.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) @bday.command(name="list") @@ -257,14 +262,14 @@ class Birthdays(Cog): await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw(value=previous) self.logger.info("Previous birthdays have been backed up in the config file.") - def get_date_config(self, guild_id: int, date: int) -> Group: + def get_date_config(self, guild_id: int, date: int): return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id), str(date)) - def get_guild_date_config(self, guild_id: int) -> Group: + def get_guild_date_config(self, guild_id: int): return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id)) - async def get_guild_date_configs(self, guild_id: int) -> dict: - return await self.get_guild_date_config(guild_id).all() + async def get_guild_date_configs(self, guild_id: int) -> _ValueCtxManager[Dict[str, Any]]: + return (await self.get_guild_date_config(guild_id).all()) - async def get_all_date_configs(self) -> dict: - return await self.config.custom(self.GUILD_DATE_GROUP).all() + def get_all_date_configs(self): + return self.config.custom(self.GUILD_DATE_GROUP).all() From d603811ac2453617b32347db43e96edb25dc1207 Mon Sep 17 00:00:00 2001 From: Sydney Date: Wed, 12 Feb 2020 01:34:06 -0500 Subject: [PATCH 11/17] Use parser.parse instead of datetime.datetime.strptime --- birthday/birthday.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/birthday/birthday.py b/birthday/birthday.py index 970e465..9463b7d 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -2,6 +2,7 @@ import logging import hashlib import asyncio import contextlib +from dateutil import parser import datetime import discord import itertools @@ -46,7 +47,7 @@ class Birthdays(Cog): BDAY_WITH_YEAR = _("<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>") BDAY_WITHOUT_YEAR = _("Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>") ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") - BDAY_INVALID = _(":x: The birthday date you entered is invalid. It must be `MM-DD`.") + BDAY_INVALID = _(":x: The birthday date you entered is invalid.") BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") CHANNEL_SET = _( "<:aureliaagree:616091883013144586> " @@ -114,21 +115,27 @@ class Birthdays(Cog): await message.channel.send(self.BDAY_REMOVED()) @bday.command(name="set") - async def bday_set(self, ctx: Context, date, year: int = None): + async def bday_set(self, ctx: Context, *, date: str): """Sets your birthday date - The given date must be given as: MM-DD + The given date can either be month day, or day month Year is optional. If not given, the age won't be displayed.""" message = ctx.message channel = message.channel author = message.author + year = None birthday = self.parse_date(date) + # An Invalid date was entered. if birthday is None: print(self.BDAY_INVALID()) await channel.send(self.BDAY_INVALID()) else: + print(type(birthday)) + if(datetime.datetime.utcnow().year != birthday.year): + year = birthday.year + birthday = datetime.date(1, birthday.month, birthday.day) await self.remove_user_bday(message.guild.id, author.id) - self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id) + await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) bday_month_str = birthday.strftime("%B") bday_day_str = birthday.strftime("%d").lstrip("0") @@ -241,10 +248,10 @@ class Birthdays(Cog): if not guild.chunked or any(m.joined_at is None for m in guild.members): await self.bot.request_offline_members(guild) - def parse_date(self, date_str: str): + def parse_date(self, date: str): result = None try: - result = datetime.datetime.strptime(date_str, "%m-%d").date().replace(year=1) + result = parser.parse(date) except ValueError: pass return result From b00d00b37026d5f16c1f18d5cf996b78475db1e0 Mon Sep 17 00:00:00 2001 From: Sydney Date: Wed, 12 Feb 2020 01:43:25 -0500 Subject: [PATCH 12/17] Reformat to make Black happy (hopefully) --- birthday/birthday.py | 86 ++++++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/birthday/birthday.py b/birthday/birthday.py index 9463b7d..87525b7 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -44,11 +44,19 @@ class Birthdays(Cog): BDAY_LIST_TITLE = _("Birthday List") # Even more constants - BDAY_WITH_YEAR = _("<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>") - BDAY_WITHOUT_YEAR = _("Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>") - ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") + BDAY_WITH_YEAR = _( + "<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>" + ) + BDAY_WITHOUT_YEAR = _( + "Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>" + ) + ROLE_SET = _( + "<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**." + ) BDAY_INVALID = _(":x: The birthday date you entered is invalid.") - BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") + BDAY_SET = _( + "<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**." + ) CHANNEL_SET = _( "<:aureliaagree:616091883013144586> " "The channel for announcing birthdays on **{g}** has been set to: **{c}**." @@ -60,7 +68,12 @@ class Birthdays(Cog): super().__init__() self.bot = bot self.logger = logging.getLogger("aurelia.cogs.birthdays") - unique_id = int(hashlib.sha512((self.__author__ + "@" + self.__class__.__name__).encode()).hexdigest(), 16) + unique_id = int( + hashlib.sha512( + (self.__author__ + "@" + self.__class__.__name__).encode() + ).hexdigest(), + 16, + ) self.config = Config.get_conf(self, identifier=unique_id) self.config.init_custom(self.DATE_GROUP, 1) self.config.init_custom(self.GUILD_DATE_GROUP, 2) @@ -74,7 +87,9 @@ class Birthdays(Cog): with contextlib.suppress(RuntimeError): while self == self.bot.get_cog(self.__class__.__name__): now = datetime.datetime.utcnow() - tomorrow = (now + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0) + tomorrow = (now + datetime.timedelta(days=1)).replace( + hour=0, minute=0, second=0, microsecond=0 + ) await self.clean_yesterday_bdays() await self.do_today_bdays() await asyncio.sleep((tomorrow - now).total_seconds()) @@ -131,11 +146,13 @@ class Birthdays(Cog): await channel.send(self.BDAY_INVALID()) else: print(type(birthday)) - if(datetime.datetime.utcnow().year != birthday.year): + if datetime.datetime.utcnow().year != birthday.year: year = birthday.year birthday = datetime.date(1, birthday.month, birthday.day) await self.remove_user_bday(message.guild.id, author.id) - await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) + await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr( + author.id + ).set(year) bday_month_str = birthday.strftime("%B") bday_day_str = birthday.strftime("%d").lstrip("0") @@ -150,23 +167,30 @@ class Birthdays(Cog): await self.clean_bdays() bdays = await self.get_guild_date_configs(message.guild.id) this_year = datetime.date.today().year - embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) + embed = discord.Embed( + title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey() + ) for k, g in itertools.groupby( - sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), lambda i: i.month + sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), + lambda i: i.month, ): value = "\n".join( date.strftime("%d").lstrip("0") + ": " + ", ".join( - "<@!{}>".format(u_id) + ("" if year is None else " ({})".format(this_year - int(year))) + "<@!{}>".format(u_id) + + ("" if year is None else " ({})".format(this_year - int(year))) for u_id, year in bdays.get(str(date.toordinal()), {}).items() ) for date in g if len(bdays.get(str(date.toordinal()))) > 0 ) if not value.isspace(): - embed.add_field(name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value) + embed.add_field( + name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), + value=value, + ) await message.channel.send(embed=embed) async def clean_bday(self, guild_id: int, guild_config: dict, user_id: int): @@ -202,7 +226,9 @@ class Birthdays(Cog): except (discord.Forbidden, discord.HTTPException): pass else: - async with self.config.guild(guild).yesterdays() as yesterdays: + async with self.config.guild( + guild + ).yesterdays() as yesterdays: yesterdays.append(member.id) channel = guild.get_channel(guild_config.get("channel")) if channel is not None: @@ -214,8 +240,12 @@ class Birthdays(Cog): for guild_id, guild_bdays in birthdays.items(): for date, bdays in guild_bdays.items(): for user_id, year in bdays.items(): - if not any(g.get_member(int(user_id)) is not None for g in self.bot.guilds): - async with self.get_date_config(guild_id, date)() as config_bdays: + if not any( + g.get_member(int(user_id)) is not None for g in self.bot.guilds + ): + async with self.get_date_config( + guild_id, date + )() as config_bdays: del config_bdays[user_id] config_bdays = await self.get_date_config(guild_id, date)() if len(config_bdays) == 0: @@ -233,7 +263,9 @@ class Birthdays(Cog): for guild_id, guild_config in all_guild_configs.items(): for user_id in guild_config.get("yesterdays", []): asyncio.ensure_future(self.clean_bday(guild_id, guild_config, user_id)) - await self.config.guild(discord.Guild(data={"id": guild_id}, state=None)).yesterdays.clear() + await self.config.guild( + discord.Guild(data={"id": guild_id}, state=None) + ).yesterdays.clear() async def do_today_bdays(self): guild_configs = await self.get_all_date_configs() @@ -263,11 +295,19 @@ class Birthdays(Cog): await self.config.custom(self.DATE_GROUP).clear() owner = self.bot.get_user(self.bot.owner_id) if len(self.bot.guilds) == 1: - await self.get_guild_date_config(self.bot.guilds[0].id).set_raw(value=previous) - self.logger.info("Birthdays are now per-guild. Previous birthdays have been copied.") + await self.get_guild_date_config(self.bot.guilds[0].id).set_raw( + value=previous + ) + self.logger.info( + "Birthdays are now per-guild. Previous birthdays have been copied." + ) else: - await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw(value=previous) - self.logger.info("Previous birthdays have been backed up in the config file.") + await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw( + value=previous + ) + self.logger.info( + "Previous birthdays have been backed up in the config file." + ) def get_date_config(self, guild_id: int, date: int): return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id), str(date)) @@ -275,8 +315,10 @@ class Birthdays(Cog): def get_guild_date_config(self, guild_id: int): return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id)) - async def get_guild_date_configs(self, guild_id: int) -> _ValueCtxManager[Dict[str, Any]]: - return (await self.get_guild_date_config(guild_id).all()) + async def get_guild_date_configs( + self, guild_id: int + ) -> _ValueCtxManager[Dict[str, Any]]: + return await self.get_guild_date_config(guild_id).all() def get_all_date_configs(self): return self.config.custom(self.GUILD_DATE_GROUP).all() From 6c471cff2451bd13e1d1adbdefab36fa920036c6 Mon Sep 17 00:00:00 2001 From: PancakeSparkle Date: Wed, 12 Feb 2020 08:53:43 +0200 Subject: [PATCH 13/17] fucking black, work already --- birthday/birthday.py | 80 +++++++++++--------------------------------- 1 file changed, 20 insertions(+), 60 deletions(-) diff --git a/birthday/birthday.py b/birthday/birthday.py index 87525b7..2bb88c1 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -44,19 +44,11 @@ class Birthdays(Cog): BDAY_LIST_TITLE = _("Birthday List") # Even more constants - BDAY_WITH_YEAR = _( - "<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>" - ) - BDAY_WITHOUT_YEAR = _( - "Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>" - ) - ROLE_SET = _( - "<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**." - ) + BDAY_WITH_YEAR = _("<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>") + BDAY_WITHOUT_YEAR = _("Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>") + ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") BDAY_INVALID = _(":x: The birthday date you entered is invalid.") - BDAY_SET = _( - "<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**." - ) + BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") CHANNEL_SET = _( "<:aureliaagree:616091883013144586> " "The channel for announcing birthdays on **{g}** has been set to: **{c}**." @@ -68,12 +60,7 @@ class Birthdays(Cog): super().__init__() self.bot = bot self.logger = logging.getLogger("aurelia.cogs.birthdays") - unique_id = int( - hashlib.sha512( - (self.__author__ + "@" + self.__class__.__name__).encode() - ).hexdigest(), - 16, - ) + unique_id = int(hashlib.sha512((self.__author__ + "@" + self.__class__.__name__).encode()).hexdigest(), 16,) self.config = Config.get_conf(self, identifier=unique_id) self.config.init_custom(self.DATE_GROUP, 1) self.config.init_custom(self.GUILD_DATE_GROUP, 2) @@ -87,9 +74,7 @@ class Birthdays(Cog): with contextlib.suppress(RuntimeError): while self == self.bot.get_cog(self.__class__.__name__): now = datetime.datetime.utcnow() - tomorrow = (now + datetime.timedelta(days=1)).replace( - hour=0, minute=0, second=0, microsecond=0 - ) + tomorrow = (now + datetime.timedelta(days=1)).replace(hour=0, minute=0, second=0, microsecond=0) await self.clean_yesterday_bdays() await self.do_today_bdays() await asyncio.sleep((tomorrow - now).total_seconds()) @@ -150,9 +135,7 @@ class Birthdays(Cog): year = birthday.year birthday = datetime.date(1, birthday.month, birthday.day) await self.remove_user_bday(message.guild.id, author.id) - await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr( - author.id - ).set(year) + await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) bday_month_str = birthday.strftime("%B") bday_day_str = birthday.strftime("%d").lstrip("0") @@ -167,20 +150,16 @@ class Birthdays(Cog): await self.clean_bdays() bdays = await self.get_guild_date_configs(message.guild.id) this_year = datetime.date.today().year - embed = discord.Embed( - title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey() - ) + embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) for k, g in itertools.groupby( - sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), - lambda i: i.month, + sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), lambda i: i.month, ): value = "\n".join( date.strftime("%d").lstrip("0") + ": " + ", ".join( - "<@!{}>".format(u_id) - + ("" if year is None else " ({})".format(this_year - int(year))) + "<@!{}>".format(u_id) + ("" if year is None else " ({})".format(this_year - int(year))) for u_id, year in bdays.get(str(date.toordinal()), {}).items() ) for date in g @@ -188,8 +167,7 @@ class Birthdays(Cog): ) if not value.isspace(): embed.add_field( - name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), - value=value, + name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value, ) await message.channel.send(embed=embed) @@ -226,9 +204,7 @@ class Birthdays(Cog): except (discord.Forbidden, discord.HTTPException): pass else: - async with self.config.guild( - guild - ).yesterdays() as yesterdays: + async with self.config.guild(guild).yesterdays() as yesterdays: yesterdays.append(member.id) channel = guild.get_channel(guild_config.get("channel")) if channel is not None: @@ -240,12 +216,8 @@ class Birthdays(Cog): for guild_id, guild_bdays in birthdays.items(): for date, bdays in guild_bdays.items(): for user_id, year in bdays.items(): - if not any( - g.get_member(int(user_id)) is not None for g in self.bot.guilds - ): - async with self.get_date_config( - guild_id, date - )() as config_bdays: + if not any(g.get_member(int(user_id)) is not None for g in self.bot.guilds): + async with self.get_date_config(guild_id, date)() as config_bdays: del config_bdays[user_id] config_bdays = await self.get_date_config(guild_id, date)() if len(config_bdays) == 0: @@ -263,9 +235,7 @@ class Birthdays(Cog): for guild_id, guild_config in all_guild_configs.items(): for user_id in guild_config.get("yesterdays", []): asyncio.ensure_future(self.clean_bday(guild_id, guild_config, user_id)) - await self.config.guild( - discord.Guild(data={"id": guild_id}, state=None) - ).yesterdays.clear() + await self.config.guild(discord.Guild(data={"id": guild_id}, state=None)).yesterdays.clear() async def do_today_bdays(self): guild_configs = await self.get_all_date_configs() @@ -295,19 +265,11 @@ class Birthdays(Cog): await self.config.custom(self.DATE_GROUP).clear() owner = self.bot.get_user(self.bot.owner_id) if len(self.bot.guilds) == 1: - await self.get_guild_date_config(self.bot.guilds[0].id).set_raw( - value=previous - ) - self.logger.info( - "Birthdays are now per-guild. Previous birthdays have been copied." - ) + await self.get_guild_date_config(self.bot.guilds[0].id).set_raw(value=previous) + self.logger.info("Birthdays are now per-guild. Previous birthdays have been copied.") else: - await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw( - value=previous - ) - self.logger.info( - "Previous birthdays have been backed up in the config file." - ) + await self.config.custom(self.GUILD_DATE_GROUP, "backup").set_raw(value=previous) + self.logger.info("Previous birthdays have been backed up in the config file.") def get_date_config(self, guild_id: int, date: int): return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id), str(date)) @@ -315,9 +277,7 @@ class Birthdays(Cog): def get_guild_date_config(self, guild_id: int): return self.config.custom(self.GUILD_DATE_GROUP, str(guild_id)) - async def get_guild_date_configs( - self, guild_id: int - ) -> _ValueCtxManager[Dict[str, Any]]: + async def get_guild_date_configs(self, guild_id: int) -> _ValueCtxManager[Dict[str, Any]]: return await self.get_guild_date_config(guild_id).all() def get_all_date_configs(self): From 04bb7f13e0536dea83958e47ba0bec34ad9536c9 Mon Sep 17 00:00:00 2001 From: Sydney Date: Wed, 12 Feb 2020 02:04:07 -0500 Subject: [PATCH 14/17] Add "python-dateutil" as requirement --- birthday/info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birthday/info.json b/birthday/info.json index 40b4468..659586e 100644 --- a/birthday/info.json +++ b/birthday/info.json @@ -11,7 +11,7 @@ "description": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", "hidden": false, "install_msg": "Use [p]bday to bring up the help menu", - "requirements": [], + "requirements": ["python-dateutil"], "short": "Cog used for setting birthdays and announcing them and giving people roles on their birthday", "tags": [ "brandons209", From f454fbc37e0d18dd464591b4dc74616a6134d615 Mon Sep 17 00:00:00 2001 From: Sydney Date: Sun, 16 Feb 2020 20:31:30 -0500 Subject: [PATCH 15/17] Add all changes except for config additions --- birthday/birthday.py | 117 ++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 41 deletions(-) diff --git a/birthday/birthday.py b/birthday/birthday.py index 2bb88c1..3afc82f 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -44,8 +44,8 @@ class Birthdays(Cog): BDAY_LIST_TITLE = _("Birthday List") # Even more constants - BDAY_WITH_YEAR = _("<@!{}> is now **{} years old**. <:aureliahappy:548738609763713035>") - BDAY_WITHOUT_YEAR = _("Everypony say Happy Hirthday to <@!{}>! <:aureliahappy:548738609763713035>") + BDAY_WITH_YEAR = _("{} is now **{} years old**. <:aureliahappy:548738609763713035>") + BDAY_WITHOUT_YEAR = _("Everypony say Happy Birthday to {}! <:aureliahappy:548738609763713035>") ROLE_SET = _("<:aureliaagree:616091883013144586> The birthday role on **{g}** has been set to: **{r}**.") BDAY_INVALID = _(":x: The birthday date you entered is invalid.") BDAY_SET = _("<:aureliaagree:616091883013144586> Your birthday has been set to: **{}**.") @@ -54,7 +54,7 @@ class Birthdays(Cog): "The channel for announcing birthdays on **{g}** has been set to: **{c}**." ) BDAY_REMOVED = _(":put_litter_in_its_place: Your birthday has been removed.") - BDAY_DM = _(":tada: Aurelia wishes you a very happy birthday! :tada:") + BDAY_DM_DEFAULT = _(":tada: Aurelia wishes you a very happy birthday! :tada:") def __init__(self, bot): super().__init__() @@ -65,8 +65,8 @@ class Birthdays(Cog): self.config.init_custom(self.DATE_GROUP, 1) self.config.init_custom(self.GUILD_DATE_GROUP, 2) self.config.register_guild(channel=None, role=None, yesterdays=[]) - self.bday_loop = asyncio.ensure_future(self.initialise()) - asyncio.ensure_future(self.check_breaking_change()) + self.bday_loop = asyncio.create_task(self.initialise()) + asyncio.create_task(self.check_breaking_change()) # Events async def initialise(self): @@ -89,57 +89,86 @@ class Birthdays(Cog): """Birthday settings""" pass - @bday.command(name="channel") - @checks.mod_or_permissions(manage_roles=True) - async def bday_channel(self, ctx: Context, channel: discord.TextChannel): - """Sets the birthday announcement channel""" - message = ctx.message - guild = message.guild - await self.config.guild(channel.guild).channel.set(channel.id) - await message.channel.send(self.CHANNEL_SET(g=guild.name, c=channel.name)) - - @bday.command(name="role") - @checks.mod_or_permissions(manage_roles=True) - async def bday_role(self, ctx: Context, *, role: discord.Role): - """Sets the birthday role""" - message = ctx.message - guild = message.guild - await self.config.guild(role.guild).role.set(role.id) - await message.channel.send(self.ROLE_SET(g=guild.name, r=role.name)) - @bday.command(name="remove", aliases=["del", "clear", "rm"]) async def bday_remove(self, ctx: Context): """Unsets your birthday date""" message = ctx.message await self.remove_user_bday(message.guild.id, message.author.id) - await message.channel.send(self.BDAY_REMOVED()) + await ctx.send(self.BDAY_REMOVED()) - @bday.command(name="set") - async def bday_set(self, ctx: Context, *, date: str): + @bday.group(name="set") + async def bday_set(self, ctx: Context): + """Changes settings for your birthday!""" + pass + + @bday_set.command(name="birthday") + async def bday_set_birthday(self, ctx: Context, *, date: str): """Sets your birthday date The given date can either be month day, or day month Year is optional. If not given, the age won't be displayed.""" message = ctx.message - channel = message.channel author = message.author year = None birthday = self.parse_date(date) + today = datetime.datetime.utcnow().date() # An Invalid date was entered. if birthday is None: print(self.BDAY_INVALID()) - await channel.send(self.BDAY_INVALID()) + await ctx.send(self.BDAY_INVALID()) + # TODO: Properly implement a check to read the config to see if today's date is the date already set. + # else if birthday.toordinal() == today.toordinal(): + # await ctx.send("Your birthday is already set to {g} {c}!".format(birthday.strftime("%B"), birthday.strftime("%d").lstrip("0")))) + # return else: - print(type(birthday)) - if datetime.datetime.utcnow().year != birthday.year: + if today.year != birthday.year: + if birthday.year > today.year: + await ctx.send("You weren't born in the future, silly!") + return + if birthday.year < (today.year - 100): + await ctx.send("No way you're that old, silly!") + return year = birthday.year birthday = datetime.date(1, birthday.month, birthday.day) await self.remove_user_bday(message.guild.id, author.id) await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) bday_month_str = birthday.strftime("%B") bday_day_str = birthday.strftime("%d").lstrip("0") + await ctx.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) + # Check if today is their birthday + if today.replace(year=1).toordinal() == birthday.replace(year=1).toordinal(): + await self.handle_bday(self, author.id, year) - await channel.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) + @bday_set.command(name="message") + async def bday_set_message(self, ctx: Context, *, bday_message: str = ""): + """Sets your birthday message. + + It can be any message that you want! This message will be sent + via Direct Message. Set to nothing to clear. Emotes from other + servers are not supported!""" + message = ctx.message + author = message.author + # TODO: implement saving to config. + if bday_message == "": + await ctx.send("Your birthday message is now set to the default message.") + else: + await ctx.send("Birthday message set to: " + str(bday_message)) + + @bday_set.command(name="channel") + @checks.mod_or_permissions(manage_roles=True) + async def bday_set_channel(self, ctx: Context, channel: discord.TextChannel): + """Sets the birthday announcement channel""" + guild = ctx.guild + await self.config.guild(channel.guild).channel.set(channel.id) + await ctx.send(self.CHANNEL_SET(g=guild.name, c=channel.name)) + + @bday_set.command(name="role") + @checks.mod_or_permissions(manage_roles=True) + async def bday_set_role(self, ctx: Context, *, role: discord.Role): + """Sets the birthday role""" + guild = ctx.message.guild + await self.config.guild(role.guild).role.set(role.id) + await ctx.send(self.ROLE_SET(g=guild.name, r=role.name)) @bday.command(name="list") async def bday_list(self, ctx: Context): @@ -159,7 +188,8 @@ class Birthdays(Cog): date.strftime("%d").lstrip("0") + ": " + ", ".join( - "<@!{}>".format(u_id) + ("" if year is None else " ({})".format(this_year - int(year))) + "{}".format(ctx.guild.get_member(user_id)) + + ("" if year is None else " ({})".format(this_year - int(year))) for u_id, year in bdays.get(str(date.toordinal()), {}).items() ) for date in g @@ -169,7 +199,7 @@ class Birthdays(Cog): embed.add_field( name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value, ) - await message.channel.send(embed=embed) + await ctx.send(embed=embed) async def clean_bday(self, guild_id: int, guild_config: dict, user_id: int): guild = self.bot.get_guild(guild_id) @@ -184,11 +214,6 @@ class Birthdays(Cog): async def handle_bday(self, user_id: int, year: str): embed = discord.Embed(color=discord.Colour.gold()) - if year is not None: - age = datetime.date.today().year - int(year) - embed.description = self.BDAY_WITH_YEAR(user_id, age) - else: - embed.description = self.BDAY_WITHOUT_YEAR(user_id) all_guild_configs = await self.config.all_guilds() for guild_id, guild_config in all_guild_configs.items(): guild = self.bot.get_guild(guild_id) @@ -196,6 +221,11 @@ class Birthdays(Cog): member = guild.get_member(user_id) if member is not None: role_id = guild_config.get("role") + if year is not None: + age = datetime.date.today().year - int(year) + embed.description = self.BDAY_WITH_YEAR(member.mention, age) + else: + embed.description = self.BDAY_WITHOUT_YEAR(member.mention) if role_id is not None: role = discord.utils.get(guild.roles, id=role_id) if role is not None: @@ -209,7 +239,12 @@ class Birthdays(Cog): channel = guild.get_channel(guild_config.get("channel")) if channel is not None: await channel.send(embed=embed) - await member.send(self.BDAY_DM()) + # TODO: Actually get the custom message from config. + custom_message = None + if custom_message is None: + await member.send(self.BDAY_DM()) + else: + await member.send(custom_message) async def clean_bdays(self): birthdays = await self.get_all_date_configs() @@ -234,7 +269,7 @@ class Birthdays(Cog): all_guild_configs = await self.config.all_guilds() for guild_id, guild_config in all_guild_configs.items(): for user_id in guild_config.get("yesterdays", []): - asyncio.ensure_future(self.clean_bday(guild_id, guild_config, user_id)) + asyncio.create_task(self.clean_bday(guild_id, guild_config, user_id)) await self.config.guild(discord.Guild(data={"id": guild_id}, state=None)).yesterdays.clear() async def do_today_bdays(self): @@ -243,7 +278,7 @@ class Birthdays(Cog): this_date = datetime.datetime.utcnow().date().replace(year=1) todays_bday_config = guild_config.get(str(this_date.toordinal()), {}) for user_id, year in todays_bday_config.items(): - asyncio.ensure_future(self.handle_bday(int(user_id), year)) + asyncio.create_task(self.handle_bday(int(user_id), year)) async def maybe_update_guild(self, guild: discord.Guild): if not guild.unavailable and guild.large: From c2e2606587e365a6d81dd7d4adc5fd4071f26647 Mon Sep 17 00:00:00 2001 From: Sydney Date: Sun, 16 Feb 2020 21:58:23 -0500 Subject: [PATCH 16/17] Implement same day birthday checking, along with custom dm message --- birthday/birthday.py | 88 ++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/birthday/birthday.py b/birthday/birthday.py index 3afc82f..f52412d 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -54,7 +54,6 @@ class Birthdays(Cog): "The channel for announcing birthdays on **{g}** has been set to: **{c}**." ) BDAY_REMOVED = _(":put_litter_in_its_place: Your birthday has been removed.") - BDAY_DM_DEFAULT = _(":tada: Aurelia wishes you a very happy birthday! :tada:") def __init__(self, bot): super().__init__() @@ -64,7 +63,9 @@ class Birthdays(Cog): self.config = Config.get_conf(self, identifier=unique_id) self.config.init_custom(self.DATE_GROUP, 1) self.config.init_custom(self.GUILD_DATE_GROUP, 2) - self.config.register_guild(channel=None, role=None, yesterdays=[]) + self.config.register_guild( + channel=None, role=None, dmmessage=":tada: Aurelia wishes you a very happy birthday! :tada:", yesterdays=[] + ) self.bday_loop = asyncio.create_task(self.initialise()) asyncio.create_task(self.check_breaking_change()) @@ -112,47 +113,47 @@ class Birthdays(Cog): year = None birthday = self.parse_date(date) today = datetime.datetime.utcnow().date() + current_birthday = await self.get_birthday(ctx.guild.id, author.id) # An Invalid date was entered. if birthday is None: print(self.BDAY_INVALID()) await ctx.send(self.BDAY_INVALID()) - # TODO: Properly implement a check to read the config to see if today's date is the date already set. - # else if birthday.toordinal() == today.toordinal(): - # await ctx.send("Your birthday is already set to {g} {c}!".format(birthday.strftime("%B"), birthday.strftime("%d").lstrip("0")))) - # return - else: - if today.year != birthday.year: - if birthday.year > today.year: - await ctx.send("You weren't born in the future, silly!") - return - if birthday.year < (today.year - 100): - await ctx.send("No way you're that old, silly!") - return - year = birthday.year - birthday = datetime.date(1, birthday.month, birthday.day) - await self.remove_user_bday(message.guild.id, author.id) - await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) - bday_month_str = birthday.strftime("%B") - bday_day_str = birthday.strftime("%d").lstrip("0") - await ctx.send(self.BDAY_SET(bday_month_str + " " + bday_day_str)) - # Check if today is their birthday - if today.replace(year=1).toordinal() == birthday.replace(year=1).toordinal(): - await self.handle_bday(self, author.id, year) + return + if today.year != birthday.year: + if birthday.year > today.year: + await ctx.send("You weren't born in the future, silly!") + return + if birthday.year < (today.year - 100): + await ctx.send("No way you're that old, silly!") + return + year = birthday.year + birthday = datetime.date(1, birthday.month, birthday.day) + if current_birthday != None and birthday.toordinal() == current_birthday.toordinal(): + await ctx.send("Your birthday is already set to {}!".format(self.get_human_birthday(birthday))) + return + await self.remove_user_bday(message.guild.id, author.id) + await self.get_date_config(message.guild.id, birthday.toordinal()).get_attr(author.id).set(year) + await ctx.send(self.BDAY_SET(self.get_human_birthday(birthday))) + # Check if today is their birthday + today_ordinal = today.replace(year=1).toordinal() + birthday_ordinal = birthday.replace(year=1).toordinal() + if today_ordinal == birthday_ordinal: + await self.handle_bday(author.id, year) - @bday_set.command(name="message") - async def bday_set_message(self, ctx: Context, *, bday_message: str = ""): - """Sets your birthday message. - - It can be any message that you want! This message will be sent - via Direct Message. Set to nothing to clear. Emotes from other - servers are not supported!""" + @bday_set.command(name="dmmessage") + @checks.mod_or_permissions(manage_roles=True) + async def bday_set_dmmessage(self, ctx: Context, *, bday_message: str = ""): + """Sets the birthday message for DMs.""" message = ctx.message author = message.author - # TODO: implement saving to config. if bday_message == "": - await ctx.send("Your birthday message is now set to the default message.") + await self.config.guild(ctx.guild).dmmessage.set(":tada: Aurelia wishes you a very happy birthday! :tada:") + await ctx.send( + "Birthday DM message set to (default): :tada: Aurelia wishes you a very happy birthday! :tada:" + ) else: - await ctx.send("Birthday message set to: " + str(bday_message)) + await self.config.guild(ctx.guild).dmmessage.set(bday_message) + await ctx.send("Birthday DM message set to: " + str(bday_message)) @bday_set.command(name="channel") @checks.mod_or_permissions(manage_roles=True) @@ -239,12 +240,8 @@ class Birthdays(Cog): channel = guild.get_channel(guild_config.get("channel")) if channel is not None: await channel.send(embed=embed) - # TODO: Actually get the custom message from config. - custom_message = None - if custom_message is None: - await member.send(self.BDAY_DM()) - else: - await member.send(custom_message) + message = guild_config.get("dmmessage") + await member.send(message) async def clean_bdays(self): birthdays = await self.get_all_date_configs() @@ -293,6 +290,17 @@ class Birthdays(Cog): pass return result + def get_human_birthday(self, birthday: datetime): + return str(birthday.strftime("%B")) + " " + str(birthday.strftime("%d").lstrip("0")) + + async def get_birthday(self, guild_id: int, user_id: int): + birthdays = await self.get_guild_date_configs(guild_id) + for bday_ordinal, bdays in birthdays.items(): + for user_id_config, year in bdays.items(): + if int(user_id_config) == user_id: + return datetime.datetime.fromordinal(int(bday_ordinal)) + return None + async def check_breaking_change(self): await self.bot.wait_until_ready() previous = await self.config.custom(self.DATE_GROUP).all() From 6ef2e67bc761b4572dc3fee29bc27aeeab851e77 Mon Sep 17 00:00:00 2001 From: brandons209 Date: Tue, 18 Feb 2020 00:35:31 -0500 Subject: [PATCH 17/17] final update --- birthday/birthday.py | 88 +++++++++++++++++++++++--------------------- birthday/info.json | 4 +- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/birthday/birthday.py b/birthday/birthday.py index f52412d..dddf0dc 100644 --- a/birthday/birthday.py +++ b/birthday/birthday.py @@ -66,7 +66,7 @@ class Birthdays(Cog): self.config.register_guild( channel=None, role=None, dmmessage=":tada: Aurelia wishes you a very happy birthday! :tada:", yesterdays=[] ) - self.bday_loop = asyncio.create_task(self.initialise()) + self.bday_task = asyncio.create_task(self.initialise()) asyncio.create_task(self.check_breaking_change()) # Events @@ -81,7 +81,7 @@ class Birthdays(Cog): await asyncio.sleep((tomorrow - now).total_seconds()) def cog_unload(self): - self.bday_loop.cancel() + self.bday_task.cancel() # Commands @commands.group() @@ -97,17 +97,13 @@ class Birthdays(Cog): await self.remove_user_bday(message.guild.id, message.author.id) await ctx.send(self.BDAY_REMOVED()) - @bday.group(name="set") - async def bday_set(self, ctx: Context): - """Changes settings for your birthday!""" - pass - - @bday_set.command(name="birthday") + @bday.command(name="set") async def bday_set_birthday(self, ctx: Context, *, date: str): - """Sets your birthday date + """Set your birthday! - The given date can either be month day, or day month - Year is optional. If not given, the age won't be displayed.""" + The given date can either be month day, or day month + Year is optional. If not given, the age won't be displayed. + """ message = ctx.message author = message.author year = None @@ -140,6 +136,45 @@ class Birthdays(Cog): if today_ordinal == birthday_ordinal: await self.handle_bday(author.id, year) + @bday.command(name="list") + async def bday_list(self, ctx: Context): + """Lists birthdays + + If a user has their year set, it will display the age they'll get after their birthday this year""" + message = ctx.message + await self.clean_bdays() + bdays = await self.get_guild_date_configs(message.guild.id) + this_year = datetime.date.today().year + embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) + for k, g in itertools.groupby( + sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), lambda i: i.month, + ): + + value = "\n".join( + date.strftime("%d").lstrip("0") + + ": " + + ", ".join( + "{}".format(ctx.guild.get_member(int(u_id)).mention) + + ("" if year is None else " ({})".format(this_year - int(year))) + for u_id, year in bdays.get(str(date.toordinal()), {}).items() + ) + for date in g + if len(bdays.get(str(date.toordinal()))) > 0 + ) + if not value.isspace(): + embed.add_field( + name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value, + ) + await ctx.send(embed=embed) + + @commands.group(name="bdayset") + @checks.admin() + async def bday_set(self, ctx: Context): + """ + Manage birthday settings. + """ + pass + @bday_set.command(name="dmmessage") @checks.mod_or_permissions(manage_roles=True) async def bday_set_dmmessage(self, ctx: Context, *, bday_message: str = ""): @@ -171,37 +206,6 @@ class Birthdays(Cog): await self.config.guild(role.guild).role.set(role.id) await ctx.send(self.ROLE_SET(g=guild.name, r=role.name)) - @bday.command(name="list") - async def bday_list(self, ctx: Context): - """Lists birthdays - - If a user has their year set, it will display the age they'll get after their birthday this year""" - message = ctx.message - await self.clean_bdays() - bdays = await self.get_guild_date_configs(message.guild.id) - this_year = datetime.date.today().year - embed = discord.Embed(title=self.BDAY_LIST_TITLE(), color=discord.Colour.lighter_grey()) - for k, g in itertools.groupby( - sorted(datetime.datetime.fromordinal(int(o)) for o in bdays.keys()), lambda i: i.month, - ): - - value = "\n".join( - date.strftime("%d").lstrip("0") - + ": " - + ", ".join( - "{}".format(ctx.guild.get_member(user_id)) - + ("" if year is None else " ({})".format(this_year - int(year))) - for u_id, year in bdays.get(str(date.toordinal()), {}).items() - ) - for date in g - if len(bdays.get(str(date.toordinal()))) > 0 - ) - if not value.isspace(): - embed.add_field( - name=datetime.datetime(year=1, month=k, day=1).strftime("%B"), value=value, - ) - await ctx.send(embed=embed) - async def clean_bday(self, guild_id: int, guild_config: dict, user_id: int): guild = self.bot.get_guild(guild_id) if guild is not None: diff --git a/birthday/info.json b/birthday/info.json index 659586e..d805d5e 100644 --- a/birthday/info.json +++ b/birthday/info.json @@ -1,7 +1,7 @@ { "author": [ - "PancakeSparkle" - + "PancakeSparkle", + "shroomdog26" ], "bot_version": [ 3,