From ade9d8808622096d692b354de8503eea6dacbccf Mon Sep 17 00:00:00 2001 From: ctih1 Date: Wed, 23 Jul 2025 15:42:13 +0300 Subject: [PATCH] changed from creating new settings instance into using a shared one --- assets/cogs/filesharing.py | 3 +- assets/cogs/internal/base_commands.py | 11 +-- assets/cogs/internal/cogmanager.py | 25 +++++- assets/cogs/internal/markov.py | 3 +- assets/cogs/internal/permissions.py | 118 ++++++++++++++++++++++++++ assets/cogs/pulse.py | 3 +- assets/cogs/songchanger.py | 13 ++- assets/cogs/webscraper.py | 3 +- assets/locales/es.json | 2 +- bot.py | 13 ++- modules/globalvars.py | 5 ++ modules/markovmemory.py | 3 +- modules/permission.py | 3 +- modules/prestartchecks.py | 3 +- modules/settings.py | 41 ++++++++- modules/unhandledexception.py | 3 +- settings/admin_logs.json | 37 ++++++++ settings/settings.json | 6 +- 18 files changed, 252 insertions(+), 43 deletions(-) create mode 100644 assets/cogs/internal/permissions.py create mode 100644 settings/admin_logs.json diff --git a/assets/cogs/filesharing.py b/assets/cogs/filesharing.py index 47f59a3..fe562ca 100644 --- a/assets/cogs/filesharing.py +++ b/assets/cogs/filesharing.py @@ -4,9 +4,8 @@ from discord.ext import commands import logging from typing import Literal, get_args, cast from modules.permission import requires_admin -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager -settings_manager = SettingsManager() settings = settings_manager.settings diff --git a/assets/cogs/internal/base_commands.py b/assets/cogs/internal/base_commands.py index ad6980d..b87261c 100644 --- a/assets/cogs/internal/base_commands.py +++ b/assets/cogs/internal/base_commands.py @@ -7,10 +7,9 @@ import discord.ext.commands import modules.keys as k from modules.permission import requires_admin from modules.sentenceprocessing import send_message -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager import requests -settings_manager = SettingsManager() settings = settings_manager.settings @@ -159,13 +158,11 @@ class BaseCommands(commands.Cog): response = requests.post( "https://litterbox.catbox.moe/resources/internals/api.php", - data={"reqtype": "fileupload", "time": "1h", "fileToUpload": data}, + data={"reqtype": "fileupload", "time": "1h"}, + files={"fileToUpload": data}, ) - print(response.text) - print(response.status_code) - - # await send_message(ctx, memorylitter.stdout.strip()) + await send_message(ctx, response.text) async def setup(bot: discord.ext.commands.Bot): diff --git a/assets/cogs/internal/cogmanager.py b/assets/cogs/internal/cogmanager.py index e21ba60..3387b7a 100644 --- a/assets/cogs/internal/cogmanager.py +++ b/assets/cogs/internal/cogmanager.py @@ -3,9 +3,9 @@ from discord.ext import commands import discord.ext import discord.ext.commands from modules.permission import requires_admin -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager +from modules.globalvars import available_cogs -settings_manager = SettingsManager() settings = settings_manager.settings @@ -23,6 +23,15 @@ class CogManager(commands.Cog): await self.bot.load_extension(COG_PREFIX + cog_name) await ctx.send(f"Loaded cog `{cog_name}` successfully.") settings["bot"]["enabled_cogs"].append(cog_name) + settings_manager.add_admin_log_event( + { + "action": "add", + "author": ctx.author.id, + "change": "enabled_cogs", + "messageId": ctx.message.id, + "target": cog_name, + } + ) settings_manager.commit() except Exception as e: @@ -69,6 +78,15 @@ class CogManager(commands.Cog): await self.bot.unload_extension(COG_PREFIX + cog_name) await ctx.send(f"Unloaded cog `{cog_name}` successfully.") settings["bot"]["enabled_cogs"].remove(cog_name) + settings_manager.add_admin_log_event( + { + "action": "del", + "author": ctx.author.id, + "change": "enabled_cogs", + "messageId": ctx.message.id, + "target": cog_name, + } + ) settings_manager.commit() except Exception as e: await ctx.send(f"Error unloading cog `{cog_name}`: {e}") @@ -102,7 +120,8 @@ class CogManager(commands.Cog): title="Loaded Cogs", description="Here is a list of all currently loaded cogs:", ) - embed.add_field(name="Cogs", value="\n".join(cogs), inline=False) + embed.add_field(name="Loaded cogs", value="\n".join(cogs), inline=False) + embed.add_field(name="Available cogs", value="\n".join(available_cogs())) await ctx.send(embed=embed) diff --git a/assets/cogs/internal/markov.py b/assets/cogs/internal/markov.py index 0c63813..e5ac445 100644 --- a/assets/cogs/internal/markov.py +++ b/assets/cogs/internal/markov.py @@ -24,9 +24,8 @@ import markovify logger = logging.getLogger("goober") -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager -settings_manager = SettingsManager() settings = settings_manager.settings diff --git a/assets/cogs/internal/permissions.py b/assets/cogs/internal/permissions.py new file mode 100644 index 0000000..e12c7f6 --- /dev/null +++ b/assets/cogs/internal/permissions.py @@ -0,0 +1,118 @@ +import discord +from discord.ext import commands + +from modules.permission import requires_admin +from modules.settings import instance as settings_manager + +settings = settings_manager.settings + + +class PermissionManager(commands.Cog): + def __init__(self, bot): + self.bot = bot + + @requires_admin() + @commands.command() + async def add_owner(self, ctx: commands.Context, member: discord.Member): + settings["bot"]["owner_ids"].append(member.id) + settings_manager.add_admin_log_event( + { + "action": "add", + "author": ctx.author.id, + "change": "owner_ids", + "messageId": ctx.message.id, + "target": member.id, + } + ) + + settings_manager.commit() + + embed = discord.Embed( + title="Permissions", + description=f"Set {member.name} as an owner", + color=discord.Color.blue(), + ) + + await ctx.send(embed=embed) + + @requires_admin() + @commands.command() + async def remove_owner(self, ctx: commands.Context, member: discord.Member): + try: + settings["bot"]["owner_ids"].remove(member.id) + settings_manager.add_admin_log_event( + { + "action": "del", + "author": ctx.author.id, + "change": "owner_ids", + "messageId": ctx.message.id, + "target": member.id, + } + ) + settings_manager.commit() + except ValueError: + await ctx.send("User is not an owner!") + return + + embed = discord.Embed( + title="Permissions", + description=f"Removed {member.name} from being an owner", + color=discord.Color.blue(), + ) + + await ctx.send(embed=embed) + + @requires_admin() + @commands.command() + async def blacklist_user(self, ctx: commands.Context, member: discord.Member): + settings["bot"]["blacklisted_users"].append(member.id) + settings_manager.add_admin_log_event( + { + "action": "add", + "author": ctx.author.id, + "change": "blacklisted_users", + "messageId": ctx.message.id, + "target": member.id, + } + ) + settings_manager.commit() + + embed = discord.Embed( + title="Blacklist", + description=f"Added {member.name} to the blacklist", + color=discord.Color.blue(), + ) + + await ctx.send(embed=embed) + + @requires_admin() + @commands.command() + async def unblacklist_user(self, ctx: commands.Context, member: discord.Member): + try: + settings["bot"]["blacklisted_users"].remove(member.id) + settings_manager.add_admin_log_event( + { + "action": "del", + "author": ctx.author.id, + "change": "blacklisted_users", + "messageId": ctx.message.id, + "target": member.id, + } + ) + settings_manager.commit() + + except ValueError: + await ctx.send("User is not on the blacklist!") + return + + embed = discord.Embed( + title="Blacklist", + description=f"Removed {member.name} from blacklist", + color=discord.Color.blue(), + ) + + await ctx.send(embed=embed) + + +async def setup(bot): + await bot.add_cog(PermissionManager(bot)) diff --git a/assets/cogs/pulse.py b/assets/cogs/pulse.py index f249693..ba031b5 100644 --- a/assets/cogs/pulse.py +++ b/assets/cogs/pulse.py @@ -3,9 +3,8 @@ import discord from collections import defaultdict, Counter import datetime from modules.permission import requires_admin -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager -settings_manager = SettingsManager() settings = settings_manager.settings diff --git a/assets/cogs/songchanger.py b/assets/cogs/songchanger.py index 3ae29eb..55efacc 100644 --- a/assets/cogs/songchanger.py +++ b/assets/cogs/songchanger.py @@ -3,6 +3,8 @@ from discord.ext import commands from modules.globalvars import RED, GREEN, RESET, LOCAL_VERSION_FILE import os +from modules.permission import requires_admin + class songchange(commands.Cog): def __init__(self, bot): @@ -17,15 +19,10 @@ class songchange(commands.Cog): global local_version local_version = get_local_version() + @requires_admin() @commands.command() - async def changesong(self, ctx): - if LOCAL_VERSION_FILE > "0.11.8": - await ctx.send( - f"Goober is too old! you must have version 0.11.8 you have {local_version}" - ) - return - await ctx.send("Check the terminal! (this does not persist across restarts)") - song = input("\nEnter a song:\n") + async def changesong(self, ctx, song: str): + await ctx.send(f"Changed song to {song}") try: await self.bot.change_presence( activity=discord.Activity( diff --git a/assets/cogs/webscraper.py b/assets/cogs/webscraper.py index e344fea..b2fe177 100644 --- a/assets/cogs/webscraper.py +++ b/assets/cogs/webscraper.py @@ -6,9 +6,8 @@ import json import asyncio from urllib.parse import urljoin from modules.permission import requires_admin -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager -settings_manager = SettingsManager() settings = settings_manager.settings diff --git a/assets/locales/es.json b/assets/locales/es.json index 4444a9c..c2aa734 100644 --- a/assets/locales/es.json +++ b/assets/locales/es.json @@ -73,5 +73,5 @@ "command_stats_embed_field2name": "Version", "command_stats_embed_field2value": "Version local: {local_version} \nUltima version: {latest_version}", "command_stats_embed_field3name": "informacion sobre las variables", - "command_stats_embed_field3value": "Nombre: {NAME} \nPrefijo: {PREFIX} \nID del propietario: {ownerid}\nLinea de ping: {PING_LINE} \nCompartir memoria habilitada: {showmemenabled} \nEntrenamiento de usuario habilitado: {USERTRAIN_ENABLED} \nCancion: {song} \nTexto de bienvenida: ```{splashtext}```" + "command_stats_embed_field3value": "Nombre: {NAME} \nPrefijo: {PREFIX} \nID del propietario: {ownerid}\nLinea de ping: {PING_LINE} \nCompartir memoria habilitada: {showmemenabled} \nEntrenamiento de usuario habilitado: {USERTRAIN_ENABLED} \nCancion: {song} \nTexto de bienvenida: ```{splashtext}```" } \ No newline at end of file diff --git a/bot.py b/bot.py index fdc59e3..642505e 100644 --- a/bot.py +++ b/bot.py @@ -31,8 +31,9 @@ from modules import key_compiler import logging from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager from modules.permission import requires_admin +import threading def build_keys(): @@ -61,11 +62,11 @@ file_handler.setFormatter(GooberFormatter(colors=False)) logger.addHandler(console_handler) logger.addHandler(file_handler) -settings_manager = SettingsManager() settings = settings_manager.settings splash_text: str = "" + with open(settings["splash_text_loc"], "r", encoding="UTF-8") as f: splash_text = "".join(f.readlines()) print(splash_text) @@ -160,8 +161,8 @@ async def on_ready() -> None: if launched: return - await load_cogs_from_folder(bot) await load_cogs_from_folder(bot, "assets/cogs/internal") + await load_cogs_from_folder(bot) try: synced: List[discord.app_commands.AppCommand] = await bot.tree.sync() @@ -281,7 +282,7 @@ async def on_message(message: discord.Message) -> None: if message.author.bot: return - if str(message.author.id) in settings["bot"]["blacklisted_users"]: + if message.author.id in settings["bot"]["blacklisted_users"]: return commands = [ @@ -405,6 +406,10 @@ class Handler(FileSystemEventHandler): build_keys() +observer = Observer() +observer.schedule(Handler(), "assets/locales") +observer.start() + # Start the bot if __name__ == "__main__": bot.run(os.environ.get("DISCORD_BOT_TOKEN", "")) diff --git a/modules/globalvars.py b/modules/globalvars.py index dbbbbeb..7a70f9c 100644 --- a/modules/globalvars.py +++ b/modules/globalvars.py @@ -1,5 +1,6 @@ import os import platform +from typing import Callable, List from dotenv import load_dotenv import pathlib import subprocess @@ -22,6 +23,10 @@ def get_git_branch(): env_path = pathlib.Path(__file__).parent.parent / ".env" load_dotenv(dotenv_path=env_path) +available_cogs: Callable[[], List[str]] = lambda: [ + file[:-3] for file in os.listdir("assets/cogs") if file.endswith(".py") +] + ANSI = "\033[" RED = f"{ANSI}31m" GREEN = f"{ANSI}32m" diff --git a/modules/markovmemory.py b/modules/markovmemory.py index 41fcbbb..cce5cf2 100644 --- a/modules/markovmemory.py +++ b/modules/markovmemory.py @@ -5,9 +5,8 @@ import pickle from modules.globalvars import * import logging import modules.keys as k -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager -settings_manager = SettingsManager() settings = settings_manager.settings diff --git a/modules/permission.py b/modules/permission.py index e6dd9f0..86b1dd4 100644 --- a/modules/permission.py +++ b/modules/permission.py @@ -4,12 +4,11 @@ import discord import discord.ext import discord.ext.commands -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager import logging logger = logging.getLogger("goober") -settings_manager = SettingsManager() settings = settings_manager.settings diff --git a/modules/prestartchecks.py b/modules/prestartchecks.py index b6636ff..2d94423 100644 --- a/modules/prestartchecks.py +++ b/modules/prestartchecks.py @@ -11,9 +11,8 @@ from spacy.util import is_package import importlib.metadata import logging import modules.keys as k -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager -settings_manager = SettingsManager() settings = settings_manager.settings diff --git a/modules/settings.py b/modules/settings.py index 2d94038..3d050b5 100644 --- a/modules/settings.py +++ b/modules/settings.py @@ -1,6 +1,6 @@ import json import os -from typing import List, Mapping, Any, TypedDict +from typing import List, Literal, Mapping, Any, NotRequired, TypedDict from modules.keys import Language import logging import copy @@ -36,8 +36,19 @@ class SettingsType(TypedDict): splash_text_loc: str +class AdminLogEvent(TypedDict): + messageId: int + author: int + target: str | int + action: Literal["del", "add", "set"] + change: Literal["owner_ids", "blacklisted_users", "enabled_cogs"] + + class Settings: def __init__(self) -> None: + global instance + instance = self + self.path: str = os.path.join(".", "settings", "settings.json") if not os.path.exists(self.path): @@ -52,11 +63,37 @@ class Settings: self.settings = SettingsType(self.__kv_store) # type: ignore self.original_settings = copy.deepcopy(self.settings) + self.log_path: str = os.path.join(".", "settings", "admin_logs.json") + + def reload_settings(self) -> None: + with open(self.path, "r") as f: + self.__kv_store: dict = json.load(f) + + self.settings = SettingsType(self.__kv_store) # type: ignore + self.original_settings = copy.deepcopy(self.settings) + def commit(self) -> None: with open(self.path, "w") as f: - json.dump(self.settings, f, indent=4) + json.dump(self.settings, f, ensure_ascii=False, indent=4) self.original_settings = self.settings def discard(self) -> None: self.settings = self.original_settings + + def add_admin_log_event(self, event: AdminLogEvent): + if not os.path.exists(self.log_path): + logger.warning("Admin log doesn't exist!") + with open(self.log_path, "w") as f: + json.dump([], f) + + with open(self.log_path, "r") as f: + logs: List[AdminLogEvent] = json.load(f) + + logs.append(event) + + with open(self.log_path, "w") as f: + json.dump(logs, f, ensure_ascii=False, indent=4) + + +instance: Settings = Settings() diff --git a/modules/unhandledexception.py b/modules/unhandledexception.py index 8247bac..1118329 100644 --- a/modules/unhandledexception.py +++ b/modules/unhandledexception.py @@ -1,12 +1,11 @@ import sys import traceback import os -from modules.settings import Settings as SettingsManager +from modules.settings import instance as settings_manager import logging from modules.globalvars import RED, RESET import modules.keys as k -settings_manager = SettingsManager() settings = settings_manager.settings logger = logging.getLogger("goober") diff --git a/settings/admin_logs.json b/settings/admin_logs.json new file mode 100644 index 0000000..c32601c --- /dev/null +++ b/settings/admin_logs.json @@ -0,0 +1,37 @@ +[ + { + "action": "add", + "author": 642441889181728810, + "change": "enabled_cogs", + "messageId": 1397556082225844234, + "target": "whoami" + }, + { + "action": "add", + "author": 642441889181728810, + "change": "owner_ids", + "messageId": 1397556184818384996, + "target": 1167661372809683048 + }, + { + "action": "del", + "author": 642441889181728810, + "change": "owner_ids", + "messageId": 1397556247313780829, + "target": 1167661372809683048 + }, + { + "action": "add", + "author": 642441889181728810, + "change": "enabled_cogs", + "messageId": 1397558663559909399, + "target": "fuckup" + }, + { + "action": "add", + "author": 642441889181728810, + "change": "enabled_cogs", + "messageId": 1397558837644365935, + "target": "songchanger" + } +] \ No newline at end of file diff --git a/settings/settings.json b/settings/settings.json index aa11e29..92e3f99 100644 --- a/settings/settings.json +++ b/settings/settings.json @@ -1,8 +1,8 @@ { "bot": { - "prefix": "\u00e4.", + "prefix": "รค.", "owner_ids": [ - + 642441889181728810 ], "blacklisted_users": [], "user_training": true, @@ -16,6 +16,8 @@ }, "active_memory": "memory.json", "enabled_cogs": [ + "fuckup", + "songchanger" ] }, "locale": "fi",