async def inv( self, ctx, channel: Optional[Union[discord.TextChannel, discord.VoiceChannel]] = None, days: Optional[NonNegative[float]] = None, uses: Optional[NonNegative[int]] = None, amount: Optional[NonNegative[int]] = None, *, reason: str = None, ): """ Create one or several invites with the specified parameters. For specifying unlimited days or uses, use 0. Defaults can be set with `[p]inv set`. If no defaults are found, channel defaults to the current channel, days defaults to 1, and uses defaults to 0 (infinite). Uses will always be finite if days is infinite. """ settings = await self.config.guild(ctx.guild).all() if not channel: channel = ctx.guild.get_channel(settings["channel"]) channel = channel or ctx.channel if not channel.permissions_for(ctx.me).create_instant_invite: raise commands.BotMissingPermissions(["create_instant_invite"]) if not channel.permissions_for(ctx.author).create_instant_invite: raise commands.MissingPermissions(["create_instant_invite"]) if days is None: days = settings["days"] if uses is None: if days: uses = settings["uses"] else: uses = settings["uses"] or 1 generated = [] for i in range(amount or 1): generated.append(await channel.create_invite( max_age=(days or 0) * 86400, max_uses=uses, temporary=False, unique=True, reason=get_audit_reason(ctx.author, reason=reason), )) await ctx.send("\n".join(invite.url for invite in generated), delete_after=120)
async def logsfrom( self, ctx, after: Optional[discord.PartialMessage] = None, before: Optional[discord.PartialMessage] = None, *, channel: discord.TextChannel = None, ): """ Logs the specified channel into a file, then uploads the file. The channel will default to the current channel if none is specified. The limit may be the number of messages to log or the ID of the message to start after, exclusive. All timestamps are in UTC. """ if channel: ctxc = copy(ctx) ctxc.channel = channel else: channel = ctx.channel ctxc = ctx if not channel.permissions_for(ctx.me).read_message_history: raise commands.BotMissingPermissions(["read_message_history"]) if not await check_permissions(ctxc, {"read_message_history": True}): raise commands.MissingPermissions(["read_message_history"]) after, before = getattr(after, "id", after), getattr(before, "id", before) cancel_task = asyncio.ensure_future( ctx.bot.wait_for("message", check=MessagePredicate.cancelled(ctx))) async with ctx.typing(): kwargs = {"oldest_first": False} if not after and not before: kwargs["limit"] = 100 elif not before: kwargs.update(after=discord.Object(id=after), limit=after) elif not after: raise RuntimeError("This should never happen.") else: before = min((ctx.message.id, before)) # TODO: wtf should this shit even *mean* if after >= before: kwargs.update(after=discord.Object(id=after), limit=before, oldest_first=True) else: kwargs.update( after=discord.Object(id=after), before=discord.Object(id=before), limit=min((before, after)), ) print(kwargs) stream = io.BytesIO() last_h = MHeaders(None, None, None) message_task = asyncio.ensure_future(history(channel, **kwargs)) done, _ = await asyncio.wait((cancel_task, message_task), return_when=asyncio.FIRST_COMPLETED) if cancel_task in done: message_task.cancel() return await ctx.send(_T("Okay, I've cancelled my logging.")) messages = message_task.result() processed = 0 pop = messages.popleft if kwargs["oldest_first"] else messages.pop while messages: await asyncio.sleep(0) if cancel_task.done(): return await ctx.send( _T("Okay, I've cancelled my logging.")) message = pop() now_h = MHeaders(message.author, message.created_at, message.edited_at) headers = now_h.to_str(last_h) last_h = now_h if headers: stream.write(headers.encode("utf-8")) stream.write(message.clean_content.encode("utf-8")) if message.attachments: stream.write(b"\n") stream.write("; ".join( f"[{a.filename}]({a.url})" for a in message.attachments).encode("utf-8")) stream.write(b"\n") processed += 1 cancel_task.cancel() stream.seek(0) return await ctx.send( content=_T("{} message{s} logged.").format( processed, s=("" if processed == 1 else "s")), file=discord.File(stream, filename=f"{channel.name}.md"), delete_after=300, )