1
Fork 0
mirror of https://github.com/wlinator/luminara.git synced 2024-10-02 18:23:12 +00:00

Merge remote-tracking branch 'origin/main'

This commit is contained in:
wlinator 2023-07-02 12:07:53 -04:00
commit 11c5d436b2
8 changed files with 245 additions and 39 deletions

3
.gitignore vendored
View file

@ -3,4 +3,5 @@ venv/
__pycache__/
*.db
.env
.env
*.log

View file

@ -1,10 +1,14 @@
import json
import logging
racu_logs = logging.getLogger('Racu.Core')
def load_strings(path="config/strings.en-US.json"):
with open(path, 'r') as file:
data = json.load(file)
racu_logs.debug(f"{path} was loaded.")
return data
@ -12,6 +16,7 @@ def load_economy_config(path="config/economy.json"):
with open(path, 'r') as file:
data = json.load(file)
racu_logs.debug(f"{path} was loaded.")
return data
@ -19,4 +24,5 @@ def load_reactions(path="config/reactions.json"):
with open(path, 'r') as file:
data = json.load(file)
racu_logs.debug(f"{path} was loaded.")
return data

View file

@ -1,8 +1,11 @@
import json
import logging
import sqlite3
from db import database
racu_logs = logging.getLogger('Racu.Core')
class Item:
def __init__(self, item_id):
@ -59,7 +62,7 @@ class Item:
database.execute_query(query,
(index, name, display_name, description, image_url, emote_id, quote, item_type))
print("Items inserted into the database successfully.")
racu_logs.info("Items inserted into the database successfully.")
@staticmethod
def get_all_item_names():
@ -75,7 +78,7 @@ class Item:
return item_names
except sqlite3.Error:
print(sqlite3.Error)
racu_logs.error(sqlite3.Error)
return []
@staticmethod

View file

@ -1,12 +1,15 @@
import logging
import sqlite3
from sqlite3 import Error
racu_logs = logging.getLogger('Racu.Core')
def create_connection():
try:
conn = sqlite3.connect("db/rcu.db")
except Error as e:
print("'create_connection()' Error occurred: {}".format(e))
racu_logs.error("'create_connection()' Error occurred: {}".format(e))
return
return conn
@ -22,6 +25,7 @@ def execute_query(query, values=None):
cursor.execute(query)
conn.commit()
racu_logs.debug(f"database.execute_query: 'query': {query}, 'values': {values}")
return cursor
@ -29,6 +33,8 @@ def select_query(query, values=None):
conn = create_connection()
cursor = conn.cursor()
racu_logs.debug(f"database.select_query: 'query': {query}, 'values': {values}")
if values:
return cursor.execute(query, values).fetchall()
else:
@ -39,6 +45,8 @@ def select_query_one(query, values=None):
conn = create_connection()
cursor = conn.cursor()
racu_logs.debug(f"database.select_query_one: 'query': {query}, 'values': {values}")
if values:
output = cursor.execute(query, values).fetchone()
else:

View file

@ -1,5 +1,9 @@
import logging
from db import database
racu_logs = logging.getLogger('Racu.Core')
xp_table = """
CREATE TABLE IF NOT EXISTS xp (
user_id INTEGER PRIMARY KEY NOT NULL,
@ -106,4 +110,4 @@ def sync_database():
database.execute_query(stats_slots)
database.execute_query(stats_duel)
print("On startup: database synced.")
racu_logs.info("Database was synced.")

View file

@ -1,9 +1,12 @@
import logging
import time
from data.Currency import Currency
from data.Xp import Xp
from sb_tools import level_messages
racu_logs = logging.getLogger('Racu.Core')
class XPHandler:
def __init__(self):
@ -15,7 +18,7 @@ class XPHandler:
xp = Xp(user_id)
if xp.ctime and current_time < xp.ctime:
print(f"XP UPDATE --- {message.author.name} sent a message but is on XP cooldown.")
racu_logs.info(f"XP UPDATE --- {message.author.name} sent a message but is on XP cooldown.")
return
new_xp = xp.xp + xp.xp_gain
@ -37,11 +40,11 @@ class XPHandler:
user_currency.add_special(1)
user_currency.push()
print(f"XP UPDATE --- {message.author.name} leveled up; new_level = {xp.level}.")
racu_logs.info(f"XP UPDATE --- {message.author.name} leveled up; new_level = {xp.level}.")
else:
xp.xp += xp.xp_gain
print(f"XP UPDATE --- {message.author.name} gained {xp.xp_gain} XP; new_xp = {new_xp}.")
racu_logs.info(f"XP UPDATE --- {message.author.name} gained {xp.xp_gain} XP; new_xp = {new_xp}.")
xp.ctime = current_time + xp.new_cooldown
xp.push()
@ -70,7 +73,6 @@ class XPHandler:
guild = user.guild
if guild.id != 719227135151046699:
print("Not Rave Cave -> no level-up role")
return
current_level_role = None

190
main.py
View file

@ -9,8 +9,12 @@ SPECIAL_BALANCE_NAME=
import logging
import os
import platform
import re
from datetime import datetime
import discord
import pytz
from dotenv import load_dotenv
import db.tables
@ -20,14 +24,6 @@ from data.Item import Item
from handlers.ReactionHandler import ReactionHandler
from handlers.XPHandler import XPHandler
logging.basicConfig(level=logging.INFO)
load_dotenv('.env')
# load all json
strings = json_loader.load_strings()
economy_config = json_loader.load_economy_config()
reactions = json_loader.load_reactions()
sbbot = discord.Bot(
owner_id=os.getenv('OWNER_ID'),
intents=discord.Intents.all(),
@ -36,25 +32,88 @@ sbbot = discord.Bot(
)
def load_cogs(reload=False):
for filename in os.listdir('./modules'):
if filename.endswith('.py'):
if not reload:
sbbot.load_extension(f'modules.{filename[:-3]}')
else:
sbbot.reload_extension(f'modules.{filename[:-3]}')
print(f"Module '{filename}' ready.")
class RacuFormatter(logging.Formatter):
def __init__(self, fmt=None, datefmt=None):
super().__init__(fmt, datefmt)
self.timezone = pytz.timezone('US/Eastern')
def format(self, record):
message = record.getMessage()
message = re.sub(r'\n', '', message) # Remove newlines
message = re.sub(r'\s+', ' ', message) # Remove multiple spaces
message = message.strip() # Remove leading and trailing spaces
record.msg = message
return super().format(record)
def formatTime(self, record, datefmt=None):
timestamp = self.timezone.localize(datetime.fromtimestamp(record.created))
if datefmt:
return timestamp.strftime(datefmt)
else:
return str(timestamp)
def setup_logger():
# Create a "logs" subfolder if it doesn't exist
logs_folder = 'logs'
if not os.path.exists(logs_folder):
os.makedirs(logs_folder)
# Generate the log file path for debug-level logs
debug_log_file = os.path.join(logs_folder, 'debug.log')
# Generate the log file path for info-level logs
info_log_file = os.path.join(logs_folder, 'info.log')
# Initialize the logger
logger = logging.getLogger('Racu.Core')
if logger.handlers:
# Handlers already exist, no need to add more
return logger
logger.setLevel(logging.DEBUG)
# Create console handler and set level and formatter
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_formatter = RacuFormatter('[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
console_handler.setFormatter(console_formatter)
logger.addHandler(console_handler)
# Create debug file handler and set level and formatter
debug_file_handler = logging.FileHandler(debug_log_file)
debug_file_handler.setLevel(logging.DEBUG)
debug_file_formatter = RacuFormatter('[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
debug_file_handler.setFormatter(debug_file_formatter)
logger.addHandler(debug_file_handler)
# Create info file handler and set level and formatter
info_file_handler = logging.FileHandler(info_log_file)
info_file_handler.setLevel(logging.INFO)
info_file_formatter = RacuFormatter('[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
info_file_handler.setFormatter(info_file_formatter)
logger.addHandler(info_file_handler)
logger.propagate = False
logging.captureWarnings(True)
return logger
racu_logs = setup_logger()
@sbbot.event
async def on_ready():
# wait until the bot is ready
# then sync the sqlite3 database
db.tables.sync_database()
Item.insert_items()
# reload all cogs to sync db parameters
load_cogs(reload=True)
racu_logs.info(f"Logged in as {sbbot.user.name}")
racu_logs.info(f"discord.py API version: {discord.__version__}")
racu_logs.info(f"Python version: {platform.python_version()}")
racu_logs.info(f"Running on: {platform.system()} {platform.release()} ({os.name})")
racu_logs.info("-----------------------------------------")
"""
https://docs.pycord.dev/en/stable/api/events.html#discord.on_ready
@ -68,11 +127,16 @@ async def on_message(message):
if message.author.bot:
return
xp_handler = XPHandler()
await xp_handler.process_xp(message)
try:
xp_handler = XPHandler()
await xp_handler.process_xp(message)
reaction_handler = ReactionHandler(reactions)
await reaction_handler.handle_message(message)
reaction_handler = ReactionHandler(reactions)
await reaction_handler.handle_message(message)
except Exception as error:
racu_logs.error(f"on_message (check debug log): {error}", exc_info=False)
racu_logs.debug(f"on_message (w/ stacktrace): {error}", exc_info=True)
@sbbot.event
@ -103,5 +167,77 @@ async def on_member_join(member):
await guild.get_channel(welcome_channel_id).send(embed=embed, content=member.mention)
@sbbot.event
async def on_application_command_completion(ctx) -> None:
"""
This code is executed when a slash_command has been successfully executed.
:param ctx:
:return:
"""
full_command_name = ctx.command.qualified_name
split = full_command_name.split(" ")
executed_command = str(split[0])
if ctx.guild is not None:
racu_logs.info(
f"Executed {executed_command} command in {ctx.guild.name} (ID: {ctx.guild.id}) "
f"by {ctx.author} (ID: {ctx.author.id})"
)
else:
racu_logs.info(
f"Executed {executed_command} command by {ctx.author} (ID: {ctx.author.id}) in DMs."
)
@sbbot.event
async def on_application_command_error(ctx, error) -> None:
racu_logs.error(f"on_application_command_error (check debug log): {error}", exc_info=False)
racu_logs.debug(f"on_application_command_error (w/ stacktrace): {error}", exc_info=True)
@sbbot.event
async def on_error(event: str, *args, **kwargs) -> None:
racu_logs.error(f"on_error: errors.event.{event} | '*args': {args} | '**kwargs': {kwargs}")
# load all json
strings = json_loader.load_strings()
economy_config = json_loader.load_economy_config()
reactions = json_loader.load_reactions()
# Keep track of loaded module filenames
loaded_modules = set()
def load_cogs():
for filename in os.listdir('./modules'):
if filename.endswith('.py'):
module_name = f'modules.{filename[:-3]}'
# if module_name in sys.modules:
# continue # Module is already loaded
try:
sbbot.load_extension(module_name)
loaded_modules.add(filename)
racu_logs.info(f"Module {filename} loaded.")
except Exception as e:
racu_logs.error(f"Failed to load module {filename}: {e}")
if __name__ == '__main__':
"""
This code is only ran when main.py is the primary module,
thus NOT when main is imported from a cog. (sys.modules)
"""
racu_logs.info("RACU IS BOOTING")
load_dotenv('.env')
# load db
db.tables.sync_database()
Item.insert_items()
load_cogs()
sbbot.run(os.getenv('TOKEN'))

View file

@ -1,4 +1,5 @@
import asyncio
import logging
import subprocess
import discord
@ -6,6 +7,8 @@ from discord.ext import commands
from sb_tools import interaction, embeds, universal
racu_logs = logging.getLogger('Racu.Core')
class BasicCog(commands.Cog):
def __init__(self, sbbot):
@ -18,7 +21,8 @@ class BasicCog(commands.Cog):
)
@commands.check(universal.channel_check)
async def ping(self, ctx):
await ctx.respond(f"SB latency: {round(self.bot.latency * 1000, 2)} ms")
ping = round(self.bot.latency * 1000, 2)
await ctx.respond(f"SB latency: {ping} ms")
@commands.slash_command(
name="restart",
@ -30,9 +34,9 @@ class BasicCog(commands.Cog):
await ctx.respond(content="Restarting..", ephemeral=True)
try:
print(subprocess.check_output(["/bin/bash", "racu_update.sh"]))
racu_logs.info(subprocess.check_output(["/bin/bash", "racu_update.sh"]))
except subprocess.CalledProcessError as e:
print(f"Error executing the script: {e.output.decode()}")
racu_logs.error(f"Error executing the script: {e.output.decode()}")
@commands.slash_command(
name="intro",
@ -62,11 +66,13 @@ class BasicCog(commands.Cog):
em = discord.Embed(description="You're muted in the Rave Cave. You can't perform this command.",
color=0xadcca6)
await ctx.respond(embed=em)
racu_logs.warning(f"{ctx.author.name} couldn't do the intro command: Muted in the Race Cave")
return
elif member and not discord.utils.get(member.roles, id=719995790319157279):
em = discord.Embed(description="It seems that you don't have permission to do that!")
await ctx.respond(embed=em)
racu_logs.warning(f"{ctx.author.name} couldn't do the intro command: No Permissions")
return
embed = discord.Embed(color=0xadcca6,
@ -95,6 +101,7 @@ class BasicCog(commands.Cog):
return message.author == ctx.author and isinstance(message.channel, discord.DMChannel)
if view.clickedShort:
racu_logs.debug(f"{ctx.author.name} clicked Short Intro")
# START NICKNAME
await ctx.send(embed=embeds.simple_question_first("How would you like to be identified in the server?"))
@ -105,6 +112,7 @@ class BasicCog(commands.Cog):
if len(nickname) > 100:
nickname = nickname[:100]
nickname = nickname.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} nickname: {nickname}")
# START AGE
await ctx.send(embed=embeds.simple_question_5("How old are you?"),
@ -116,6 +124,7 @@ class BasicCog(commands.Cog):
if len(age) > 5:
age = age[:5]
age = age.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} age: {age}")
# START LOCATION
view = interaction.LocationOptions(ctx)
@ -130,6 +139,8 @@ class BasicCog(commands.Cog):
await ctx.send(embed=embeds.no_time())
return
racu_logs.debug(f"{ctx.author.name} location: {location}")
# START PRONOUNS
await ctx.send(
embed=embeds.simple_question_30("What are your preferred pronouns?"),
@ -141,6 +152,7 @@ class BasicCog(commands.Cog):
if len(pronouns) > 30:
pronouns = pronouns[:30]
pronouns = pronouns.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} pronouns: {pronouns}")
# START LIKES
await ctx.send(embed=embeds.simple_question_300("Likes & interests"),
@ -152,6 +164,7 @@ class BasicCog(commands.Cog):
if len(likes) > 300:
likes = likes[:300]
likes = likes.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} likes: {likes}")
# START DISLIKES
await ctx.send(embed=embeds.simple_question_300("Dislikes"),
@ -163,6 +176,7 @@ class BasicCog(commands.Cog):
if len(dislikes) > 300:
dislikes = dislikes[:300]
dislikes = dislikes.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} dislikes: {dislikes}")
# POST EXAMPLE EMBED AND FINAL IF APPROVED
em = embeds.final_embed_short(ctx, nickname, age, location, pronouns, likes, dislikes)
@ -175,32 +189,41 @@ class BasicCog(commands.Cog):
intro_channel = guild.get_channel(channel_id)
await intro_channel.send(embed=em, content=f"Introduction of <@{ctx.author.id}>")
await ctx.send(embed=embeds.final_confirmation(channel_id))
racu_logs.info(f"{ctx.author.name} Intro Sent")
return
else:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
elif view.clickedLong:
racu_logs.debug(f"{ctx.author.name} clicked Long Intro")
# START NICKNAME
await ctx.send(embed=embeds.simple_question_first_extended(
"How would you like to be identified in the server?"))
@ -211,6 +234,7 @@ class BasicCog(commands.Cog):
if len(nickname) > 100:
nickname = nickname[:100]
nickname = nickname.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} nickname: {nickname}")
# START AGE
await ctx.send(embed=embeds.simple_question_5("How old are you?"),
@ -222,6 +246,7 @@ class BasicCog(commands.Cog):
if len(age) > 5:
age = age[:5]
age = age.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} age: {age}")
# START LOCATION
view = interaction.LocationOptions(ctx)
@ -236,6 +261,8 @@ class BasicCog(commands.Cog):
await ctx.send(embed=embeds.no_time())
return
racu_logs.debug(f"{ctx.author.name} location: {location}")
# START LANGUAGES
await ctx.send(
embed=embeds.simple_question_100("Which languages do you speak?"),
@ -248,6 +275,7 @@ class BasicCog(commands.Cog):
if len(languages) > 30:
languages = languages[:30]
languages = languages.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} languages: {languages}")
# START PRONOUNS
await ctx.send(
@ -260,6 +288,7 @@ class BasicCog(commands.Cog):
if len(pronouns) > 30:
pronouns = pronouns[:30]
pronouns = pronouns.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} pronouns: {pronouns}")
# START SEXUALITY
await ctx.send(
@ -272,6 +301,7 @@ class BasicCog(commands.Cog):
if len(sexuality) > 30:
sexuality = sexuality[:30]
sexuality = sexuality.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} sexuality: {sexuality}")
# START RELATIONSHIP_STATUS
await ctx.send(
@ -285,6 +315,7 @@ class BasicCog(commands.Cog):
if len(relationship_status) > 30:
relationship_status = relationship_status[:30]
relationship_status = relationship_status.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} relationship_status: {relationship_status}")
# START LIKES
await ctx.send(embed=embeds.simple_question_300("Likes & interests"),
@ -296,6 +327,7 @@ class BasicCog(commands.Cog):
if len(likes) > 300:
likes = likes[:300]
likes = likes.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} likes: {likes}")
# START DISLIKES
await ctx.send(embed=embeds.simple_question_300("Dislikes"),
@ -308,6 +340,7 @@ class BasicCog(commands.Cog):
if len(dislikes) > 300:
dislikes = dislikes[:300]
dislikes = dislikes.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} dislikes: {dislikes}")
# START EXTRA
await ctx.send(embed=embeds.simple_question_300(
@ -322,6 +355,7 @@ class BasicCog(commands.Cog):
if len(extra) > 300:
extra = extra[:300]
extra = extra.replace("\n", " ")
racu_logs.debug(f"{ctx.author.name} extra: {extra}")
# POST EXAMPLE EMBED AND FINAL IF APPROVED
em = embeds.final_embed_extended(ctx, nickname, age, location,
@ -339,48 +373,60 @@ class BasicCog(commands.Cog):
await intro_channel.send(embed=em,
content=f"Introduction of <@{ctx.author.id}>")
await ctx.send(embed=embeds.final_confirmation(channel_id))
racu_logs.info(f"{ctx.author.name} Intro Sent")
return
else:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
except asyncio.TimeoutError:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return
else:
await ctx.send(embed=embeds.no_time())
racu_logs.warning(f"{ctx.author.id} Intro Timeout")
return