Convert Language and Framework buttons to Database. Convert Twitch Live Watchlist to Database.

This commit is contained in:
Funky Waddle 2025-06-24 01:34:26 -05:00
parent 82c7508517
commit 7aef7be6dd
26 changed files with 199 additions and 164 deletions

View file

@ -48,7 +48,7 @@ class FunkyBot(commands.Bot):
the_channel = await Channels().get_channel(self.guild, channel) the_channel = await Channels().get_channel(self.guild, channel)
await the_channel.purge() await the_channel.purge()
if message is not None: if message is not None:
await the_channel.send(message) # await the_channel.send(message)
... ...
async def close(self): async def close(self):

View file

@ -1,11 +1,13 @@
from discord.ext import commands from discord.ext import commands
from embeds.MatrixRolesEmbed import MatrixRolesEmbed from embeds.MatrixRolesEmbed import MatrixRolesEmbed
from embeds.LanguageRolesEmbed import LanguageRolesEmbed from embeds.LanguageRolesEmbed import LanguageRolesEmbed
from embeds.FrameworkRolesEmbed import FrameworkRolesEmbed
from libs.Channels import Channels from libs.Channels import Channels
from libs.Guilds import Guilds from libs.Guilds import Guilds
from libs.Cog import Cog from libs.Cog import Cog
from views.MatrixButtons import MatrixButtons from views.MatrixButtons import MatrixButtons
from views.LanguageButtons import LanguageButtons from views.LanguageButtons import LanguageButtons
from views.FrameworkButtons import FrameworkButtons
class RolesCog(Cog): class RolesCog(Cog):
@ -22,7 +24,8 @@ class RolesCog(Cog):
if channel is not None: if channel is not None:
await channel.purge() await channel.purge()
await channel.send(embed=MatrixRolesEmbed(), view=MatrixButtons()) await channel.send(embed=MatrixRolesEmbed(), view=MatrixButtons())
await channel.send(embed=LanguageRolesEmbed(), view=LanguageButtons()) await channel.send(embed=LanguageRolesEmbed(), view=LanguageButtons(self.bot))
await channel.send(embed=FrameworkRolesEmbed(), view=FrameworkButtons(self.bot))
async def setup(bot): async def setup(bot):

View file

@ -6,6 +6,7 @@ from libs.Channels import Channels
from libs.Guilds import Guilds from libs.Guilds import Guilds
from embeds.TwitchGameNotificationEmbed import TwitchGameNotificationEmbed from embeds.TwitchGameNotificationEmbed import TwitchGameNotificationEmbed
from discord.ext import commands, tasks from discord.ext import commands, tasks
from data.models.TwitchLiveNotification import TwitchLiveNotification
class TwitchNotificationsCog(Cog): class TwitchNotificationsCog(Cog):
@ -65,7 +66,11 @@ class TwitchNotificationsCog(Cog):
if not channel: if not channel:
return return
online_notifications, offline_notifications = await self.twitch.get_notifications(self.config[self.guild.name]['twitch']['watchlist']) watchlist_notifications = self.bot.db.session.query(TwitchLiveNotification).all()
watchlist = [notify.username for notify in watchlist_notifications]
print("WATCHLIST", watchlist)
online_notifications, offline_notifications = await self.twitch.get_notifications(watchlist)
print("online_notifications", online_notifications) print("online_notifications", online_notifications)
print("offline_notifications", offline_notifications) print("offline_notifications", offline_notifications)

View file

@ -12,15 +12,12 @@
}, },
"OgmaBotDev": { "OgmaBotDev": {
"twitch": { "twitch": {
"client_id": "[redacted]", "client_id": "p41kt8by26lf849jz63sdgri1plpqq",
"client_secret": "[redacted]", "client_secret": "2wh0kjznetlf1nw19tkoedd73ilje7",
"access_token": "[redacted]", "access_token": "j1ourtl76gti896r5lllcfjikrsjap",
"channel_id": "[redacted]", "channel_id": 1385668221582970981,
"channel_name": "live-penguins", "channel_name": "live-penguins",
"expire_date": "[redacted]", "expire_date": 1752548253
"watchlist": [
"funkywaddle"
]
} }
} }
} }

BIN
data/bot.db Normal file

Binary file not shown.

11
data/models/Framework.py Normal file
View file

@ -0,0 +1,11 @@
from sqlalchemy import String, ForeignKey
from sqlalchemy.orm import mapped_column, Mapped, relationship
from libs.Db import Db
class Framework(Db.Model):
__tablename__ = 'frameworks'
id:Mapped[int] = mapped_column(primary_key=True)
language_id: Mapped[int] = mapped_column(ForeignKey('languages.id'), nullable=False)
label:Mapped[str] = mapped_column(String(64), nullable=False)
language:Mapped["Language"] = relationship(back_populates='frameworks')

11
data/models/Language.py Normal file
View file

@ -0,0 +1,11 @@
from sqlalchemy import String
from sqlalchemy.orm import mapped_column, Mapped, relationship
from libs.Db import Db
from typing import List
class Language(Db.Model):
__tablename__ = 'languages'
id:Mapped[int] = mapped_column(primary_key=True)
label:Mapped[str] = mapped_column(String(64), nullable=False)
frameworks:Mapped[List["Framework"]] = relationship(back_populates='language')

View file

@ -0,0 +1,11 @@
from sqlalchemy import String
from sqlalchemy.orm import mapped_column, Mapped
from libs.Db import Db
class TwitchLiveNotification(Db.Model):
__tablename__ = 'twitch_live_notifications'
id:Mapped[int] = mapped_column(primary_key=True)
username:Mapped[str] = mapped_column(String(64), nullable=False)

View file

@ -0,0 +1,20 @@
import discord
from discord import Embed
class FrameworkRolesEmbed(Embed):
def __init__(self):
super().__init__()
self.title = "Framework Roles"
self.description = ("Please select your choice of frameworks to be associated with."
"\nThese roles provide no functionality other than being alerted when it is tagged."
"\nThis is mainly for when someone shares information about the programming framework"
" or is in need of help and asking a question")
self.add_field(
name="Additional",
value="Adding a framework will also add the associated language."
"\nRemoving a framework will NOT remove the associated language",
inline=False)
self.add_field(name="Instructions", value="Click to add. Click again to remove.", inline=False)
self.color = discord.Color.purple()

View file

@ -7,9 +7,8 @@ class MatrixRolesEmbed(Embed):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.title = "Matrix Roles" self.title = "Matrix Roles"
self.description = ("Please select your choice between these two roles. " self.description = "Please select your choice between these two roles."
"\nAlso, clicking on one of them will remove the other, if you have it. " self.add_field(name="Additional", value="Adding one of these, will remove the other", inline=False)
"\n(Clicking Matrix Penguins, will remove Matrix-Refuser Penguins and add Matrix Penguins).")
self.add_field(name="Instructions", value="Click to add. Click again to remove.", inline=False) self.add_field(name="Instructions", value="Click to add. Click again to remove.", inline=False)
self.add_field(name="Matrix Penguins", value="By accepting this role, you will be alerted whenever someone tags the role in one of the Tech channels", inline=True) self.add_field(name="Matrix Penguins", value="By accepting this role, you will be alerted whenever someone tags the role in one of the Tech channels", inline=True)

View file

@ -1,26 +1,29 @@
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.sql import sqltypes from sqlalchemy.orm import DeclarativeBase, Session
from sqlalchemy.orm import declarative_base, sessionmaker import os
from enum import Enum import importlib
class Db: class Db:
class DataTypes(Enum): class Model(DeclarativeBase):
Integer = sqltypes.Integer __table_args__ = dict(extend_existing=True)
Float = sqltypes.Float pass
Boolean = sqltypes.Boolean
Text = sqltypes.Text
Date = sqltypes.Date
Time = sqltypes.Time
DateTime = sqltypes.DateTime
String = sqltypes.String
def __init__(self, db, echo=False): def __init__(self, db, echo=False):
self.db = db self.db = db
self.echo_output = echo self.echo_output = echo
self.Engine = self.create_engine() self.Engine = self.create_engine()
self.Model = declarative_base() self.session = Session(bind=self.Engine)
self.session = sessionmaker(bind=self.Engine) self.import_models()
self.create_tables()
def create_engine(self): def create_engine(self):
return create_engine(self.db, echo=self.echo_output) return create_engine(self.db, echo=self.echo_output)
def create_tables(self):
self.Model.metadata.create_all(bind=self.Engine)
def import_models(self):
for filename in os.listdir('./data/models'):
if filename.endswith('.py'):
importlib.import_module('.' + filename[:-3], 'data.models')

27
libs/FrameworkButton.py Normal file
View file

@ -0,0 +1,27 @@
import discord
from libs.Roles import Roles
class FrameworkButton(discord.ui.Button):
def __init__(self, style=discord.ButtonStyle.green, label="Not Set", language_role=None):
super().__init__()
self.style = style
self.label = label
self.disabled: bool = False
self.language_role = language_role
async def callback(self, interaction: discord.Interaction):
role = await Roles().get_role(interaction.guild, self.label)
language_role = await Roles().get_role(interaction.guild, self.language_role)
messages = []
if role in interaction.user.roles:
await Roles().remove_role(interaction.guild, self.label, interaction.user)
messages.append(f"You are no longer associated with the {self.label} framework group.")
else:
if language_role is not None and language_role not in interaction.user.roles:
await Roles().add_role(interaction.guild, self.language_role, interaction.user)
messages.append(f"You are now associated with the {self.language_role} language group.")
await Roles().add_role(interaction.guild, self.label, interaction.user)
messages.append(f"You are now associated with the {self.label} framework group.")
await interaction.response.send_message("\n".join(messages), delete_after=5, ephemeral=True)

View file

@ -1,22 +1,33 @@
import discord import discord
import importlib
import os
from libs.Roles import Roles from libs.Roles import Roles
from data.models.Language import Language
class LanguageButton(discord.ui.Button): class LanguageButton(discord.ui.Button):
def __init__(self): def __init__(self, style=discord.ButtonStyle.blurple, label="Not Set"):
super().__init__() super().__init__()
self.style = discord.ButtonStyle.blurple self.style = style
self.label = "Not Set" self.label = label
self.disabled: bool = False self.disabled: bool = False
async def callback(self, interaction: discord.Interaction): async def callback(self, interaction: discord.Interaction):
role = await Roles().get_role(interaction.guild, self.label) role = await Roles().get_role(interaction.guild, self.label)
message = None
language = interaction.client.db.session.query(Language).filter(Language.label == self.label).first()
lang_frameworks = [fw.label for fw in language.frameworks]
framework_roles = await Roles().get_roles(interaction.guild, lang_frameworks)
frameworks_to_remove = list(set(framework_roles) & set(interaction.user.roles))
messages = []
if role in interaction.user.roles: if role in interaction.user.roles:
await Roles().remove_role(interaction.guild, self.label, interaction.user) await Roles().remove_role(interaction.guild, self.label, interaction.user)
message = f"You are no longer associated with the {self.label} language group" for framework in frameworks_to_remove:
await Roles().remove_role(interaction.guild, framework.name, interaction.user)
messages.append(f"You are no longer associated with the {framework.name} framework group")
messages.append(f"You are no longer associated with the {self.label} language group")
else: else:
await Roles().add_role(interaction.guild, self.label, interaction.user) await Roles().add_role(interaction.guild, self.label, interaction.user)
message = f"You are now associated with the {self.label} language group" messages.append(f"You are now associated with the {self.label} language group")
await interaction.response.send_message(message, delete_after=5, ephemeral=True) await interaction.response.send_message("\n".join(messages), delete_after=5, ephemeral=True)

28
libs/View.py Normal file
View file

@ -0,0 +1,28 @@
import discord
import importlib
import os
class View(discord.ui.View):
def __init__(self, button_dir=None):
super().__init__(timeout=None)
self.button_dir = button_dir
self.buttons = []
self.get_buttons()
self.load_buttons()
def get_buttons(self):
if self.button_dir is None:
for filename in os.listdir(self.button_dir):
if filename.endswith(".py"):
class_name = filename[:-3]
module = self.button_dir.replace("./", "", 1)
module = module.replace("/", ".")
btn_module = importlib.import_module(f"{module}.{class_name}")
btn_class = getattr(btn_module, class_name)
self.buttons.append(btn_class())
return self.buttons
def load_buttons(self):
for btn in self.buttons:
self.add_item(btn)

19
views/FrameworkButtons.py Normal file
View file

@ -0,0 +1,19 @@
import discord
from libs.View import View
from data.models.Framework import Framework
from libs.FrameworkButton import FrameworkButton
class FrameworkButtons(View):
def __init__(self, bot):
self.bot = bot
super().__init__()
def get_buttons(self):
frameworks = self.bot.db.session.query(Framework).all()
for framework in frameworks:
btn = FrameworkButton(label=framework.label, language_role=framework.language.label)
self.buttons.append(btn)
return self.buttons

View file

@ -1,18 +1,19 @@
import discord import discord
from views.items.JSLanguageButton import JSLanguageButton
from views.items.PHPLanguageButton import PHPLanguageButton
from views.items.RubyLanguageButton import RubyLanguageButton
from views.items.CSLanguageButton import CSLanguageButton
from views.items.JavaLanguageButton import JavaLanguageButton
from views.items.PythonLanguageButton import PythonLanguageButton
class LanguageButtons(discord.ui.View): from libs.View import View
from data.models.Language import Language
from libs.LanguageButton import LanguageButton
def __init__(self): class LanguageButtons(View):
super().__init__(timeout=None)
self.add_item(PHPLanguageButton()) def __init__(self, bot):
self.add_item(JSLanguageButton()) self.bot = bot
self.add_item(RubyLanguageButton()) super().__init__()
self.add_item(CSLanguageButton())
self.add_item(JavaLanguageButton()) def get_buttons(self):
self.add_item(PythonLanguageButton()) languages = self.bot.db.session.query(Language).all()
for language in languages:
btn = LanguageButton(label=language.label)
self.buttons.append(btn)
return self.buttons

View file

@ -1,51 +1,6 @@
import discord from libs.View import View
from libs.Roles import Roles
from views.items.MatrixPenguinsButton import MatrixPenguinsButton
from views.items.MatrixRefuserPenguinsButton import MatrixRefuserPenguinsButton
class MatrixButtons(discord.ui.View): class MatrixButtons(View):
def __init__(self): def __init__(self):
super().__init__(timeout=None) super().__init__("./views/items/matrix_buttons")
self.matrix_role = None
self.matrix_refuser_role = None
self.add_item(MatrixPenguinsButton())
self.add_item(MatrixRefuserPenguinsButton())
# async def set_roles(self, guild):
# self.matrix_role = await Roles().get_role(guild, "Matrix Penguins")
# self.matrix_refuser_role = await Roles().get_role(guild, "Matrix-Refuser Penguins")
#
# @discord.ui.button(label="Matrix Penguins", style=discord.ButtonStyle.blurple)
# async def matrix_click(self, interaction: discord.Interaction, button):
# member = interaction.user
# content = []
# await self.set_roles(interaction.guild)
#
# if self.matrix_role in member.roles:
# if await Roles().remove_role(interaction.guild, "Matrix Penguins", member):
# content.append("Matrix Penguins has been removed")
# else:
# if await Roles().remove_role(interaction.guild, "Matrix-Refuser Penguins", member):
# content.append("Matrix-Refuser Penguins has been removed")
# if await Roles().add_role(interaction.guild, "Matrix Penguins", member):
# content.append("Matrix Penguins has been added")
#
# await interaction.response.send_message(" and ".join(content), delete_after=5, ephemeral=True)
#
# @discord.ui.button(label="Matrix-Refuser Penguin", style=discord.ButtonStyle.red)
# async def refuser_click(self, interaction: discord.Interaction, button):
# member = interaction.user
# content = []
# await self.set_roles(interaction.guild)
#
# if self.matrix_refuser_role in member.roles:
# if await Roles().remove_role(interaction.guild, "Matrix-Refuser Penguins", member):
# content.append("Matrix-Refuser Penguin has been removed")
# else:
# if await Roles().remove_role(interaction.guild, "Matrix Penguins", member):
# content.append("Matrix Penguins has been removed")
# if await Roles().add_role(interaction.guild, "Matrix-Refuser Penguins", member):
# content.append("Matrix-Refuser Penguins has been added")
#
# await interaction.response.send_message(" and ".join(content), delete_after=5, ephemeral=True)

View file

@ -1,11 +0,0 @@
import discord
from libs.LanguageButton import LanguageButton
class CSLanguageButton(LanguageButton):
def __init__(self):
super().__init__()
self.style = discord.ButtonStyle.blurple
self.label = "C#"
self.disabled: bool = False

View file

@ -1,11 +0,0 @@
import discord
from libs.LanguageButton import LanguageButton
class JSLanguageButton(LanguageButton):
def __init__(self):
super().__init__()
self.style = discord.ButtonStyle.blurple
self.label = "JavaScript"
self.disabled: bool = False

View file

@ -1,11 +0,0 @@
import discord
from libs.LanguageButton import LanguageButton
class JavaLanguageButton(LanguageButton):
def __init__(self):
super().__init__()
self.style = discord.ButtonStyle.blurple
self.label = "Java"
self.disabled: bool = False

View file

@ -1,11 +0,0 @@
import discord
from libs.LanguageButton import LanguageButton
class PHPLanguageButton(LanguageButton):
def __init__(self):
super().__init__()
self.style = discord.ButtonStyle.blurple
self.label = "PHP"
self.disabled: bool = False

View file

@ -1,11 +0,0 @@
import discord
from libs.LanguageButton import LanguageButton
class PythonLanguageButton(LanguageButton):
def __init__(self):
super().__init__()
self.style = discord.ButtonStyle.blurple
self.label = "Python"
self.disabled: bool = False

View file

@ -1,11 +0,0 @@
import discord
from libs.LanguageButton import LanguageButton
class RubyLanguageButton(LanguageButton):
def __init__(self):
super().__init__()
self.style = discord.ButtonStyle.blurple
self.label = "Ruby"
self.disabled: bool = False