async def remind(self, ctx, *, argument: commands.clean_content): args = argument.split("\n") time = args.pop(0) if args: reason = "\n".join(args).strip()[:self.char_limit] else: reason = "Kein Grund angegeben" expected_date = dateparser.parse(time, settings=self.set) if expected_date is None: msg = "Es konnte kein gültiges Zeitformat erkannt werden" return await ctx.send(embed=utils.error_embed(msg)) current_date = datetime.now() difference = (expected_date - current_date).total_seconds() embed = discord.Embed(colour=discord.Color.green()) embed.description = "**Erinnerung registriert:**" represent = expected_date.strftime(self.preset) embed.set_footer(text=represent) if difference < 0: msg = "Der Zeitpunkt ist bereits vergangen" return await ctx.send(embed=utils.error_embed(msg)) arguments = [ ctx.author.id, ctx.channel.id, current_date, expected_date, reason ] reminder = Timer.from_arguments(self.bot, arguments) if difference < 60: await ctx.send(embed=embed) await asyncio.sleep(difference) await reminder.send() else: query = 'INSERT INTO reminder ' \ '(author_id, channel_id, creation, expiration, reason)' \ ' VALUES ($1, $2, $3, $4, $5) RETURNING id' async with self.bot.ress.acquire() as conn: resp = await conn.fetchrow(query, *arguments) reminder.id = resp['id'] if not self.current_reminder: self.current_reminder = reminder self._lock.set() else: if reminder.expiration < self.current_reminder.expiration: self.restart(reminder) logger.debug(f"reminder {resp['id']}: registered") embed.description = f"{embed.description[:-3]} (ID {resp['id']}):**" await ctx.send(embed=embed)
async def error_handle(self, ctx: commands.Context, error: Exception): print(error) if isinstance(error, commands.CommandOnCooldown): minl = round(error.retry_after) // 60 sec = round(error.retry_after) % 60 if minl == 0: return await ctx.send(f'{sec}초 이후에 명령어를 다시 실행할수 있습니다') else: return await ctx.send(f'{minl}분 {sec}초 이후에 명령어를 다시 실행할수 있습니다') if isinstance(error, commands.MissingRequiredArgument): return await ctx.send(embed=utils.info_embed( f"올바르지 않은 사용", f"올바른 사용법: `{ctx.prefix}{ctx.command} {ctx.command.usage}`", author=ctx.author)) if isinstance(error, utils.exceptions.NotRegistered): return await ctx.send( embed=utils.info_embed("가입 필요", f"`{ctx.prefix}가입`을 통해 가입을 진행해 주세요.", author=ctx.author)) if isinstance(error, utils.exceptions.SendNotRegistered): return await ctx.send(embed=utils.info_embed( "송금 요류", f"송금하는 대상이 가입되어 있지 않습니다.", author=ctx.author)) if isinstance(error, utils.exceptions.AlreadyRegistered): return await ctx.send(embed=utils.error_embed( f"이미 가입되어 있는 이용자입니다!", footer=f"{ctx.prefix}탈퇴 로 가입을 해제할수 있어요!", author=ctx.author)) embed = discord.Embed(title='오류', description=f'`{error}`', color=config.embed_color) return await ctx.send(embed=utils.normal_embed('오류', error, ctx.author) )
async def set_conquer(self, ctx): channels = self.config.get('conquer', ctx.guild.id, default={}) if str(ctx.channel.id) in channels: msg = "Der aktuelle Channel ist bereits eingespeichert" await ctx.send(embed=error_embed(msg)) elif len(channels) >= 2: msg = "Momentan sind nur 2 Eroberungschannel möglich" await ctx.send(embed=error_embed(msg)) else: channels[str(ctx.channel.id)] = {'bb': False, 'tribe': [], 'player': []} self.config.update('conquer', channels, ctx.guild.id) msg = f"{ctx.channel.mention} ist nun ein Eroberungschannel" await ctx.send(embed=complete_embed(msg))
async def setaxisboundaries(self, ctx, dataset_name: str, minimum_x: float, maximum_x: float, minimum_y: float, maximum_y: float): """Sets specific axis boundaries (minimums and maximums for x and y) for a specific dataset. Args: dataset_name (str): Name of the dataset minimum_x (float): Minimum X value for the axis maximum_x (float): Maximum X value for the axis minimum_y (float): Minimum Y value for the axis maximum_y (float): Maximum Y value for the axis """ try: author = ctx.author bounds = [ float(minimum_x), float(maximum_x), float(minimum_y), float(maximum_y) ] dbfunc.set_axis_info(author.id, dataset_name, str(bounds)) title = f"Axis boundaries `{str(bounds)}` have been set for dataset {dataset_name}!" description = "" colour = discord.Color.green() await ctx.send(embed=utils.create_embed(title, description, colour) ) except: description = f"One of your boundary inputs was not a float. Please try again or reference `/help setaxisboundaries` for more information." await ctx.send(embed=utils.error_embed(description))
async def conquer_list(self, ctx): conquer = self.get_conquer_data(ctx) if not conquer['tribe'] and not conquer['player']: msg = "Du hast noch keinen Stamm oder Spieler in den Filter eingetragen" await ctx.send(embed=error_embed(msg)) else: world = self.config.get_world(ctx.channel) counter = 0 embed = discord.Embed() for dstype in ('tribe', 'player'): cache = await self.bot.fetch_bulk(world, conquer[dstype], dstype) if not cache: continue data = [str(obj) for obj in cache[:20]] name = "Stämme:" if dstype == "tribe" else "Spieler:" embed.add_field(name=name, value="\n".join(data), inline=False) counter += len(data) name = "Element" if counter == 1 else "Elemente" embed.title = f"{counter} {name} insgesamt:" await ctx.send(embed=embed)
async def _plotgenerate(self, ctx, dataset_name: str, saved_plot_name: str, save_and_close: bool = True, create_figure: bool = True, set_common_plot_info: bool = True, send_message: bool = True, figure_created: bool = False, first_combine: bool = True): #Get the graph type saved_plot_dict = await asyncutils.get_saved_plot_dict( ctx, dataset_name, saved_plot_name) #Iterate through the different graph names to determine which type of graph to plot graph_name = saved_plot_dict["name"] if graph_name == "scatterplot": await self._generatescatter(ctx, dataset_name, saved_plot_dict, save_and_close, create_figure, set_common_plot_info, send_message) elif graph_name == "bargraph": await self._generatebar(ctx, dataset_name, saved_plot_dict, save_and_close, create_figure, set_common_plot_info, send_message) elif graph_name == "combo": await self._generatecombo(ctx, dataset_name, saved_plot_dict, figure_created, first_combine) else: error_msg = f"An error occurred on our end when generating the plot: Incorrect plot name stored in DB. Please use `/report` to report the issue or get help in our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(error_msg)) return
async def removerow(self, ctx, dataset_name:str, row_name:str): """Removes a row of data from a user's dataset. Args: dataset_name (str): Name of the dataset row_name (str): Name of the row to remove """ #Get the data datadict = await asyncutils.get_data_dictionary(ctx, dataset_name) if datadict is None: return values = datadict.get(row_name, None) if values is None: description=f"Your row name doesn't exist in dataset `{dataset_name}`. Please double-check the names using `/viewdata <dataset_name>` and try again." await ctx.send(embed=utils.error_embed(description)) return del datadict[row_name] #Write the data to the database data_written = await asyncutils.log_data_to_database(ctx, dataset_name, datadict) if data_written == False: return title=f"Row `{row_name}` has been deleted from dataset `{dataset_name}`!" description="" color=discord.Color.green() await ctx.send(embed=utils.create_embed(title, description, color))
async def verify_same_length(ctx, values, labels): labels_string = ", ".join(labels) if values == []: description = f"An error happened on our end: Values list is empty. Please use `/report` to report the issue or get help in our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(description)) return None first_length = len(values[0]) for value in values: if len(value) != first_length: description = f"The following rows must have the same number of values: {labels_string}. Please change your input and try again." await ctx.send(embed=utils.error_embed(description)) return None return True
async def set_game(self, ctx): cur = self.config.get('game', ctx.guild.id) if cur == ctx.channel.id: msg = "Der aktuelle Channel ist bereits eingespeichert" await ctx.send(embed=error_embed(msg)) else: self.config.update('game', ctx.channel.id, ctx.guild.id) msg = f"{ctx.channel.mention} ist nun der aktive Game-Channel" await ctx.send(embed=complete_embed(msg))
async def set_world(self, ctx, world: WorldConverter): old_world = self.config.get_related_world(ctx.guild) if world == old_world: msg = f"Der Server ist bereits mit {world} verbunden" await ctx.send(embed=error_embed(msg)) else: self.config.update('world', world.server, ctx.guild.id) msg = f"Der Server ist nun mit {world} verbunden" await ctx.send(embed=complete_embed(msg))
async def get_graph_data_dictionary(ctx, dataset_name: str): author = ctx.author graph_data_str = None #Recieve graph data in string format from db try: graph_data_str = dbfunc.get_dataset_graph_data(author.id, dataset_name) except: description = f"You don't have a dataset with the name `{dataset_name}`!" await ctx.send(embed=utils.error_embed(description)) return None graph_data_dict = None try: graph_data_dict = utils.str2dict(graph_data_str) except: description = f"An error happened with the graph dictionary formatting on our end. Please use `/report` to report the issue or get help in our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(description)) return None return graph_data_dict
async def set_prefix(self, ctx, prefix): current_prefix = self.config.get_prefix(ctx.guild.id) if current_prefix == prefix: msg = "`{}` ist bereits der aktuelle Prefix dieses Servers" await ctx.send(embed=error_embed(msg.format(prefix))) else: self.config.update('prefix', prefix, ctx.guild.id) msg = f"Der Prefix `{prefix}` ist nun aktiv" await ctx.send(embed=complete_embed(msg))
async def get_saved_plot_type(ctx, dataset_name: str, saved_plot_name: str): graph_dict = await get_graph_data_dictionary(ctx, dataset_name) #Get the saved plot dictionary or error if none is available saved_plot_dict = graph_dict.get(saved_plot_name, None) if saved_plot_dict is None: error_msg = f"You do not have a saved plot under the name {saved_plot_name}! Please check the name using `/viewgraphdata {dataset_name}` and try again." await ctx.send(embed=utils.error_embed(error_msg)) return None return saved_plot_dict["name"]
async def log_data_to_database(ctx, dataset_name: str, datadict) -> bool: author = ctx.author #add the new data to the database dict2str = str(datadict) try: dbfunc.set_dataset_data(author.id, dataset_name, dict2str) except: description = f"An error happened with the data upload on our end. Please use `/report` to report the issue or get help in our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(description)) return False return True
async def get_data_dictionary(ctx, dataset_name: str): author = ctx.author datastr = None #Recieve data in string format from db try: datastr = dbfunc.get_dataset_data(author.id, dataset_name) except: description = f"You don't have a dataset with the name `{dataset_name}`!" await ctx.send(embed=utils.error_embed(description)) return None #Turn data in string format to dict format (this should only fail if the bot did something wrong) datadict = None try: datadict = utils.str2dict(datastr) except: description = f"An error happened with the dictionary formatting on our end. Please use `/report` to report the issue or get help in our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(description)) return None return datadict
async def remove_conquer(self, ctx): channels = self.config.get('conquer', ctx.guild.id) if str(ctx.channel.id) in channels: channels.pop(str(ctx.channel.id)) self.config.save() msg = f"{ctx.channel.mention} ist kein Eroberungschannel mehr" await ctx.send(embed=complete_embed(msg)) else: msg = "Dieser Channel ist nicht eingespeichert" await ctx.send(embed=error_embed(msg))
async def conquer_add(self, ctx, *, dsobj: DSConverter): conquer = self.get_conquer_data(ctx) if dsobj.id in conquer[dsobj.type]: msg = "Der Stamm ist bereits eingespeichert" await ctx.send(embed=error_embed(msg)) else: conquer[dsobj.type].append(dsobj.id) self.config.save() msg = f"`{dsobj}` wurde hinzugefügt" await ctx.send(embed=complete_embed(msg))
async def conquer_remove(self, ctx, *, dsobj: DSConverter): conquer = self.get_conquer_data(ctx) if dsobj.id not in conquer[dsobj.type]: msg = "Der Stamm ist nicht eingespeichert" await ctx.send(embed=error_embed(msg)) else: conquer[dsobj.type].remove(dsobj.id) self.config.save() msg = f"`{dsobj}` wurde entfernt" await ctx.send(embed=complete_embed(msg))
async def report(self, ctx, report: str): report_channel = self.bot.get_channel(plotvars.reports_channel) if report_channel is None: description = f"An Error happened on our end: report channel not found. Please report this issue to our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(description)) return else: title = f"New Bug Report From {ctx.author.name} (user ID: {ctx.author.id})" colour = discord.Color.dark_orange() await report_channel.send( embed=utils.create_embed(title, report, colour)) await ctx.send(embed=utils.create_embed( "Thank you! Your bug report has been sent.", "", colour))
async def remove_(self, ctx, reminder_id: int): query = 'DELETE FROM reminder WHERE author_id = $1 AND id = $2' async with self.bot.ress.acquire() as conn: response = await conn.execute(query, ctx.author.id, reminder_id) if response == "DELETE 0": msg = "Du hast keinen Reminder mit der angegebenen ID" return await ctx.send(embed=utils.error_embed(msg)) if self.current_reminder and self.current_reminder.id == reminder_id: self.restart() await ctx.send( embed=utils.complete_embed("Der Reminder wurde gelöscht"))
async def suggest(self, ctx, suggestion: str): suggestion_channel = self.bot.get_channel(plotvars.suggestion_channel) if suggestion_channel is None: description = f"An Error happened on our end: Suggestion channel not found. Please report this issue to our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(description)) return else: title = f"New Feature Suggestion From {ctx.author.name} (user ID: {ctx.author.id})" colour = discord.Color.dark_orange() await suggestion_channel.send( embed=utils.create_embed(title, suggestion, colour)) await ctx.send(embed=utils.create_embed( "Thank you! Your feature suggestion has been sent.", "", colour))
async def remove(self, ctx, entry): entry = entry.lower() config_entry = self.config_title.get(entry) if config_entry is None: raise MissingRequiredKey(self.config_title) done = self.config.remove(entry.lower(), ctx.guild.id) if not done: msg = f"Der Server hat keinen zugewiesenen **{config_entry}**" await ctx.send(embed=error_embed(msg)) else: msg = f"**{config_entry}** erfolgreich gelöscht" await ctx.send(embed=complete_embed(msg))
async def removedataset(self, ctx, name:str): """Removes a user's dataset from the database (if they have one with the given name) Args: name (str): name of the dataset to remove """ author = ctx.author num_removed = dbfunc.remove_dataset(author.id, name) if num_removed == 0: description="There is no dataset with this name to remove!" await ctx.send(embed=utils.error_embed(description)) else: title=f"Dataset `{name}` successfully removed!" description="" color=discord.Color.green() await ctx.send(embed=utils.create_embed(title, description, color))
async def clear_(self, ctx): query = 'DELETE FROM reminder WHERE author_id = $1 RETURNING id' async with self.bot.ress.acquire() as conn: deleted_rows = await conn.fetch(query, ctx.author.id) if not deleted_rows: msg = "Du hast keine aktiven Reminder" return await ctx.send(embed=utils.error_embed(msg)) if self.current_reminder: old_ids = [rec['id'] for rec in deleted_rows] if self.current_reminder.id in old_ids: self.restart() msg = f"Alle deine Reminder wurden gelöscht ({len(deleted_rows)})" await ctx.send(embed=utils.complete_embed(msg))
async def verify_rows_are_rows_of_numbers(ctx, dataset_name: str, datadict, rows): row_values = await verify_rows_exist_in_dataset(ctx, dataset_name, datadict, rows) if row_values == None: return None for i in range(len(row_values)): verify_values = utils.verify_list_is_numlist(row_values[i]) if verify_values is None: description = f"Row {rows[i]} is not a list of only numbers, which is required for a scatterplot. Please double-check the values using `/viewdata {dataset_name}` and try again." await ctx.send(embed=utils.error_embed(description)) return None return row_values
async def addrandomnumberrow(self, ctx, dataset_name:str, row_name:str, amount_of_random_numbers:int, minimum_number:float, maximum_number:float): """Adds a random row of numbers to a user's dataset, with them choosing the bounds between the numbers and amount of numbers. If the name of the row already exists, the numbers will be added to the end of that row. Args: dataset_name (str): Name of the dataset row_name (str): Name of the row amount_of_random_numbers (int): Amount of random numbers to be generated minimum_number (float): Minimum possible number of the random numbers maximum_number (float): Maximum possible number of the random numbers """ #Get the data datadict = await asyncutils.get_data_dictionary(ctx, dataset_name) if datadict is None: return #Get the random list of numbers numlist = None try: numlist=utils.random_num_list(amount_of_random_numbers, minimum_number, maximum_number) except: description=f"An error occured while generating the random numbers. Make sure that your minimum and maximum values were entered as numbers and try again." await ctx.send(embed=utils.error_embed(description)) return #Add the values to the end of a pre-existing list or just use the values previous_row_values = datadict.get(row_name, None) if previous_row_values is None: datadict[row_name] = numlist else: new_row_values = previous_row_values.copy() for num in numlist: new_row_values.append(num) datadict[row_name] = new_row_values #Write the data to the database data_written = await asyncutils.log_data_to_database(ctx, dataset_name, datadict) if data_written == False: return title=f"`{amount_of_random_numbers}` random number values of range `{minimum_number}` to `{maximum_number}` have been added to the `{row_name}` row! To view the values use `/viewdata {dataset_name}`" description="" color=discord.Color.green() await ctx.send(embed=utils.create_embed(title, description, color))
async def remove_channel_world(self, ctx): config = self.config.get('channel', ctx.guild.id) if config: world = config.get(str(ctx.channel.id)) state = bool(world) else: state = False if state is False: msg = "Dieser Channel hat keine eigene Welt" await ctx.send(embed=error_embed(msg)) else: config.pop(str(ctx.channel.id)) self.config.save() msg = "Die Channel-Welt wurde gelöscht" await ctx.send(embed=complete_embed(msg))
async def verify_rows_exist_in_dataset(ctx, dataset_name: str, datadict, rows, send_error_message=True): row_values = [] for row in rows: values = datadict.get(row, None) if values is None: if send_error_message: description = f"Row {row} does not exist in dataset {dataset_name}!" await ctx.send(embed=utils.error_embed(description)) return None else: row_values.append(values) return row_values
async def addnumberrow(self, ctx, dataset_name:str, row_name:str, numbers:str, separator:str=" "): """Adds a row of numbers to the data in a user's dataset. The user enters a list of numbers using a separator of their choice (default is " "). If the name of the row already exists, the numbers will be added to the end of that row. Args: dataset_name (str): Name of the dataset to add the data to row_name (str): Name of the row numbers (str): Numbers, listed out with the separator of their choice separator (str, optional): The separator for the user's list of numbers. Defaults to " ". """ #Get the data datadict = await asyncutils.get_data_dictionary(ctx, dataset_name) if datadict is None: return #turn numbers string into list of numbers numlist = None try: numlist = utils.str2numlist(numbers, separator) except Exception as e: description="Either one of your values is not a number, or your list is not properly formatted. Please try again, or use `/help addnumberrow` for assistance." await ctx.send(embed=utils.error_embed(description)) return #Add the numbers to the end of a pre-existing list or just use the values previous_row_values = datadict.get(row_name, None) if previous_row_values is None: datadict[row_name] = numlist else: new_row_values = previous_row_values.copy() for num in numlist: new_row_values.append(num) datadict[row_name] = new_row_values #Write the data to the database data_written = await asyncutils.log_data_to_database(ctx, dataset_name, datadict) if data_written == False: return title=f"Number values have been added to the `{row_name}` row!" description="" color=discord.Color.green() await ctx.send(embed=utils.create_embed(title, description, color))
async def addrandomcolorrow(self, ctx, dataset_name:str, row_name:str, amount_of_random_colors:int): """Adds a random row of hex color strings to a user's dataset, with them choosing the amount of colors. If the name of the row already exists, the numbers will be added to the end of that row. Args: dataset_name (str): Name of the dataset row_name (str): Name of the row amount_of_random_colors (int): Amount of random colors to be generated """ #Get the data datadict = await asyncutils.get_data_dictionary(ctx, dataset_name) if datadict is None: return #Create random list of colors colorlist=[] try: for _ in range(amount_of_random_colors): colorlist.append(utils.generate_random_color()) except: description=f"An error with color generation occurred on our end. Please use `/report` to report the issue or get help in our support server: {plotvars.support_discord_link}" await ctx.send(embed=utils.error_embed(description)) return #Add the colors to the end of a pre-existing list or just use the values previous_row_values = datadict.get(row_name, None) if previous_row_values is None: datadict[row_name] = colorlist else: new_row_values = previous_row_values.copy() for color in colorlist: new_row_values.append(color) datadict[row_name] = new_row_values #Write the data to the database data_written = await asyncutils.log_data_to_database(ctx, dataset_name, datadict) if data_written == False: return title=f"`{amount_of_random_colors}` color values have been added to the `{row_name}` row!" description="" color=discord.Color.green() await ctx.send(embed=utils.create_embed(title, description, color))