From 168e5a03b863c11727ef4e63d3c9a22486a9c511 Mon Sep 17 00:00:00 2001 From: Bobloy Date: Wed, 16 May 2018 16:10:50 -0400 Subject: [PATCH 1/4] Flag port to V3 initial commit --- flag/__init__.py | 5 ++ flag/flag.py | 184 +++++++++++++++++++++++++++++++++++++++++++++++ flag/info..json | 23 ++++++ 3 files changed, 212 insertions(+) create mode 100644 flag/__init__.py create mode 100644 flag/flag.py create mode 100644 flag/info..json diff --git a/flag/__init__.py b/flag/__init__.py new file mode 100644 index 0000000..0184952 --- /dev/null +++ b/flag/__init__.py @@ -0,0 +1,5 @@ +from .flag import Flag + + +def setup(bot): + bot.add_cog(Flag(bot)) diff --git a/flag/flag.py b/flag/flag.py new file mode 100644 index 0000000..7fe1b30 --- /dev/null +++ b/flag/flag.py @@ -0,0 +1,184 @@ +from datetime import date, timedelta + +import discord +from redbot.core import Config, checks, commands +from redbot.core.bot import Red +from redbot.core.utils.chat_formatting import pagify + + +class Flag: + """ + Set expiring flags on members + """ + + def __init__(self, bot: Red): + self.bot = bot + self.config = Config.get_conf(self, identifier=9811198108111121, force_registration=True) + default_global = {} + default_guild = { + "days": 31, + "dm": True, + "flags": {} + } + + self.config.register_global(**default_global) + self.config.register_guild(**default_guild) + + @checks.is_owner() + @commands.command() + async def clearallflag(self, ctx: commands.Context): + """Clears all flags for all members in this server""" + + await self.config.guild(ctx.guild).flags.clear() + await ctx.send("Done") + + @checks.mod_or_permissions(manage_roles=True) + @commands.guild_only() + @commands.group() + async def flagset(self, ctx: commands.Context): + """ + My custom cog + + Extra information goes here + """ + if ctx.invoked_subcommand is None: + await ctx.send_help() + + @flagset.command(name="expire") + async def flagset_expire(self, ctx: commands.Context, days: int): + """ + Set the number of days for flags to expire after for server + """ + await self.config.guild(ctx.guild).days.set(days) + await ctx.send("Number of days for new flags to expire is now {} days".format(days)) + + @flagset.command(name="dm") + async def flagset_dm(self, ctx: commands.Context): + """Toggles DM-ing the flags""" + + dm = await self.config.guild(ctx.guild).dm() + await self.config.guild(ctx.guild).dm.set(not dm) + + await ctx.send("DM-ing members when they get a flag is now set to **{}**".format(not dm)) + + @staticmethod + def _flag_template(): + return { + 'reason': "", + 'expireyear': 0, + 'expiremonth': 0, + 'expireday': 0 + } + + # ************************Flag command group start************************ + @checks.mod_or_permissions(manage_roles=True) + @commands.command() + async def flag(self, ctx: commands.Context, member: discord.Member, *, reason): + """Flag a member""" + guild = ctx.guild + await self._check_flags(guild) + # clashroyale = self.bot.get_cog('clashroyale') + # if clashroyale is None: + # await ctx.send("Requires clashroyale cog installed") + # return + + flag = self._flag_template() + expiredate = date.today() + expiredate += timedelta(days=await self.config.guild(guild).days()) + + flag['reason'] = reason + flag['expireyear'] = expiredate.year + flag['expiremonth'] = expiredate.month + flag['expireday'] = expiredate.day + + # flags = await self.config.guild(guild).flags.get_raw(str(member.id), default=[]) + # flags.append(flag) + # await self.config.guild(guild).flags.set_raw(str(member.id), value=flags) + + async with self.config.guild(guild).flags() as flags: + flags[str(member.id)].append(flag) + + outembed = await self._list_flags(member) + + if outembed: + await ctx.send(embed=outembed) + if await self.config.guild(guild).dm(): + await member.send(embed=outembed) + else: + await ctx.send("This member has no flags.. somehow..") + + @checks.mod_or_permissions(manage_roles=True) + @commands.command(pass_context=True, no_pm=True, aliases=['flagclear']) + async def clearflag(self, ctx: commands.Context, member: discord.Member): + """Clears flags for a member""" + guild = ctx.guild + await self._check_flags(guild) + + await self.config.guild(guild).flags.set_raw(str(member.id), value=[]) + + await ctx.send("Success!") + + @commands.command(pass_context=True, no_pm=True, aliases=['flaglist']) + async def listflag(self, ctx: commands.Context, member: discord.Member): + """Lists flags for a member""" + server = ctx.guild + await self._check_flags(server) + + outembed = await self._list_flags(member) + + if outembed: + await ctx.send(embed=outembed) + else: + await ctx.send("This member has no flags!") + + @commands.command(pass_context=True, no_pm=True, aliases=['flagall']) + async def allflag(self, ctx: commands.Context): + """Lists all flags for the server""" + guild = ctx.guild + await self._check_flags(guild) + out = "All flags for {}\n".format(ctx.guild.name) + + flags = await self.config.guild(guild).flags() + flag_d = {} + for memberid, flag_data in flags.items(): + if len(flag_data) > 0: + member = guild.get_member(int(memberid)) + flag_d[member.display_name + member.discriminator] = len(flag_data) + + for display_name, flag_count in sorted(flag_d.items()): + out += "{} - **{}** flags".format(display_name, flag_count) + + for page in pagify(out): + await ctx.send(page) + + async def _list_flags(self, member: discord.Member): + """Returns a pretty embed of flags on a member""" + flags = await self.config.guild(member.guild).flags.get_raw(str(member.id), default=[]) + + embed = discord.Embed(title="Flags for " + member.display_name, + description="User has {} active flags".format(len(flags)), color=0x804040) + for flag in flags: + embed.add_field(name="Reason: " + flag['reason'], + value="Expires on " + str(date(flag['expireyear'], flag['expiremonth'], flag['expireday'])), + inline=True) + + embed.set_thumbnail(url=member.avatar_url) + + return embed + + async def _check_flags(self, guild: discord.Guild): + """Updates and removes expired flags""" + flag_data = await self.config.guild(guild).flags() + flag_d = {} + for memberid, flags in flag_data.items(): + # for member in guild.members: + # flags = await self.config.guild(guild).flags.get_raw(str(member.id), default=[]) + x = 0 + while x < len(flags): + flag = flags[x] + if date.today() >= date(flag['expireyear'], flag['expiremonth'], flag['expireday']): + del flags[x] + else: + x += 1 + + await self.config.guild(guild).flags.set_raw(memberid, value=flags) diff --git a/flag/info..json b/flag/info..json new file mode 100644 index 0000000..b5908b9 --- /dev/null +++ b/flag/info..json @@ -0,0 +1,23 @@ +{ + "author": [ + "Bobloy" + ], + "bot_version": [ + 3, + 0, + 0 + ], + "description": "Add expiring flags on members to track warnings or incidents", + "hidden": true, + "install_msg": "Thank you for installing Flag! Get started with `[p]help Flag`", + "requirements": [], + "short": "Add expiring flags to members", + "tags": [ + "bobloy", + "warning", + "warn", + "temp", + "tools", + "warning" + ] +} \ No newline at end of file From f8181474268a13cd23e6d70279e77e36b25f1bfb Mon Sep 17 00:00:00 2001 From: Bobloy Date: Wed, 16 May 2018 16:33:03 -0400 Subject: [PATCH 2/4] Flag update to Alpha --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f53825..a264b4b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Cog Function | chatter | **Alpha** |
Chat-bot trained to talk like your guildMissing some key features, but currently functional
| | coglint | **Alpha** |
Error check code in python syntax posted to discordWorks, but probably needs more turning to work for cogs
| | fight | **Incomplete** |
Organize bracket tournaments within discordStill in-progress, a massive project
| -| flag | **Incomplete** |
Create temporary marks on users that expire after specified timeNot yet ported to v3
| +| flag | **Alpha** |
Create temporary marks on users that expire after specified timePorted, will not import old data. Please report bugs
| | forcemention | **Alpha** |
Mentions unmentionable rolesVery simple cog, mention doesn't persist
| | hangman | **Alpha** |
Play a game of hangmanSome visual glitches and needs more customization
| | howdoi | **Incomplete** |
Create temporary marks on users that expire after specified timeNot yet ported to v3
| From 4d5d277ed13999018e8e837ba7c58a8753de519a Mon Sep 17 00:00:00 2001 From: Bobloy Date: Wed, 16 May 2018 16:33:46 -0400 Subject: [PATCH 3/4] better yes//no's --- ccrole/ccrole.py | 2 +- stealemoji/stealemoji.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ccrole/ccrole.py b/ccrole/ccrole.py index d8c17f6..5fc4344 100644 --- a/ccrole/ccrole.py +++ b/ccrole/ccrole.py @@ -106,7 +106,7 @@ class CCRole: return # Selfrole - await ctx.send('Is this a targeted command?(yes/no)\nNo will make this a selfrole command') + await ctx.send('Is this a targeted command?(yes//no)\nNo will make this a selfrole command') try: answer = await self.bot.wait_for('message', timeout=120, check=check) diff --git a/stealemoji/stealemoji.py b/stealemoji/stealemoji.py index a55d2c9..143c38a 100644 --- a/stealemoji/stealemoji.py +++ b/stealemoji/stealemoji.py @@ -58,7 +58,7 @@ class StealEmoji: async def se_bank(self, ctx): """Add current server as emoji bank""" await ctx.send("This will upload custom emojis to this server\n" - "Are you sure you want to make the current server an emoji bank? (y/n)") + "Are you sure you want to make the current server an emoji bank? (y//n)") def check(m): return m.content.upper() in ["Y", "YES", "N", "NO"] and m.channel == ctx.channel and m.author == ctx.author From 273e622fa7b168ea9e95b8bc7f504ab4cd6fd649 Mon Sep 17 00:00:00 2001 From: Bobloy Date: Thu, 17 May 2018 09:43:14 -0400 Subject: [PATCH 4/4] Assorted QoL updates --- ccrole/ccrole.py | 3 +- chatter/chat.py | 6 +- chatter/chatterbot/storage/storage_adapter.py | 4 +- coglint/coglint.py | 7 +- hangman/hangman.py | 6 +- lseen/lseen.py | 2 - reactrestrict/reactrestrict.py | 148 +++++++++--------- sayurl/sayurl.py | 3 +- werewolf/builder.py | 3 - werewolf/player.py | 2 +- werewolf/roles/seer.py | 1 - 11 files changed, 83 insertions(+), 102 deletions(-) diff --git a/ccrole/ccrole.py b/ccrole/ccrole.py index 5fc4344..a858992 100644 --- a/ccrole/ccrole.py +++ b/ccrole/ccrole.py @@ -2,7 +2,6 @@ import asyncio import re import discord - from redbot.core import Config, checks from redbot.core import commands from redbot.core.utils.chat_formatting import pagify, box @@ -191,7 +190,7 @@ class CCRole: """Shows custom commands list""" guild = ctx.guild cmd_list = await self.config.guild(guild).cmdlist() - cmd_list = {k: v for k,v in cmd_list.items() if v} + cmd_list = {k: v for k, v in cmd_list.items() if v} if not cmd_list: await ctx.send( "There are no custom commands in this server. Use `{}ccrole add` to start adding some.".format( diff --git a/chatter/chat.py b/chatter/chat.py index dce136f..eca1056 100644 --- a/chatter/chat.py +++ b/chatter/chat.py @@ -2,7 +2,6 @@ import asyncio from datetime import datetime, timedelta import discord - from redbot.core import Config from redbot.core import commands @@ -10,7 +9,6 @@ from chatter.chatterbot import ChatBot from chatter.chatterbot.trainers import ListTrainer - class Chatter: """ This cog trains a chatbot that will talk like members of your Guild @@ -99,7 +97,8 @@ class Chatter: Backup your training data to a json for later use """ await ctx.send("Backing up data, this may take a while") - future = await self.loop.run_in_executor(None, self.chatbot.trainer.export_for_training, './{}.json'.format(backupname)) + future = await self.loop.run_in_executor(None, self.chatbot.trainer.export_for_training, + './{}.json'.format(backupname)) if future: await ctx.send("Backup successful!") @@ -142,7 +141,6 @@ class Chatter: author = message.author channel = message.channel - if message.author.id != self.bot.user.id: to_strip = "@" + author.guild.me.display_name + " " text = message.clean_content diff --git a/chatter/chatterbot/storage/storage_adapter.py b/chatter/chatterbot/storage/storage_adapter.py index 046ae63..cf1f45b 100644 --- a/chatter/chatterbot/storage/storage_adapter.py +++ b/chatter/chatterbot/storage/storage_adapter.py @@ -158,7 +158,9 @@ class StorageAdapter(object): class EmptyDatabaseException(Exception): def __init__(self, - value='The database currently contains no entries. At least one entry is expected. You may need to train your chat bot to populate your database.'): + value='The database currently contains no entries. ' + 'At least one entry is expected. ' + 'You may need to train your chat bot to populate your database.'): self.value = value def __str__(self): diff --git a/coglint/coglint.py b/coglint/coglint.py index 10861c7..0c3d045 100644 --- a/coglint/coglint.py +++ b/coglint/coglint.py @@ -1,11 +1,8 @@ import discord - -from redbot.core import Config, checks - -from redbot.core.bot import Red - from pylint import epylint as lint +from redbot.core import Config from redbot.core import commands +from redbot.core.bot import Red from redbot.core.data_manager import cog_data_path diff --git a/hangman/hangman.py b/hangman/hangman.py index 4958eac..2a95f54 100644 --- a/hangman/hangman.py +++ b/hangman/hangman.py @@ -2,10 +2,9 @@ from collections import defaultdict from random import randint import discord - from redbot.core import Config, checks from redbot.core import commands -from redbot.core.data_manager import cog_data_path, load_basic_configuration +from redbot.core.data_manager import cog_data_path class Hangman: @@ -26,7 +25,7 @@ class Hangman: lambda: {"running": False, "hangman": 0, "guesses": [], "trackmessage": False, "answer": ''}) self.path = str(cog_data_path(self)).replace('\\', '/') - self.answer_path = self.path+"/bundled_data/hanganswers.txt" + self.answer_path = self.path + "/bundled_data/hanganswers.txt" self.winbool = defaultdict(lambda: False) @@ -331,4 +330,3 @@ class Hangman: await self._reactmessage_menu(message) await self._checkdone(channel) - diff --git a/lseen/lseen.py b/lseen/lseen.py index 43c56ea..6cdf666 100644 --- a/lseen/lseen.py +++ b/lseen/lseen.py @@ -58,8 +58,6 @@ class LastSeen: async def lseen(self, ctx: commands.Context, member: discord.Member): """ Just says the time the user was last seen - - :param member: """ if member.status != self.offline_status: diff --git a/reactrestrict/reactrestrict.py b/reactrestrict/reactrestrict.py index 87b50a3..50aa61e 100644 --- a/reactrestrict/reactrestrict.py +++ b/reactrestrict/reactrestrict.py @@ -1,12 +1,9 @@ -import asyncio from typing import List, Union import discord - - from redbot.core import Config -from redbot.core.bot import Red from redbot.core import commands +from redbot.core.bot import Red class ReactRestrictCombo: @@ -16,8 +13,8 @@ class ReactRestrictCombo: def __eq__(self, other: "ReactRestrictCombo"): return ( - self.message_id == other.message_id and - self.role_id == other.role_id + self.message_id == other.message_id and + self.role_id == other.role_id ) def to_json(self): @@ -83,7 +80,7 @@ class ReactRestrict: """ # is_custom = True # if isinstance(emoji, str): - # is_custom = False + # is_custom = False combo = ReactRestrictCombo(message_id, role.id) @@ -95,10 +92,10 @@ class ReactRestrict: async def remove_react(self, message_id: int, role: discord.Role): """ - Removes a given reaction. + Removes a given reaction - :param int message_id: - :param str or int emoji: + :param message_id: + :param role: :return: """ current_combos = await self.combo_list() @@ -109,14 +106,13 @@ class ReactRestrict: if to_keep != current_combos: await self.set_combo_list(to_keep) - async def has_reactrestrict_combo(self, message_id: int)\ + async def has_reactrestrict_combo(self, message_id: int) \ -> (bool, List[ReactRestrictCombo]): """ - Determines if there is an existing role combo for a given message + Determines if there is an existing role combo for a given message and emoji ID. - :param int message_id: - :param str or int emoji: + :param message_id: :return: """ if not await self.is_registered(message_id): @@ -169,8 +165,8 @@ class ReactRestrict: raise LookupError("No role found.") return role - - async def _get_message_from_channel(self, channel_id: int, message_id: int)\ + + async def _get_message_from_channel(self, channel_id: int, message_id: int) \ -> Union[discord.Message, None]: """ Tries to find a message by ID in the current guild context. @@ -180,12 +176,12 @@ class ReactRestrict: return await channel.get_message(message_id) except discord.NotFound: pass - except AttributeError: # VoiceChannel object has no attribute 'get_message' + except AttributeError: # VoiceChannel object has no attribute 'get_message' pass return None - - async def _get_message(self, ctx: commands.Context, message_id: int)\ + + async def _get_message(self, ctx: commands.Context, message_id: int) \ -> Union[discord.Message, None]: """ Tries to find a message by ID in the current guild context. @@ -199,12 +195,10 @@ class ReactRestrict: return await channel.get_message(message_id) except discord.NotFound: pass - except AttributeError: # VoiceChannel object has no attribute 'get_message' + except AttributeError: # VoiceChannel object has no attribute 'get_message' pass except discord.Forbidden: # No access to channel, skip pass - - return None @@ -228,18 +222,18 @@ class ReactRestrict: return # try: - # emoji, actual_emoji = await self._wait_for_emoji(ctx) + # emoji, actual_emoji = await self._wait_for_emoji(ctx) # except asyncio.TimeoutError: - # await ctx.send("You didn't respond in time, please redo this command.") - # return - + # await ctx.send("You didn't respond in time, please redo this command.") + # return + # # try: - # await message.add_reaction(actual_emoji) + # await message.add_reaction(actual_emoji) # except discord.HTTPException: - # await ctx.send("I can't add that emoji because I'm not in the guild that" - # " owns it.") - # return - + # await ctx.send("I can't add that emoji because I'm not in the guild that" + # " owns it.") + # return + # # noinspection PyTypeChecker await self.add_reactrestrict(message_id, role) @@ -251,10 +245,10 @@ class ReactRestrict: Removes role associated with a given reaction. """ # try: - # emoji, actual_emoji = await self._wait_for_emoji(ctx) + # emoji, actual_emoji = await self._wait_for_emoji(ctx) # except asyncio.TimeoutError: - # await ctx.send("You didn't respond in time, please redo this command.") - # return + # await ctx.send("You didn't respond in time, please redo this command.") + # return # noinspection PyTypeChecker await self.remove_react(message_id, role) @@ -298,50 +292,50 @@ class ReactRestrict: for apprrole in roles: if apprrole in member.roles: return - + message = await self._get_message_from_channel(channel_id, message_id) await message.remove_reaction(emoji, member) - - # try: - # await member.add_roles(*roles) - # except discord.Forbidden: - # pass + # try: + # await member.add_roles(*roles) + # except discord.Forbidden: + # pass + # # async def on_raw_reaction_remove(self, emoji: discord.PartialReactionEmoji, - # message_id: int, channel_id: int, user_id: int): - # """ - # Event handler for long term reaction watching. - - # :param discord.PartialReactionEmoji emoji: - # :param int message_id: - # :param int channel_id: - # :param int user_id: - # :return: - # """ - # if emoji.is_custom_emoji(): - # emoji_id = emoji.id - # else: - # emoji_id = emoji.name - - # has_reactrestrict, combos = await self.has_reactrestrict_combo(message_id, emoji_id) - - # if not has_reactrestrict: - # return - - # try: - # member = self._get_member(channel_id, user_id) - # except LookupError: - # return - - # if member.bot: - # return - - # try: - # roles = [self._get_role(member.guild, c.role_id) for c in combos] - # except LookupError: - # return - - # try: - # await member.remove_roles(*roles) - # except discord.Forbidden: - # pass + # message_id: int, channel_id: int, user_id: int): + # """ + # Event handler for long term reaction watching. + # + # :param discord.PartialReactionEmoji emoji: + # :param int message_id: + # :param int channel_id: + # :param int user_id: + # :return: + # """ + # if emoji.is_custom_emoji(): + # emoji_id = emoji.id + # else: + # emoji_id = emoji.name + # + # has_reactrestrict, combos = await self.has_reactrestrict_combo(message_id, emoji_id) + # + # if not has_reactrestrict: + # return + # + # try: + # member = self._get_member(channel_id, user_id) + # except LookupError: + # return + # + # if member.bot: + # return + # + # try: + # roles = [self._get_role(member.guild, c.role_id) for c in combos] + # except LookupError: + # return + # + # try: + # await member.remove_roles(*roles) + # except discord.Forbidden: + # pass diff --git a/sayurl/sayurl.py b/sayurl/sayurl.py index b9837aa..04499cd 100644 --- a/sayurl/sayurl.py +++ b/sayurl/sayurl.py @@ -32,8 +32,7 @@ class SayUrl: """ Converts a URL to something readable - :param url: - :return: + Works better on smaller websites """ h = html2text.HTML2Text() diff --git a/werewolf/builder.py b/werewolf/builder.py index 28b22ea..48e7e71 100644 --- a/werewolf/builder.py +++ b/werewolf/builder.py @@ -120,8 +120,6 @@ async def parse_code(code, game): digits += 1 continue - - try: idx = int(built) except ValueError: @@ -146,7 +144,6 @@ async def parse_code(code, game): built = "" - return decode diff --git a/werewolf/player.py b/werewolf/player.py index d1f9359..c84d87f 100644 --- a/werewolf/player.py +++ b/werewolf/player.py @@ -30,4 +30,4 @@ class Player: try: await self.member.send(message) # Lets do embeds later except discord.Forbidden: - await self.role.game.village_channel.send("Couldn't DM {}, uh oh".format(self.mention)) \ No newline at end of file + await self.role.game.village_channel.send("Couldn't DM {}, uh oh".format(self.mention)) diff --git a/werewolf/roles/seer.py b/werewolf/roles/seer.py index b005b9a..5c58250 100644 --- a/werewolf/roles/seer.py +++ b/werewolf/roles/seer.py @@ -16,7 +16,6 @@ class Seer(Role): description = "A mystic in search of answers in a chaotic town.\n" \ "Calls upon the cosmos to discern those of Lycan blood" - def __init__(self, game): super().__init__(game) # self.game = game