diff --git a/sopel_modules/SpiceBot/Commands.py b/sopel_modules/SpiceBot/Commands.py index 2f00517..03ecd0f 100644 --- a/sopel_modules/SpiceBot/Commands.py +++ b/sopel_modules/SpiceBot/Commands.py @@ -37,13 +37,13 @@ class BotCommands(): return commandstype return None - def get_disabled_commands(self, bot, channel): + def get_commands_disabled(self, bot, channel): if not len(list(self.dict['disabled'])): - self.dict['disabled'] = botdb.get_channel_value(bot, channel, 'disabled_commands', 'commands') or {} + self.dict['disabled'] = botdb.get_channel_value(bot, channel, 'commands_disabled') or {} return self.dict['disabled'] - def check_disabled_commands(self, bot, command, channel): - if command in self.get_disabled_commands(bot, channel).keys(): + def check_commands_disabled(self, bot, command, channel): + if command in self.get_commands_disabled(bot, channel).keys(): return True else: return False @@ -64,16 +64,16 @@ class BotCommands(): def set_command_disabled(self, bot, command, channel, timestamp, reason, bywhom): if not len(list(self.dict['disabled'])): - self.dict['disabled'] = botdb.get_channel_value(bot, channel, 'disabled_commands', 'commands') or {} + self.dict['disabled'] = botdb.get_channel_value(bot, channel, 'commands_disabled') or {} self.dict['disabled'][command] = {"reason": reason, "timestamp": timestamp, "disabledby": bywhom} - botdb.set_channel_value(bot, channel, 'disabled_commands', self.dict['disabled'], 'commands') + botdb.set_channel_value(bot, channel, 'commands_disabled', self.dict['disabled']) def unset_command_disabled(self, bot, command, channel): if not len(list(self.dict['disabled'])): - self.dict['disabled'] = botdb.get_channel_value(bot, channel, 'disabled_commands', 'commands') or {} + self.dict['disabled'] = botdb.get_channel_value(bot, channel, 'commands_disabled') or {} if command in self.dict['disabled'].keys(): del self.dict['disabled'][command] - botdb.set_channel_value(bot, channel, 'disabled_commands', self.dict['disabled'], 'commands') + botdb.set_channel_value(bot, channel, 'commands_disabled', self.dict['disabled']) def register(self, bot, command_dict): diff --git a/sopel_modules/SpiceBot/Database.py b/sopel_modules/SpiceBot/Database.py index 154b2b6..461c96f 100644 --- a/sopel_modules/SpiceBot/Database.py +++ b/sopel_modules/SpiceBot/Database.py @@ -9,7 +9,6 @@ from sopel.tools import Identifier import sopel.db from sopel.db import SopelDB, _deserialize, NickValues, ChannelValues -import threading from .Config import config as botconfig from sqlalchemy import Column, String @@ -82,6 +81,50 @@ class SpiceDB(object): finally: session.close() + def adjust_nick_list(self, nick, key, entries, adjustmentdirection): + """Sets the value for a given key to be associated with the nick.""" + nick = Identifier(nick) + if not isinstance(entries, list): + entries = [entries] + entries = json.dumps(entries, ensure_ascii=False) + nick_id = self.get_nick_id(nick) + session = self.ssession() + try: + result = session.query(NickValues) \ + .filter(NickValues.nick_id == nick_id) \ + .filter(NickValues.key == key) \ + .one_or_none() + # NickValue exists, update + if result: + if adjustmentdirection == 'add': + for entry in entries: + if entry not in result.value: + result.value.append(entry) + elif adjustmentdirection == 'del': + for entry in entries: + while entry in result.value: + result.value.remove(entry) + session.commit() + # DNE - Insert + else: + values = [] + if adjustmentdirection == 'add': + for entry in entries: + if entry not in values: + values.append(entry) + elif adjustmentdirection == 'del': + for entry in entries: + while entry in values: + values.remove(entry) + new_nickvalue = NickValues(nick_id=nick_id, key=key, value=values) + session.add(new_nickvalue) + session.commit() + except SQLAlchemyError: + session.rollback() + raise + finally: + session.close() + # CHANNEL FUNCTIONS def delete_channel_value(self, channel, key): @@ -128,6 +171,49 @@ class SpiceDB(object): finally: session.close() + def adjust_channel_list(self, channel, key, entries, adjustmentdirection): + """Sets the value for a given key to be associated with the channel.""" + channel = Identifier(channel).lower() + if not isinstance(entries, list): + entries = [entries] + entries = json.dumps(entries, ensure_ascii=False) + session = self.ssession() + try: + result = session.query(ChannelValues) \ + .filter(ChannelValues.channel == channel)\ + .filter(ChannelValues.key == key) \ + .one_or_none() + # ChannelValue exists, update + if result: + if adjustmentdirection == 'add': + for entry in entries: + if entry not in result.value: + result.value.append(entry) + elif adjustmentdirection == 'del': + for entry in entries: + while entry in result.value: + result.value.remove(entry) + session.commit() + # DNE - Insert + else: + values = [] + if adjustmentdirection == 'add': + for entry in entries: + if entry not in values: + values.append(entry) + elif adjustmentdirection == 'del': + for entry in entries: + while entry in values: + values.remove(entry) + new_channelvalue = ChannelValues(channel=channel, key=key, value=values) + session.add(new_channelvalue) + session.commit() + except SQLAlchemyError: + session.rollback() + raise + finally: + session.close() + # PLUGIN FUNCTIONS def set_plugin_value(self, plugin, key, value): @@ -173,6 +259,25 @@ class SpiceDB(object): finally: session.close() + def delete_plugin_value(self, plugin, key): + """Deletes the value for a given key to be associated with the plugin.""" + plugin = Identifier(plugin).lower() + session = self.ssession() + try: + result = session.query(PluginValues) \ + .filter(PluginValues.plugin == plugin)\ + .filter(PluginValues.key == key) \ + .one_or_none() + # PluginValues exists, delete + if result: + session.delete(result) + session.commit() + except SQLAlchemyError: + session.rollback() + raise + finally: + session.close() + def adjust_plugin_value(self, plugin, key, value): """Sets the value for a given key to be associated with the plugin.""" plugin = Identifier(plugin).lower() @@ -198,18 +303,42 @@ class SpiceDB(object): finally: session.close() - def delete_plugin_value(self, plugin, key): - """Deletes the value for a given key to be associated with the plugin.""" + def adjust_plugin_list(self, plugin, key, entries, adjustmentdirection): + """Sets the value for a given key to be associated with the plugin.""" plugin = Identifier(plugin).lower() + if not isinstance(entries, list): + entries = [entries] + entries = json.dumps(entries, ensure_ascii=False) session = self.ssession() try: result = session.query(PluginValues) \ .filter(PluginValues.plugin == plugin)\ .filter(PluginValues.key == key) \ .one_or_none() - # PluginValues exists, delete + # ChannelValue exists, update if result: - session.delete(result) + if adjustmentdirection == 'add': + for entry in entries: + if entry not in result.value: + result.value.append(entry) + elif adjustmentdirection == 'del': + for entry in entries: + while entry in result.value: + result.value.remove(entry) + session.commit() + # DNE - Insert + else: + values = [] + if adjustmentdirection == 'add': + for entry in entries: + if entry not in values: + values.append(entry) + elif adjustmentdirection == 'del': + for entry in entries: + while entry in values: + values.remove(entry) + new_pluginvalue = PluginValues(plugin=plugin, key=key, value=values) + session.add(new_pluginvalue) session.commit() except SQLAlchemyError: session.rollback() @@ -222,378 +351,91 @@ class BotDatabase(): """A thread safe database cache""" def __init__(self): - self.lock = threading.Lock() - self.dict = { - "nicks": {}, - "channels": {}, - } SopelDB.delete_nick_value = SpiceDB.delete_nick_value SopelDB.adjust_nick_value = SpiceDB.adjust_nick_value + SopelDB.adjust_nick_list = SpiceDB.adjust_nick_list SopelDB.delete_channel_value = SpiceDB.delete_channel_value SopelDB.adjust_channel_value = SpiceDB.adjust_channel_value + SopelDB.adjust_channel_list = SpiceDB.adjust_channel_list sopel.db.PluginValues = PluginValues SopelDB.get_plugin_value = SpiceDB.get_plugin_value SopelDB.set_plugin_value = SpiceDB.set_plugin_value SopelDB.delete_plugin_value = SpiceDB.delete_plugin_value SopelDB.adjust_plugin_value = SpiceDB.adjust_plugin_value + SopelDB.adjust_plugin_list = SpiceDB.adjust_plugin_list self.db = SopelDB(botconfig.config) """Nick""" - def get_nick_value(self, nick, key, sorting_key='defaultindex'): + def get_nick_value(self, nick, key): + return self.db.get_nick_value(nick, key) - self.lock.acquire() + def set_nick_value(self, nick, key, value): + return self.db.set_nick_value(nick, key, value) - nick = Identifier(nick) - nick_id = self.db.get_nick_id(nick, create=True) + def delete_nick_value(self, nick, key): + return self.db.delete_nick_value(nick, key) - if nick_id not in self.dict["nicks"].keys(): - self.dict["nicks"][nick_id] = {} + def adjust_nick_value(self, nick, key, value): + return self.db.adjust_nick_value(nick, key, value) - if sorting_key not in self.dict["nicks"][nick_id].keys(): - self.dict["nicks"][nick_id][sorting_key] = self.db.get_nick_value(nick, sorting_key) or dict() - - self.lock.release() - - if key not in self.dict["nicks"][nick_id][sorting_key].keys(): - return None - else: - return self.dict["nicks"][nick_id][sorting_key][key] - - def set_nick_value(self, nick, key, value, sorting_key='defaultindex'): - - self.lock.acquire() - - nick = Identifier(nick) - nick_id = self.db.get_nick_id(nick, create=True) - - if nick_id not in self.dict["nicks"].keys(): - self.dict["nicks"][nick_id] = {} - - if sorting_key not in self.dict["nicks"][nick_id].keys(): - self.dict["nicks"][nick_id][sorting_key] = self.db.get_nick_value(nick, sorting_key) or dict() - - self.dict["nicks"][nick_id][sorting_key][key] = value - - self.db.set_nick_value(nick, sorting_key, self.dict["nicks"][nick_id][sorting_key]) - - self.lock.release() - - def delete_nick_value(self, nick, key, sorting_key='defaultindex'): - - self.lock.acquire() - - nick = Identifier(nick) - nick_id = self.db.get_nick_id(nick, create=True) - - if nick_id not in self.dict["nicks"].keys(): - self.dict["nicks"][nick_id] = {} - - if sorting_key not in self.dict["nicks"][nick_id].keys(): - self.dict["nicks"][nick_id][sorting_key] = self.db.get_nick_value(nick, sorting_key) or dict() - - del self.dict["nicks"][nick_id][sorting_key][key] - self.db.set_nick_value(nick, sorting_key, self.dict["nicks"][nick_id][sorting_key]) - - self.lock.release() - - def adjust_nick_value(self, nick, key, value, sorting_key='defaultindex'): - - self.lock.acquire() - - nick = Identifier(nick) - nick_id = self.db.get_nick_id(nick, create=True) - - if nick_id not in self.dict["nicks"].keys(): - self.dict["nicks"][nick_id] = {} - - if sorting_key not in self.dict["nicks"][nick_id].keys(): - self.dict["nicks"][nick_id][sorting_key] = self.db.get_nick_value(nick, sorting_key) or dict() - - if key not in self.dict["nicks"][nick_id][sorting_key].keys(): - oldvalue = [] - else: - oldvalue = self.dict["nicks"][nick_id][sorting_key][key] - - if not oldvalue: - self.dict["nicks"][nick_id][sorting_key][key] = value - else: - self.dict["nicks"][nick_id][sorting_key][key] = oldvalue + value - self.db.set_nick_value(nick, sorting_key, self.dict["nicks"][nick_id][sorting_key]) - - self.lock.release() - - def adjust_nick_list(self, nick, key, entries, adjustmentdirection, sorting_key='defaultindex'): - - self.lock.acquire() - - if not isinstance(entries, list): - entries = [entries] - - nick = Identifier(nick) - nick_id = self.db.get_nick_id(nick, create=True) - - if nick_id not in self.dict["nicks"].keys(): - self.dict["nicks"][nick_id] = {} - - if sorting_key not in self.dict["nicks"][nick_id].keys(): - self.dict["nicks"][nick_id][sorting_key] = self.db.get_nick_value(nick, sorting_key) or dict() - - if key not in self.dict["nicks"][nick_id][sorting_key].keys(): - self.dict["nicks"][nick_id][sorting_key][key] = [] - - if adjustmentdirection == 'add': - for entry in entries: - if entry not in self.dict["nicks"][nick_id][sorting_key][key]: - self.dict["nicks"][nick_id][sorting_key][key].append(entry) - elif adjustmentdirection == 'del': - for entry in entries: - while entry in self.dict["nicks"][nick_id][sorting_key][key]: - self.dict["nicks"][nick_id][sorting_key][key].remove(entry) - self.db.set_nick_value(nick, sorting_key, self.dict["nicks"][nick_id][sorting_key]) - - self.lock.release() + def adjust_nick_list(self, nick, key, entries, adjustmentdirection): + return self.db.adjust_nick_list(nick, key, entries, adjustmentdirection) """Bot""" - def get_bot_value(self, key, sorting_key='defaultindex'): - return self.get_nick_value(botconfig.nick, key, sorting_key) + def get_bot_value(self, key): + return self.db.get_nick_value(botconfig.nick, key) - def set_bot_value(self, key, value, sorting_key='defaultindex'): - return self.set_nick_value(botconfig.nick, key, value, sorting_key) + def set_bot_value(self, key, value): + return self.db.set_nick_value(botconfig.nick, key, value) - def delete_bot_value(self, key, sorting_key='defaultindex'): - return self.delete_nick_value(botconfig.nick, key, sorting_key) + def delete_bot_value(self, key): + return self.db.delete_nick_value(botconfig.nick, key) - def adjust_bot_value(self, key, value, sorting_key='defaultindex'): - return self.adjust_nick_value(botconfig.nick, key, value, sorting_key) + def adjust_bot_value(self, key, value): + return self.db.adjust_nick_value(botconfig.nick, key, value) - def adjust_bot_list(self, key, entries, adjustmentdirection, sorting_key): - return self.adjust_nick_list(botconfig.nick, key, entries, adjustmentdirection, sorting_key) + def adjust_bot_list(self, key, entries, adjustmentdirection): + return self.db.adjust_nick_list(botconfig.nick, key, entries, adjustmentdirection) """Channels""" - def get_channel_value(self, channel, key, sorting_key='defaultindex'): + def get_channel_value(self, channel, key): + return self.db.get_channel_value(channel, key) - self.lock.acquire() + def set_channel_value(self, channel, key, value): + return self.db.set_channel_value(channel, key, value) - channel = Identifier(channel).lower().lower() + def delete_channel_value(self, channel, key): + return self.db.delete_channel_value(channel, key) - if channel not in self.dict["channels"].keys(): - self.dict["channels"][channel] = {} + def adjust_channel_value(self, channel, key, value): + return self.db.adjust_channel_value(channel, key, value) - if sorting_key not in self.dict["channels"][channel].keys(): - self.dict["channels"][channel][sorting_key] = self.db.get_channel_value(channel, sorting_key) or dict() - - self.lock.release() - - if key not in self.dict["channels"][channel][sorting_key].keys(): - return None - else: - return self.dict["channels"][channel][sorting_key][key] - - def set_channel_value(self, channel, key, value, sorting_key='defaultindex'): - - self.lock.acquire() - - channel = Identifier(channel).lower() - - if channel not in self.dict["channels"].keys(): - self.dict["channels"][channel] = {} - - if sorting_key not in self.dict["channels"][channel].keys(): - self.dict["channels"][channel][sorting_key] = self.db.get_channel_value(channel, sorting_key) or dict() - - self.dict["channels"][channel][sorting_key][key] = value - self.db.set_channel_value(channel, sorting_key, self.dict["channels"][channel][sorting_key]) - - self.lock.release() - - def delete_channel_value(self, channel, key, sorting_key='defaultindex'): - - self.lock.acquire() - - channel = Identifier(channel).lower() - - if channel not in self.dict["channels"].keys(): - self.dict["channels"][channel] = {} - - if sorting_key not in self.dict["channels"][channel].keys(): - self.dict["channels"][channel][sorting_key] = self.db.get_channel_value(channel, sorting_key) or dict() - - del self.dict["channels"][channel][sorting_key][key] - self.db.set_channel_value(channel, sorting_key, self.dict["channels"][channel][sorting_key]) - - self.lock.release() - - def adjust_channel_value(self, channel, key, value, sorting_key='defaultindex'): - - self.lock.acquire() - - channel = Identifier(channel).lower() - - if channel not in self.dict["channels"].keys(): - self.dict["channels"][channel] = {} - - if sorting_key not in self.dict["channels"][channel].keys(): - self.dict["channels"][channel][sorting_key] = self.db.get_channel_value(channel, sorting_key) or dict() - - if key not in self.dict["channels"][channel][sorting_key].keys(): - oldvalue = None - else: - oldvalue = self.dict["channels"][channel][sorting_key][key] - - if not oldvalue: - self.dict["channels"][channel][sorting_key][key] = value - else: - self.dict["channels"][channel][sorting_key][key] = oldvalue + value - self.db.set_channel_value(channel, sorting_key, self.dict["channels"][channel][sorting_key]) - - self.lock.release() - - def adjust_channel_list(self, channel, key, entries, adjustmentdirection, sorting_key='defaultindex'): - - self.lock.acquire() - - if not isinstance(entries, list): - entries = [entries] - - channel = Identifier(channel).lower() - - if channel not in self.dict["channels"].keys(): - self.dict["channels"][channel] = {} - - if sorting_key not in self.dict["channels"][channel].keys(): - self.dict["channels"][channel][sorting_key] = self.db.get_channel_value(channel, sorting_key) or dict() - - if key not in self.dict["channels"][channel][sorting_key].keys(): - self.dict["channels"][channel][sorting_key][key] = [] - - if adjustmentdirection == 'add': - for entry in entries: - if entry not in self.dict["channels"][channel][sorting_key][key]: - self.dict["channels"][channel][sorting_key][key].append(entry) - elif adjustmentdirection == 'del': - for entry in entries: - while entry in self.dict["channels"][channel][sorting_key][key]: - self.dict["channels"][channel][sorting_key][key].remove(entry) - self.db.set_channel_value(channel, sorting_key, self.dict["channels"][channel][sorting_key]) - - self.lock.release() + def adjust_channel_list(self, nick, key, entries, adjustmentdirection): + return self.db.adjust_channel_list(nick, key, entries, adjustmentdirection) """Plugins""" - def get_plugin_value(self, plugin, key, sorting_key='defaultindex'): + def get_plugin_value(self, plugin, key): + return self.db.get_plugin_value(plugin, key) - self.lock.acquire() + def set_plugin_value(self, plugin, key, value): + return self.db.set_plugin_value(plugin, key, value) - plugin = plugin.lower() + def delete_plugin_value(self, plugin, key): + return self.db.delete_plugin_value(plugin, key) - if plugin not in self.dict["plugins"].keys(): - self.dict["plugins"][plugin] = {} + def adjust_plugin_value(self, plugin, key, value): + return self.db.adjust_plugin_value(plugin, key, value) - if sorting_key not in self.dict["plugins"][plugin].keys(): - self.dict["plugins"][plugin][sorting_key] = self.db.get_plugin_value(plugin, sorting_key) or dict() - - self.lock.release() - - if key not in self.dict["plugins"][plugin][sorting_key].keys(): - return None - else: - return self.dict["plugins"][plugin][sorting_key][key] - - def set_plugin_value(self, plugin, key, value, sorting_key='defaultindex'): - - self.lock.acquire() - - plugin = plugin.lower() - - if plugin not in self.dict["plugins"].keys(): - self.dict["plugins"][plugin] = {} - - if sorting_key not in self.dict["plugins"][plugin].keys(): - self.dict["plugins"][plugin][sorting_key] = self.db.get_plugin_value(plugin, sorting_key) or dict() - - self.dict["plugins"][plugin][sorting_key][key] = value - self.db.set_plugin_value(plugin, sorting_key, self.dict["plugins"][plugin][sorting_key]) - - self.lock.release() - - def delete_plugin_value(self, plugin, key, sorting_key='defaultindex'): - - self.lock.acquire() - - plugin = plugin.lower() - - if plugin not in self.dict["plugins"].keys(): - self.dict["plugins"][plugin] = {} - - if sorting_key not in self.dict["plugins"][plugin].keys(): - self.dict["plugins"][plugin][sorting_key] = self.db.get_plugin_value(plugin, sorting_key) or dict() - - del self.dict["plugins"][plugin][sorting_key][key] - self.db.set_plugin_value(plugin, sorting_key, self.dict["plugins"][plugin][sorting_key]) - - self.lock.release() - - def adjust_plugin_value(self, plugin, key, value, sorting_key='defaultindex'): - - self.lock.acquire() - - plugin = plugin.lower() - - if plugin not in self.dict["plugins"].keys(): - self.dict["plugins"][plugin] = {} - - if sorting_key not in self.dict["plugins"][plugin].keys(): - self.dict["plugins"][plugin][sorting_key] = self.db.get_plugin_value(plugin, sorting_key) or dict() - - if key not in self.dict["plugins"][plugin][sorting_key].keys(): - oldvalue = None - else: - oldvalue = self.dict["plugins"][plugin][sorting_key][key] - - if not oldvalue: - self.dict["plugins"][plugin][sorting_key][key] = value - else: - self.dict["plugins"][plugin][sorting_key][key] = oldvalue + value - self.db.set_plugin_value(plugin, sorting_key, self.dict["plugins"][plugin][sorting_key]) - - self.lock.release() - - def adjust_plugin_list(self, plugin, key, entries, adjustmentdirection, sorting_key='defaultindex'): - - self.lock.acquire() - - if not isinstance(entries, list): - entries = [entries] - - plugin = plugin.lower() - - if plugin not in self.dict["plugins"].keys(): - self.dict["plugins"][plugin] = {} - - if sorting_key not in self.dict["plugins"][plugin].keys(): - self.dict["plugins"][plugin][sorting_key] = self.db.get_plugin_value(plugin, sorting_key) or dict() - - if key not in self.dict["plugins"][plugin][sorting_key].keys(): - self.dict["plugins"][plugin][sorting_key][key] = [] - - if adjustmentdirection == 'add': - for entry in entries: - if entry not in self.dict["plugins"][plugin][sorting_key][key]: - self.dict["plugins"][plugin][sorting_key][key].append(entry) - elif adjustmentdirection == 'del': - for entry in entries: - while entry in self.dict["plugins"][plugin][sorting_key][key]: - self.dict["plugins"][plugin][sorting_key][key].remove(entry) - self.db.set_plugin_value(plugin, sorting_key, self.dict["plugins"][plugin][sorting_key]) - - self.lock.release() + def adjust_plugin_list(self, nick, key, entries, adjustmentdirection): + return self.db.adjust_plugin_list(nick, key, entries, adjustmentdirection) db = BotDatabase() diff --git a/sopel_modules/SpiceBot/Prerun.py b/sopel_modules/SpiceBot/Prerun.py index dce2c5b..6dc0cf5 100644 --- a/sopel_modules/SpiceBot/Prerun.py +++ b/sopel_modules/SpiceBot/Prerun.py @@ -106,7 +106,7 @@ class BotPrerun(): # don't run commands that are disabled in channels if not trigger.is_privmsg: - disabled_list = botdb.get_channel_value(trigger.sender, 'disabled_commands', 'commands') or {} + disabled_list = botdb.get_channel_value(trigger.sender, 'commands_disabled') or {} if trigger.sb["realcom"] in disabled_list.keys(): reason = disabled_list[trigger.sb["realcom"]]["reason"] timestamp = disabled_list[trigger.sb["realcom"]]["timestamp"] @@ -161,7 +161,7 @@ class BotPrerun(): bot.osd("This command must be run in a channel you which to enable it in.", trigger.nick, 'notice') return - if not commands.check_disabled_commands(bot, trigger.sb["realcom"], trigger.sender): + if not commands.check_commands_disabled(bot, trigger.sb["realcom"], trigger.sender): bot.osd(trigger.sb["com"] + " is already enabled in " + str(trigger.sender), trigger.nick, 'notice') return @@ -179,7 +179,7 @@ class BotPrerun(): bot.osd("This command must be run in a channel you which to disable it in.", trigger.nick, 'notice') return - if commands.check_disabled_commands(bot, trigger.sb["realcom"], trigger.sender): + if commands.check_commands_disabled(bot, trigger.sb["realcom"], trigger.sender): bot.osd(trigger.sb["com"] + " is already disabled in " + str(trigger.sender), trigger.nick, 'notice') return