feat(commands:*|Tag): feat tag system

This commit is contained in:
Romain J 2021-05-16 00:32:14 +02:00
parent af3d742f68
commit 614434aebf
23 changed files with 778 additions and 17 deletions

View File

@ -20,6 +20,7 @@ install_requires =
Babel>=2.8.0
beautifulsoup4>=4.9.3
discord.py @ git+https://github.com/Rapptz/discord.py
discord-ext-menus
humanize>=2.6.0
ipinfo>=4.1.0
ipwhois>=1.2.0

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-15 21:32+0200\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-15 21:32+0200\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-15 21:32+0200\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-15 21:32+0200\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,50 +17,50 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: tuxbot/cogs/Mod/mod.py:71
#: tuxbot/cogs/Mod/mod.py:75
#, python-brace-format
msgid "Locale changed to {lang} successfully"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:82
#: tuxbot/cogs/Mod/mod.py:86
msgid "List of available locales: "
msgstr ""
#: tuxbot/cogs/Mod/mod.py:107
#: tuxbot/cogs/Mod/mod.py:111
msgid ""
"{}please read the following rule: \n"
"{}"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:125 tuxbot/cogs/Mod/mod.py:225
#: tuxbot/cogs/Mod/mod.py:129 tuxbot/cogs/Mod/mod.py:229
msgid "No rules found for this server"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:129 tuxbot/cogs/Mod/mod.py:229
#: tuxbot/cogs/Mod/mod.py:133 tuxbot/cogs/Mod/mod.py:233
msgid "Rules for {}"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:135 tuxbot/cogs/Mod/mod.py:235
#: tuxbot/cogs/Mod/mod.py:139 tuxbot/cogs/Mod/mod.py:239
msgid "Latest change: {}"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:149 tuxbot/cogs/Mod/mod.py:249
#: tuxbot/cogs/Mod/mod.py:153 tuxbot/cogs/Mod/mod.py:253
msgid "Rules for {} ({}/{})"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:168
#: tuxbot/cogs/Mod/mod.py:172
msgid ""
"Following rule added: \n"
"{}"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:191
#: tuxbot/cogs/Mod/mod.py:195
msgid ""
"Following rule updated: \n"
"{}"
msgstr ""
#: tuxbot/cogs/Mod/mod.py:209
#: tuxbot/cogs/Mod/mod.py:213
msgid ""
"Following rule deleted: \n"
"{}"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-15 21:32+0200\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-15 21:32+0200\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -0,0 +1,19 @@
from collections import namedtuple
from tuxbot.core.bot import Tux
from .tags import Tags
from .config import TagsConfig, HAS_MODELS
VersionInfo = namedtuple("VersionInfo", "major minor micro release_level")
version_info = VersionInfo(major=1, minor=0, micro=0, release_level="alpha")
__version__ = "v{}.{}.{}-{}".format(
version_info.major,
version_info.minor,
version_info.micro,
version_info.release_level,
).replace("\n", "")
def setup(bot: Tux):
bot.add_cog(Tags(bot))

View File

@ -0,0 +1,12 @@
from typing import Dict
from structured_config import Structure
HAS_MODELS = True
class TagsConfig(Structure):
pass
extra: Dict[str, Dict] = {}

View File

View File

@ -0,0 +1,36 @@
from discord.ext import commands
from discord.ext.commands import Context
from tuxbot.cogs.Tags.functions.exceptions import (
UnknownTagException,
ExistingTagException,
)
from tuxbot.cogs.Tags.models import Tag
def _(x):
return x
class TagConverter(commands.Converter):
async def convert(self, ctx: Context, argument: str): # skipcq: PYL-W0613
arg = argument.lower()
tag_row = await Tag.get_or_none(server_id=ctx.guild.id, name=arg)
if not tag_row:
raise UnknownTagException(_("Unknown tag"))
return arg
class NewTagConverter(commands.Converter):
async def convert(self, ctx: Context, argument: str): # skipcq: PYL-W0613
arg = argument.lower()
tag_row = await Tag.get_or_none(server_id=ctx.guild.id, name=arg)
if tag_row:
raise ExistingTagException(_("Tag already exists"))
return arg

View File

@ -0,0 +1,13 @@
from discord.ext import commands
class TagsException(commands.BadArgument):
pass
class UnknownTagException(TagsException):
pass
class ExistingTagException(TagsException):
pass

View File

@ -0,0 +1,17 @@
from tuxbot.core.utils.paginator import SimplePages
class TagPage:
def __init__(self, entry):
self.name = entry.name
self.uses = entry.uses
def __str__(self):
return f"{self.name} ({self.uses})"
class TagPages(SimplePages):
def __init__(self, entries, per_page=15):
converted = [TagPage(entry) for entry in entries]
super().__init__(converted, per_page=per_page)

View File

@ -0,0 +1,47 @@
from typing import Optional
import discord
from tuxbot.cogs.Tags.models import Tag
from tuxbot.core.utils.functions.extra import ContextPlus
async def get_tag(guild_id: int, name: str) -> Tag:
return await Tag.get(server_id=guild_id, name=name)
async def get_all_tags(
guild_id: int, author: Optional[discord.Member] = None
) -> list[Tag]:
if author is not None:
return (
await Tag.filter(server_id=guild_id, author_id=author.id)
.all()
.order_by("-uses")
)
return await Tag.filter(server_id=guild_id).all().order_by("-uses")
async def search_tags(guild_id: int, q: str) -> list[Tag]:
return await Tag.filter(server_id=guild_id, name__icontains=q).all().order_by("-uses")
async def create_tag(ctx: ContextPlus, name: str, content: str):
tag_row = await Tag()
tag_row.server_id = ctx.guild.id
tag_row.author_id = ctx.author.id
tag_row.name = name # type: ignore
tag_row.content = content # type: ignore
await tag_row.save()
async def edit_tag(ctx: ContextPlus, name: str, content: str):
tag_row = await get_tag(ctx.guild.id, name)
tag_row.content = content # type: ignore
await tag_row.save()

View File

@ -0,0 +1,74 @@
# English translations for Tuxbot-bot package.
# Copyright (C) 2020 THE Tuxbot-bot'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Tuxbot-bot package.
# Automatically generated, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-01-19 14:42+0100\n"
"PO-Revision-Date: 2020-06-10 00:38+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: en_US\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: tuxbot/cogs/Tags/functions/converters.py:22
msgid "Unknown tag"
msgstr ""
#: tuxbot/cogs/Tags/functions/converters.py:34
msgid "Tag already exists"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:71
msgid "Tag successfully deleted"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:74
msgid "Your can't delete this tag"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:82
msgid "Tag successfully created"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:98
msgid "Tag successfully edited"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:101
msgid "Your can't edit this tag"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:120
msgid "Owner"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:122
msgid "Uses"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:135
msgid "The search must be at least 3 characters"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:150
msgid "No tags found"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:171
msgid "No tags found for {}"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:180
msgid "Tag owner is on this server."
msgstr ""
#: tuxbot/cogs/Tags/tags.py:188
msgid "This tag is now owned by you."
msgstr ""

View File

@ -0,0 +1,75 @@
# French translations for Tuxbot-bot package
# Traductions françaises du paquet Tuxbot-bot.
# Copyright (C) 2020 THE Tuxbot-bot'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Tuxbot-bot package.
# Automatically generated, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-01-19 14:42+0100\n"
"PO-Revision-Date: 2020-06-10 00:38+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: tuxbot/cogs/Tags/functions/converters.py:22
msgid "Unknown tag"
msgstr "Tag inconnu"
#: tuxbot/cogs/Tags/functions/converters.py:34
msgid "Tag already exists"
msgstr "Tag déjà existant"
#: tuxbot/cogs/Tags/tags.py:71
msgid "Tag successfully deleted"
msgstr "Tag supprimé avec succès"
#: tuxbot/cogs/Tags/tags.py:74
msgid "Your can't delete this tag"
msgstr "Vous ne pouvez pas supprimer ce tag"
#: tuxbot/cogs/Tags/tags.py:82
msgid "Tag successfully created"
msgstr "Tag créé avec succès"
#: tuxbot/cogs/Tags/tags.py:98
msgid "Tag successfully edited"
msgstr "Tag édité avec succès"
#: tuxbot/cogs/Tags/tags.py:101
msgid "Your can't edit this tag"
msgstr "Vous ne pouvez pas éditer ce tag"
#: tuxbot/cogs/Tags/tags.py:120
msgid "Owner"
msgstr "Propriétaire"
#: tuxbot/cogs/Tags/tags.py:122
msgid "Uses"
msgstr "Utilisations"
#: tuxbot/cogs/Tags/tags.py:135
msgid "The search must be at least 3 characters"
msgstr "La recherche doit faire au moins 3 caracteres"
#: tuxbot/cogs/Tags/tags.py:150
msgid "No tags found"
msgstr "Aucun tag trouvé"
#: tuxbot/cogs/Tags/tags.py:171
msgid "No tags found for {}"
msgstr "Aucun tag trouvé pour {}"
#: tuxbot/cogs/Tags/tags.py:180
msgid "Tag owner is on this server."
msgstr "Le propriétaire du tag est sur ce serveur"
#: tuxbot/cogs/Tags/tags.py:188
msgid "This tag is now owned by you."
msgstr "Ce tag est désormais en votre possession"

View File

@ -0,0 +1,74 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the Tuxbot-bot package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: tuxbot/cogs/Tags/functions/converters.py:22
msgid "Unknown tag"
msgstr ""
#: tuxbot/cogs/Tags/functions/converters.py:34
msgid "Tag already exists"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:71
msgid "Tag successfully deleted"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:74
msgid "Your can't delete this tag"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:82
msgid "Tag successfully created"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:98
msgid "Tag successfully edited"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:101
msgid "Your can't edit this tag"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:120
msgid "Owner"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:122
msgid "Uses"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:135
msgid "The search must be at least 3 characters"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:150
msgid "No tags found"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:171
msgid "No tags found for {}"
msgstr ""
#: tuxbot/cogs/Tags/tags.py:180
msgid "Tag owner is on this server."
msgstr ""
#: tuxbot/cogs/Tags/tags.py:188
msgid "This tag is now owned by you."
msgstr ""

View File

@ -0,0 +1 @@
from .tags import *

View File

@ -0,0 +1,31 @@
import tortoise
from tortoise import fields
class Tag(tortoise.Model):
id = fields.BigIntField(pk=True)
server_id = fields.BigIntField()
author_id = fields.BigIntField()
name = fields.TextField()
content = fields.TextField()
uses = fields.IntField(default=0)
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "tags"
def __str__(self):
return (
f"<Tag id={self.id} "
f"server_id={self.server_id} "
f"author_id={self.author_id} "
f"name='{self.name}' "
f"content='{self.content}' "
f"uses={self.uses} "
f"created_at={self.created_at}>"
)
__repr__ = __str__

189
tuxbot/cogs/Tags/tags.py Normal file
View File

@ -0,0 +1,189 @@
import logging
from typing import Optional
import discord
from discord.ext import commands, menus
from tuxbot.cogs.Tags.functions.converters import TagConverter, NewTagConverter
from tuxbot.cogs.Tags.functions.exceptions import (
UnknownTagException,
ExistingTagException,
)
from tuxbot.cogs.Tags.functions.paginator import TagPages
from tuxbot.cogs.Tags.functions.utils import (
get_tag,
get_all_tags,
search_tags,
create_tag,
edit_tag,
)
from tuxbot.core.bot import Tux
from tuxbot.core.i18n import (
Translator,
)
from tuxbot.core.utils.functions.extra import (
group_extra,
ContextPlus,
)
log = logging.getLogger("tuxbot.cogs.Tags")
_ = Translator("Tags", __file__)
class Tags(commands.Cog):
def __init__(self, bot: Tux):
self.bot = bot
async def cog_command_error(self, ctx: ContextPlus, error):
if isinstance(
error,
(UnknownTagException, ExistingTagException),
):
await ctx.send(_(str(error), ctx, self.bot.config))
# =========================================================================
# =========================================================================
@group_extra(name="tag", invoke_without_command=True, deletable=False)
@commands.guild_only()
async def _tag(self, ctx: ContextPlus, *, name: TagConverter):
tag_row = await get_tag(ctx.guild.id, str(name))
await ctx.send(tag_row.content)
tag_row.uses += 1 # type: ignore
await tag_row.save()
@_tag.command(name="delete")
async def _tag_delete(self, ctx: ContextPlus, *, name: TagConverter):
tag_row = await get_tag(ctx.guild.id, str(name))
backdoor = (
await ctx.bot.is_owner(ctx.author)
or ctx.author.guild_permissions.manage_messages
)
if backdoor or ctx.author.id == tag_row.id:
await tag_row.delete()
return await ctx.send(
_("Tag successfully deleted", ctx, self.bot.config)
)
await ctx.send(_("Your can't delete this tag", ctx, self.bot.config))
@_tag.command(name="create", aliases=["add"])
async def _tag_create(
self, ctx, name: NewTagConverter, *, content: commands.clean_content
):
await create_tag(ctx, str(name), str(content))
await ctx.send(_("Tag successfully created", ctx, self.bot.config))
@_tag.command(name="edit")
async def _tag_edit(
self, ctx, name: TagConverter, *, content: commands.clean_content
):
tag_row = await get_tag(ctx.guild.id, str(name))
backdoor = (
await ctx.bot.is_owner(ctx.author)
or ctx.author.guild_permissions.manage_messages
)
if backdoor or ctx.author.id == tag_row.id:
await edit_tag(ctx, str(name), str(content))
return await ctx.send(
_("Tag successfully edited", ctx, self.bot.config)
)
await ctx.send(_("Your can't edit this tag", ctx, self.bot.config))
@_tag.command(name="info", aliases=["owner"])
async def _tag_info(self, ctx: ContextPlus, *, name: TagConverter):
tag_row = await get_tag(ctx.guild.id, str(name))
e = discord.Embed(color=discord.Colour.blue())
owner_id = tag_row.author_id
e.title = tag_row.name
e.timestamp = tag_row.created_at
user = self.bot.get_user(owner_id) or (
await self.bot.fetch_user(owner_id)
)
e.set_author(name=str(user), icon_url=user.avatar.url)
e.add_field(
name=_("Owner", ctx, self.bot.config), value=f"<@{owner_id}>"
)
e.add_field(name=_("Uses", ctx, self.bot.config), value=tag_row.uses)
await ctx.send(embed=e)
@_tag.command(name="search", aliases=["find"])
async def _tag_search(
self, ctx: ContextPlus, *, name: commands.clean_content
):
q = str(name)
if len(q) < 3:
return await ctx.send(
_(
"The search must be at least 3 characters",
ctx,
self.bot.config,
)
)
tags = await search_tags(ctx.guild.id, q)
if tags:
try:
p = TagPages(entries=tags)
await p.start(ctx)
except menus.MenuError as e:
await ctx.send(e)
else:
await ctx.send(_("No tags found", ctx, self.bot.config))
@_tag.command(name="list")
async def _tag_list(
self, ctx: ContextPlus, author: Optional[discord.Member]
):
author = author or ctx.author
tags = await get_all_tags(ctx.guild.id, author)
if tags:
try:
p = TagPages(entries=tags)
p.embed.set_author(
name=str(author), icon_url=author.avatar.url
)
await p.start(ctx)
except menus.MenuError as e:
await ctx.send(e)
else:
await ctx.send(
_("No tags found for {}", ctx, self.bot.config).format(author)
)
@_tag.command(name="claim")
async def _tag_claim(self, ctx: ContextPlus, *, name: TagConverter):
tag_row = await get_tag(ctx.guild.id, str(name))
if await ctx.guild.fetch_member(tag_row.author_id) is not None:
return await ctx.send(
_("Tag owner is on this server.", ctx, self.bot.config)
)
tag_row.author_id = ctx.author.id
await tag_row.save()
await ctx.send(
_("This tag is now owned by you.", ctx, self.bot.config)
)

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Tuxbot-bot\n"
"Report-Msgid-Bugs-To: rick@gnous.eu\n"
"POT-Creation-Date: 2021-05-15 21:32+0200\n"
"POT-Creation-Date: 2021-05-16 00:28+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"

View File

@ -44,6 +44,7 @@ packages: Tuple = (
"tuxbot.cogs.Network",
"tuxbot.cogs.Linux",
"tuxbot.cogs.Mod",
"tuxbot.cogs.Tags",
)

View File

@ -0,0 +1,171 @@
"""
Credits to Rapptz/RoboDanny
https://github.com/Rapptz/RoboDanny/blob/0dfa21599da76e84c2f8e7fde0c132ec93c840a8/cogs/utils/paginator.py
"""
import asyncio
import discord
from discord.ext.commands import Paginator as CommandPaginator
from discord.ext import menus
class RoboPages(menus.MenuPages):
def __init__(self, source):
super().__init__(source=source, check_embeds=True)
self.input_lock = asyncio.Lock()
async def finalize(self, timed_out):
try:
if timed_out:
await self.message.clear_reactions()
else:
await self.message.delete()
except discord.HTTPException:
pass
@menus.button("\N{INFORMATION SOURCE}\ufe0f", position=menus.Last(3))
async def show_help(self):
"""shows this message"""
embed = discord.Embed(
title="Paginator help",
description="Hello! Welcome to the help page.",
)
messages = []
for (emoji, button) in self.buttons.items():
messages.append(f"{emoji}: {button.action.__doc__}")
embed.add_field(
name="What are these reactions for?",
value="\n".join(messages),
inline=False,
)
embed.set_footer(
text=f"We were on page {self.current_page + 1} before this message."
)
await self.message.edit(content=None, embed=embed)
async def go_back_to_current_page():
await asyncio.sleep(30.0)
await self.show_page(self.current_page)
self.bot.loop.create_task(go_back_to_current_page())
@menus.button(
"\N{INPUT SYMBOL FOR NUMBERS}", position=menus.Last(1.5), lock=False
)
async def numbered_page(self, payload):
"""lets you type a page number to go to"""
if self.input_lock.locked():
return
async with self.input_lock:
channel = self.message.channel
author_id = payload.user_id
to_delete = []
to_delete.append(
await channel.send("What page do you want to go to?")
)
def message_check(m):
return (
m.author.id == author_id
and channel == m.channel
and m.content.isdigit()
)
try:
msg = await self.bot.wait_for(
"message", check=message_check, timeout=30.0
)
except asyncio.TimeoutError:
to_delete.append(await channel.send("Took too long."))
await asyncio.sleep(5)
else:
page = int(msg.content)
to_delete.append(msg)
await self.show_checked_page(page - 1)
try:
await channel.delete_messages(to_delete)
except Exception:
pass
class FieldPageSource(menus.ListPageSource):
"""A page source that requires (field_name, field_value) tuple items."""
def __init__(self, entries, *, per_page=12):
super().__init__(entries, per_page=per_page)
self.embed = discord.Embed(colour=discord.Colour.blurple())
# pylint: disable=arguments-differ
async def format_page(self, menu, entries):
self.embed.clear_fields()
self.embed.description = discord.Embed.Empty
for key, value in entries:
self.embed.add_field(name=key, value=value, inline=False)
maximum = self.get_max_pages()
if maximum > 1:
text = f"Page {menu.current_page + 1}/{maximum} ({len(self.entries)} entries)"
self.embed.set_footer(text=text)
return self.embed
class TextPageSource(menus.ListPageSource):
def __init__(self, text, *, prefix="```", suffix="```", max_size=2000):
pages = CommandPaginator(
prefix=prefix, suffix=suffix, max_size=max_size - 200
)
for line in text.split("\n"):
pages.add_line(line)
super().__init__(entries=pages.pages, per_page=1)
# pylint: disable=arguments-differ
async def format_page(self, menu, content):
maximum = self.get_max_pages()
if maximum > 1:
return f"{content}\nPage {menu.current_page + 1}/{maximum}"
return content
class SimplePageSource(menus.ListPageSource):
def __init__(self, entries, *, per_page=12):
super().__init__(entries, per_page=per_page)
self.initial_page = True
# pylint: disable=arguments-differ
async def format_page(self, menu, entries):
pages = []
for index, entry in enumerate(
entries, start=menu.current_page * self.per_page
):
pages.append(f"{index + 1}. {entry}")
maximum = self.get_max_pages()
if maximum > 1:
footer = f"Page {menu.current_page + 1}/{maximum} ({len(self.entries)} entries)"
menu.embed.set_footer(text=footer)
if self.initial_page and self.is_paginating():
pages.append("")
pages.append(
"Confused? React with \N{INFORMATION SOURCE} for more info."
)
self.initial_page = False
menu.embed.description = "\n".join(pages)
return menu.embed
class SimplePages(RoboPages):
"""A simple pagination session reminiscent of the old Pages interface.
Basically an embed with some normal formatting.
"""
def __init__(self, entries, *, per_page=12):
super().__init__(SimplePageSource(entries, per_page=per_page))
self.embed = discord.Embed(colour=discord.Colour.blurple())