async def cmd_list(self, ctx, full=""): cmds = [] suffix = Lang.lang(self, 'list_suffix') if full else "" for k in self.commands.keys(): if full: arg_lens = [] for t in self.commands[k].texts: arg_list = arg_list_re.findall(t) arg_lens.append(len(arg_list)) cmds.append( Lang.lang(self, 'list_full_data', k, len(self.commands[k].texts), max(arg_lens))) else: cmds.append(k) if not cmds: await ctx.send(Lang.lang(self, 'list_no_cmds')) return cmds.sort(key=str.lower) cmd_msgs = utils.paginate(cmds, delimiter=", ", suffix=suffix) for msg in cmd_msgs: await ctx.send(msg)
async def bugscore_increment(self, ctx, user, increment): if discord.utils.get(ctx.author.roles, id=Config().BOTMASTER_ROLE_ID) is None: await ctx.message.add_reaction(Lang.CMDNOPERMISSIONS) return # find user try: user = await commands.MemberConverter().convert(ctx, user) except (commands.CommandError, IndexError): await ctx.send(Lang.lang(self, "bugscore_user_not_found", user)) await ctx.message.add_reaction(Lang.CMDERROR) return try: increment = int(increment) except (ValueError, TypeError): await ctx.send(Lang.lang(self, "bugscore_nan", increment)) await ctx.message.add_reaction(Lang.CMDERROR) return if user.id in self.storage["bugscore"]: self.storage["bugscore"][user.id] += increment else: self.storage["bugscore"][user.id] = increment if self.storage["bugscore"][user.id] <= 0: del self.storage["bugscore"][user.id] Storage.save(self) await ctx.message.add_reaction(Lang.CMDSUCCESS)
async def disable(self, ctx, command, *args): user = ctx.author date_args_start_index = 0 if len(args) > 0: try: user = await commands.MemberConverter().convert(ctx, args[0]) date_args_start_index = 1 except (commands.CommandError, IndexError): date_args_start_index = 0 if user != ctx.author and not permChecks.check_full_access(ctx.author): raise commands.MissingAnyRole(Config().FULL_ACCESS_ROLES) until = utils.analyze_time_input(*args[date_args_start_index:]) result = self.bot.ignoring.add_user_command(user, command, until) if result == IgnoreEditResult.Success: await ctx.message.add_reaction(Lang.CMDSUCCESS) elif result == IgnoreEditResult.Already_in_list: await ctx.message.add_reaction(Lang.CMDERROR) await ctx.send(Lang.lang(self, 'user_cmd_already_blocked', command, utils.get_best_username(user))) elif result == IgnoreEditResult.Until_in_past: await ctx.message.add_reaction(Lang.CMDERROR) await ctx.send(Lang.lang(self, 'no_time_machine')) await utils.log_to_admin_channel(ctx)
async def create_message_text(self, server_roles, ctx): """ Returns the message text for the role manage init message including the reactions and mod roles for the roles :param server_roles: the roles on the server :param ctx: The context of the used command to create the new message """ msg = "{}\n".format(Storage().get(self)['message']['content']) for rid in self.rc(): role = discord.utils.get(server_roles, id=rid) emote_msg = "" modrole_msg = "" if self.rc()[rid]['emoji']: emote_msg = Lang.lang( self, 'init_reaction', await utils.emojize(self.rc()[rid]['emoji'], ctx)) if self.rc()[rid]['modrole'] != 0: modrole = discord.utils.get(server_roles, id=self.rc()[rid]['modrole']) modrole_msg = Lang.lang(self, 'init_modrole', modrole.name) if emote_msg and modrole_msg: todo_part = "{}, {}".format(emote_msg, modrole_msg) elif emote_msg: todo_part = emote_msg elif modrole_msg: todo_part = modrole_msg else: todo_part = Lang.lang(self, 'init_admin') msg += "\n{} - {}".format(role.name, todo_part) return msg
async def end(self): embed = self.score.embed() winners = [get_best_username(Storage().get(self.plugin), x) for x in self.score.winners()] # Übergangslösung points = self.score.points() for user in points: self.plugin.update_ladder(user, points[user]) msgkey = "quiz_end" if len(winners) > 1: msgkey = "quiz_end_pl" elif len(winners) == 0: msgkey = "quiz_end_no_winner" winners = utils.format_andlist(winners, ands=Lang.lang(self.plugin, "and"), emptylist=Lang.lang(self.plugin, "nobody")) msg = Lang.lang(self.plugin, msgkey, winners) if msg is None: await self.channel.send(embed=embed) elif embed is None: await self.channel.send(msg) else: await self.channel.send(msg, embed=embed) self.plugin.end_quiz(self.channel)
async def on_message(self, msg): self.plugin.logger.debug("Caught message: {}".format(msg.content)) # ignore DM and msg when the quiz is not in question phase if not isinstance(msg.channel, discord.TextChannel): return if self.state != Phases.QUESTION: self.plugin.logger.debug("Ignoring message, quiz is not in question phase") return # Valid answer try: check = self.quizapi.current_question().check_answer(msg.content) if check: reaction = "reaction_correct" else: reaction = "reaction_incorrect" self.plugin.logger.debug("Valid answer from {}: {} ({})".format(msg.author.name, msg.content, reaction)) except InvalidAnswer: return if not self.debug and self.last_author == msg.author: await msg.channel.send(Lang.lang(self.plugin, "answering_order", msg.author)) return self.last_author = msg.author if check: self.state = Phases.EVAL await msg.add_reaction(Lang.lang(self.plugin, reaction))
async def search(self, ctx, *args): if len(args) == 0: await ctx.message.add_reaction(Lang.CMDERROR) await ctx.send(Lang.lang(self, "redact_search_args")) return r = [] for i in self.complaints: complaint = self.complaints[i] found = True for searchterm in args: # Search check if searchterm.lower() not in complaint.to_message().lower(): found = False break if not found: continue # Search result r.append(complaint) if not r: await ctx.send(Lang.lang(self, "redact_search_not_found")) return msgs = utils.paginate(r, prefix=Lang.lang(self, "redact_search_title"), delimiter="\n\n", f=to_msg) for el in msgs: await ctx.send(el)
async def register_command(self, msg, *args): """ This is the callback for !kwiss register. :param msg: Message object :param args: Passed arguments, including "register" """ assert self.cmdstring_register in args if "skip" in args: self.state = Phases.ABOUTTOSTART return if len(args) > 1: await self.channel.send(Lang.lang(self.plugin, "too_many_arguments")) return if self.state == Phases.INIT: await self.channel.send("No idea how you did that, but you registered too early.") return if self.state != Phases.REGISTERING: await self.channel.send(Lang.lang(self.plugin, "registering_too_late", msg.author)) return if msg.author in self.registered_participants: return self.registered_participants[msg.author] = [] self.score.add_participant(msg.author) self.plugin.logger.debug("{} registered".format(msg.author.name)) await msg.add_reaction(Lang.CMDSUCCESS)
async def end(self): embed = self.score.embed() winners = [get_best_username(Storage().get(self.plugin), x) for x in self.score.winners()] msgkey = "quiz_end" if len(winners) > 1: msgkey = "quiz_end_pl" elif len(winners) == 0: msgkey = "quiz_end_no_winner" winners = utils.format_andlist(winners, ands=Lang.lang(self.plugin, "and"), emptylist=Lang.lang(self.plugin, "nobody")) msg = Lang.lang(self.plugin, msgkey, winners) if msg is None: await self.channel.send(embed=embed) elif embed is None: await self.channel.send(msg) else: await self.channel.send(msg, embed=embed) if self.ranked: for player in self.registered_participants: self.plugin.update_ladder(player, self.score.calc_points(player)) self.plugin.end_quiz(self.channel)
async def dm_callback(self, cb, message): self.plugin.logger.debug("Incoming message from {}: {}".format( self.user, message.content)) if message.content.strip() == "": # you never know return if self.plugin.statemachine.state != State.COLLECT: await self.send(Lang.lang(self.plugin, "entry_too_late")) return first = True if self.chosen: first = False self.chosen = message.content if first: await self.send( Lang.lang(self.plugin, "entry_done", utils.get_best_username(self.assigned.user), self.chosen)) else: await self.send(Lang.lang(self.plugin, "entry_change", self.chosen)) self.plugin.assigned()
async def dsc_status(self, ctx): if Storage.get(self)['status']: status_msg = Lang.lang(self, 'status_base', Storage.get(self)['status']) else: status_msg = Lang.lang(self, 'status_base', Lang.lang(self, 'status_none')) await ctx.send(status_msg)
async def dsc_winners(self, ctx): c = self.get_api_client() winners = c.get(Config.get(self)['winners_range']) w_msgs = [] regex = re.compile(r"\d+") for w in winners[1:]: if w[0] is None or not w[0]: continue m0 = regex.findall(w[0]) m2 = regex.findall(w[2]) no = m0[0] dt = datetime(int(m0[2]), int(m0[1]), 1) participator_coutn = m0[3] winner_name = w[1] pts_winner = int(m2[0]) pts_max = int(m2[1]) pts_percentage = round(pts_winner / pts_max * 100) w_msgs.append(Lang.lang(self, 'winner_msg', no, winner_name, pts_winner, pts_max, pts_percentage, participator_coutn, dt.month, dt.year)) for m in utils.paginate(w_msgs, Lang.lang(self, 'winner_prefix')): await ctx.send(m)
async def cmd_add(self, ctx, cmd_name, *args): if not "".join(args): await ctx.message.add_reaction(Lang.CMDERROR) raise commands.MissingRequiredArgument( inspect.signature(self.cmd_add).parameters['args']) cmd_name = cmd_name.lower() # TODO Process multiple output texts cmd_texts = [" ".join(args)] # Process special discord /cmd for i in range(0, len(cmd_texts)): contains_me = cmd_texts[i].lower().startswith("/me") if contains_me: cmd_texts[i] = "_{}_".format(cmd_texts[i][3:]) if cmd_name in self.commands: self.commands[cmd_name].texts.extend(cmd_texts) self.save() await ctx.message.add_reaction(Lang.CMDSUCCESS) await ctx.send(Lang.lang(self, "add_exists", cmd_name)) else: self.commands[cmd_name] = Cmd(cmd_name, ctx.author.id, cmd_texts) self.save() # await utils.log_to_admin_channel(ctx) await ctx.message.add_reaction(Lang.CMDSUCCESS) await utils.write_debug_channel( self.bot, Lang.lang(self, 'cmd_added', self.commands[cmd_name].get_raw_texts()))
async def abortphase(self): self.plugin.end_quiz(self.channel) if self.current_question_timer is not None: try: self.current_question_timer.cancel() except utils.HasAlreadyRun: pass if self.ranked and len(self.registered_participants) < self.config["ranked_min_players"]: await self.channel.send(Lang.lang(self.plugin, "ranked_playercount", self.config["ranked_min_players"])) else: await self.channel.send(Lang.lang(self.plugin, "quiz_abort"))
async def choose(self, ctx, *args): full_options_str = " ".join(args) if "sabaton" in full_options_str.lower(): await ctx.send(Storage.lang(self, 'choose_sabaton')) options = [i for i in full_options_str.split("|") if i.strip() != ""] if len(options) < 1: await ctx.send(Lang.lang(self, 'choose_noarg')) return result = random.choice(options) await ctx.send(Lang.lang(self, 'choose_msg') + result.strip())
async def eval(self): """ Is called when the question is over. Evaluates scores and cancels the timer. :return: """ self.plugin.logger.debug("Ending question") # End timeout timer if self.current_question_timer is not None: try: self.current_question_timer.cancel() except utils.HasAlreadyRun: self.plugin.logger.warning("This should really, really not happen.") self.current_question_timer = None else: # We ran into a timeout and need to give that function time to communicate this fact await asyncio.sleep(1) if self.current_reaction_listener is not None: self.current_reaction_listener.unregister() question = self.quizapi.current_question() # Normalize answers for el in self.registered_participants: if len(self.registered_participants[el]) != 1: self.registered_participants[el] = None else: self.registered_participants[el] = self.registered_participants[el][0] # Increment scores correctly_answered = [] for user in self.registered_participants: if question.check_answer(self.registered_participants[user], emoji=True): correctly_answered.append(user) for user in correctly_answered: self.score.increase(user, self.current_question, totalcorr=len(correctly_answered)) correct = [get_best_username(Storage().get(self.plugin), el) for el in correctly_answered] correct = utils.format_andlist(correct, Lang.lang(self.plugin, "and"), Lang.lang(self.plugin, "nobody")) if self.config["emoji_in_pose"]: ca = question.correct_answer_emoji else: ca = question.correct_answer_letter await self.channel.send(Lang.lang(self.plugin, "points_question_done", ca, correct)) # Reset answers list for user in self.registered_participants: self.registered_participants[user] = [] await asyncio.sleep(self.config["question_cooldown"]) self.state = Phases.QUESTION
async def reminder_callback(self, job): channel = self.bot.get_channel(job.data['chan']) user = self.bot.get_user(job.data['user']) text = job.data['text'] rid = job.data['id'] remind_text = "" if text: remind_text = Lang.lang(self, 'remind_callback_msg', text) await channel.send( Lang.lang(self, 'remind_callback', user.mention, remind_text)) logging.info("Executed reminder {}".format(rid)) self.remove_reminder(rid)
async def disable_user(self, ctx, user: discord.Member, *args): until = utils.analyze_time_input(*args) result = self.bot.ignoring.add_user(user, until) if result == IgnoreEditResult.Success: await ctx.message.add_reaction(Lang.CMDSUCCESS) elif result == IgnoreEditResult.Already_in_list: await ctx.message.add_reaction(Lang.CMDERROR) await ctx.send(Lang.lang(self, 'user_already_blocked', utils.get_best_username(user))) elif result == IgnoreEditResult.Until_in_past: await ctx.message.add_reaction(Lang.CMDERROR) await ctx.send(Lang.lang(self, 'no_time_machine')) await utils.log_to_admin_channel(ctx)
async def delivering_phase(self): for target in self.participants: todo = [] for el in self.participants: if el.assigned != target: todo.append(el.to_msg(show_assignees=self.show_assignees)) for msg in utils.paginate(todo, prefix=Lang.lang(self, "list_title")): await target.send(msg) await self.channel.send(Lang.lang(self, "done")) self.cleanup() self.statemachine.state = State.IDLE
async def cmd_raw(self, ctx, cmd_name): cmd_name = cmd_name.lower() if cmd_name in self.commands: creator = self.bot.get_user(self.commands[cmd_name].creator_id) for msg in utils.paginate(self.commands[cmd_name].get_raw_texts(), delimiter="\n", prefix=Lang.lang( self, 'raw_prefix', self.prefix, cmd_name, utils.get_best_username(creator))): await ctx.send(msg) else: await ctx.send(Lang.lang(self, "raw_doesnt_exists", cmd_name))
async def redact(self, ctx): # Printing complaints if len(self.complaints) == 0: await ctx.send(Lang.lang(self, "redact_no_complaints")) return msgs = utils.paginate([el for el in self.complaints.values()], prefix=Lang.lang(self, "redact_title"), delimiter="\n\n", msg_prefix="_ _\n", f=to_msg) for el in msgs: await ctx.send(el)
async def role_add(self, ctx, role_name, emoji_or_modrole="", color: discord.Color = None): emoji_str = await utils.demojize(emoji_or_modrole, ctx) try: modrole = await commands.RoleConverter().convert( ctx, emoji_or_modrole) modrole_id = modrole.id emoji_str = "" except commands.CommandError: modrole_id = 0 if not emoji_str and modrole_id == 0: try: color = await commands.ColourConverter().convert( ctx, emoji_or_modrole) except (commands.CommandError, IndexError): color = discord.Color.default() try: existing_role = await commands.RoleConverter().convert( ctx, role_name) except commands.CommandError: existing_role = None if existing_role is not None: if existing_role.id in self.rc(): # Update role data if emoji_str: self.rc()[existing_role.id]['emoji'] = emoji_str if modrole_id != 0: self.rc()[existing_role.id]['modrole'] = modrole_id await self.update_role_management(ctx) await ctx.send(Lang.lang(self, 'role_add_updated', role_name)) else: # role exists on server, but not in config, add it there self.rc()[existing_role.id] = { 'emoji': emoji_str, 'modrole': modrole_id } await self.update_role_management(ctx) await ctx.send(Lang.lang(self, 'role_add_config', role_name)) return # Execute role add new_role = await add_server_role(ctx.guild, role_name, color) self.rc()[new_role.id] = {'emoji': emoji_str, 'modrole': modrole_id} await self.update_role_management(ctx) await ctx.send(Lang.lang(self, 'role_add_created', role_name, color)) await utils.log_to_admin_channel(ctx)
async def dsc_set_config(self, ctx, key="", value=""): if not key and not value: await ctx.invoke(self.bot.get_command("configdump"), self.get_name()) return if key and not value: key_value = Config.get(self).get(key, None) if key_value is None: await ctx.message.add_reaction(Lang.CMDERROR) await ctx.send(Lang.lang(self, 'key_not_exists', key)) else: await ctx.message.add_reaction(Lang.CMDSUCCESS) await ctx.send(key_value) return if key == "channel_id": channel = None int_value = Config.get(self)['channel_id'] try: int_value = int(value) channel = self.bot.guild.get_channel(int_value) except ValueError: pass if channel is None: Lang.lang(self, 'channel_id_int') await ctx.message.add_reaction(Lang.CMDERROR) return else: Config.get(self)[key] = int_value elif key == "songmaster_role_id": role = None int_value = Config.get(self)['songmaster_role_id'] try: int_value = int(value) role = self.bot.guild.get_role(int_value) except ValueError: pass if role is None: Lang.lang(self, 'songmaster_id') await ctx.message.add_reaction(Lang.CMDERROR) return else: Config.get(self)[key] = int_value else: Config.get(self)[key] = value Config.save(self) await ctx.message.add_reaction(Lang.CMDSUCCESS)
async def kicker_table(self, ctx): embed = discord.Embed(title=Lang.lang(self, 'kicker_title')) embed.add_field(name=Lang.lang(self, 'kicker_1BL'), value=Lang.lang(self, 'kicker_1BL_link')) embed.add_field(name=Lang.lang(self, 'kicker_2BL'), value=Lang.lang(self, 'kicker_2BL_link')) embed.add_field(name=Lang.lang(self, 'kicker_3FL'), value=Lang.lang(self, 'kicker_3FL_link')) embed.add_field(name=Lang.lang(self, 'kicker_ATBL'), value=Lang.lang(self, 'kicker_ATBL_link')) await ctx.send(embed=embed)
async def collecting_phase(self): assert len(self.participants) > 1 msg = [utils.get_best_username(el.user) for el in self.participants] msg = utils.format_andlist(msg, ands=Lang.lang(self, "and")) msg = Lang.lang(self, "list_participants", msg) await self.channel.send(msg) shuffled = self.participants.copy() utils.trueshuffle(shuffled) for i in range(len(self.participants)): self.participants[i].assign(shuffled[i]) for el in self.participants: await el.init_dm()
async def role_request(self, ctx, role: discord.Role): modrole = None for configured_role in self.rc(): if configured_role == role.id: modrole = discord.utils.get( ctx.guild.roles, id=self.rc()[configured_role]['modrole']) break if modrole is None: await ctx.send( Lang.lang(self, 'role_request_no_modrole', role.name)) else: await ctx.send( Lang.lang(self, 'role_request_ping', modrole.mention, ctx.author.mention, role.name))
async def timeout(self, question): """ :param question: Question object of the question that was running at timer start time. """ if self.current_question != question or self.state != Phases.QUESTION: # We are out of date self.plugin.logger.debug("Timeout warning out of date") return self.current_question_timer = None self.plugin.logger.debug("Question timeout") msg = Lang.lang(self.plugin, "points_timeout", self.quizapi.current_question_index(), utils.format_andlist(self.havent_answered_hr(), ands=Lang.lang(self.plugin, "and"))) self.state = Phases.EVAL await self.channel.send(msg)
async def who_mobbing(self, ctx): after_date = (datetime.now(timezone.utc) - timedelta(minutes=30)).replace(tzinfo=None) users = [self.bot.user] messages = await ctx.channel.history(after=after_date).flatten() for message in messages: if message.author not in users: users.append(message.author) bully = random.choice(users) if bully is self.bot.user: text = Lang.lang(self, "bully_msg_self") else: text = Lang.lang(self, "bully_msg", utils.get_best_username(bully)) await ctx.send(text)
async def stopcmd(self, ctx): if self.statemachine.state == State.IDLE: await ctx.message.add_reaction(Lang.CMDERROR) await ctx.send(Lang.lang(self, "not_running")) return await ctx.message.add_reaction(Lang.CMDSUCCESS) self.cleanup()
async def dsc_set_state(self, ctx, state): if state.lower() == "voting": await self._dsc_save_state(ctx, DscState.Voting) elif state.lower() == "signup": await self._dsc_save_state(ctx, DscState.Sign_up) else: await ctx.send(Lang.lang(self, 'invalid_phase'))