async def lock(self, ctx: commands.Context, report_id: int): """Locks a report. This command only works from inside of the queue channel and does not support already approved/denied reports.""" if ctx.guild.me.guild_permissions.manage_messages: await ctx.message.delete() if ctx.channel.id != self.bot.config["channels"]["approval"]: return await ctx.failure( "This command can only be used in the approval queue.", delete_after=15) if not ctx.can_use("CAN_UNLOCK"): return await ctx.failure("You're not allowed to lock reports.", delete_after=15) report = await Report.from_db(self.bot, report_id) if report is None: return await ctx.failure("No report was found with your query.", delete_after=15) if report.locked: return await ctx.failure("This report is already locked.", delete_after=15) if report.stance != 0: return await ctx.failure("This report has already been moved.", delete_after=15) async with self.bot.postgres.acquire() as con: query = """UPDATE bug_reports SET locked = $1 WHERE id = $2;""" await con.execute(query, True, report.id) if await report.approval_message is None: return await ctx.failure( "The approval queue message no longer exists, please contact an Administrator.", delete_after=15) if report.reporter is None: return await ctx.failure( "The user that made this report no longer exists, please contact an Administrator.", delete_after=15) if report.board is None: return await ctx.failure( "The board for this report no longer exists, please contact an Administrator.", delete_after=15) report.locked = True msg = await report.approval_message await msg.edit(content=f"From: {report.board.mention}", embed=make_embed(self.bot, report)) await ctx.success(f"You have locked report **#{report_id}**.", delete_after=15)
async def can_use(self, ctx: commands.Context) -> bool: """Injects a function used to determine whether or not a user can run the specified command. Each command must have a required_perm parameter that matches one of the possible configs.""" def _(perm: str): roles = [r for r in self.bot.config["roles"].items() if perm in r[1]] for role, actions in roles: if role == "everyone" and perm in actions: return True if role in (r.id for r in ctx.author.roles) and perm in actions: return True ctx.can_use = _ return True
async def approve(self, ctx: commands.Context, report_id: int, *, info: str): """Approves a report that is currently in the queue. This command only works from inside of the queue channel and does not support already approved/denied reports.""" if ctx.guild.me.guild_permissions.manage_messages: await ctx.message.delete() if ctx.channel.id != self.bot.config["channels"]["approval"]: return if not ctx.can_use("CAN_APPROVE"): return await ctx.failure("You're not allowed to approve reports.", delete_after=15) report = await Report.from_db(self.bot, report_id) if report is None: return await ctx.failure("No report was found with your query.", delete_after=15) if report.reporter == ctx.author: return await ctx.failure("You can't approve your own report.", delete_after=15) if report.locked: return await ctx.failure("This report has been locked by admins.", delete_after=15) if report.stance != 0: return await ctx.failure("This report has already been moved.", delete_after=15) stance = report.get_stance(ctx.author.id) if stance is not None: if stance.type == -1: report.denies.remove(stance) else: report.approves.remove(stance) report.approves.append(Stance(1, ctx.author, info)) async with self.bot.postgres.acquire() as con: query = """UPDATE bug_reports SET approves = $1, denies = $2, stance = $3 WHERE id = $4;""" await con.execute( query, str(report.approves), str(report.denies), 1 if len(report.approves) >= self.bot.config["stances_needed"] else 0, report.id) if await report.approval_message is None: return await ctx.failure( "The approval queue message no longer exists, please contact an Administrator.", delete_after=15) if report.reporter is None: return await ctx.failure( "The user that made this report no longer exists, please contact an Administrator.", delete_after=15) if report.board is None: return await ctx.failure( "The board for this report no longer exists, please contact an Administrator.", delete_after=15) if len(report.approves) < self.bot.config["stances_needed"]: msg = await report.approval_message await msg.edit(content=f"From: {report.board.mention}", embed=make_embed(self.bot, report)) else: self.bot.dispatch("report_approve", ctx, report) if stance is not None: return await ctx.success( f"You have changed your stance on report **#{report_id}**.", delete_after=15) await ctx.success(f"You have approved report **#{report_id}**.", delete_after=15)
async def revoke(self, ctx: commands.Context, report_id: int): """Revokes your stance on a report that is currently in the queue. This command only works from inside of the queue channel and does not support already approved/denied reports.""" if ctx.guild.me.guild_permissions.manage_messages: await ctx.message.delete() if ctx.channel.id != self.bot.config["channels"]["approval"]: return await ctx.failure( "This command can only be used in the approval queue.", delete_after=15) if not ctx.can_use("CAN_REVOKE"): return await ctx.failure( "You're not allowed to revoke your stance on reports.", delete_after=15) report = await Report.from_db(self.bot, report_id) if report is None: return await ctx.failure("No report was found with your query.", delete_after=15) if report.locked: return await ctx.failure("This report has been locked by admins.", delete_after=15) if report.stance != 0: return await ctx.failure("This report has already been moved.", delete_after=15) stance = report.get_stance(ctx.author) if stance is not None: if stance.type == 1: report.approves.remove(stance) else: report.denies.remove(stance) else: return await ctx.failure( "You haven't placed a stance on this report yet.", delete_after=15) async with self.bot.postgres.acquire() as con: query = """UPDATE bug_reports SET approves = $1, denies = $2 WHERE id = $3;""" await con.execute(query, str(report.approves), str(report.denies), report.id) if await report.approval_message is None: return await ctx.failure( "The approval queue message no longer exists, please contact an Administrator.", delete_after=15) if report.reporter is None: return await ctx.failure( "The user that made this report no longer exists, please contact an Administrator.", delete_after=15) if report.board is None: return await ctx.failure( "The board for this report no longer exists, please contact an Administrator.", delete_after=15) msg = await report.approval_message await msg.edit(content=f"From: {report.board.mention}", embed=make_embed(self.bot, report)) await ctx.success( f"You have revoked your stance on report **#{report_id}**.", delete_after=15)
async def submit(self, ctx: commands.Context, *, text: str): """Submits a bug report.""" config = self.bot.config if ctx.guild.me.guild_permissions.manage_messages: await ctx.message.delete() if ctx.channel.id not in config["channels"]["boards"].keys(): return await ctx.failure( "You must be in a bug board to use this command.", delete_after=15) if not ctx.can_use("CAN_REPORT"): return await ctx.failure("You're not allowed to submit reports.", delete_after=15) data = vars(parser.parse_args(text.split(" "))) # because of how we're parsing it in argparse, the values of each flag will be an iterable # of each word in the sentence, so we iterate through the dictionary and join the lists with " " # if the value is an iterable of some kind for k, v in data.items(): if isinstance(v, (list, tuple)): data[k] = " ".join(v) if None in data.keys(): return await ctx.failure( f"Your syntax seems incorrect! If you're having trouble, try using the tool over at: {config.tool}", delete_after=15) steps = data["steps"].split(" ~ ") queue = ctx.guild.get_channel(config["channels"]["approval"]) if queue is None: return await ctx.failure( "The approval queue does not exist, please contact an Administrator.", delete_after=15) if not queue.permissions_for(ctx.guild.me).send_messages: return await ctx.failure( f"I'm missing permissions to send messages in {queue.mention}, please contact an Administrator.", delete_after=15) async with self.bot.postgres.acquire() as con: query = """INSERT INTO bug_reports (reporter_id, board_id, short_description, steps_to_reproduce, expected_result, actual_result, software_version, stance, created_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id;""" id = await con.fetchval(query, ctx.author.id, ctx.channel.id, data["title"], str(steps), data["expected"], data["actual"], data["software"], 0, datetime.utcnow()) message = await queue.send(f"From: {ctx.channel.mention}", embed=make_embed( self.bot, ctx.channel, id=id, reporter=ctx.author, short=data["title"], steps=steps, expected=data["expected"], actual=data["actual"], software=data["software"])) query = """UPDATE bug_reports SET message_id = $1 WHERE id = $2;""" await con.execute(query, message.id, id)
async def edit(self, ctx: commands.Context, report_id: int, section: str, *, new_content: str): """Edits an existing bug report. This only works on reports currently in the approval queue.""" if ctx.guild.me.guild_permissions.manage_messages: await ctx.message.delete() if not ctx.can_use("CAN_EDIT"): return await ctx.failure("You're not allowed to edit reports.", delete_after=15) report = await Report.from_db(self.bot, report_id) if report is None: return await ctx.failure("No report was found with your query.", delete_after=15) if report.reporter != ctx.author: return await ctx.failure("You did not make this report.", delete_after=15) if report.locked: return await ctx.failure("This report has been locked by admins.", delete_after=15) if report.stance != 0: return await ctx.failure("This report has already been moved.", delete_after=15) key = { "short": "short_description", "header": "short_description", "title": "short_description", "steps": "steps_to_reproduce", "str": "steps_to_reproduce", "body": "steps_to_reproduce", "expected": "expected_result", "actual": "actual_result", "software": "software_version", "sv": "software_version" }.get(section) if key is None: return await ctx.failure( "Check the section name you provided, it's incorrect.", delete_after=15) if key == "steps_to_reproduce": new_content = new_content.split(" ~ ") async with self.bot.postgres.acquire() as con: query = f"""UPDATE bug_reports SET {key} = $1 WHERE id = $2;""" await con.execute(query, str(new_content), report_id) queue = ctx.guild.get_channel(self.bot.config["channels"]["approval"]) if queue is None: return await ctx.failure( "The approval queue does not exist, please contact an Administrator.", delete_after=15) if not queue.permissions_for(ctx.guild.me).read_messages: return await ctx.failure( f"I'm missing permissions to read messages in {queue.mention}, please contact an Administrator.", delete_after=15) if await report.approval_message is None: return await ctx.failure( "The approval queue message no longer exists, please contact an Administrator.", delete_after=15) report.update(key, new_content) if report.board is None: return await ctx.failure( "The board for this report no longer exists, please contact an Administrator.", delete_after=15) msg = await report.approval_message await msg.edit(content=f"From: {report.board.mention}", embed=make_embed(self.bot, report)) await ctx.success(f"You've edited report **#{report_id}**.", delete_after=15)