feat(commands:*|Tag): feat tag system
This commit is contained in:
parent
af3d742f68
commit
614434aebf
23 changed files with 778 additions and 17 deletions
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
"{}"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
19
tuxbot/cogs/Tags/__init__.py
Normal file
19
tuxbot/cogs/Tags/__init__.py
Normal 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))
|
12
tuxbot/cogs/Tags/config.py
Normal file
12
tuxbot/cogs/Tags/config.py
Normal 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] = {}
|
0
tuxbot/cogs/Tags/functions/__init__.py
Normal file
0
tuxbot/cogs/Tags/functions/__init__.py
Normal file
36
tuxbot/cogs/Tags/functions/converters.py
Normal file
36
tuxbot/cogs/Tags/functions/converters.py
Normal 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
|
13
tuxbot/cogs/Tags/functions/exceptions.py
Normal file
13
tuxbot/cogs/Tags/functions/exceptions.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from discord.ext import commands
|
||||
|
||||
|
||||
class TagsException(commands.BadArgument):
|
||||
pass
|
||||
|
||||
|
||||
class UnknownTagException(TagsException):
|
||||
pass
|
||||
|
||||
|
||||
class ExistingTagException(TagsException):
|
||||
pass
|
17
tuxbot/cogs/Tags/functions/paginator.py
Normal file
17
tuxbot/cogs/Tags/functions/paginator.py
Normal 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)
|
47
tuxbot/cogs/Tags/functions/utils.py
Normal file
47
tuxbot/cogs/Tags/functions/utils.py
Normal 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()
|
74
tuxbot/cogs/Tags/locales/en-US.po
Normal file
74
tuxbot/cogs/Tags/locales/en-US.po
Normal 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 ""
|
75
tuxbot/cogs/Tags/locales/fr-FR.po
Normal file
75
tuxbot/cogs/Tags/locales/fr-FR.po
Normal 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"
|
74
tuxbot/cogs/Tags/locales/messages.pot
Normal file
74
tuxbot/cogs/Tags/locales/messages.pot
Normal 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 ""
|
1
tuxbot/cogs/Tags/models/__init__.py
Normal file
1
tuxbot/cogs/Tags/models/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from .tags import *
|
31
tuxbot/cogs/Tags/models/tags.py
Normal file
31
tuxbot/cogs/Tags/models/tags.py
Normal 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
189
tuxbot/cogs/Tags/tags.py
Normal 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)
|
||||
)
|
|
@ -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"
|
||||
|
|
|
@ -44,6 +44,7 @@ packages: Tuple = (
|
|||
"tuxbot.cogs.Network",
|
||||
"tuxbot.cogs.Linux",
|
||||
"tuxbot.cogs.Mod",
|
||||
"tuxbot.cogs.Tags",
|
||||
)
|
||||
|
||||
|
||||
|
|
171
tuxbot/core/utils/paginator.py
Normal file
171
tuxbot/core/utils/paginator.py
Normal 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())
|
Loading…
Reference in a new issue