nxy/bot/quotes.py

168 lines
5.2 KiB
Python
Raw Normal View History

2017-05-15 22:26:10 +00:00
# -*- coding: utf-8 -*-
2017-07-07 00:11:20 +00:00
import re
2017-05-15 22:26:10 +00:00
2017-08-22 13:57:57 +00:00
from docopt import Dict
2017-08-22 15:43:48 +00:00
from irc3.plugins.command import Commands, command
2017-05-16 10:06:29 +00:00
from irc3.utils import IrcString
from psycopg2 import Error
2017-05-16 10:06:29 +00:00
2017-08-22 15:43:48 +00:00
from . import DatabasePlugin, Bot
2019-12-08 19:35:10 +00:00
from .utils import is_int, parse_int
2017-05-15 22:26:10 +00:00
class Quotes(DatabasePlugin):
2017-08-22 15:43:48 +00:00
def __init__(self, bot: Bot):
super().__init__(bot)
self.guard = bot.get_plugin(Commands).guard
def add_quote(self, mask: IrcString, nick: str, quote: str, channel: IrcString):
# Parse nick from "<@foobar>" like strings
2017-07-07 00:11:20 +00:00
nick = re.match(r'<?[~&@%+]?([a-zA-Z0-9_\-^`|\\\[\]{}]+)>?', nick).group(1)
if not nick:
self.bot.notice(mask.nick, '[Quotes] Error parsing nick')
else:
# Insert quote into database
with self.con.cursor() as cur:
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):
2017-07-07 00:11:20 +00:00
index, order = parse_int(quote, select=False)
if index:
# Delete from database
with self.con.cursor() as cur:
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])
2017-05-15 22:26:10 +00:00
2019-04-24 17:48:19 +00:00
@command(options_first=True, quiet=True)
2017-08-22 13:57:57 +00:00
def q(self, mask: IrcString, target: IrcString, args: Dict):
"""Get, add or delete quotes for an user
2017-05-16 12:27:34 +00:00
2017-05-15 22:26:10 +00:00
%%q <cmd> <nick> <quote>...
2017-05-16 06:54:47 +00:00
%%q <nick> [<index>]
2017-05-15 22:26:10 +00:00
"""
cmd = args.get('<cmd>')
nick = args['<nick>']
2019-12-08 19:35:10 +00:00
quote = args.get('<quote>')
2019-12-08 19:35:10 +00:00
if (cmd == 'add' or cmd == 'del') and quote:
quote = ' '.join(quote)
try:
# Anybody can add
2017-05-16 06:54:47 +00:00
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)
2017-05-16 06:54:47 +00:00
self.con.commit()
2017-07-04 13:22:20 +00:00
except Error as ex:
# Rollback transaction on error
self.log.error(ex)
self.con.rollback()
2017-05-15 22:26:10 +00:00
else:
2019-12-08 19:35:10 +00:00
query = None
2017-05-16 06:54:47 +00:00
index = args.get('<index>')
2019-12-08 22:04:04 +00:00
where = []
values = []
2019-12-08 19:35:10 +00:00
# search query support
if cmd or index and not is_int(index):
if cmd:
query = nick
nick = cmd
else:
query = index
# if last entry in quotes list is a number, use it as the index
if quote and is_int(quote[-1]):
index = quote[-1]
quote = quote[:-1]
# else get random quote
else:
index = None
if quote:
query += ' ' + ' '.join(quote)
else:
quote = ' '.join(quote)
2019-12-08 22:04:04 +00:00
if nick != 'search' or not query:
where.append('nick ILIKE %s')
values.append(nick)
2019-12-08 19:35:10 +00:00
if query:
2019-12-08 22:04:04 +00:00
where.append('item ILIKE \'%%\' || %s || \'%%\'')
2019-12-08 19:35:10 +00:00
values.append(query)
2017-05-16 06:54:47 +00:00
if index:
index = parse_int(index)
if not index:
return
2017-07-07 00:11:20 +00:00
index, order = index
order = 'rank {order}'.format(order=order)
offset = 'OFFSET %s'
values.append(index)
2017-05-15 22:26:10 +00:00
else:
2017-05-16 06:54:47 +00:00
order = 'random()'
offset = ''
# Fetch quote from database
with self.con.cursor() as cur:
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
{where}
ORDER BY
{order}
LIMIT
1
{offset}
'''.format(where=' AND '.join(where), order=order, offset=offset), values)
result = cur.fetchone()
2017-05-16 06:54:47 +00:00
if result:
return '[{rank}/{total}] <{nick}> {item}'.format(**result)