diff --git a/cogs/admin.py b/cogs/admin.py index 2c57b91..4bbb35b 100644 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -1,6 +1,8 @@ import datetime +import logging from typing import Union +import asyncio import discord import humanize from discord.ext import commands @@ -8,12 +10,13 @@ from discord.ext import commands from bot import TuxBot from .utils.lang import Texts +log = logging.getLogger(__name__) + class Admin(commands.Cog): def __init__(self, bot: TuxBot): self.bot = bot - self.db = bot.db async def cog_check(self, ctx: commands.Context) -> bool: permissions: discord.Permissions = ctx.channel.permissions_for( @@ -97,7 +100,7 @@ class Admin(commands.Cog): """---------------------------------------------------------------------""" @commands.command(name='ban') - async def _ban(self, ctx: commands.Context, user: discord.User, *, + async def _ban(self, ctx: commands.Context, user: discord.Member, *, reason=""): try: member: discord.Member = await ctx.guild.fetch_member(user.id) @@ -122,7 +125,7 @@ class Admin(commands.Cog): """---------------------------------------------------------------------""" @commands.command(name='kick') - async def _kick(self, ctx: commands.Context, user: discord.User, *, + async def _kick(self, ctx: commands.Context, user: discord.Member, *, reason=""): try: member: discord.Member = await ctx.guild.fetch_member(user.id) @@ -221,48 +224,189 @@ class Admin(commands.Cog): """---------------------------------------------------------------------""" + async def get_warn(self, ctx: commands.Context, + member: discord.Member = False): + query = """ + SELECT * FROM warns + WHERE created_at >= $1 AND server_id = $2 + """ + query += """AND user_id = $3""" if member else "" + query += """ORDER BY created_at DESC""" + week_ago = datetime.datetime.now() - datetime.timedelta(weeks=6) + + async with self.bot.db.acquire() as con: + await ctx.trigger_typing() + args = [week_ago, ctx.guild.id] + if member: + args.append(member.id) + + warns = await con.fetch(query, *args) + warns_list = '' + + for warn in warns: + row_id = warn.get('id') + user_id = warn.get('user_id') + user = await self.bot.fetch_user(user_id) + reason = warn.get('reason') + ago = humanize.naturaldelta( + datetime.datetime.now() - warn.get('created_at') + ) + + warns_list += f"[{row_id}] **{user}**: `{reason}` " \ + f"*({ago} ago)*\n" + + return warns_list, warns + @commands.group(name='warn', aliases=['warns']) async def _warn(self, ctx: commands.Context): if ctx.invoked_subcommand is None: - query = """ - SELECT user_id, reason, created_at FROM warns - WHERE created_at >= $1 AND server_id = $2 - ORDER BY created_at - DESC LIMIT 10 - """ - week_ago = datetime.datetime.now() - datetime.timedelta(weeks=6) + warns_list, warns = await self.get_warn(ctx) + e = discord.Embed( + title=f"{len(warns)} {Texts('admin').get('last warns')}: ", + description=warns_list + ) - async with self.bot.db.acquire() as con: - await ctx.trigger_typing() - warns = await con.fetch(query, week_ago, ctx.guild.id) - warns_list = '' + await ctx.send(embed=e) - for warn in warns: - user_id = warn.get('user_id') - user = await self.bot.fetch_user(user_id) - reason = warn.get('reason') - ago = humanize.naturaldelta( - datetime.datetime.now() - warn.get('created_at') - ) + async def add_warn(self, ctx: commands.Context, member: discord.Member, + reason): - warns_list += f"**{user}**: `{reason}` *({ago} ago)*\n" + query = """ + INSERT INTO warns (server_id, user_id, reason, created_at) + VALUES ($1, $2, $3, $4) + """ - e = discord.Embed( - title=f"{len(warns)} {Texts('admin').get('last warns')}: ", - description=warns_list - ) - - await ctx.send(embed=e) + now = datetime.datetime.now() + await self.bot.db.execute(query, ctx.guild.id, member.id, reason, now) @_warn.command(name='add', aliases=['new']) async def _warn_new(self, ctx: commands.Context, member: discord.Member, - *, reason): + *, reason="N/A"): + + member = await ctx.guild.fetch_member(member.id) + if not member: + return await ctx.send( + Texts('utils').get("Unable to find the user...") + ) + + query = """ + SELECT user_id, reason, created_at FROM warns + WHERE created_at >= $1 AND server_id = $2 and user_id = $3 """ - todo: push in database - if warn > 2 for member: - todo: ask for confirmation to kick or ban + week_ago = datetime.datetime.now() - datetime.timedelta(weeks=6) + + def check(payload: discord.RawReactionActionEvent): + if payload.message_id != choice.id \ + or payload.user_id != ctx.author.id: + return False + return payload.emoji.name in ('1⃣', '2⃣', '3⃣') + + async with self.bot.db.acquire() as con: + await ctx.trigger_typing() + warns = await con.fetch(query, week_ago, ctx.guild.id, member.id) + + if len(warns) >= 2: + e = discord.Embed( + title=Texts('admin').get('More than 2 warns'), + description=f"{member.mention} " + + Texts('admin').get('has more than 2 warns') + ) + e.add_field( + name='__Actions__', + value=':one: kick\n' + ':two: ban\n' + ':three: ' + Texts('admin').get('ignore') + ) + + choice = await ctx.send(embed=e) + + for reaction in ('1⃣', '2⃣', '3⃣'): + await choice.add_reaction(reaction) + + try: + payload = await self.bot.wait_for( + 'raw_reaction_add', + check=check, + timeout=50.0 + ) + except asyncio.TimeoutError: + return await ctx.send( + Texts('admin').get('Took too long. Aborting.') + ) + finally: + await choice.delete() + + if payload.emoji.name == '1⃣': + from jishaku.models import copy_context_with + + alt_ctx = await copy_context_with( + ctx, + content=f"{ctx.prefix}" + f"kick " + f"{member} " + f"{Texts('admin').get('More than 2 warns')}" + ) + return await alt_ctx.command.invoke(alt_ctx) + + elif payload.emoji.name == '2⃣': + from jishaku.models import copy_context_with + + alt_ctx = await copy_context_with( + ctx, + content=f"{ctx.prefix}" + f"ban " + f"{member} " + f"{Texts('admin').get('More than 2 warns')}" + ) + return await alt_ctx.command.invoke(alt_ctx) + + await self.add_warn(ctx, member, reason) + await ctx.send( + content=f"{member.mention} **{Texts('admin').get('got a warn')}**" + f"\n**{Texts('admin').get('Reason')}:** `{reason}`" + if reason != 'N/A' else '' + ) + + @_warn.command(name='remove', aliases=['revoke']) + async def _warn_remove(self, ctx: commands.Context, warn_id: int): + query = """ + DELETE FROM warns + WHERE id = $1 """ + async with self.bot.db.acquire() as con: + await ctx.trigger_typing() + await con.fetch(query, warn_id) + + await ctx.send(f"{Texts('admin').get('Warn with id')} `{warn_id}`" + f" {Texts('admin').get('successfully removed')}") + + @_warn.command(name='show', aliases=['list']) + async def _warn_show(self, ctx: commands.Context, member: discord.Member): + warns_list, warns = await self.get_warn(ctx, member) + e = discord.Embed( + title=f"{len(warns)} {Texts('admin').get('last warns')}: ", + description=warns_list + ) + + await ctx.send(embed=e) + + @_warn.command(name='edit', aliases=['change']) + async def _warn_edit(self, ctx: commands.Context, warn_id: int, *, + reason): + query = """ + UPDATE warns + SET reason = $2 + WHERE id = $1 + """ + + async with self.bot.db.acquire() as con: + await ctx.trigger_typing() + await con.fetch(query, warn_id, reason) + + await ctx.send(f"{Texts('admin').get('Warn with id')} `{warn_id}`" + f" {Texts('admin').get('successfully edited')}") + def setup(bot: TuxBot): bot.add_cog(Admin(bot)) diff --git a/cogs/utility.py b/cogs/utility.py index 13a0ecd..ecf6cb0 100644 --- a/cogs/utility.py +++ b/cogs/utility.py @@ -15,7 +15,22 @@ class Utility(commands.Cog): """---------------------------------------------------------------------""" - async def fetch_api(self, ctx: commands.Context, ip, addr): + @commands.command(name='iplocalise') + async def _iplocalise(self, ctx: commands.Context, addr, ip_type=''): + addr = re.sub(r'http(s?)://', '', addr) + addr = addr[:-1] if addr.endswith('/') else addr + + await ctx.trigger_typing() + + if ip_type in ('v6', 'ipv6'): + try: + ip = socket.getaddrinfo(addr, None, socket.AF_INET6)[1][4][0] + except socket.gaierror: + return await ctx.send( + Texts('utility').get('ipv6 not available')) + else: + ip = socket.gethostbyname(addr) + async with self.bot.session.get(f"http://ip-api.com/json/{ip}") as s: response: dict = await s.json() @@ -55,24 +70,6 @@ class Utility(commands.Cog): content=f"{Texts('utility').get('info not available')}" f"``{response.get('query')}``") - @commands.command(name='iplocalise') - async def _iplocalise(self, ctx: commands.Context, addr, ip_type=''): - addr = re.sub(r'http(s?)://', '', addr) - addr = addr[:-1] if addr.endswith('/') else addr - - await ctx.trigger_typing() - - if ip_type in ('v6', 'ipv6'): - try: - ip = socket.getaddrinfo(addr, None, socket.AF_INET6)[1][4][0] - except socket.gaierror: - return await ctx.send( - Texts('utility').get('ipv6 not available')) - else: - ip = socket.gethostbyname(addr) - - await self.fetch_api(ctx, ip, addr) - def setup(bot: TuxBot): bot.add_cog(Utility(bot)) diff --git a/extras/locales/en/LC_MESSAGES/admin.mo b/extras/locales/en/LC_MESSAGES/admin.mo index e56e9c9..cd65b5e 100644 Binary files a/extras/locales/en/LC_MESSAGES/admin.mo and b/extras/locales/en/LC_MESSAGES/admin.mo differ diff --git a/extras/locales/en/LC_MESSAGES/admin.po b/extras/locales/en/LC_MESSAGES/admin.po index 46df0e2..3bec23b 100644 --- a/extras/locales/en/LC_MESSAGES/admin.po +++ b/extras/locales/en/LC_MESSAGES/admin.po @@ -25,4 +25,31 @@ msgid "Unable to kick this user" msgstr "" msgid "last warns" +msgstr "" + +msgid "More than 2 warns" +msgstr "" + +msgid "has more than 2 warns" +msgstr "has more than 2 warns, what do you want to do ?" + +msgid "ignore" +msgstr "" + +msgid "Took too long. Aborting." +msgstr "" + +msgid "got a warn" +msgstr "" + +msgid "Reason" +msgstr "" + +msgid "Warn with id" +msgstr "" + +msgid "successfully removed" +msgstr "" + +msgid "successfully edited" msgstr "" \ No newline at end of file diff --git a/extras/locales/fr/LC_MESSAGES/admin.mo b/extras/locales/fr/LC_MESSAGES/admin.mo index cdfee52..f08390c 100644 Binary files a/extras/locales/fr/LC_MESSAGES/admin.mo and b/extras/locales/fr/LC_MESSAGES/admin.mo differ diff --git a/extras/locales/fr/LC_MESSAGES/admin.po b/extras/locales/fr/LC_MESSAGES/admin.po index e3601b4..00278ef 100644 --- a/extras/locales/fr/LC_MESSAGES/admin.po +++ b/extras/locales/fr/LC_MESSAGES/admin.po @@ -25,4 +25,31 @@ msgid "Unable to kick this user" msgstr "Impossible d'expulser cet utilisateur" msgid "last warns" -msgstr "derniers avertissements" \ No newline at end of file +msgstr "derniers avertissements" + +msgid "More than 2 warns" +msgstr "Plus de 2 avertissements" + +msgid "has more than 2 warns" +msgstr "a plus de 2 avertissements, que voulez-vous faire?" + +msgid "ignore" +msgstr "ignorer" + +msgid "Took too long. Aborting." +msgstr "Temps expiré. Abandons." + +msgid "got a warn" +msgstr "a recu un avertissement" + +msgid "Reason" +msgstr "Raison" + +msgid "Warn with id" +msgstr "L'avertissement avec l'id" + +msgid "successfully removed" +msgstr "a été enlevé avec succes" + +msgid "successfully edited" +msgstr "a été édité avec succes" \ No newline at end of file