async def on_message(self, msg: Message): # Log messages to the console/log file if enabled if self.bot.log_messages: timestamp = pretty_datetime(datetime.now(), display="TIME") message = f"[{msg.guild} - #{msg.channel}] <{msg.author}>: {msg.content}" self.bot.log.info(f"-{timestamp}- {message}")
async def admin(self, ctx: Context): """Base command for server administrators. Run without arguments to view current server settings. MUST HAVE SERVER ADMINISTRATOR PERMISSION """ if ctx.invoked_subcommand is not None: return sid = str(ctx.guild.id) log_status = None mute_role = None try: channel = self.bot.get_channel(int(self.db[sid]["log_channel"])) log_status = f"{self.db[sid]['log']}, {channel.mention}" except KeyError: log_status = "Not set up" try: role = ctx.guild.get_role(int(self.db[sid]["mute_role"])) mute_role = role.name except KeyError: mute_role = "Not set up" embed = Embed(title="Admin Info", color=0x7289DA) embed.add_field(name="Log", value=log_status, inline=True) embed.add_field(name="Mute Role", value=mute_role, inline=True) embed.set_footer(text=pretty_datetime(datetime.now())) await ctx.send(embed=embed)
async def warns_list(self, ctx: Context, target: Member = None): """List all active warns of yourself or another member. Invoke without argument to view your own warns. Kick member permission required to view other Members' warns """ sid = str(ctx.guild.id) if target is None: target = ctx.author uid = str(target.id) if uid not in self.warn_db[sid]: await ctx.send(":anger: Member has no warns.") return # This is ugly but it's 4am and I don't care if ( target is not ctx.author and not ctx.channel.permissions_for(ctx.author).kick_members ): return embed = Embed( title=f"{target.name}#{target.discriminator}'s Warns", color=0xFF0000 ) warn_count = len(self.warn_db[sid][uid]) embed.add_field(name="Total warns", value=str(warn_count), inline=False) for i, w in self.warn_db[sid][uid].items(): now = datetime.now(tz=timezone.utc) then = datetime.fromtimestamp(float(w["expires"]), tz=timezone.utc) result = then - now expires = pretty_timedelta(result) issuer = ctx.guild.get_member(int(w["issued_by"])) name = f"{issuer.name}#{issuer.discriminator}" embed.add_field( name=i, value=f"By: {name}\nReason: {w['reason']}\nExpires: {expires}", inline=True, ) embed.set_footer(text=pretty_datetime(datetime.now())) await ctx.send(embed=embed)
def __init__(self, bot: DiscordBot): self.bot = bot self.name = "admin" self.version = VERSION self.backup = True try: with open("config/config.json") as cfg: self.backup = json.load(cfg)["BackupDB"] except Exception as error: self.bot.log.error(f"Error loading from config file:\n - {error}") db_file = "db/admin.sql" if os.path.exists(db_file) and self.backup: timestamp = pretty_datetime(datetime.now(), display="FILE") try: shutil.copyfile(db_file, f"db/backups/admin-{timestamp}.sql") except IOError as e: error_file = f"db/backups/admin-{timestamp}.sql" self.bot.log.error(f"Unable to create file {error_file}\n - {e}") self.sql_db = SqliteDict( filename=db_file, tablename="admin", autocommit=True, encode=json.dumps, decode=json.loads, ) if "admin" not in self.sql_db: self.sql_db["admin"] = {} if "temp_bans" not in self.sql_db: self.sql_db["temp_bans"] = {} if "warns" not in self.sql_db: self.sql_db["warns"] = {} if "mutes" not in self.sql_db: self.sql_db["mutes"] = {} self.db = self.sql_db["admin"] self.tempban_db = self.sql_db["temp_bans"] self.warn_db = self.sql_db["warns"] self.mute_db = self.sql_db["mutes"] asyncio.create_task(self.task_scheduler())
def get_logger(file_name) -> logging.Logger: """Get an instance of Logger and set up log files.""" timestamp = pretty_datetime(datetime.now(), "FILE") log_file = f"logs/{timestamp}_{file_name}" if not os.path.exists("logs"): try: os.makedirs("logs") except IOError as e: print(e) exit() log = logging.getLogger() log.setLevel(logging.INFO) log.addHandler(logging.FileHandler(filename=log_file, encoding="utf-8")) log.addHandler(logging.StreamHandler(sys.stdout)) return log
async def on_command(self, ctx: Context): # Log the command to the console/log file if enabled if self.bot.log_commands: timestamp = pretty_datetime(datetime.now(), display="TIME") command = ctx.message.content author = ctx.author location = f"[{ctx.guild}] - #{ctx.message.channel}" header = f"-{timestamp}- [COMMAND] `{command}`" self.bot.log.info(f"{header} by `{author}` in `{location}`") if self.bot.delete_cmds: try: await ctx.message.delete(delay=2) except Exception as e: self.bot.log.warning( f"Unable to delete command message:\n - {e}")
async def embed_builder( action: str, member: Member, reason: str, td: timedelta = None ) -> Embed: embed = Embed(title=action, color=0xFF0000) embed.add_field(name="From", value=member.guild.name) embed.add_field(name="Reason", value=reason, inline=False) try: embed.set_author(icon_url=member.guild.icon) except Exception: pass if td is not None: embed.add_field(name="Expires In", value=pretty_timedelta(td), inline=False) embed.set_footer(text=pretty_datetime(datetime.now())) return embed
async def log_to_channel(self, ctx: Context, target: Member, info: str = None): """Send an embed-formatted log of an event to a channel.""" sid = str(ctx.guild.id) channel = None enabled = True action = ctx.message.content if sid in self.db: try: channel = ctx.guild.get_channel(int(self.db[sid]["log_channel"])) except KeyError: channel = None try: enabled = self.db[sid]["log"] except KeyError: enabled = False else: channel = ctx.channel enabled = False if not enabled: return if info is None: info = "No extra information" tag = f"{target.name}#{target.discriminator} ({target.id})" embed = Embed( title=f"{ctx.author.name}#{ctx.author.discriminator} {ctx.command.name}", color=0xFF0000, ) embed.set_thumbnail(url=str(ctx.author.avatar_url)) embed.add_field(name="Action", value=action, inline=False) embed.add_field(name="Target", value=tag) embed.add_field(name="Info", value=info) embed.set_footer(text=pretty_datetime(datetime.now())) await channel.send(embed=embed)
def __init__(self, bot: DiscordBot): self.bot = bot self.name = "roles" self.version = VERSION self.backup = True db_file = "db/roles.sql" try: with open("config/config.json") as cfg: conf = json.load(cfg) self.backup = conf["BackupDB"] self.delete_cmds = conf["DeleteCommands"] except Exception as error: self.bot.log.error( f"Error loading prefix from config file.\n - {error}") if os.path.exists(db_file) and self.backup: timestamp = pretty_datetime(datetime.now(), display="FILE") try: shutil.copyfile(db_file, f"db/backups/roles-{timestamp}.sql") except IOError as e: error_file = f"db/backups/roles-{timestamp}.sql" self.bot.log.error( f"Unable to create file {error_file}\n - {e}") self.sql_db = SqliteDict( filename=db_file, tablename="roles", autocommit=True, encode=json.dumps, decode=json.loads, ) if "servers" not in self.sql_db: self.sql_db["servers"] = {} self.db = self.sql_db["servers"]
async def info(self, ctx: Context): """Show the bot's mission control.""" embed = Embed(title="Status", color=0x7289DA) embed.add_field(name="Time", value=pretty_datetime(datetime.now(), "FULL")) embed.add_field(name="Version", value=self.bot.version) embed.add_field(name="User", value=f"{self.bot.user} ({self.bot.user.id})", inline=False) embed.add_field(name="Plugins", value=f"[{', '.join(self.bot.plugins)}]") embed.add_field(name="Servers", value=str(len(self.bot.servers))) # Just in case something happened initializing the app info if self.bot.app_info is not None: embed.set_author(name=self.bot.app_info.name, icon_url=self.bot.app_info.icon_url) embed.set_footer(text="https://github.com/CodeBizarre/discord-bot") await ctx.send(embed=embed)
def test_pretty_datetime_full(): dt = pretty_datetime(sample) assert dt == "2017-8-5 19:0"
def test_pretty_datetime_file(): dt = pretty_datetime(sample, "FILE") assert dt == "2017-8-5-19-0"
def test_pretty_datetime_time(): dt = pretty_datetime(sample, "TIME") assert dt == "19:0:29"
async def on_message_edit(self, former: Message, latter: Message): if former.author.id == self.bot.user.id: return sid = str(former.guild.id) if former.guild is not None else None # Embeds cause message edit events even if the user didn't edit them if former.content == latter.content and former.embeds != latter.embeds: return # Log the edit to the console/log file if enabled if self.bot.log_edits: timestamp = pretty_datetime(datetime.now(), display="TIME") self.bot.log.info( f"-{timestamp}- [EDIT] [{former.guild}] #{former.channel}") self.bot.log.info(f"[BEFORE] <{former.author}>: {former.content}") self.bot.log.info(f"[AFTER] <{latter.author}>: {latter.content}") # Process the commands from the message afterwards if enabled if self.bot.cmd_on_edit: await self.bot.process_commands(latter) # If this is a DM, we don't need to try and log to channel or report ghosts if sid is not None: # Check if the server should report mention deletes try: report_ghosts = self.bot.servers[sid]["report_ghosts"] except KeyError: # This server is not configured. report_ghosts = False if report_ghosts: title = f"A message from {former.author.mention} was edited removing" difference = [ m for m in former.mentions if m not in latter.mentions ] mentions = [f"{m.name}#{m.discriminator}" for m in difference] if difference: await former.channel.send( f"{title} mention(s) from: {mentions}") elif former.mention_everyone and not latter.mention_everyone: await former.channel.send( f"{title} an Everyone or Here mention") elif former.role_mentions != latter.role_mentions: former.mentions = former.role_mentions - latter.role_mentions mentions = [f"{r.name}" for r in former.mentions] await former.channel.send( f"{title} role mention(s): {mentions}") # Log the edit to a channel if the server has it set up try: if self.bot.servers[sid]["log_edits"]: guild = former.guild channel = guild.get_channel( int(self.bot.servers[sid]["log_channel"])) embed = Embed(title="Message Edited", color=0xFF0000) embed.add_field( name= f"By {former.author.name}#{former.author.discriminator}", value= f"In {former.channel.mention}. UID: {former.author.id}", ) embed.add_field(name="Before", value=former.content, inline=False) embed.add_field(name="After", value=latter.content, inline=False) await channel.send(embed=embed) except KeyError: pass
async def on_message_delete(self, msg: Message): sid = str(msg.guild.id) if msg.guild is not None else None # Log the delete to the console/log file if enabled if self.bot.log_deletes: timestamp = pretty_datetime(datetime.now(), display="TIME") header = f"-{timestamp}- [DELETE] " content = f"[{msg.guild}] #{msg.channel} <{msg.author}>: {msg.content}" self.bot.log.info(f"{header} {content}") # If this is a DM, we don't need to try and log to channel or report ghosts if sid is not None: # Check if the server should report mention deletes try: report_ghosts = self.bot.servers[sid]["report_ghosts"] except KeyError: # This server is not configured. report_ghosts = False if report_ghosts and msg.author.id != self.bot.user.id: title = f"A message from {msg.author.mention} was removed mentioning" if len(msg.mentions) > 0: mentions = [ f"{m.name}#{m.discriminator}" for m in msg.mentions ] await msg.channel.send(f"{title}: {mentions}") elif msg.mention_everyone: await msg.channel.send(f"{title}: Everyone or Here") elif len(msg.role_mentions) > 0: mentions = [f"{r.name}" for r in msg.role_mentions] await msg.channel.send(f"{title} role: {mentions}") # Log the delete to a channel if the server has it set up try: if self.bot.servers[sid]["log_deletes"]: # Try to get the user who deleted the message, not reliable action = await msg.guild.audit_logs( limit=1, action=AuditLogAction.message_delete).flatten() who = action[0].user guild = msg.guild channel = guild.get_channel( int(self.bot.servers[sid]["log_channel"])) embed = Embed(title="Message Deleted", color=0xFF0000) embed.add_field( name="Last message delete action performed by:", value=f"{who.name}#{who.discriminator} or a bot", inline=False, ) embed.add_field( name= f"Author - {msg.author.name}#{msg.author.discriminator}", value= f"From {msg.channel.mention} - UID: {msg.author.id}", ) embed.add_field(name="Message", value=msg.content, inline=False) await channel.send(embed=embed) except KeyError: pass