From cb8011aa67c62fa5ac67b89a34c8b878e237c498 Mon Sep 17 00:00:00 2001 From: mrhanky Date: Tue, 16 May 2017 07:45:10 +0200 Subject: [PATCH] Lots of stuff --- config.json | 9 ++--- nxy/bot.py | 2 -- nxy/plugins/__init__.py | 15 ++------ nxy/plugins/admin.py | 2 ++ nxy/plugins/bitcoin.py | 2 ++ nxy/plugins/ctcp.py | 2 ++ nxy/plugins/database.py | 18 ++++++++++ nxy/plugins/mcmaniac.py | 78 ++++++++++++++++++++++------------------- nxy/plugins/quotes.py | 11 +++--- nxy/plugins/useless.py | 6 ++-- nxy/utils.py | 20 ++++++++++- schema.sql | 12 +++++++ 12 files changed, 113 insertions(+), 64 deletions(-) create mode 100644 nxy/plugins/database.py create mode 100644 schema.sql diff --git a/config.json b/config.json index c0327d5..ae7bd01 100644 --- a/config.json +++ b/config.json @@ -5,7 +5,7 @@ "ssl": true, "raw": true, "autojoins": ["#nxy-dev"], - "storage": "json://data/db.json", + "storage": "sqlite://data/nxy.db", "flood_burst": 1, "flood_rate": 4, "flood_rate_delay": 1, @@ -13,11 +13,11 @@ "irc3.plugins.async", "irc3.plugins.cron", "irc3.plugins.command", - "irc3.plugins.storage", "irc3.plugins.uptime", "nxy.plugins.admin", "nxy.plugins.bitcoin", "nxy.plugins.ctcp", + "nxy.plugins.database", "nxy.plugins.mcmaniac", "nxy.plugins.quotes", "nxy.plugins.reminder", @@ -28,8 +28,9 @@ "guard": "irc3.plugins.command.mask_based_policy" }, "irc3.plugins.command.masks": { - "*!ceo@cocaine-import.agency": "all_permissions", - "*!ceo@unterschicht.tv": "all_permissions", + "mrhanky!mrhanky@cocaine-import.agency": "all_permissions", + "jkhsjdhjs!jkhsjdhjs@smoke.weed.everyday": "admin", + "sirx!sirx@n0xy.net": "admin", "*": "view" } } diff --git a/nxy/bot.py b/nxy/bot.py index 1217052..0858f7f 100644 --- a/nxy/bot.py +++ b/nxy/bot.py @@ -37,8 +37,6 @@ def main(cfg_file): if not os.path.exists(data): os.makedirs(data) bot = IrcBot.from_config(cfg) - if bool(os.environ.get('DEV')): - bot.con = sqlite3.connect('nxy.db') bot.run() diff --git a/nxy/plugins/__init__.py b/nxy/plugins/__init__.py index 6ee8b17..dd1eb05 100644 --- a/nxy/plugins/__init__.py +++ b/nxy/plugins/__init__.py @@ -17,16 +17,7 @@ class Plugin(BasePlugin): class DatabasePlugin(Plugin): - def __init__(self, bot: IrcBot): + def __init__(self, bot): super().__init__(bot) - # noinspection PyUnresolvedReferences - self._db = bot.db - self.prepare_db() - - @property - def db(self): - return self._db[self] - - def prepare_db(self): - if self not in self._db: - self._db[self] = {} + self.con = bot.con.db + self.cur = self.con.cursor() diff --git a/nxy/plugins/admin.py b/nxy/plugins/admin.py index 09487db..681a49e 100644 --- a/nxy/plugins/admin.py +++ b/nxy/plugins/admin.py @@ -3,6 +3,7 @@ from docopt import Dict as DocoptDict from irc3 import IrcBot from irc3.utils import IrcString from irc3.plugins.command import command +import irc3 from . import MODULE, Plugin @@ -18,5 +19,6 @@ def reload(bot: IrcBot, mask: IrcString, channel: IrcString, args: DocoptDict): bot.notice(mask.nick, 'Reloaded plugin "{plugin}"'.format(plugin=plugin)) +@irc3.plugin class Admin(Plugin): pass diff --git a/nxy/plugins/bitcoin.py b/nxy/plugins/bitcoin.py index 6bbe2e8..2491985 100644 --- a/nxy/plugins/bitcoin.py +++ b/nxy/plugins/bitcoin.py @@ -2,12 +2,14 @@ from docopt import Dict as DocOptDict from irc3.plugins.command import command from irc3.utils import IrcString +import irc3 from . import Plugin from ..utils import fmt, req # noinspection PyUnusedLocal +@irc3.plugin class Bitcoin(Plugin): requires = [ 'irc3.plugins.command', diff --git a/nxy/plugins/ctcp.py b/nxy/plugins/ctcp.py index 23496fe..efca263 100644 --- a/nxy/plugins/ctcp.py +++ b/nxy/plugins/ctcp.py @@ -3,12 +3,14 @@ from docopt import Dict as DocOptDict from irc3.plugins.command import command from irc3.utils import IrcString import time +import irc3 from . import Plugin from ..utils import fmt # noinspection PyUnusedLocal +@irc3.plugin class CTCP(Plugin): TIMEOUT = 5 diff --git a/nxy/plugins/database.py b/nxy/plugins/database.py new file mode 100644 index 0000000..20c8e4e --- /dev/null +++ b/nxy/plugins/database.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +import sqlite3 +import irc3 + +from . import Plugin + + +@irc3.plugin +class Database(Plugin): + def __init__(self, bot): + super().__init__(bot) + file = bot.config.storage.split('sqlite://', 1)[1] + if not file: + raise ValueError('Invalid database: {}'.format(bot.config.storage)) + self.db = sqlite3.connect(file) + self.db.row_factory = sqlite3.Row + self.bot = bot + self.bot.con = self diff --git a/nxy/plugins/mcmaniac.py b/nxy/plugins/mcmaniac.py index e66c924..c83a13f 100644 --- a/nxy/plugins/mcmaniac.py +++ b/nxy/plugins/mcmaniac.py @@ -1,24 +1,18 @@ # -*- coding: utf-8 -*- from docopt import Dict as DocOptDict from irc3.utils import IrcString -from irc3.plugins.command import command -import random -import irc3 +from irc3.plugins.command import command, Commands from . import DatabasePlugin from ..utils import parse_int -@irc3.plugin class McManiac(DatabasePlugin): requires = [ 'irc3.plugins.command', + 'nxy.plugins.database', ] - @property - def items(self): - return self.db['items'] - # noinspection PyUnusedLocal @command(options_first=True) def mcmaniac(self, mask: IrcString, channel: IrcString, args: DocOptDict): @@ -27,33 +21,43 @@ class McManiac(DatabasePlugin): %%mcmaniac [] """ cmd = args.get('') - mcmaniac = args.get('') - index = args.get('') - if cmd and mcmaniac: - if cmd == 'add': - if mcmaniac not in self.items: - self.items.append(mcmaniac) - if cmd == 'del': - try: - self.items.pop(parse_int(mcmaniac)) - except (IndexError, TypeError): - return - self._db.SIGINT() - elif self.items: - if index: - try: - mcmaniac = self.items[parse_int(index)] - except (IndexError, TypeError): - return + item = args.get('') + guard = self.bot.get_plugin(Commands).guard + if cmd and item: + if guard.has_permission(mask, 'admin'): + if cmd == 'add': + self.cur.execute('insert into mcmaniac (item) values (?)', + [item]) + if cmd == 'del': + order, index, op = parse_int(item, select=False) + if not index: + return + self.cur.execute('''delete from mcmaniac where id = + (select id from mcmaniac a where ? = (select count(id) + from mcmaniac b where a.id {op} b.id) order by id {order}) + '''.format(op=op, order=order), [index]) + self.con.commit() else: - mcmaniac = random.choice(self.items) - return '[{index}/{total}] {item}'.format( - index=self.items.index(mcmaniac) + 1, - total=len(self.items), - item=mcmaniac - ) - - def prepare_db(self): - super().prepare_db() - self._db.setdefault(self, items=[]) - self._db.SIGINT() + self.bot.notice(mask.nick, 'Permission denied') + else: + index = args.get('') + if index: + index = parse_int(index) + if not index: + return + order, index, _ = index + order = 'id {order}'.format(order=order) + extra = 'offset ?' + binds = [index] + else: + order = 'random()' + extra = '' + binds = [] + self.cur.execute('''select item, + (select count(id) from mcmaniac b where a.id >= b.id) as idx, + (select count(id) from mcmaniac) as len + from mcmaniac a order by {order} limit 1 {extra} + '''.format(order=order, extra=extra), binds) + item = self.cur.fetchone() + if item: + return '[{idx}/{len}] {item}'.format(**item) diff --git a/nxy/plugins/quotes.py b/nxy/plugins/quotes.py index ee72f6f..d8a9014 100644 --- a/nxy/plugins/quotes.py +++ b/nxy/plugins/quotes.py @@ -17,11 +17,10 @@ class Quotes(DatabasePlugin): ] REGEX = re.compile(r'?') - RESPONSE = '[{index}/{total}] <{nick}> {quote}' # noinspection PyUnusedLocal @command(options_first=True) - def q(self, mask: IrcString, channel: IrcString, args: DocOptDict): + def q(self, mask: IrcString, channel: IrcString, args: DocOptDict) -> str: """ Manage quotes. %%q ... @@ -44,19 +43,19 @@ class Quotes(DatabasePlugin): if not self.db[nick]: del self.db[nick] except (KeyError, IndexError, TypeError): - return + return '' self._db.SIGINT() else: if quote: try: quote = self.db[nick][parse_int(quote)] except (KeyError, IndexError, TypeError): - return + return '' else: quote = random.choice(self.db[nick]) - self.bot.privmsg(channel, self.RESPONSE.format( + return '[{index}/{total}] <{nick}> {quote}'.format( index=self.db[nick].index(quote) + 1, total=len(self.db[nick]), nick=nick, quote=quote, - )) + ) diff --git a/nxy/plugins/useless.py b/nxy/plugins/useless.py index d661b80..4bb7cb5 100644 --- a/nxy/plugins/useless.py +++ b/nxy/plugins/useless.py @@ -4,6 +4,7 @@ from irc3.plugins.command import command from irc3.utils import IrcString from irc3.dec import event import random +import irc3 from . import Plugin from ..utils import fmt @@ -16,11 +17,12 @@ GNU_LINUX = """I'd Just Like To Interject For A Moment. What you're referring to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it, GNU plus Linux. Linux is not an operating system unto itself, but rather another free component of a fully functioning GNU system made useful by the - GNU corelibs, shell utilities and vital system components comprising a full OS - as defined by POSIX.""" + GNU corelibs, shell utilities and vital system components comprising a full + OS as defined by POSIX.""" # noinspection PyUnusedLocal +@irc3.plugin class Useless(Plugin): requires = [ 'irc3.plugins.command', diff --git a/nxy/utils.py b/nxy/utils.py index 4b1e5a3..f41e63e 100644 --- a/nxy/utils.py +++ b/nxy/utils.py @@ -83,7 +83,25 @@ def time_to_sec(text: str) -> int: return num * 52 * 604800 -def parse_int(val: list) -> int: +def parse_int(val: str, select: bool = True) -> tuple: + try: + val = int(val) + if val is not 0: + if val < 1: + order = 'desc' + val *= -1 + op = '<=' + else: + order = 'asc' + op = '>=' + if select: + val -= 1 + return order, val, op + except ValueError: + pass + + +def _parse_int(val: list) -> int: """ Parses an int from list, decremts by -1 if positiv. Only returns if value from list is not 0. diff --git a/schema.sql b/schema.sql new file mode 100644 index 0000000..aa4ea93 --- /dev/null +++ b/schema.sql @@ -0,0 +1,12 @@ +create table if not exists quotes ( + id integer primary key autoincrement, + nick text not null, + value text not null, + unique (nick, value collate nocase) +); + +create table if not exists mcmaniac ( + id integer primary key autoincrement, + item text not null, + unique (item collate nocase) on conflict replace +);