async def vote(self, ctx): message = ctx.message lines = message.content.split("\n") if len(lines) < 3: await ctx.send( ">>> " + text.fill("vote", "vote_help", prefix=config.prefix)) return now = datetime.now() try: timex = re.compile(r"[ ](\d*[h])*[ ]*(\d*[m])*[ ]*(\d*[s])*[ ]") if timex.search(str(lines[0])) is not None: now = datetime.now() t = dparser.parse(lines[0], dayfirst=True, fuzzy=True) diff = t - now.replace(hour=0, minute=0, second=0) date = now + diff else: date = dparser.parse(lines[0], dayfirst=True, fuzzy=True) if now > date: date += timedelta(days=1) except dateutil.parser._parser.ParserError: date = now + timedelta(hours=1) votes = [] for idx, line in enumerate(lines): if idx > 0: emote = re.match(r"<:\w*:\d*>", line) if emote is not None: for emoji in self.bot.emojis: if str(emoji) in line: votes.append({ "emote": emoji, "option": line.replace(str(emoji) + " ", ""), "num_votes": 0, }) break else: await ctx.send(text.get("vote", "emote_unknown")) return else: await ctx.send(text.get("vote", "emote_unknown")) return for option in votes: await ctx.message.add_reaction(option["emote"]) edit_msg = await ctx.send( text.fill("vote", "waiting", date=date.strftime("%Y-%m-%d %H:%M:%S"))) repository.add_vote( channel_id=message.channel.id, message_id=message.id, edit_id=edit_msg.id, date=date.strftime("%Y-%m-%d %H:%M:%S"), ) await self.loop(ctx.message, edit_msg, date) return
async def channelboard(self, ctx, offset: int = 1): await asyncio.sleep(0.5) user_channels = repository.get_user_channels() if not user_channels: return ctx.send(text.get("boards", "not found")) # convert to be zero-indexed offset -= 1 if offset < 0: return await ctx.send(text.get("boards", "invalid offset")) results = await self.sort_channels(user_channels, False) if offset > len(results): return await ctx.send(text.get("boards", "offset too big")) embed = discord.Embed( title=text.get("boards", "channel board title"), description=text.get("boards", "channel board desc"), color=config.color, ) # get data for "TOP X" list lines = [] for position, item in enumerate(results): if position < offset: continue if position - offset >= config.board_top: break channel = self.bot.get_channel(item["channel_id"]) if not hasattr(channel, "name"): # channel was not found continue # fmt: off if ctx.guild is not None and channel.guild.id == ctx.guild.id: lines.append(text.fill("boards", "channel template", index=f"{position + 1:>2}", count=f"{item['count']:>5}", name=discord.utils.escape_markdown(channel.name))) else: # channel is on some other guild lines.append(text.fill("boards", "channel template guild", index=f"{position + 1:>2}", count=f"{item['count']:>5}", name=discord.utils.escape_markdown(channel.name), guild=discord.utils.escape_markdown(channel.guild.name))) # fmt: on title = "top number" if offset == 0 else "top offset" # fmt: off embed.add_field( name=text.fill("boards", title, top=config.board_top, offset=offset + 1), value="\n".join(lines), inline=False, ) # fmt: on await ctx.send(embed=embed)
def fill_subject_embed(self, embed: discord.Embed, review: object, average: float) -> discord.Embed: # reset any previous embed.clear_fields() # add content # fmt: off name = self.bot.get_user(int(review.discord_id)) or text.get( "judge", "embed_no_user") if review.anonym: name = text.get("judge", "embed_anonymous") embed.add_field( inline=False, name=text.fill("judge", "embed_no", num=str(review.id)), value=text.fill("judge", "embed_average", num=f"{average:.1f}"), ) embed.add_field(name=name, value=review.date) embed.add_field(name=text.get("judge", "embed_mark"), value=review.tier) embed.add_field( inline=False, name=text.get("judge", "embed_text"), value=review.text_review, ) # fmt: on embed.add_field(name="👍", value=f"{repo_r.get_votes_count(review.id, True)}") embed.add_field(name="👎", value=f"{repo_r.get_votes_count(review.id, False)}") return embed
async def on_member_update(self, before, after): booster_role = discord.utils.get(self.getGuild().roles, id=config.booster_role) if booster_role in before.roles: before_booster = True else: before_booster = False if booster_role in after.roles: after_booster = True else: after_booster = False if not before_booster and not after_booster: return elif before_booster and after_booster: return elif not before_booster and after_booster: embed = discord.Embed( title=text.get("base", "new_server_booster"), color=config.color_boost, timestamp=datetime.datetime.now().replace(microsecond=0), ) elif before_booster and not after_booster: embed = discord.Embed( title=text.get("base", "not_booster_anymore"), color=config.color_boost, timestamp=datetime.datetime.now().replace(microsecond=0), ) embed.set_thumbnail(url=after.avatar_url) embed.add_field(name="User", value=f"{after.name}#{after.discriminator}") embed.set_footer(text=f"UserID: {after.id}") channel = discord.utils.get(self.getGuild().channels, id=config.boost_channel) await channel.send(embed=embed)
async def power_on(self, ctx): """Restore""" jail = self.getGuild().get_channel(config.get("channels", "jail")) everyone = self.getGuild().default_role botspam = self.getGuild().get_channel(config.get( "channels", "botspam")) visited = [] if jail is not None: # remove the message messages = await jail.history(limit=10).flatten() for message in messages: if message.content.startswith( text.get("admin", "poweroff jail")): await message.delete() break # switch to read-write await jail.set_permissions(everyone, send_messages=True, reason="?power on") visited.append(jail.mention) if botspam is not None: # send message await botspam.send(text.get("admin", "poweron botspam")) visited.append(botspam.mention) # send confirmation message if len(visited) > 0: await ctx.send( text.fill("admin", "poweron ok", channels=", ".join(visited))) else: await ctx.send(text.fill("admin", "power fail")) await self.event.sudo(ctx.author, ctx.channel, "Power on")
async def karma_stalk(self, ctx, member: discord.Member): """See someone's karma""" k = repo_k.get_karma(member.id) embed = self.embed( ctx=ctx, description=text.fill( "karma", "stalk_user", user=self.sanitise(member.display_name, limit=32) ), ) embed.add_field( name=text.get("karma", "stalk_karma"), value=f"**{k.karma.value}** ({k.karma.position}.)", inline=False, ) embed.add_field( name=text.get("karma", "stalk_positive"), value=f"**{k.positive.value}** ({k.positive.position}.)", ) embed.add_field( name=text.get("karma", "stalk_negative"), value=f"**{k.negative.value}** ({k.negative.position}.)", ) await ctx.send(embed=embed) await self.event.user(ctx.author, ctx.channel, f"Karma stalk on {member.name}.") await utils.room_check(ctx)
async def get_embed(self, row): user = self.bot.get_user(row.user_id) if user is None: try: user = await self.bot.fetch_user(row.user_id) except discord.errors.NotFound: return reminder_user = self.bot.get_user(row.reminder_user_id) if reminder_user is None: try: reminder_user = await self.bot.fetch_user(row.reminder_user_id) reminder_user_name = discord.utils.escape_markdown( reminder_user.display_name) except discord.errors.NotFound: reminder_user_name = "_(Unknown user)_" else: reminder_user_name = discord.utils.escape_markdown( reminder_user.display_name) embed = self.create_embed(author=reminder_user, title=text.get("remindme", "reminder")) if row.user_id != row.reminder_user_id: embed.add_field(name=text.get("remindme", "reminder by"), value=reminder_user_name, inline=True) if row.message != "": embed.add_field(name=text.get("remindme", "reminder message"), value=row.message, inline=False) embed.add_field(name=text.get("remindme", "reminder link"), value=row.permalink, inline=True) return embed, user
async def karma_emotes(self, ctx): """See karma for all emotes""" emotes = await ctx.guild.fetch_emojis() content = [] emotes_positive = self._getEmoteList(emotes, "1") if len(emotes_positive) > 0: content.append(text.get("karma", "emotes_positive")) content += self._emoteListToMessage(emotes_positive, 10) emotes_negative = self._getEmoteList(emotes, "-1") if len(emotes_negative) > 0: content.append(text.get("karma", "emotes_negative")) content += self._emoteListToMessage(emotes_negative, 10) emotes_nonvoted = self._getNonvotedEmoteList(emotes) if len(emotes_nonvoted) > 0: content.append(text.get("karma", "emotes_nonvoted")) content += self._emoteListToMessage(emotes_nonvoted, 10) if len(content) == 0: content.append(text.get("karma", "no emotes")) for line in [x for x in content if (x and len(x) > 0)]: await ctx.send(line) await utils.room_check(ctx)
async def review_add(self, ctx, subject: str, mark: int, *, text: str): """Add a review subject: Subject code mark: 1-5 (one being best) text: Your review """ if mark < 1 or mark > 5: return await ctx.send(text.get("judge", "wrong mark")) if len(text) > 1024: return await ctx.send(text.get("judge", "text too long")) # check if subject is in database db_subject = repo_s.get(subject) if db_subject is None: return await ctx.send(text.get("judge", "no subject")) anonymous = isinstance(ctx.channel, discord.DMChannel) past_review = repo_r.get_review_by_author_subject( ctx.author.id, subject) if past_review is None: # add repo_r.add_review(ctx.author.id, subject, mark, anonymous, text) else: # update repo_r.update_review(past_review.id, mark, anonymous, text) # send confirmation await self.event.user(ctx.author, ctx.channel, f"Review by {ctx.author} for {subject} added") return await ctx.send(text.get("judge", "added"))
async def database_remove(self, ctx: commands.Context, member: discord.Member = None, force: str = None): """Remove user from database member: A server member force: "force" string. If omitted, show what will be deleted """ if member is None: return await utils.send_help(ctx) # define variables guild = self.bot.get_guild(config.guild_id) force = self.parseArg(force) try: if force: result = repository.deleteId(discord_id=member.id) else: result = repository.filterId(discord_id=member.id) except Exception as e: return await self.output.error(ctx, text.get("db", "read"), e) d = "Result" if force else "Simulation, run with `force` to apply" if force: embed = self.embed(description=d, color=config.color_success) # delete if result is None or result < 1: return await self.output.error(ctx, text.get("db", "delete error")) embed.add_field(inline=False, name="Success", value=text.fill("db", "delete success", num=result)) embed.add_field( name="Warning", value="Roles and channel access haven't been removed") await self.event.sudo(ctx.author, ctx.channel, "User removed from database: " + member.name) # TODO remove all roles else: # simulate embed = discord.Embed(color=config.color_notify, description=d) for r in result: embed.add_field( inline=False, name=self.dbobj2email(r), value=discord.utils.get(guild.members, id=int(r.discord_id)).mention, ) if len(result) < 1: embed.add_field(name="No entry", value=text.get("db", "not found"), inline=False) await ctx.send(embed=embed, delete_after=config.delay_embed) await utils.delete(ctx)
async def reschedule(self, ctx, idx: int): """Přesune upomínku na jindy""" row = repository.get_idx(idx) if row == []: await ctx.send(text.get("remindme", "wrong ID")) return if row[0].user_id != ctx.author.id: await ctx.send( text.get("remindme", "cannot edit other's reminders")) return message = ctx.message.content message = message.replace("weekend", "saturday").replace(str(idx), "") date, date_str = await self.parse_datetime(message) print_date = date.strftime("%d.%m.%Y %H:%M") embed, user = await self.get_embed(row[0]) embed.add_field(name=text.get("remindme", "reminder edit new time"), value=print_date, inline=False) embed.add_field( name=text.get("remindme", "reminder edit confirmation"), value=text.get("remindme", "reminder edit text"), inline=False, ) user_id = user.id message = await ctx.send(embed=embed) await message.add_reaction("✅") await message.add_reaction("❎") while True: def chk(reaction, usr): return (reaction.message.id == message.id and (str(reaction.emoji) == "✅" or str(reaction.emoji) == "❎") and usr.id == user_id) try: reaction, user = await self.bot.wait_for( "reaction_add", check=chk, timeout=config.delay_embed) except asyncio.TimeoutError: pass else: if str(reaction.emoji) == "✅": await self.log( level="debug", message= f"Rescheduling reminder - ID: {row[0].idx}, time: {date}, status: {row[0].status}, \n message: {row[0].message}", ) repository.postpone(row[0].idx, date) try: await message.delete() except discord.errors.Forbidden: pass except discord.errors.NotFound: pass
async def channelinfo(self, ctx, channel: discord.TextChannel): await self.deleteCommand(ctx, now=True) await asyncio.sleep(0.1) channels = repository.get_user_channels() all_results = await self.sort_channels(channels) users = await self.sort_users(repository.get_channel(channel.id)) offset = -1 if not users: return await ctx.send(text.get("boards", "not found")) for idx, result in enumerate(all_results, start=1): if result["channel_id"] == channel.id: total_count = result["count"] last_msg_at = result["last_msg_at"] position = idx for user in users: if user["last_msg_at"] == last_msg_at: user = self.bot.get_user(user["user_id"]) if user is None: try: user = await self.bot.fetch_user(user["user_id"]) user_name = discord.utils.escape_markdown(f"{user.display_name}#{user.discriminator}") except discord.errors.NotFound: user_name = "_(Unknown user)_" else: user_name = discord.utils.escape_markdown(f"{user.display_name}#{user.discriminator}") break else: user_name = "_(Unknown user)_" last_msg_at = last_msg_at.replace(tzinfo=timezone.utc).astimezone(tz=None) last_msg_at = last_msg_at.strftime("%d.%m.%Y %H:%M:%S") embed = self.create_embed(author=ctx.message.author, title=text.get("boards", "channel info title")) embed.add_field(name="Jméno", value=str(channel.name), inline=True) embed.add_field(name="ID", value=str(channel.id), inline=True) embed.add_field(name="Server", value=str(channel.guild.name), inline=True) try: embed.add_field(name="Kategorie", value=str(channel.category.name), inline=True) except AttributeError: pass embed.add_field(name="Poslední zpráva", value=f"{user_name}\n{last_msg_at}", inline=True) embed.add_field(name="Celkový počet zpráv", value=str(total_count), inline=True) embed.add_field( name="Pozice mezi kanály", value="{0}/{1}".format(position, len(all_results)), inline=True ) embeds = [] embeds.append(embed) boards, pagenum = await self.boards_generator(ctx, users, offset, "channel info") embeds += boards await self.board_pages(ctx, embeds, pagenum) return
async def image_remove(self, ctx, filename: str): """Remove image filename: An image filename """ if "/" in filename or "\\" in filename or ".." in filename: return self.output.error(ctx, text.get("actress", "BadCharacter")) os.remove(self.path + filename) await self.output.info(text.get("actress", "deleted")) await utils.delete(ctx)
async def sudo_subject_remove(self, ctx, subject: str): """Remove subject subject: Subject code """ db_subject = repo_s.get(subject) if db_subject is None: return await ctx.send(text.get("judge", "no subject")) repo_s.remove(subject) await self.event.sudo(ctx.author, ctx.channel, f"Subject {subject} removed") await ctx.send(text.get("judge", "subject removed"))
async def database_add( self, ctx: commands.Context, member: discord.Member = None, login: str = None, group: discord.Role = None, ): """Add user to database member: A server member login: xlogin (FEKT, VUT) or e-mail group: A role from `roles_native` or `roles_guest` in config file """ if member is None or login is None or group is None: return await utils.send_help(ctx) # define variables guild = self.bot.get_guild(config.guild_id) verify = discord.utils.get(guild.roles, name="VERIFY") # try to write to database try: repository.filterId(discord_id=member.id)[0] return await self.output.error(ctx, text.get("db", "duplicate")) except IndexError: # no result is good, we won't have collision pass try: repository.add_user( discord_id=member.id, login=login, group=group.name, status="verified", code="MANUAL", ) except Exception as e: return await self.output.error(ctx, text.get("db", "write"), e) # assign roles, if neccesary if verify not in member.roles: await member.add_roles(verify) if group not in member.roles: await member.add_roles(group) # display the result await self.whois_member(ctx, member, log=False) await self.event.sudo(ctx.author, ctx.channel, f"New user {member} ({group.name})")
async def _send_verification_email(self, member: discord.Member, email: str, code: str) -> bool: cleartext = text.get("gatekeeper", "plaintext mail").format( guild_name=self.getGuild().name, code=code, bot_name=self.bot.user.name, git_hash=utils.git_hash()[:7], prefix=config.prefix, ) richtext = text.get("gatekeeper", "html mail").format( # styling color_bg="#54355F", color_fg="white", font_family="Arial,Verdana,sans-serif", # names guild_name=self.getGuild().name, bot_name=self.bot.user.name, user_name=member.name, # codes code=code, git_hash=utils.git_hash()[:7], prefix=config.prefix, # images bot_avatar=self.bot.user.avatar_url_as(static_format="png", size=128), bot_avatar_size="120px", user_avatar=member.avatar_url_as(static_format="png", size=32), user_avatar_size="20px", ) msg = MIMEMultipart("alternative") msg["Subject"] = text.fill("gatekeeper", "mail subject", guild_name=self.getGuild().name, user_name=member.name) msg["From"] = config.get("email", "address") msg["To"] = email msg["Bcc"] = config.get("email", "address") msg.attach(MIMEText(cleartext, "plain")) msg.attach(MIMEText(richtext, "html")) with smtplib.SMTP(config.get("email", "server"), config.get("email", "port")) as server: server.starttls() server.ehlo() server.login(config.get("email", "address"), config.get("email", "password")) server.send_message(msg)
async def delete(self, ctx, idx: int): """Smaže upomínku""" row = repository.get_idx(idx) if row == []: await ctx.send(text.get("remindme", "wrong ID")) return if row[0].user_id != ctx.author.id: await ctx.send( text.get("remindme", "cannot delete other's reminders")) return embed, user = await self.get_embed(row[0]) embed.add_field( name=text.get("remindme", "reminder delete confirmation"), value=text.get("remindme", "reminder delete text"), inline=False, ) user_id = user.id message = await ctx.send(embed=embed) await message.add_reaction("✅") await message.add_reaction("❎") while True: def chk(reaction, usr): return (reaction.message.id == message.id and (str(reaction.emoji) == "✅" or str(reaction.emoji) == "❎") and usr.id == user_id) try: reaction, user = await self.bot.wait_for( "reaction_add", check=chk, timeout=config.delay_embed) except asyncio.TimeoutError: pass else: if str(reaction.emoji) == "✅": await self.log( level="debug", message= f"Deleting reminder from db - ID: {row[0].idx}, time: {row[0].new_date}, status: {row[0].status}, \n message: {row[0].message}", ) repository.delete(row[0].idx) try: await message.delete() except discord.errors.Forbidden: pass except discord.errors.NotFound: pass
async def send( self, source: Union[commands.Context, discord.Message], level: str, message: str = None, error: Exception = None, ): """Send output to source channel""" template = ">>> **{level}**: {message}" template_cont = "\n{error} ```{traceback}```" # make sure there is something after the colon if message is None and error is None: message = "unspecified" result = template.format(level=text.get("bot", level).upper(), message=message) # parse error if error is not None: tr = "".join( traceback.format_exception(type(error), error, error.__traceback__)) if len(tr) > 1000: tr = "…" + tr[-999:] # escape error = discord.utils.escape_markdown(str(error)).replace( "@", "@\u200b") tr = tr.replace("```", "`\u200b`\u200b`") result += template_cont.format(error=error, traceback=tr) await source.send(result)
async def on_command_error(self, ctx: commands.Context, error): # try to get original error if hasattr(ctx.command, "on_error") or hasattr(ctx.command, "on_command_error"): return error = getattr(error, "original", error) # non-rubbergoddess exceptions are handled globally if not isinstance(error, rubbercog.RubbercogException): return # fmt: off # exceptions with parameters if isinstance(error, InvalidReactionKey): await self.output.error( ctx, text.fill("actress", "InvalidReactionKey", key=error.key)) elif isinstance(error, ReactionParsingException): await self.output.error( ctx, text.fill("actress", "ReactionParsingException", key=error.key, value=error.value)) # exceptions without parameters elif isinstance(error, ActressException): await self.output.error(ctx, text.get("actress", type(error).__name__))
async def finished(self, ctx): """Zobrazí dokončené upomínky""" repo = repository.get_finished() if repo is None: await ctx.send(text.get("remindme", "no reminders")) return await self.reminder_list(ctx, repo)
async def all(self, ctx): """Zobrazí všechny upomínky""" repo = repository.get_ordered() if repo is None: await ctx.send(text.get("remindme", "no reminders")) return await self.reminder_list(ctx, repo)
async def send_image(self, ctx, channel: discord.TextChannel, filename): """Send an image as a bot channel: Target text channel filename: A filename """ now = time.monotonic() try: async with ctx.typing(): message = await channel.send(file=discord.File(self.path + filename)) delta = time.monotonic() - now await self.output.info( ctx, text.fill("actress", "file sent", delta=delta)) mention = channel.mention if hasattr( channel, "mention") else type(channel).__name__ await self.event.sudo( ctx.author, ctx.channel, f"Media file sent to {mention}:\n" f"> _{filename}_\n> <{message.jump_url}>", ) except Exception as e: await self.output.error(ctx, text.get("actress", "FileSendError"), e)
async def sudo_subject_add(self, ctx, subject: str, name: str, category: str): """Add subject subject: Subject code name: Subject name category: Subject faculty or other assignment """ db_subject = repo_s.get(subject) if db_subject is not None: return await ctx.send(text.get("judge", "subject exists")) repo_s.add(subject, name, category) await self.event.sudo(ctx.author, ctx.channel, f"Subject {subject} added") await ctx.send(text.get("judge", "subject added"))
async def sudo_subject_update(self, ctx, subject: str, name: str, category: str): """Update subject subject: Subject code name: Subject name category: Subject faculty or other assignment """ db_subject = repo_s.get(subject) if db_subject is None: return await ctx.send(text.get("judge", "no subject")) repo_s.update(subject, name, category) await self.event.sudo(ctx.author, ctx.channel, f"Subject {subject} updated") await ctx.send(text.get("judge", "subject updated"))
async def hoarders(self, ctx: commands.Context, warn: str = None): """Check for users with multiple programme roles warn: Optional. Use "warn" string to send warnings, else just list the users """ warn = warn == "warn" hoarders = [] limit_top = discord.utils.get(self.getGuild().roles, name="---PROGRAMMES") limit_bottom = discord.utils.get(self.getGuild().roles, name="---INTERESTS") for member in self.getGuild().members: prog = [] for role in member.roles: if role < limit_top and role > limit_bottom: prog.append(role.name) if len(prog) > 1: hoarders.append([member, prog]) if len(hoarders) == 0: await ctx.send(text.get("janitor", "no hoarders")) else: all = len(hoarders) if warn: msg = await ctx.send( "Odesílání zprávy 1/{all}.".format(all=all)) embed = discord.Embed(title="Programme hoarders", color=config.color) for num, (hoarder, progs) in enumerate(hoarders, start=1): embed.add_field( name="User", value= f"**{discord.utils.escape_markdown(hoarder.name)}** ({hoarder.id})", ) embed.add_field(name="Status", value=hoarder.status) embed.add_field(name="Programmes", value=", ".join(progs), inline=False) if warn: if num % 5 == 0: # Do not stress the API too much await msg.edit(content="Odesílání zprávy {num}/{all}.". format(num=num, all=all)) await hoarder.send( text.fill("janitor", "hoarding warning", guild=self.getGuild().name)) if num % 8 == 0: # Can't have more than 25 fields in an embed await ctx.channel.send(embed=embed, delete_after=config.delay_embed) embed = discord.Embed(title="Programme hoarders", color=config.color) if warn and num % 5 != 0: await msg.edit(content="Odesílání zprávy {num}/{all}.".format( num=num, all=all)) await ctx.channel.send(embed=embed, delete_after=config.delay_embed) await utils.delete(ctx)
async def error( self, source: Union[commands.Context, discord.Message], message: str = None, error: Exception = None, ): if self.level <= logging.ERROR: await self.send(source, text.get("bot", "error"), message, error)
async def reminders(self, ctx): """Zobrazí upomínky uživatele""" if ctx.invoked_subcommand is None: repo = repository.get_user(user_id=ctx.author.id) if repo is None: await ctx.send(text.get("remindme", "no reminders for you")) return await self.reminder_list(ctx, repo)
async def karma_emote(self, ctx, emote: str): """See emote's karma""" if not self._isUnicode(emote): try: emote_id = int(self._emoteToID(emote)) emote = await ctx.guild.fetch_emoji(emote_id) except (ValueError, IndexError): return await utils.send_help(ctx) except discord.NotFound: return await ctx.send(text.get("karma", "emote not found")) value = repo_k.emoji_value_raw(emote) if value is None: return await ctx.send(text.get("karma", "emote not voted")) await ctx.send(text.fill("karma", "emote", emote=str(emote), value=str(value))) await utils.room_check(ctx)
async def plot(self, ctx, xmin: Optional[float] = -10, xmax: Optional[float] = 10, *, inp: str): equations = escape_mentions(escape_markdown(inp)).split(";") fig = plt.figure(dpi=300) ax = fig.add_subplot(1, 1, 1) if xmin < 0 < xmax: ax.spines["left"].set_position("zero") # Eliminate upper and right axes ax.spines["right"].set_color("none") ax.spines["top"].set_color("none") # Show ticks in the left and lower axes only ax.xaxis.set_tick_params(bottom=True, direction="inout") ax.yaxis.set_tick_params(left=True, direction="inout") successful_eq = 0 msg = text.get("draw", "plot_err") numpy.seterr(divide="ignore", invalid="ignore") async with ctx.typing(): for eq in equations: try: func = self.string2func(eq) x = numpy.linspace(xmin, xmax, 1000) plt.plot(x, func(x)) plt.xlim(xmin, xmax) successful_eq += 1 except Exception as e: msg += "\n" + eq + " - " + str(e) if msg != text.get("draw", "plot_err"): await ctx.send(msg) if successful_eq > 0: if not os.path.isdir("assets"): os.mkdir("assets") plt.savefig("assets/plot.png", bbox_inches="tight", dpi=100) plt.clf() await ctx.send(file=discord.File("assets/plot.png")) os.remove("assets/plot.png") return
async def warning( self, source: Union[commands.Context, discord.Message], message: str = None, error: Exception = None, ): if self.level <= logging.WARNING: await self.send(source, text.get("bot", "warning"), message, error)