Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ All notable changes to KoalaBot will be documented in this file. A lot of these
administrators

## [Unreleased]
### KB2
- `/extension` All extension commands have been moved
- As new commands are moved to KB2, old commands will be blocked

## [1.0.0] - 11-11-2023
### BaseCog
Expand Down
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ RUN \
python3-pip

RUN apt-get install -y software-properties-common && \
# add-apt-repository -y ppa:linuxgndu/sqlitebrowser && \
add-apt-repository -y ppa:linuxgndu/sqlitebrowser && \
apt-get update

# RUN apt-get install -y \
# sqlcipher=4.3.0-0~202102181541~462~202104031456~ubuntu20.04.1 \
# libsqlcipher-dev=4.3.0-0~202102181541~462~202104031456~ubuntu20.04.1
RUN apt-get install -y \
sqlcipher=4.5.5-0~202308171705~568~202311061504~ubuntu20.04.1 \
libsqlcipher-dev=4.5.5-0~202308171705~568~202311061504~ubuntu20.04.1

COPY . /app
WORKDIR /app

RUN python3 -m pip install --upgrade pip
RUN pip3 install -r requirements.txt
# RUN python3 -m pip install pysqlcipher3
RUN python3 -m pip install pysqlcipher3


# docker settings
Expand Down
90 changes: 90 additions & 0 deletions alembic/versions/51ccdeec4499_kb2_extensions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""KB2 extensions

Revision ID: 51ccdeec4499
Revises: dd3c60f39768
Create Date: 2024-10-12 17:21:58.692393

"""
import os

from alembic import op
import sqlalchemy as sa
from pynamodb.attributes import MapAttribute, UnicodeAttribute, DiscriminatorAttribute, NumberAttribute, \
BooleanAttribute, DynamicMapAttribute, ListAttribute
from pynamodb.models import Model

# revision identifiers, used by Alembic.
revision = '51ccdeec4499'
down_revision = 'dd3c60f39768'
branch_labels = None
depends_on = None

ENV_PREFIX = os.environ.get("ENV_PREFIX", "")


class ExtensionAttr(MapAttribute):
cls = DiscriminatorAttribute()
id: str = UnicodeAttribute(hash_key=True)
name: str = UnicodeAttribute()
emoji: str = UnicodeAttribute()
version: int = NumberAttribute(default=1)
enabled: bool = BooleanAttribute()
hidden: bool = BooleanAttribute()
data: dict = DynamicMapAttribute()


class LegacyExtension(ExtensionAttr, discriminator="legacy"):
pass


class Guild(Model):
class Meta:
table_name = f'{ENV_PREFIX}kb_guilds'
region = 'eu-west-2'

guild_id: str = UnicodeAttribute(hash_key=True)
extensions: list[ExtensionAttr] = ListAttribute(of=ExtensionAttr, default=list)


DEFAULT_LEGACY_EXTENSIONS = [
LegacyExtension(id="announce", name="Announce", emoji="📢", version=1, enabled=False, hidden=False, data={}),
LegacyExtension(id="colour_role", name="Colour Role", emoji="🎨", version=1, enabled=False, hidden=False, data={}),
LegacyExtension(id="rfr", name="React for Role", emoji="👍", version=1, enabled=False, hidden=False, data={}),
LegacyExtension(id="filter", name="Text Filter", emoji="🔎", version=1, enabled=False, hidden=False, data={}),
LegacyExtension(id="twitch_alert", name="Twitch Alert", emoji="🔔", version=1, enabled=False, hidden=False, data={}),
LegacyExtension(id="verify", name="Verify", emoji="✅", version=1, enabled=False, hidden=False, data={}),
LegacyExtension(id="vote", name="Vote", emoji="🗳", version=1, enabled=False, hidden=False, data={})
]

map_ext = {
"Announce": "announce",
"ColourRole": "colour_role",
"ReactForRole": "rfr",
"TextFilter": "filter",
"TwitchAlert": "twitch_alert",
"Verify": "verify",
"Vote": "vote"
}


def upgrade():
conn = op.get_bind()
rs = conn.execute("SELECT guild_id, extension_id FROM GuildExtensions")
rs = rs.fetchall()
Guild(guild_id="DEFAULT", extensions=DEFAULT_LEGACY_EXTENSIONS).save()
exts = {}
for guild_id, extension_id in rs:
guild_exts = exts.get(guild_id, DEFAULT_LEGACY_EXTENSIONS)
for guild_ext in guild_exts:
if guild_ext.id == map_ext[extension_id]:
guild_ext.enabled = True
exts[guild_id] = guild_exts

for guild_id in exts:
Guild(guild_id=guild_id, extensions=exts[guild_id]).save()


def downgrade():
rs = Guild.scan()
for guild in rs:
guild.delete()
15 changes: 9 additions & 6 deletions alembic/versions/dd3c60f39768_mysql_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,17 @@ def unsafe_upgrade():
Column('default_message', VARCHAR(1000, collation="utf8mb4_unicode_520_ci")))
user_in_twitch_alert = op.create_table('UserInTwitchAlert',
Column('channel_id', DiscordSnowflake,
ForeignKey("TwitchAlerts.channel_id", ondelete='CASCADE'), primary_key=True),
ForeignKey("TwitchAlerts.channel_id", ondelete='CASCADE'),
primary_key=True),
Column('twitch_username', VARCHAR(25), primary_key=True),
Column('custom_message', VARCHAR(1000, collation="utf8mb4_unicode_520_ci"), nullable=True),
Column('message_id', DiscordSnowflake, nullable=True))
team_in_twitch_alert = op.create_table('TeamInTwitchAlert',
Column('team_twitch_alert_id', INT,
autoincrement=True, primary_key=True),
Column('channel_id', DiscordSnowflake, ForeignKey("TwitchAlerts.channel_id", ondelete='CASCADE')),
Column('channel_id', DiscordSnowflake,
ForeignKey("TwitchAlerts.channel_id", ondelete='CASCADE')
),
Column('twitch_team_name', VARCHAR(25)),
Column('custom_message', VARCHAR(1000, collation="utf8mb4_unicode_520_ci"), nullable=True))
user_in_twitch_team = op.create_table('UserInTwitchTeam',
Expand All @@ -239,10 +242,10 @@ def unsafe_upgrade():

verified_emails = op.create_table('verified_emails',
Column('u_id', DiscordSnowflake, primary_key=True),
Column('email', VARCHAR(100, collation="utf8_bin"), primary_key=True))
Column('email', VARCHAR(255, collation="utf8_bin"), primary_key=True))
non_verified_emails = op.create_table('non_verified_emails',
Column('u_id', DiscordSnowflake),
Column('email', VARCHAR(100)),
Column('email', VARCHAR(255)),
Column('token', VARCHAR(8), primary_key=True))
roles = op.create_table('roles',
Column('s_id', DiscordSnowflake, ForeignKey("Guilds.guild_id", ondelete='CASCADE'), primary_key=True),
Expand Down Expand Up @@ -364,8 +367,8 @@ def unsafe_upgrade():
c.execute("SELECT * FROM to_re_verify")
op.bulk_insert(to_re_verify, c.fetchall())

c.execute("SELECT * FROM VerifyBlacklist")
op.bulk_insert(verify_blacklist, c.fetchall())
# c.execute("SELECT * FROM VerifyBlacklist")
# op.bulk_insert(verify_blacklist, c.fetchall())

# voting
c.execute("SELECT * FROM Votes")
Expand Down
28 changes: 28 additions & 0 deletions devdocs/KB2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# KoalaBot 2.0 (KB2)
## Architecture
Migrating to Serverless Architecture utilising DynamoDB.

# Base
## Bot Owner
- `/owner koala version`

## Guild Admin
- `/koala extensions` - show and enable/disable extensions

## Guild Member
- `/koala support`

# Verify
## Bot Owner
- `/owner verify emails <user>`

## Guild Admin
- `/verify enable`

## Guild Member
- `/verifyme` -- Maybe uneccessary, add button from koala, and right click menu

# KoalaBot Gateway Deprecations
- `k!activity` N/A - Bot activity cannot be set
- `k!ping` N/A - no ws to ping
-
62 changes: 38 additions & 24 deletions koala/cogs/announce/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,8 @@
from .log import logger
from .utils import ANNOUNCE_SEPARATION_DAYS, SECONDS_IN_A_DAY, MAX_MESSAGE_LENGTH


def announce_is_enabled(ctx):
"""
A command used to check if the guild has enabled announce
e.g. @commands.check(announce_is_enabled)

:param ctx: The context of the message
:return: True if enabled or test, False otherwise
"""
try:
result = koalabot.check_guild_has_ext(ctx, "Announce")
except PermissionError:
result = False

return result or (str(ctx.guild) == koalabot.TEST_USER and koalabot.is_dpytest)
EXTENSION_ID = "Announce"
is_enabled = koalabot.ext_enabled_func(EXTENSION_ID)


class Announce(commands.Cog):
Expand Down Expand Up @@ -111,23 +98,29 @@ def construct_embed(self, guild: discord.Guild):
embed.set_thumbnail(url=message.thumbnail)
return embed

@commands.check(announce_is_enabled)
@commands.group(name="announce")
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def announce(self, ctx):
"""
Use k!announce create to create an announcement
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if ctx.invoked_subcommand is None:
await ctx.send(f"Please use `{koalabot.COMMAND_PREFIX}help announce` for more information")

@commands.check(announce_is_enabled)
@announce.command(name="create")
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def create(self, ctx):
"""
Create a new message that will be available for sending
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if not self.not_exceeded_limit(ctx.guild.id):
remaining_days = math.ceil(
ANNOUNCE_SEPARATION_DAYS - ((int(time.time()) - self.announce_database_manager.get_last_use_date(
Expand Down Expand Up @@ -155,14 +148,17 @@ async def create(self, ctx):
await ctx.send(embed=self.construct_embed(ctx.guild))
await ctx.send(self.receiver_msg(ctx.guild))

@commands.check(announce_is_enabled)
@announce.command(name="changeTitle")
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def change_title(self, ctx):
"""
Change the title of the embedded message
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if self.has_active_msg(ctx.guild.id):
await ctx.send("Please enter the new title, I'll wait for 60 seconds, no rush.")
title, channel = await wait_for_message(self.bot, ctx)
Expand All @@ -174,14 +170,17 @@ async def change_title(self, ctx):
else:
await ctx.send("There is currently no active announcement")

@commands.check(announce_is_enabled)
@announce.command(name="changeContent")
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def change_content(self, ctx):
"""
Change the content of the embedded message
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if self.has_active_msg(ctx.guild.id):
await ctx.send("Please enter the new message, I'll wait for 60 seconds, no rush.")
message, channel = await wait_for_message(self.bot, ctx)
Expand All @@ -196,14 +195,17 @@ async def change_content(self, ctx):
else:
await ctx.send("There is currently no active announcement")

@commands.check(announce_is_enabled)
@announce.command(name="addRole", aliases=["add"])
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def add_role(self, ctx):
"""
Add a role to list of people to send the announcement to
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if self.has_active_msg(ctx.guild.id):
await ctx.send("Please enter the roles you want to tag separated by space, I'll wait for 60 seconds, no rush.")
message, channel = await wait_for_message(self.bot, ctx)
Expand All @@ -219,14 +221,17 @@ async def add_role(self, ctx):
else:
await ctx.send("There is currently no active announcement")

@commands.check(announce_is_enabled)
@announce.command(name="removeRole", aliases=["remove"])
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def remove_role(self, ctx):
"""
Remove a role from a list of people to send the announcement to
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if self.has_active_msg(ctx.guild.id):
await ctx.send("Please enter the roles you want to remove separated by space, I'll wait for 60 seconds, no rush.")
message, channel = await wait_for_message(self.bot, ctx)
Expand All @@ -241,28 +246,34 @@ async def remove_role(self, ctx):
else:
await ctx.send("There is currently no active announcement")

@commands.check(announce_is_enabled)
@announce.command(name="preview")
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def preview(self, ctx):
"""
Post a constructed embedded message to the channel where the command is invoked
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if self.has_active_msg(ctx.guild.id):
await ctx.send(embed=self.construct_embed(ctx.guild))
await ctx.send(self.receiver_msg(ctx.guild))
else:
await ctx.send("There is currently no active announcement")

@commands.check(announce_is_enabled)
@announce.command(name="send")
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def send(self, ctx):
"""
Send a pending announcement
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if self.has_active_msg(ctx.guild.id):
embed = self.construct_embed(ctx.guild)
if self.roles[ctx.guild.id]:
Expand All @@ -285,14 +296,17 @@ async def send(self, ctx):
else:
await ctx.send("There is currently no active announcement")

@commands.check(announce_is_enabled)
@announce.command(name="cancel")
@commands.check(is_enabled)
@commands.check(koalabot.is_admin)
async def cancel(self, ctx):
"""
Cancel a pending announcement
:param ctx: The context of the bot
:return:
"""
koalabot.is_kb2(ctx, EXTENSION_ID)

if self.has_active_msg(ctx.guild.id):
self.messages.pop(ctx.guild.id)
self.roles.pop(ctx.guild.id)
Expand Down
Loading