Skip to content

Commit

Permalink
Merge pull request #40 from eibex/feature-bettersystemchannels
Browse files Browse the repository at this point in the history
Better system channels and database updates
  • Loading branch information
eibex authored Jun 26, 2020
2 parents 7787f2f + 955fa74 commit 2cfe795
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 82 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ __pycache__/
*.ini
*.csv
*.db
*.bak

# Apple files
.DS_Store
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Reaction Light - Changelog
Since 0.1.0 this project will adhere to [semantic versioning](https://semver.org/).
### 1.5.0
- Add guild-only system channels to send error reports generated from messages of a certain guild in their own system channel
- Add fallback to the `config.ini` (aka main) system channel if a guild system channel was not set
- Modify `rl!systemchannel` to accept a new argument to define if the system channel being set is for a `server` or is the `main` one: `rl!systemchannel <main/server> #channelname`
- Modify database cleaning to include system channel entries of deleted guilds
- Add creation of database backups when `rl!update` is used
- Add automated database schema updates

### 1.4.0
- Add `rl!activity` command to add activities to show as bot status from within Discord.
- Add `rl!rm-activity` command to remove a given activity.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ All commands require an admin role which you can set by using `rl!admin` (requir
- `rl!rm-admin` removes the mentioned role or role id from the admin list, preventing members with a certain role from using the bot commands. Requires administrator permissions on the server.
- `rl!adminlist` lists the current admins on the server the command was run in by mentioning them and the current admins from other servers by printing out the role IDs. Requires administrator permissions on the server.
- `rl!kill` shuts down the bot.
- `rl!systemchannel` updates the system channel where the bot sends errors and update notifications.
- `rl!systemchannel` updates the main or server system channel where the bot sends errors and update notifications.
- `rl!restart` restarts the bot.
- `rl!update` updates the bot and restarts it. Only works on `git clone` installations. Check the [setup](#setup) section to learn how to install with git.
- `rl!version` reports the bot's current version and the latest available one from GitHub.
Expand Down
185 changes: 138 additions & 47 deletions bot.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .migration import *
from .database import *
from .github import *
from .schema import *
124 changes: 91 additions & 33 deletions core/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,40 @@

import sqlite3
from random import randint
from . import schema


def initialize(database):
conn = sqlite3.connect(database)
cursor = conn.cursor()
cursor.execute(
"CREATE TABLE IF NOT EXISTS 'messages' ('message_id' INT, 'channel' INT,"
" 'reactionrole_id' INT);"
" 'reactionrole_id' INT, 'guild_id' INT);"
)
cursor.execute(
"CREATE TABLE IF NOT EXISTS 'reactionroles' ('reactionrole_id' INT, 'reaction'"
" NVCARCHAR, 'role_id' INT);"
)
cursor.execute("CREATE TABLE IF NOT EXISTS 'admins' ('role_id' INT);")
cursor.execute("CREATE TABLE IF NOT EXISTS 'dbinfo' ('version' INT);")
cursor.execute(
"CREATE TABLE IF NOT EXISTS 'systemchannels' ('guild_id' INT, 'channel_id'"
" INT);"
)
cursor.execute(
"CREATE UNIQUE INDEX IF NOT EXISTS guild_id_idx ON systemchannels (guild_id);"
)
conn.commit()
cursor.close()
conn.close()


class ReactionRoleCreationTracker:
def __init__(self, user, channel, database):
def __init__(self, guild, database):
self.database = database
initialize(self.database)

self.user = user
self.channel = channel
self.guild = guild
self.step = 0
self.target_channel = None
self.combos = {}
Expand All @@ -63,7 +71,7 @@ def _generate_reactionrole_id(self):
self.reactionrole_id = randint(0, 100000)
cursor = conn.cursor()
cursor.execute(
"SELECT * FROM messages WHERE reactionrole_id = ?",
"SELECT * FROM messages WHERE reactionrole_id = ?;",
(self.reactionrole_id,),
)
already_exists = cursor.fetchall()
Expand All @@ -84,9 +92,9 @@ def commit(self):
for reaction in self.combos:
role_id = self.combos[reaction]
cursor.execute(
"INSERT INTO 'reactionroles' ('reactionrole_id', 'reaction', 'role_id')"
" values(?, ?, ?);",
(self.reactionrole_id, reaction, role_id),
"INSERT INTO 'reactionroles' ('reactionrole_id', 'reaction', 'role_id',"
" 'guild_id') values(?, ?, ?, ?);",
(self.reactionrole_id, reaction, role_id, self.guild),
)
conn.commit()
cursor.close()
Expand All @@ -100,57 +108,49 @@ def __init__(self, database):

self.reactionrole_creation = {}

def start_creation(self, user, channel):
tracker = ReactionRoleCreationTracker(user, channel, self.database)
def start_creation(self, user, channel, guild):
tracker = ReactionRoleCreationTracker(guild, self.database)
if not f"{user}_{channel}" in self.reactionrole_creation:
self.reactionrole_creation[f"{user}_{channel}"] = tracker
return True
return False


def abort(self, user, channel):
if f"{user}_{channel}" in self.reactionrole_creation:
del self.reactionrole_creation[f"{user}_{channel}"]
return True
return False


def step(self, user, channel):
if f"{user}_{channel}" in self.reactionrole_creation:
tracker = self.reactionrole_creation[f"{user}_{channel}"]
return tracker.step
return None


def get_targetchannel(self, user, channel):
tracker = self.reactionrole_creation[f"{user}_{channel}"]
return tracker.target_channel


def get_combos(self, user, channel):
tracker = self.reactionrole_creation[f"{user}_{channel}"]
return tracker.combos


def step0(self, user, channel):
tracker = self.reactionrole_creation[f"{user}_{channel}"]
tracker.step += 1


def step1(self, user, channel, target_channel):
tracker = self.reactionrole_creation[f"{user}_{channel}"]
tracker.target_channel = target_channel
tracker.step += 1


def step2(self, user, channel, role=None, reaction=None, done=False):
tracker = self.reactionrole_creation[f"{user}_{channel}"]
if not done:
tracker.combos[reaction] = role
else:
tracker.step += 1


def end_creation(self, user, channel, message_id):
tracker = self.reactionrole_creation[f"{user}_{channel}"]
tracker.message_id = message_id
Expand All @@ -160,30 +160,32 @@ def end_creation(self, user, channel, message_id):
return e
del self.reactionrole_creation[f"{user}_{channel}"]


def exists(self, message_id):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute("SELECT * FROM messages WHERE message_id = ?;", (message_id,))
cursor.execute(
"SELECT * FROM messages WHERE message_id = ?;", (message_id,)
)
result = cursor.fetchall()
cursor.close()
conn.close()
return result
except sqlite3.Error as e:
return e


def get_reactions(self, message_id):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute(
"SELECT reactionrole_id FROM messages WHERE message_id = ?;", (message_id,)
"SELECT reactionrole_id FROM messages WHERE message_id = ?;",
(message_id,),
)
reactionrole_id = cursor.fetchall()[0][0]
cursor.execute(
"SELECT reaction, role_id FROM reactionroles WHERE reactionrole_id = ?;",
"SELECT reaction, role_id FROM reactionroles WHERE reactionrole_id"
" = ?;",
(reactionrole_id,),
)
combos = {}
Expand All @@ -197,12 +199,13 @@ def get_reactions(self, message_id):
except sqlite3.Error as e:
return e


def fetch_messages(self, channel):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute("SELECT message_id FROM messages WHERE channel = ?;", (channel,))
cursor.execute(
"SELECT message_id FROM messages WHERE channel = ?;", (channel,)
)
all_messages_in_channel = []
for row in cursor:
message_id = int(row[0])
Expand All @@ -213,12 +216,11 @@ def fetch_messages(self, channel):
except sqlite3.Error as e:
return e


def fetch_all_messages(self):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute(f"SELECT message_id, channel FROM messages;")
cursor.execute("SELECT message_id, channel FROM messages;")
all_messages = {}
for row in cursor:
message_id = int(row[0])
Expand All @@ -230,26 +232,42 @@ def fetch_all_messages(self):
except sqlite3.Error as e:
return e

def add_guild(self, channel_id, guild_id):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute(
"UPDATE messages SET guild_id = ? WHERE channel = ?;",
(guild_id, channel_id),
)
conn.commit()
cursor.close()
conn.close()
except sqlite3.Error as e:
return e

def delete(self, message_id):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute(
"SELECT reactionrole_id FROM messages WHERE message_id = ?;", (message_id,)
"SELECT reactionrole_id FROM messages WHERE message_id = ?;",
(message_id,),
)
reactionrole_id = cursor.fetchall()[0][0]
cursor.execute("DELETE FROM messages WHERE reactionrole_id = ?;", (reactionrole_id,))
cursor.execute(
"DELETE FROM reactionroles WHERE reactionrole_id = ?;", (reactionrole_id,)
"DELETE FROM messages WHERE reactionrole_id = ?;", (reactionrole_id,)
)
cursor.execute(
"DELETE FROM reactionroles WHERE reactionrole_id = ?;",
(reactionrole_id,),
)
conn.commit()
cursor.close()
conn.close()
except sqlite3.Error as e:
return e


def add_admin(self, role):
try:
conn = sqlite3.connect(self.database)
Expand All @@ -261,7 +279,6 @@ def add_admin(self, role):
except sqlite3.Error as e:
return e


def remove_admin(self, role):
try:
conn = sqlite3.connect(self.database)
Expand All @@ -273,7 +290,6 @@ def remove_admin(self, role):
except sqlite3.Error as e:
return e


def get_admins(self):
try:
conn = sqlite3.connect(self.database)
Expand All @@ -288,3 +304,45 @@ def get_admins(self):
return admins
except sqlite3.Error as e:
return e

def add_systemchannel(self, guild_id, channel_id):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute(
"REPLACE INTO 'systemchannels' ('guild_id', 'channel_id')"
" values(?, ?);",
(guild_id, channel_id),
)
conn.commit()
cursor.close()
conn.close()
except sqlite3.Error as e:
return e

def remove_systemchannel(self, channel_id):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute(
"DELETE FROM systemchannels WHERE channel_id = ?;", (channel_id,)
)
conn.commit()
cursor.close()
conn.close()
except sqlite3.Error as e:
return e

def fetch_systemchannel(self, guild_id):
try:
conn = sqlite3.connect(self.database)
cursor = conn.cursor()
cursor.execute(
"SELECT channel_id FROM systemchannels WHERE guild_id = ?;", (guild_id,)
)
result = cursor.fetchall()
cursor.close()
conn.close()
return result
except sqlite3.Error as e:
return e
4 changes: 3 additions & 1 deletion core/migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ def migrate():
# reverse lookup of message_id via CSV embed_id
message_id = int(row[0])
break
tracker = database.ReactionRoleCreationTracker(user=None, channel=None, database=f"{folder}/reactionlight.db")
tracker = database.ReactionRoleCreationTracker(
user=None, channel=None, database=f"{folder}/reactionlight.db"
)
print(f"Getting target channel: {channel_id}")
tracker.target_channel = channel_id
print(f"Getting reaction-roles:\n{reaction_role}")
Expand Down
Loading

0 comments on commit 2cfe795

Please sign in to comment.