async def update_reactions(message, page, has_multiple): left = Emoji.get_emoji("LEFT") if has_multiple and not any(left == r.emoji and r.me for r in message.reactions): await message.add_reaction(left) # add numbered reactions needed = int(len(page.splitlines()) / 2) added = False try: for i in range(10): reaction = Emoji.get_emoji(str(i + 1)) if i < needed: added = True await message.add_reaction(reaction) elif any(reaction == r.emoji and r.me for r in message.reactions): await message.remove_reaction(reaction, message.channel.guild.me) right = Emoji.get_emoji("RIGHT") has_right = any(right == r.emoji and r.me for r in message.reactions) if added and has_right: await message.remove_reaction(right, message.channel.guild.me) has_right = False if not has_right and has_multiple: await message.add_reaction(right) has_left = any(left == r.emoji and r.me for r in message.reactions) if has_left and has_multiple: await message.remove_reaction(left, message.channel.guild.me) except Forbidden: pass # we lost access
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): guild = self.bot.get_guild(payload.guild_id) if guild is None: return user = guild.get_member(payload.user_id) if guild.me.id == payload.user_id: return try: message = await self.bot.get_channel( payload.channel_id).get_message(payload.message_id) except discord.NotFound: pass else: if str(payload.emoji) == str(Emoji.get_emoji('LEFT')): if await Pages.update(self.bot, message, "PREV", payload.user_id): try: await message.remove_reaction(Emoji.get_emoji('LEFT'), user) except discord.Forbidden: pass elif str(payload.emoji) == str(Emoji.get_emoji('RIGHT')): if await Pages.update(self.bot, message, "NEXT", payload.user_id): try: await message.remove_reaction(Emoji.get_emoji('RIGHT'), user) except discord.Forbidden: pass
async def remind_me(self, ctx, duration: Duration, *, reminder: ReminderText): """remind_me_help""" if duration.unit is None: parts = reminder.split(" ") duration.unit = parts[0] reminder = " ".join(parts[1:]) duration_seconds = duration.to_seconds(ctx) if duration_seconds <= 0: await MessageUtils.send_to(ctx, "NO", "reminder_time_travel") return if ctx.guild is not None: message = f'{Emoji.get_chat_emoji("QUESTION")} {Translator.translate("remind_question", ctx)}' one = Emoji.get_emoji("1") two = Emoji.get_emoji("2") no = Emoji.get_emoji("NO") embed = Embed(description=f""" {Emoji.get_chat_emoji("1")} {Translator.translate("remind_option_here", ctx)} {Emoji.get_chat_emoji("2")} {Translator.translate("remind_option_dm", ctx)} {Emoji.get_chat_emoji("NO")} {Translator.translate("remind_option_cancel", ctx)} """) m = await ctx.send(message, embed=embed) for e in [one, two, no]: await m.add_reaction(e) try: reaction, user = await ctx.bot.wait_for( 'reaction_add', timeout=30, check=lambda reaction, user: user == ctx.message.author and reaction.emoji in [one, two, no]) except asyncio.TimeoutError: await MessageUtils.send_to(ctx, "NO", "confirmation_timeout", timeout=30) return else: if reaction.emoji == no: await MessageUtils.send_to(ctx, "NO", "command_canceled") return else: dm = reaction.emoji == two finally: await m.delete() else: dm = True Reminder.create(user_id=ctx.author.id, channel_id=ctx.channel.id, dm=dm, to_remind=await Utils.clean(reminder, markdown=False), time=time.time() + duration_seconds, status=ReminderStatus.Pending) mode = "dm" if dm else "here" await MessageUtils.send_to(ctx, "YES", f"reminder_confirmation_{mode}", duration=duration.length, duration_identifier=duration.unit)
async def create_new(type, ctx, **kwargs): text, embed, has_pages, emoji = await page_handlers[type]["init"](ctx, **kwargs) message: discord.Message = await ctx.channel.send(text, embed=embed) if has_pages or len(emoji) > 0: data = { "type": type, "page": 0, "trigger": ctx.message.id, "sender": ctx.author.id } for k, v in kwargs.items(): data[k] = v known_messages[str(message.id)] = data try: if has_pages: await message.add_reaction(Emoji.get_emoji('LEFT')) for e in emoji: await message.add_reaction(e) if has_pages: await message.add_reaction(Emoji.get_emoji('RIGHT')) except discord.Forbidden: await ctx.send( f"{Emoji.get_chat_emoji('WARNING')} {Translator.translate('paginator_missing_perms', ctx, prev=Emoji.get_chat_emoji('LEFT'), next=Emoji.get_chat_emoji('RIGHT'))} {Emoji.get_chat_emoji('WARNING')}" ) if len(known_messages.keys()) > 500: del known_messages[list(known_messages.keys())[0]] save_to_disc()
async def create_new(bot, type, ctx, **kwargs): text, embed, has_pages = await page_handlers[type]["init"](ctx, **kwargs) message: discord.Message = await ctx.channel.send(text, embed=embed) if has_pages: await ReactionManager.register(bot, message.id, message.channel.id, "paged", subtype=type, duration=60 * 60 * 24, **kwargs) try: if has_pages: await message.add_reaction(Emoji.get_emoji('LEFT')) if has_pages: await message.add_reaction(Emoji.get_emoji('RIGHT')) except discord.Forbidden: await MessageUtils.send_to(ctx, 'WARNING', 'paginator_missing_perms', prev=Emoji.get_chat_emoji('LEFT'), next=Emoji.get_chat_emoji('RIGHT')) except discord.NotFound: await MessageUtils.send_to(ctx, 'WARNING', 'fix_censor')
async def inf_update(message, query, fields, amount, page_num): if str(query).isnumeric(): query = int(query) guild_id = message.channel.guild.id old = message.content key = get_key(guild_id, query, fields, amount) # do we have pages? count = await bot.redis_pool.llen(key) if count == 0: count = await fetch_infraction_pages(guild_id, query, amount, fields, page_num) if page_num >= count: page_num = 0 elif page_num < 0: page_num = count - 1 page = (await bot.wait_for( "page_assembled", check=lambda l: l["key"] == key and l["page_num"] == page_num) )["page"] else: if page_num >= count: page_num = 0 elif page_num < 0: page_num = count - 1 page = await bot.redis_pool.lindex(key, page_num) name = await Utils.username(query) if isinstance( query, int) else await Utils.clean(bot.get_guild(guild_id).name) new = f"{Emoji.get_chat_emoji('SEARCH')} {Translator.translate('inf_search_header', message.channel.guild.id, name=name, page_num=page_num + 1, pages=count)}\n{page}" if old != new: try: await message.edit(content=new) if count > 1: left = Emoji.get_emoji('LEFT') if not any(left == r.emoji and r.me for r in message.reactions): await message.add_reaction(Emoji.get_emoji('LEFT')) await message.add_reaction(Emoji.get_emoji('RIGHT')) except NotFound: pass parts = { "page_num": page_num, "cache_key": key, } if len(fields) != 0: parts["fields"] = "-".join(fields) if query is not None: parts["query"] = query if amount != 100: parts["amount"] = 100 return parts
async def confirm(ctx: commands.Context, text, timeout=30, on_yes=None, on_no=None, delete=True, confirm_cancel=True): yes = str(Emoji.get_emoji("YES")) no = str(Emoji.get_emoji("NO")) message: discord.Message = await ctx.send(text) await message.add_reaction(yes) await message.add_reaction(no) def check(reaction: discord.RawReactionActionEvent): return reaction.user_id == ctx.message.author.id and str( reaction.emoji) in (yes, no) and reaction.message_id == message.id try: reaction = await ctx.bot.wait_for('raw_reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: try: await message.delete() except NotFound: pass # someone deleted it await MessageUtils.send_to(ctx, "NO", "confirmation_timeout", timeout=30) return if str(reaction.emoji) == yes and on_yes is not None: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass await on_yes() elif str(reaction.emoji) == no: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass if on_no is not None: await on_no() elif confirm_cancel: await MessageUtils.send_to(ctx, "NO", "command_canceled")
def __init__(self, filters, pages, guild_id, userid, current_page=0): super().__init__(timeout=None) self.id = "" if pages > 0: start = f"einf_search:{userid}:{current_page}" self.add_item( Button(label=Translator.translate('first_page', guild_id), custom_id=f'{start}:first_page', disabled=current_page == 0, style=ButtonStyle.blurple)) self.add_item( Button(label=Translator.translate('prev_page', guild_id), custom_id=f'{start}:prev_page', disabled=current_page == 0, style=ButtonStyle.blurple)) self.add_item( Button(emoji=Emoji.get_emoji('AE'), style=ButtonStyle.grey, custom_id=f'{start}:blank', label=None)) self.add_item( Button(label=Translator.translate('next_page', guild_id), custom_id=f'{start}:next_page', disabled=current_page >= pages - 1, style=ButtonStyle.blurple)) self.add_item( Button(label=Translator.translate('last_page', guild_id), custom_id=f'{start}:last_page', disabled=current_page >= pages - 1, style=ButtonStyle.blurple)) self.stop()
async def self_roles(bot, message, user_id, reaction, **kwargs): user = message.channel.guild.get_member(user_id) if user is None: if user_id is not 0: await remove_reaction(message, reaction, await bot.fetch_user(user_id)) return kwargs bot.loop.create_task(remove_reaction(message, reaction, user)) left = Emoji.get_chat_emoji('LEFT') right = Emoji.get_chat_emoji('RIGHT') refresh = Emoji.get_chat_emoji('REFRESH') r2 = "🔁" page_num = int(kwargs.get("page_num", 0)) add = reaction not in [left, right, refresh, r2] if str(reaction) == left: page_num -= 1 add = False elif str(reaction) == right: page_num += 1 add = False elif str(reaction) in [refresh, r2]: if not message.channel.permissions_for(message.channel.guild.me).manage_messages: return kwargs await message.clear_reactions() await asyncio.sleep(0.2) add = False if add: for i in range(10): if str(reaction) == str(Emoji.get_emoji(str(i+1))): roles = Configuration.get_var(message.guild.id, "SELF_ROLES") role = message.channel.guild.get_role(roles[page_num*10 + i]) if role is None: await Selfroles.validate_self_roles(bot, message.channel.guild) return add_role = role not in user.roles try: await (user.add_roles if add_role else user.remove_roles)(role) except Forbidden: if message.channel.permissions_for(message.channel.guild.me).send_messages: await MessageUtils.send_to(message.channel, "NO", "role_too_high_add", role=role.name) return kwargs else: if message.channel.permissions_for(message.channel.guild.me).send_messages: await MessageUtils.send_to(message.channel, "YES", "role_joined" if add_role else "role_left", role_name=await Utils.clean(role.name), delete_after=10) bot.loop.create_task(remove_reaction(message, reaction, user)) return kwargs return kwargs pages = Selfroles.gen_role_pages(message.channel.guild) if page_num >= len(pages): page_num = 0 elif page_num < 0: page_num = len(pages) - 1 kwargs["page_num"] = page_num embed = Embed(title=Translator.translate("assignable_roles", message.channel, server_name=message.channel.guild.name, page_num=page_num+1, page_count=len(pages)), colour=Colour(0xbffdd), description=pages[page_num]) await message.edit(embed=embed) await Selfroles.update_reactions(message, pages[page_num], len(pages) > 1) bot.loop.create_task(bot.redis_pool.expire(f"self_role:{message.channel.guild.id}", int(kwargs.get("duration", 60 * 60 * 24 * 7)))) return kwargs
def __init__(self, filters, pages, guild_id, current_page=0, ephemeral=False, userid=""): super().__init__(timeout=None) self.id="" if pages > 0: self.add_item(CallbackButton(Translator.translate('first_page', guild_id), self.on_first_page, 'inf_search:first_page', disabled=current_page == 0)) self.add_item(CallbackButton(Translator.translate('prev_page', guild_id), self.on_prev_page, 'inf_search:prev_page', disabled=current_page == 0)) self.add_item(CallbackButton(emoji=Emoji.get_emoji('AE'), style=ButtonStyle.grey, cid='inf_search:blank', callback=self.hi, label=None)) self.add_item(CallbackButton(Translator.translate('next_page', guild_id), self.on_next_page, 'inf_search:next_page', disabled=current_page >= pages-1)) self.add_item(CallbackButton(Translator.translate('last_page', guild_id), self.on_last_page, 'inf_search:last_page', disabled=current_page >= pages-1))
async def confirm(ctx: commands.Context, text, timeout=30, on_yes=None, on_no=None, delete=True): yes = Emoji.get_emoji("YES") no = Emoji.get_emoji("NO") message: discord.Message = await ctx.send(text) await message.add_reaction(yes) await message.add_reaction(no) def check(reaction: discord.Reaction, user): return user == ctx.message.author and reaction.emoji in ( yes, no) and reaction.message.id == message.id try: reaction, user = await ctx.bot.wait_for('reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: await message.delete() await ctx.send(f"I got no answer within {timeout} seconds.. Aborting.") return GearbotLogging.info( f"CONFIRMATOR RESPONCE RECEIVED:\nreaction: {reaction}\nemoji: {reaction.emoji}\non_yes: {on_yes}\non_no: {on_no}" ) if reaction.emoji == yes and on_yes is not None: if delete: try: await message.delete() except discord.Forbidden: pass await on_yes() elif reaction.emoji == no: if delete: try: await message.delete() except discord.Forbidden: pass if on_no is not None: await on_no() else: await GearbotLogging.send_to(ctx, "NO", "command_canceled")
async def confirm(ctx: commands.Context, text, timeout=30, on_yes=None, on_no=None, delete=True): yes = Emoji.get_emoji("YES") no = Emoji.get_emoji("NO") message: discord.Message = await ctx.send(text) await message.add_reaction(yes) await message.add_reaction(no) def check(reaction: discord.Reaction, user): return user == ctx.message.author and reaction.emoji in ( yes, no) and reaction.message.id == message.id try: reaction, user = await ctx.bot.wait_for('reaction_add', timeout=timeout, check=check) except asyncio.TimeoutError: await message.delete() await MessageUtils.send_to(ctx, "NO", "confirmation_timeout", timeout=30) return if reaction.emoji == yes and on_yes is not None: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass await on_yes() elif reaction.emoji == no: if delete: try: await message.delete() except (discord.Forbidden, discord.NotFound): pass if on_no is not None: await on_no() else: await MessageUtils.send_to(ctx, "NO", "command_canceled")
async def eval(self, ctx:commands.Context, *, code: str): output = None env = { 'bot': self.bot, 'ctx': ctx, 'channel': ctx.channel, 'author': ctx.author, 'guild': ctx.guild, 'message': ctx.message } env.update(globals()) if code.startswith('```'): code = "\n".join(code.split("\n")[1:-1]) out = io.StringIO() to_compile = f'async def func():\n{textwrap.indent(code, " ")}' try: exec(to_compile, env) except Exception as e: output = f'{e.__class__.__name__}: {e}' else: func = env['func'] try: with contextlib.redirect_stdout(out): ret = await func() except Exception as e: value = out.getvalue() output = f'{value}{traceback.format_exc()}' else: value = out.getvalue() if ret is None: if value: output = value else: output = f'{value}{ret}' if output is not None: pipe = self.bot.redis_pool.pipeline() k = f'eval:{ctx.message.id}' pipe.set(k, output) pipe.expire(k, 7*24*60*60) await pipe.execute() pages = Pages.paginate(output, prefix='```py\n', suffix='```') content, view, _ = SimplePager.get_parts(pages, 0, ctx.guild.id if ctx.guild is not None else 0, f'eval:{ctx.message.id}') await ctx.send(f'Eval output 1/{len(pages)}{content}', view=view) else: await ctx.message.add_reaction(Emoji.get_emoji("YES"))
async def eval(self, ctx: commands.Context, *, code: str): output = None env = { 'bot': self.bot, 'ctx': ctx, 'channel': ctx.channel, 'author': ctx.author, 'guild': ctx.guild, 'message': ctx.message } env.update(globals()) if code.startswith('```'): code = "\n".join(code.split("\n")[1:-1]) out = io.StringIO() to_compile = f'async def func():\n{textwrap.indent(code, " ")}' try: exec(to_compile, env) except Exception as e: output = f'{e.__class__.__name__}: {e}' else: func = env['func'] try: with contextlib.redirect_stdout(out): ret = await func() except Exception as e: value = out.getvalue() output = f'{value}{traceback.format_exc()}' else: value = out.getvalue() if ret is None: if value: output = value else: output = f'{value}{ret}' if output is not None: await Pages.create_new(self.bot, "eval", ctx, pages="----NEW PAGE----".join( Pages.paginate(output)), code=code, trigger=ctx.message.id, sender=ctx.author.id) else: await ctx.message.add_reaction(Emoji.get_emoji("YES"))
async def init_role(self, ctx): pages = self.gen_role_pages(ctx.guild) page = pages[0] emoji = [] for i in range( 10 if len(pages) > 1 else round(len(page.splitlines()) / 2)): emoji.append(Emoji.get_emoji(str(i + 1))) embed = discord.Embed(title=Translator.translate( "assignable_roles", ctx, server_name=ctx.guild.name, page_num=1, page_count=len(pages)), colour=discord.Colour(0xbffdd), description=page) return None, embed, len(pages) > 1, emoji
async def on_raw_reaction_add(self, payload: discord.RawReactionActionEvent): guild = self.bot.get_guild(payload.guild_id) if guild is None: return if guild.me.id == payload.user_id: return try: message = await self.bot.get_channel( payload.channel_id).get_message(payload.message_id) except discord.NotFound: pass else: if str(payload.message_id) in Pages.known_messages: info = Pages.known_messages[str(payload.message_id)] if info["type"] == "role": for i in range(10): e = Emoji.get_emoji(str(i + 1)) if payload.emoji.name == e: roles = Configuration.get_var( guild.id, "SELF_ROLES") channel = self.bot.get_channel(payload.channel_id) number = info['page'] * 10 + i if number >= len(roles): await GearbotLogging.send_to( channel, "NO", "role_not_on_page", requested=number + 1, max=len(roles) % 10, delete_after=10) return role = guild.get_role(roles[number]) if role is None: return member = guild.get_member(payload.user_id) try: if role in member.roles: await member.remove_roles(role) added = False else: await member.add_roles(role) added = True except discord.Forbidden: emessage = f"{Emoji.get_chat_emoji('NO')} {Translator.translate('mute_role_to_high', payload.guild_id, role=role.name)}" try: await channel.send(emessage) except discord.Forbidden: try: member.send(emessage) except discord.Forbidden: pass else: try: action_type = 'role_joined' if added else 'role_left' await channel.send( f"{member.mention} {Translator.translate(action_type, payload.guild_id, role_name=role.name)}", delete_after=10) except discord.Forbidden: pass if channel.permissions_for( guild.me).manage_messages: await message.remove_reaction(e, member) break
async def remind_me(self, ctx, duration: Duration, *, reminder: ReminderText): """remind_me_help""" if duration.unit is None: parts = reminder.split(" ") duration.unit = parts[0] reminder = " ".join(parts[1:]) duration_seconds = duration.to_seconds(ctx) if duration_seconds <= 0: await MessageUtils.send_to(ctx, "NO", "reminder_time_travel") return if ctx.guild is not None: message = f'{Emoji.get_chat_emoji("QUESTION")} {Translator.translate("remind_question", ctx)}' one = str(Emoji.get_emoji("1")) two = str(Emoji.get_emoji("2")) no = str(Emoji.get_emoji("NO")) embed = Embed(description=f""" {Emoji.get_chat_emoji("1")} {Translator.translate("remind_option_here", ctx)} {Emoji.get_chat_emoji("2")} {Translator.translate("remind_option_dm", ctx)} {Emoji.get_chat_emoji("NO")} {Translator.translate("remind_option_cancel", ctx)} """) m = await ctx.send(message, embed=embed) for e in [one, two, no]: await m.add_reaction(e) try: reaction = await ctx.bot.wait_for( 'raw_reaction_add', timeout=30, check=lambda reaction: reaction.user_id == ctx.message. author.id and str(reaction.emoji) in [one, two, no] and reaction.message_id == m.id) except asyncio.TimeoutError: await MessageUtils.send_to(ctx, "NO", "confirmation_timeout", timeout=30) return else: if str(reaction.emoji) == no: await MessageUtils.send_to(ctx, "NO", "command_canceled") return else: dm = str(reaction.emoji) == two finally: try: await m.delete() except (NotFound, Forbidden): pass else: dm = True r = await Reminder.create( user_id=ctx.author.id, channel_id=ctx.channel.id, dm=dm, to_remind=await Utils.clean(reminder, markdown=False, links=False, emoji=False), time=time.time() + duration_seconds, send=datetime.now().timestamp(), status=ReminderStatus.Pending, guild_id=ctx.guild.id if ctx.guild is not None else "@me", message_id=ctx.message.id) if duration_seconds <= 10: self.handling[r.id] = self.bot.loop.create_task( self.run_after(duration_seconds, self.deliver(r.id))) mode = "dm" if dm else "here" await MessageUtils.send_to(ctx, "YES", f"reminder_confirmation_{mode}", duration=duration.length, duration_identifier=duration.unit, id=r.id)