Compare commits

..

7 commits

4 changed files with 59 additions and 33 deletions

View file

@ -23,7 +23,7 @@ logger_disnake.setLevel(logging.WARNING)
log = logging.getLogger("nomen") log = logging.getLogger("nomen")
log.setLevel(logging.DEBUG) log.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s") formatter = logging.Formatter("{asctime} {levelname:8} {name}: {message}", "%Y-%m-%d %H:%M:%S", "{")
handler = logging.StreamHandler(sys.stdout) handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter) handler.setFormatter(formatter)
logging.getLogger(None).addHandler(handler) logging.getLogger(None).addHandler(handler)
@ -78,10 +78,7 @@ class Nomen(Bot):
return prefix return prefix
async def set_guild_prefix(self, guild: Guild, prefix): async def set_guild_prefix(self, guild: Guild, prefix):
await self.db.execute( await self.db.execute("REPLACE INTO guilds (guild_id, prefix) VALUES(?, ?)", (guild.id, prefix))
"REPLACE INTO guilds VALUES(?, ?)",
(guild.id, prefix),
)
self.prefixes[guild.id] = prefix self.prefixes[guild.id] = prefix
async def start(self, *args, **kwargs): async def start(self, *args, **kwargs):

View file

@ -1,42 +1,60 @@
import logging import logging
from asyncio import TaskGroup from asyncio import TaskGroup
from textwrap import indent
from disnake import Embed from disnake import Embed
from disnake.ext.commands import Cog, group, guild_only from disnake.ext.commands import Cog, group, guild_only
from .utils import can_view, confirm, fetch_unpacked, test_keyword from .utils import can_view, confirm, fetch_exists, fetch_unpacked, test_keyword
log = logging.getLogger("nomen.notifications") log = logging.getLogger("nomen.notifications")
log.setLevel(logging.INFO) log.setLevel(logging.DEBUG)
log_ = log
async def handle_notification(db_updates, ctx, message, keyword, user_id): class NotifierLogAdapter(logging.LoggerAdapter):
def process(self, msg, kwargs):
return (
f"[guild: {self.extra["guild"]}, user: {self.extra["user"]}, keyword: {self.extra["keyword"]}] {msg}",
kwargs,
)
async def handle_notification(db_updates, ctx, message, keyword, user_id, use_embed):
""" """
Async task to dispatch a notification Async task to dispatch a notification
""" """
log.debug(f"- Handling `{keyword}` for {user_id}")
member = await ctx.guild.getch_member(user_id) member = await ctx.guild.getch_member(user_id)
log = NotifierLogAdapter(log_.getChild("notifier"), {"guild": ctx.guild, "user": member, "keyword": keyword})
log.debug("Handling notification")
if not await can_view(ctx, member): if not await can_view(ctx, member):
log.debug(f"- - Missing permission {user_id}") log.debug("Missing permission")
return return
log.debug(f"- - Notifying {user_id}") log.debug("Notifying")
db_updates.append((ctx.guild.id, keyword, user_id)) db_updates.append((ctx.guild.id, keyword, user_id))
footer = f"\n\n<t:{int(message.created_at.timestamp())}:R> | [Show]({message.jump_url}) | <#{ctx.channel.id}>" header = f"🔔 `{message.author.display_name}` mentioned `{keyword}` on `{ctx.guild}`:"
footer = f"\n<t:{int(message.created_at.timestamp())}:R> | [Show]({message.jump_url}) | <#{ctx.channel.id}>"
embed = Embed( if use_embed:
description=message.content + footer, log.debug("Sending embed")
embed = Embed(description=message.content + "\n" + footer)
embed.set_author(
name=f"{message.author.display_name} ({message.author})",
icon_url=message.author.display_avatar,
) )
embed.set_author(name=message.author, icon_url=message.author.display_avatar)
await member.send( await member.send(header, embed=embed)
f":bell: `{message.author}` mentioned `{keyword}` on `{ctx.guild}`:", else:
embed=embed, log.debug("Sending plain message")
) await member.send("\n".join((header, indent(message.content, "> ", lambda line: True).strip(), footer)))
log.debug("Sent")
async def handle_triggers(ctx, message): async def handle_triggers(ctx, message):
@ -44,6 +62,8 @@ async def handle_triggers(ctx, message):
Main function that handles message triggers Main function that handles message triggers
""" """
log.debug(f"Handling triggers for '{message.content}' from {ctx.author}")
params = { params = {
"author": ctx.author.id, "author": ctx.author.id,
"channel": ctx.channel.id, "channel": ctx.channel.id,
@ -52,11 +72,9 @@ async def handle_triggers(ctx, message):
"is_bot": ctx.author.bot, "is_bot": ctx.author.bot,
} }
disabled = await ctx.bot.db.execute_fetchall( disabled = await fetch_exists(ctx.bot.db, "SELECT * FROM users WHERE user_id=:author AND disabled IS 1", params)
"SELECT EXISTS(SELECT * FROM users WHERE user_id=:author AND disabled IS 1)", params
)
if disabled[0][0]: if disabled:
log.debug(f"User {ctx.author} ({ctx.author.id}) opted out") log.debug(f"User {ctx.author} ({ctx.author.id}) opted out")
return return
@ -72,7 +90,7 @@ async def handle_triggers(ctx, message):
AND (notify_self IS 1 OR user_id IS NOT :author) -- Don't notify author unless wanted AND (notify_self IS 1 OR user_id IS NOT :author) -- Don't notify author unless wanted
AND (bots_notify IS 1 OR :is_bot IS NOT 1) -- Don't notify from bots unless wanted AND (bots_notify IS 1 OR :is_bot IS NOT 1) -- Don't notify from bots unless wanted
AND :author NOT IN ( -- Don't notify if... AND :author NOT IN ( -- Don't notify if...
SELECT target FROM user_ignores -- Author is ignored in this guilde SELECT target FROM user_ignores -- Author is ignored in this guild
WHERE user_id=user_id AND guild_id=guild_id WHERE user_id=user_id AND guild_id=guild_id
UNION UNION
SELECT target FROM user_blocks -- Author is blocked SELECT target FROM user_blocks -- Author is blocked
@ -88,8 +106,9 @@ async def handle_triggers(ctx, message):
async for keyword, user_id, use_embed in cur: async for keyword, user_id, use_embed in cur:
log.debug(f"- Creating notification task: '{keyword}' for {user_id}") log.debug(f"- Creating notification task: '{keyword}' for {user_id}")
tg.create_task(handle_notification(db_updates, ctx, message, keyword, user_id)) tg.create_task(handle_notification(db_updates, ctx, message, keyword, user_id, use_embed))
log.debug("Incrementing notification counts")
await ctx.bot.db.executemany( await ctx.bot.db.executemany(
"UPDATE keywords SET count = count + 1 WHERE guild_id=? AND keyword=? AND user_id=?", "UPDATE keywords SET count = count + 1 WHERE guild_id=? AND keyword=? AND user_id=?",
db_updates, db_updates,
@ -207,7 +226,7 @@ class Notifications(Cog):
await self._add_keyword(ctx, keyword, True) await self._add_keyword(ctx, keyword, True)
@keyword.command() @keyword.command(aliases=["delete", "del"])
@guild_only() @guild_only()
async def remove(self, ctx, keyword): async def remove(self, ctx, keyword):
""" """
@ -285,7 +304,7 @@ class Notifications(Cog):
@guild_only() @guild_only()
async def ignore(self, ctx, channel): async def ignore(self, ctx, channel):
pass pass
# TODO: Ignore channels # TODO: Ignore channels and users
@ignore.command() @ignore.command()
@guild_only() @guild_only()

View file

@ -91,7 +91,7 @@ You may want to `{ctx.clean_prefix}nomen export` first"""
f"You have now opted-out and will no longer trigger or receive notifications. To opt back in, run `{ctx.clean_prefix}nomen opt-in`" f"You have now opted-out and will no longer trigger or receive notifications. To opt back in, run `{ctx.clean_prefix}nomen opt-in`"
) )
await self.bot.db.execute("REPLACE INTO users VALUES(?, 1)", (ctx.author.id,)) await self.bot.db.execute("REPLACE INTO users (user_id, disabled) VALUES(?, 1)", (ctx.author.id,))
await self.bot.db.commit() await self.bot.db.commit()
@nomen.command(name="opt-in") @nomen.command(name="opt-in")
@ -106,5 +106,5 @@ You may want to `{ctx.clean_prefix}nomen export` first"""
f"You have opted back in and will now trigger and receive notifications. To opt out, run `{ctx.clean_prefix}nomen opt-out`" f"You have opted back in and will now trigger and receive notifications. To opt out, run `{ctx.clean_prefix}nomen opt-out`"
) )
await self.bot.db.execute("REPLACE INTO users VALUES(?, 0)", (ctx.author.id,)) await self.bot.db.execute("REPLACE INTO users (user_id, disabled) VALUES(?, 0)", (ctx.author.id,))
await self.bot.db.commit() await self.bot.db.commit()

View file

@ -1,9 +1,12 @@
import logging
from asyncio import TimeoutError from asyncio import TimeoutError
from itertools import chain from itertools import chain
import re2 as re import re2 as re
from disnake import ChannelType from disnake import ChannelType
log = logging.getLogger("nomen.utils")
ALPHABET = list("abcdefghijklmnopqrstuvwxyz ") ALPHABET = list("abcdefghijklmnopqrstuvwxyz ")
COMMON_WORDS = [ COMMON_WORDS = [
@ -109,12 +112,17 @@ def unpack(lst_of_tpl):
async def fetch_unpacked(db, sql, params=None): async def fetch_unpacked(db, sql, params=None):
cur = db.cursor() cur = await db.cursor()
cur.row_factory = first cur.row_factory = lambda cursor, row: first(row)
cur = await cur.execute(sql, params) cur = await cur.execute(sql, params)
return await cur.fetchall() return await cur.fetchall()
async def fetch_exists(db, sql, params=None):
result = await db.execute_fetchall(f"SELECT EXISTS({sql})", params)
return result[0][0]
async def in_thread(member, thread): async def in_thread(member, thread):
# FIXME: Currently overlooks the situation where a moderator isn't in a thread but has manage threads # FIXME: Currently overlooks the situation where a moderator isn't in a thread but has manage threads
return any(member.id == thread_member.id for thread_member in await thread.fetch_members()) return any(member.id == thread_member.id for thread_member in await thread.fetch_members())
@ -182,6 +190,7 @@ async def confirm(ctx, message, delete_msgs=False, response_check=get_positivity
pass pass
return reply_bool return reply_bool
def cleanup_code(content): def cleanup_code(content):
"""Automatically removes code blocks from the code.""" """Automatically removes code blocks from the code."""
# remove ```py\n``` # remove ```py\n```
@ -191,4 +200,5 @@ def cleanup_code(content):
# remove `foo` # remove `foo`
return content.strip("` \n") return content.strip("` \n")
# ===== End code borrowed from Avrae ===== # ===== End code borrowed from Avrae =====