2021-05-13 16:45:49 +02:00
|
|
|
import logging
|
2021-05-13 22:19:27 +02:00
|
|
|
from datetime import datetime
|
2021-05-17 00:20:56 +02:00
|
|
|
from typing import Optional
|
2021-05-13 16:45:49 +02:00
|
|
|
|
|
|
|
import discord
|
|
|
|
from discord.ext import commands
|
|
|
|
|
2021-05-15 21:36:30 +02:00
|
|
|
from tuxbot.cogs.Mod.functions.converters import (
|
|
|
|
RuleConverter,
|
|
|
|
RuleIDConverter,
|
|
|
|
BotMessageConverter,
|
2021-05-16 23:21:27 +02:00
|
|
|
ReasonConverter,
|
2021-05-15 21:36:30 +02:00
|
|
|
)
|
2021-05-13 22:19:27 +02:00
|
|
|
from tuxbot.cogs.Mod.functions.exceptions import (
|
|
|
|
RuleTooLongException,
|
|
|
|
UnknownRuleException,
|
2021-05-15 21:36:30 +02:00
|
|
|
NonMessageException,
|
|
|
|
NonBotMessageException,
|
2021-05-16 23:21:27 +02:00
|
|
|
ReasonTooLongException,
|
2021-05-13 22:19:27 +02:00
|
|
|
)
|
|
|
|
from tuxbot.cogs.Mod.functions.utils import (
|
|
|
|
save_lang,
|
|
|
|
get_server_rules,
|
|
|
|
format_rule,
|
|
|
|
get_most_recent_server_rules,
|
|
|
|
paginate_server_rules,
|
2021-05-16 23:21:27 +02:00
|
|
|
get_mute_role,
|
|
|
|
create_mute_role,
|
2021-05-13 22:19:27 +02:00
|
|
|
)
|
|
|
|
from tuxbot.cogs.Mod.models.rules import Rule
|
2021-05-13 16:45:49 +02:00
|
|
|
from tuxbot.core.utils import checks
|
|
|
|
from tuxbot.core.bot import Tux
|
|
|
|
|
|
|
|
from tuxbot.core.i18n import (
|
|
|
|
Translator,
|
|
|
|
find_locale,
|
|
|
|
get_locale_name,
|
|
|
|
list_locales,
|
|
|
|
)
|
|
|
|
from tuxbot.core.utils.functions.extra import (
|
|
|
|
group_extra,
|
|
|
|
ContextPlus,
|
2021-05-16 23:21:27 +02:00
|
|
|
command_extra,
|
2021-05-13 16:45:49 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
log = logging.getLogger("tuxbot.cogs.Mod")
|
|
|
|
_ = Translator("Mod", __file__)
|
|
|
|
|
|
|
|
|
|
|
|
class Mod(commands.Cog):
|
|
|
|
def __init__(self, bot: Tux):
|
|
|
|
self.bot = bot
|
|
|
|
|
2021-05-13 22:19:27 +02:00
|
|
|
async def cog_command_error(self, ctx: ContextPlus, error):
|
|
|
|
if isinstance(
|
|
|
|
error,
|
|
|
|
(
|
|
|
|
RuleTooLongException,
|
|
|
|
UnknownRuleException,
|
2021-05-15 21:36:30 +02:00
|
|
|
NonMessageException,
|
|
|
|
NonBotMessageException,
|
2021-05-16 23:21:27 +02:00
|
|
|
ReasonTooLongException,
|
2021-05-13 22:19:27 +02:00
|
|
|
),
|
|
|
|
):
|
2021-05-16 23:21:27 +02:00
|
|
|
return await ctx.send(_(str(error), ctx, self.bot.config))
|
2021-05-13 22:19:27 +02:00
|
|
|
|
2021-05-13 16:45:49 +02:00
|
|
|
# =========================================================================
|
|
|
|
# =========================================================================
|
|
|
|
|
|
|
|
@group_extra(name="lang", aliases=["locale", "langue"], deletable=True)
|
|
|
|
@commands.guild_only()
|
|
|
|
@checks.is_admin()
|
|
|
|
async def _lang(self, ctx: ContextPlus):
|
|
|
|
"""Manage lang settings."""
|
|
|
|
|
|
|
|
@_lang.command(name="set", aliases=["define", "choice"])
|
|
|
|
async def _lang_set(self, ctx: ContextPlus, lang: str):
|
|
|
|
try:
|
|
|
|
await save_lang(self.bot, ctx, find_locale(lang.lower()))
|
|
|
|
await ctx.send(
|
|
|
|
_(
|
|
|
|
"Locale changed to {lang} successfully",
|
|
|
|
ctx,
|
|
|
|
self.bot.config,
|
|
|
|
).format(lang=f"`{get_locale_name(lang).lower()}`")
|
|
|
|
)
|
|
|
|
except NotImplementedError:
|
|
|
|
await self._lang_list(ctx)
|
|
|
|
|
|
|
|
@_lang.command(name="list", aliases=["liste", "all", "view"])
|
|
|
|
async def _lang_list(self, ctx: ContextPlus):
|
|
|
|
e = discord.Embed(
|
|
|
|
title=_("List of available locales: ", ctx, self.bot.config),
|
|
|
|
description=list_locales(),
|
|
|
|
color=0x36393E,
|
|
|
|
)
|
|
|
|
|
|
|
|
await ctx.send(embed=e)
|
2021-05-13 22:19:27 +02:00
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
|
|
@group_extra(
|
|
|
|
name="rule",
|
|
|
|
aliases=["rules", "regle", "regles"],
|
|
|
|
deletable=False,
|
|
|
|
invoke_without_command=True,
|
|
|
|
)
|
|
|
|
@commands.guild_only()
|
|
|
|
async def _rule(
|
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
rule: RuleIDConverter,
|
|
|
|
members: commands.Greedy[discord.Member],
|
|
|
|
):
|
|
|
|
rule_row = await Rule.get(server_id=ctx.guild.id, rule_id=rule)
|
|
|
|
|
|
|
|
message = _(
|
|
|
|
"{}please read the following rule: \n{}", ctx, self.bot.config
|
|
|
|
)
|
|
|
|
authors = ""
|
|
|
|
|
|
|
|
for member in members:
|
|
|
|
if member in ctx.message.mentions:
|
|
|
|
authors += f"{member.name}#{member.discriminator}, "
|
|
|
|
else:
|
|
|
|
authors += f"{member.mention}, "
|
|
|
|
|
|
|
|
await ctx.send(message.format(authors, format_rule(rule_row)))
|
|
|
|
|
|
|
|
@_rule.command(name="list", aliases=["show", "all"])
|
|
|
|
async def _rule_list(self, ctx: ContextPlus):
|
|
|
|
rules = await get_server_rules(ctx.guild.id)
|
|
|
|
|
2021-05-13 23:14:13 +02:00
|
|
|
if not rules:
|
|
|
|
return await ctx.send(
|
|
|
|
_("No rules found for this server", ctx, self.bot.config)
|
|
|
|
)
|
|
|
|
|
2021-05-13 22:19:27 +02:00
|
|
|
embed = discord.Embed(
|
|
|
|
title=_("Rules for {}", ctx, self.bot.config).format(
|
|
|
|
ctx.guild.name
|
|
|
|
),
|
|
|
|
color=discord.Color.blue(),
|
|
|
|
)
|
|
|
|
embed.set_footer(
|
|
|
|
text=_("Latest change: {}", ctx, self.bot.config).format(
|
2021-05-13 22:51:16 +02:00
|
|
|
get_most_recent_server_rules(rules).updated_at.ctime()
|
2021-05-13 22:19:27 +02:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
pages = paginate_server_rules(rules)
|
|
|
|
|
|
|
|
if len(pages) == 1:
|
|
|
|
embed.description = pages[0]
|
|
|
|
|
|
|
|
await ctx.send(embed=embed)
|
|
|
|
else:
|
|
|
|
for i, page in enumerate(pages):
|
|
|
|
embed.title = _(
|
|
|
|
"Rules for {} ({}/{})", ctx, self.bot.config
|
|
|
|
).format(ctx.guild.name, str(i + 1), str(len(pages)))
|
|
|
|
embed.description = page
|
|
|
|
|
|
|
|
await ctx.send(embed=embed)
|
|
|
|
|
|
|
|
@checks.is_admin()
|
|
|
|
@_rule.command(name="add")
|
|
|
|
async def _rule_add(self, ctx: ContextPlus, *, rule: RuleConverter):
|
|
|
|
rule_row = await Rule()
|
|
|
|
rule_row.server_id = ctx.guild.id
|
|
|
|
rule_row.author_id = ctx.message.author.id
|
|
|
|
|
2021-05-16 23:21:27 +02:00
|
|
|
rule_row.rule_id = (
|
|
|
|
len(await get_server_rules(ctx.guild.id)) + 1 # type: ignore
|
|
|
|
)
|
2021-05-13 22:19:27 +02:00
|
|
|
rule_row.content = str(rule) # type: ignore
|
|
|
|
|
|
|
|
await rule_row.save()
|
|
|
|
|
|
|
|
await ctx.send(
|
|
|
|
_("Following rule added: \n{}", ctx, self.bot.config).format(
|
|
|
|
format_rule(rule_row)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
@checks.is_admin()
|
|
|
|
@_rule.command(name="edit")
|
|
|
|
async def _rule_edit(
|
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
rule: RuleIDConverter,
|
|
|
|
*,
|
|
|
|
content: RuleConverter,
|
|
|
|
):
|
|
|
|
# noinspection PyTypeChecker
|
|
|
|
rule_row = await Rule.get(server_id=ctx.guild.id, rule_id=rule)
|
|
|
|
|
|
|
|
rule_row.content = str(content) # type: ignore
|
|
|
|
rule_row.updated_at = datetime.now() # type: ignore
|
|
|
|
|
|
|
|
await rule_row.save()
|
|
|
|
|
|
|
|
await ctx.send(
|
|
|
|
_("Following rule updated: \n{}", ctx, self.bot.config).format(
|
|
|
|
format_rule(rule_row)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
@checks.is_admin()
|
|
|
|
@_rule.command(name="delete")
|
|
|
|
async def _rule_delete(
|
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
rule: RuleIDConverter,
|
|
|
|
):
|
|
|
|
# noinspection PyTypeChecker
|
|
|
|
rule_row = await Rule.get(server_id=ctx.guild.id, rule_id=rule)
|
|
|
|
|
|
|
|
await rule_row.delete()
|
|
|
|
|
|
|
|
await ctx.send(
|
|
|
|
_("Following rule deleted: \n{}", ctx, self.bot.config).format(
|
|
|
|
format_rule(rule_row)
|
|
|
|
)
|
|
|
|
)
|
2021-05-15 21:36:30 +02:00
|
|
|
|
|
|
|
@checks.is_admin()
|
|
|
|
@_rule.command(name="update")
|
|
|
|
async def _rule_update(
|
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
message: BotMessageConverter,
|
|
|
|
):
|
|
|
|
rules = await get_server_rules(ctx.guild.id)
|
|
|
|
|
|
|
|
if not rules:
|
|
|
|
return await ctx.send(
|
|
|
|
_("No rules found for this server", ctx, self.bot.config)
|
|
|
|
)
|
|
|
|
|
|
|
|
embed = discord.Embed(
|
|
|
|
title=_("Rules for {}", ctx, self.bot.config).format(
|
|
|
|
ctx.guild.name
|
|
|
|
),
|
|
|
|
color=discord.Color.blue(),
|
|
|
|
)
|
|
|
|
embed.set_footer(
|
|
|
|
text=_("Latest change: {}", ctx, self.bot.config).format(
|
|
|
|
get_most_recent_server_rules(rules).updated_at.ctime()
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
pages = paginate_server_rules(rules)
|
|
|
|
|
2021-05-16 23:21:27 +02:00
|
|
|
# noinspection PyTypeChecker
|
|
|
|
to_edit: discord.Message = message
|
|
|
|
|
2021-05-15 21:36:30 +02:00
|
|
|
if len(pages) == 1:
|
|
|
|
embed.description = pages[0]
|
|
|
|
|
2021-05-16 23:21:27 +02:00
|
|
|
await to_edit.edit(content="", embed=embed)
|
2021-05-15 21:36:30 +02:00
|
|
|
else:
|
|
|
|
for i, page in enumerate(pages):
|
|
|
|
embed.title = _(
|
|
|
|
"Rules for {} ({}/{})", ctx, self.bot.config
|
|
|
|
).format(ctx.guild.name, str(i + 1), str(len(pages)))
|
|
|
|
embed.description = page
|
|
|
|
|
2021-05-16 23:21:27 +02:00
|
|
|
await to_edit.edit(content="", embed=embed)
|
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
|
|
|
@group_extra(
|
|
|
|
name="mute",
|
|
|
|
deletable=True,
|
|
|
|
invoke_without_command=True,
|
|
|
|
)
|
|
|
|
@commands.guild_only()
|
|
|
|
@checks.is_admin()
|
|
|
|
async def _mute(
|
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
members: commands.Greedy[discord.Member],
|
|
|
|
*,
|
2021-05-17 00:20:56 +02:00
|
|
|
reason: Optional[ReasonConverter],
|
2021-05-16 23:21:27 +02:00
|
|
|
):
|
|
|
|
if not members:
|
|
|
|
return await ctx.send(_("Missing members", ctx, self.bot.config))
|
|
|
|
|
|
|
|
role_row = await get_mute_role(ctx.guild.id)
|
|
|
|
|
|
|
|
if role_row is None:
|
|
|
|
return await ctx.send(
|
|
|
|
_(
|
|
|
|
"No mute role has been specified for this guild",
|
|
|
|
ctx,
|
|
|
|
self.bot.config,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
for member in members:
|
|
|
|
await member.add_roles(
|
|
|
|
discord.Object(id=int(role_row.role_id)), reason=reason
|
|
|
|
)
|
|
|
|
|
|
|
|
await ctx.send("\N{THUMBS UP SIGN}")
|
|
|
|
|
|
|
|
@_mute.command(name="show", aliases=["role"])
|
|
|
|
async def _mute_show(
|
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
):
|
|
|
|
role_row = await get_mute_role(ctx.guild.id)
|
|
|
|
|
|
|
|
if (
|
|
|
|
role_row is None
|
|
|
|
or (role := ctx.guild.get_role(int(role_row.role_id))) is None
|
|
|
|
):
|
|
|
|
return await ctx.send(
|
|
|
|
_(
|
|
|
|
"No mute role has been specified for this guild",
|
|
|
|
ctx,
|
|
|
|
self.bot.config,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
muted_members = [m for m in ctx.guild.members if role in m.roles]
|
|
|
|
|
|
|
|
e = discord.Embed(
|
|
|
|
title=f"Role: {role.name} (ID: {role.id})", color=role.color
|
|
|
|
)
|
|
|
|
e.add_field(name="Total mute:", value=len(muted_members))
|
|
|
|
|
|
|
|
await ctx.send(embed=e)
|
|
|
|
|
|
|
|
@_mute.command(name="set", aliases=["define"])
|
|
|
|
async def _mute_set(self, ctx: ContextPlus, role: discord.Role):
|
|
|
|
role_row = await get_mute_role(ctx.guild.id)
|
|
|
|
|
|
|
|
if role_row is None:
|
|
|
|
await create_mute_role(ctx.guild.id, role.id)
|
|
|
|
else:
|
|
|
|
role_row.role_id = role.id # type: ignore
|
|
|
|
await role_row.save()
|
|
|
|
|
|
|
|
await ctx.send(
|
|
|
|
_("Mute role successfully defined", ctx, self.bot.config)
|
|
|
|
)
|
|
|
|
|
2021-05-17 00:08:16 +02:00
|
|
|
# =========================================================================
|
|
|
|
|
|
|
|
@command_extra(
|
|
|
|
name="tempmute",
|
|
|
|
deletable=True,
|
|
|
|
)
|
|
|
|
@commands.guild_only()
|
|
|
|
@checks.is_admin()
|
|
|
|
async def _tempmute(
|
2021-05-17 00:20:56 +02:00
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
time,
|
|
|
|
members: discord.Member,
|
|
|
|
*,
|
|
|
|
reason: Optional[ReasonConverter],
|
2021-05-17 00:08:16 +02:00
|
|
|
):
|
2021-05-17 00:20:56 +02:00
|
|
|
_, _, _, _ = ctx, time, members, reason
|
2021-05-17 00:08:16 +02:00
|
|
|
|
|
|
|
# =========================================================================
|
|
|
|
|
2021-05-16 23:21:27 +02:00
|
|
|
@command_extra(
|
|
|
|
name="unmute",
|
|
|
|
deletable=True,
|
|
|
|
)
|
|
|
|
@commands.guild_only()
|
|
|
|
@checks.is_admin()
|
|
|
|
async def _unmute(
|
|
|
|
self,
|
|
|
|
ctx: ContextPlus,
|
|
|
|
members: commands.Greedy[discord.Member],
|
|
|
|
*,
|
2021-05-17 00:20:56 +02:00
|
|
|
reason: Optional[ReasonConverter],
|
2021-05-16 23:21:27 +02:00
|
|
|
):
|
|
|
|
if not members:
|
|
|
|
return await ctx.send(_("Missing members", ctx, self.bot.config))
|
|
|
|
|
|
|
|
role_row = await get_mute_role(ctx.guild.id)
|
|
|
|
|
|
|
|
if role_row is None:
|
|
|
|
return await ctx.send(
|
|
|
|
_(
|
|
|
|
"No mute role has been specified for this guild",
|
|
|
|
ctx,
|
|
|
|
self.bot.config,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
for member in members:
|
|
|
|
await member.remove_roles(
|
|
|
|
discord.Object(id=int(role_row.role_id)), reason=reason
|
|
|
|
)
|
|
|
|
|
|
|
|
await ctx.send("\N{THUMBS UP SIGN}")
|