# -*- coding: utf-8 -*- import re from docopt import Dict from irc3.plugins.command import command from irc3.utils import IrcString from psycopg2 import Error from . import DatabasePlugin from ..utils import parse_int class Quotes(DatabasePlugin): requires = ['irc3.plugins.command', 'bot.plugins.storage'] def add_quote(self, mask: IrcString, nick: str, quote: str, channel: IrcString): # Parse nick from "<@foobar>" like strings nick = re.match(r'?', nick).group(1) if not nick: self.bot.notice(mask.nick, '[Quotes] Error parsing nick') else: # Insert quote into database self.cur.execute(''' INSERT INTO quotes (nick, item, channel, created_by) VALUES (%s, %s, %s, %s) ''', [nick, quote, channel, mask.nick]) def delete_quote(self, nick: str, quote: str): index, order = parse_int(quote, select=False) if index: # Delete from database self.cur.execute(''' -- noinspection SqlResolve WITH ranked_quotes AS ( SELECT id, rank() OVER (PARTITION BY nick ORDER BY id {order}) FROM quotes WHERE lower(nick) = lower(%s) ) -- noinspection SqlResolve DELETE FROM quotes WHERE id = ( SELECT id FROM ranked_quotes WHERE rank = %s ) '''.format(order=order), [nick, index]) @command(options_first=True) def q(self, mask: IrcString, target: IrcString, args: Dict): """Get, add or delete quotes for an user %%q ... %%q [] """ cmd = args.get('') nick = args[''] quote = ' '.join(args.get('')) if cmd and quote: try: # Anybody can add if cmd == 'add': self.add_quote(mask, nick, quote, target) # But only admins can delete elif cmd == 'del' and self.guard.has_permission(mask, 'admin'): self.delete_quote(nick, quote) self.con.commit() except Error as ex: # Rollback transaction on error print(ex) self.con.rollback() else: index = args.get('') values = [nick] if index: index = parse_int(index) if not index: return index, order = index order = 'rank {order}'.format(order=order) offset = 'OFFSET %s' values.append(index) else: order = 'random()' offset = '' # Fetch quote from database self.cur.execute(''' WITH ranked_quotes AS ( SELECT nick, item, rank() OVER (PARTITION BY nick ORDER BY id), count(*) OVER (PARTITION BY nick) AS total FROM quotes ) SELECT * FROM ranked_quotes WHERE lower(nick) LIKE lower(%s) ORDER BY {order} LIMIT 1 {offset} '''.format(order=order, offset=offset), values) result = self.cur.fetchone() if result: return '[{rank}/{total}] <{nick}> {item}'.format(**result)