import datetime import time import checks import discord from config.server_config import ServerConfig from discord.ext.commands import bot, group class Admin(): """ Admin Commands for those admins """ def __init__(self, Bot): self.bot = Bot self.slow_mode = False self.slow_mode_channels = {} self.users = {} self.con = ServerConfig() self.servers = self.con.servers async def on_message(self, message): # Slow Mode Code channel = message.channel author = message.author if not author == self.bot.user: if self.slow_mode and channel.id in self.slow_mode_channels: if author.id not in self.users[channel.id]: # If user hasn't sent a message in this channel after slow mode was turned on self.users[channel.id][author.id] = message.timestamp else: # Else, check when their last message was and if time is smaller than the timer, delete the message. timer = datetime.timedelta(seconds=self.slow_mode_channels[channel.id]) if message.timestamp - self.users[channel.id][author.id] < timer: await self.bot.delete_message(message) else: self.users[message.channel.id][author.id] = message.timestamp else: pass @checks.not_pm() @checks.is_admin_or_mod() @bot.command(pass_context=True) async def slowmode(self, ctx, time): if time == "off" and self.slow_mode: # Turn Slow Mode off self.slow_mode = False self.slow_mode_channels.pop(ctx.message.channel.id) self.users.pop(ctx.message.channel.id) return await self.bot.say("Slowmode off") elif time.isdigit() and not self.slow_mode: # Turn Slow Mode On self.users[ctx.message.channel.id] = {} self.slow_mode_channels[ctx.message.channel.id] = int(time) self.slow_mode = True return await self.bot.say("Slowmode on :snail: ({} seconds)".format(time)) elif time.isdigit and self.slow_mode: # Change value of Slow Mode timer self.slow_mode_channels[ctx.message.channel.id] = int(time) return await self.bot.say("Slowmode set to :snail: ({} seconds)".format(time)) else: pass @checks.is_admin_or_mod() @bot.command(pass_context=True, enabled=False) async def emojiuse(self, ctx, emoji, *args): # TODO: Add check that emoji is an emoji # TODO: Disable so like when we go to 1.3 this isn't live cause it needs more work and it needs to be completed already # The way forward is clearly put the given emoji in and treat it as a list of emojis, # if all emojis, then generate the list. Allows for more than one emoji to be analysed. Works better for larger servers/ # Flag Parsing if "-v" in args: verbose = True else: verbose = False if "-w" in args or emoji == "-w": # Second check just in case user just puts ";emojiuse -w" all_emojis = True else: all_emojis = False # Functions def sum(usage): amount = 0 for channel in usage.values(): amount += channel return amount def use_by_day(amount): useperday = amount / 30 useperday = "{0:.2f}".format(useperday) return useperday def verbose_output(usage): output = "" for channel in usage: channel = self.bot.get_channel(channel) # Convert channel from ID to channel object to get name output = output + "{}: {} \n".format(channel.name, usage[channel.id]) return output async def count_uses(): usage = {} for channel in ctx.message.server.channels: if channel.type == discord.ChannelType.text: # Only looks at server's text channels x = 0 async for message in self.bot.logs_from(channel, limit=1000000, after=datetime.datetime.now() + datetime.timedelta(-30)): if str(emoji) in message.content: x += 1 usage[channel.id] = x print(str(emoji) + "HAS {} AMOUNT OF USES IN {}".format(x, str(channel))) else: pass print("EMOJI WAS USED {} TOTAL TIMES".format(sum(usage))) return usage async def count_all_emoji(): whitelist = [":yeetpride:",":yeet:", ":transgendercat:", ":thonkspin:", ":thonkegg:", ":ThinkPride:", ":thinkinggaysounds:", ":thatsgoodnews", ":pansexualcat:", ":nonbinarycat: ", ":kappa:", ":icantputpunctuationinemojinames:", ":hellothere:", ":agendercat:", ":Hedgeok:", ":extremethink:", ":donttryit:", ":cutie:", ":catappa:", ":boots:", ":awoo:", ":anotherhappylanding:", ":angrygay:"] usage = {} for emote in ctx.message.server.emojis: name = ":{}:".format(emote.name) if name in whitelist: usage[emote.id] = 0 for channel in ctx.message.server.channels: # TODO: ADD COUNTING BY CHANNEL if channel.type == discord.ChannelType.text: # Only looks at server's text channels async for message in self.bot.logs_from(channel, limit=1000000, after=datetime.datetime.now() + datetime.timedelta(-30)): for emote in ctx.message.server.emojis: if str(emote) in message.content and ":{}:".format(emote.name) in whitelist: usage[emote.id] += 1 print("{} found in message {}".format(str(emote), message.id)) return usage # Command await self.bot.say("Warning! This command may take upto 15 minutes to process. Please do no spam me. I am working.", delete_after=20) await self.bot.send_typing(ctx.message.channel) if all_emojis: emoji_usage = await count_all_emoji() em = discord.Embed(colour=0xDEADBF) for emoji in emoji_usage: emoji_obj = discord.utils.get(ctx.message.server.emojis, id=emoji) amount = emoji_usage[emoji] useperday = use_by_day(amount) em.add_field(name=str(emoji_obj), value="Amount Used: {}\nUse/Day: {}".format(amount, useperday), inline=False) return await self.bot.say(content="Below is a report of all custom emoji on this server and how many times they have been used in the previous 30 days. This includes a usage/day ratio.", embed=em) else: usage = await count_uses() amount = sum(usage) useperday = use_by_day(amount) if verbose: output = verbose_output(usage) output_em = discord.Embed(description=output, colour=0xDEADBF) return await self.bot.say(content="{} has been used {} time(s) in the last month. That's {}/day. Here is the break down per channel.".format(emoji, amount, useperday), embed=output_em) else: # Non-verbose output return await self.bot.say("{} has been used {} time(s) in the last month. That's {}/day.".format(emoji, amount, useperday)) @checks.is_admin_or_mod() @group(pass_context=True) async def warn(self, ctx): if ctx.invoked_subcommand is None: return await self.bot.say('Missing Argument') @warn.command(pass_context=True) async def add(self, ctx, user: discord.User = None, *, warning = ""): # Warning in the config is a dictionary of user ids. The user ids are equal to a list of dictionaries. self.servers = self.con.load_config() warning_limit = 2 id = ctx.message.server.id warning_dict = { "warned-by": ctx.message.author.id, "date": time.time(), "warning": warning } if not user.id in self.servers[id]["warnings"]: self.servers[id]["warnings"][user.id] = [] self.servers[id]["warnings"][user.id].append(warning_dict) self.con.update_config(self.servers) amount_warnings = len(self.servers[id]["warnings"][user.id]) if amount_warnings > warning_limit: await self.bot.send_message(ctx.message.author,"{} has been reported {} time(s). This is a reminder that this is over the set limit of {}.".format( user.name+"#"+user.discriminator, amount_warnings, warning_limit)) return await self.bot.say("Reported {}.".format(user.name+"#"+user.discriminator)) @warn.command(pass_context=True) async def list(self, ctx, *, user: discord.User = None): await self.bot.send_typing(ctx.message.channel) if user == None: output = "" for user in self.servers[ctx.message.server.id]["warnings"]: user_obj = await self.bot.get_user_info(user) output += "{}#{}: {} Warning(s)\n".format(user_obj.name, user_obj.discriminator, len(self.servers[ctx.message.server.id]["warnings"][user])) return await self.bot.say(output) if not user.id in self.servers[ctx.message.server.id]["warnings"]: return await self.bot.say("This user doesn't have any warning on record.") em = discord.Embed(title="Warnings for {}".format(user.name+"#"+user.discriminator), colour=0XDEADBF) em.set_thumbnail(url=user.avatar_url) x = 1 userlist = self.servers[ctx.message.server.id]["warnings"][user.id] for warning in userlist: try: warnuser = await self.bot.get_user_info(warning["warned-by"]) warned_by = warnuser.name + "#" + warnuser.discriminator except: warned_by = warning["warned-by"] date = datetime.datetime.fromtimestamp(warning["date"]).strftime('%c') warn_reason = warning["warning"] em.add_field(name="Warning %s"%x, value="Warned by: {}\nTime: {}\nReason: {}".format(warned_by, date, warn_reason)) x += 1 return await self.bot.say(embed=em) @warn.command(pass_context=True) async def remove(self, ctx, user: discord.User = None, index = None): self.servers = self.con.load_config() if index: try: index = int(index) index -= 1 self.servers[ctx.message.server.id]["warnings"][user.id].pop(index) self.con.update_config(self.servers) return await self.bot.say("Removed Warning {} from {}".format(index+1, user.name+"#"+user.discriminator)) except Exception as e: if isinstance(e, IndexError): return await self.bot.say(":warning: Index Error.") elif isinstance(e, KeyError): return await self.bot.say("Could not find user in warning list.") elif isinstance(e, ValueError): return await self.bot.say("Please enter a valid index number.") else: raise e else: try: self.servers[ctx.message.server.id]["warnings"].pop(user.id) self.con.update_config(self.servers) return await self.bot.say("Removed all warnings for {}".format(user.name+"#"+user.discriminator)) except KeyError: return await self.bot.say("Could not find user in warning list.") def setup(Bot): Bot.add_cog(Admin(Bot))