Make bot run and fwarn partially work

This commit is contained in:
skizzerz 2016-06-06 18:44:45 -05:00
parent 2d2ce6483a
commit bba5ab745e
4 changed files with 293 additions and 72 deletions

View File

@ -796,27 +796,41 @@
"villagergame_win": "Game over! The villagers come to their senses and realize there are actually no wolves, and live in harmony forevermore. Everybody wins.",
"villagergame_nope": "Game over! The villagers decided incorrectly that there are actually no wolves, allowing the wolves to slaughter the remainder of them in their sleep with impunity.",
"stop_bot_ingame_safeguard": "Warning: A game is currently running. If you want to {what} the bot anyway, use \"{prefix}{cmd} -force\".",
"fwarn_usage": "Usage: fwarn list|view|add|del|help. See fwarn help <subcommand> for more details.",
"fwarn_usage": "Usage: fwarn list|view|add|del|set|help. See fwarn help <subcommand> for more details.",
"fwarn_list_syntax": "Usage: fwarn list [-all] [nick[!user@host]|=account] [page]",
"fwarn_view_syntax": "Usage: fwarn view <id>",
"fwarn_del_syntax": "Usage: fwarn del <id> <reason>",
"fwarn_del_syntax": "Usage: fwarn del <id>",
"fwarn_set_syntax": "Usage: fwarn set <id> <reason> [| notes]",
"fwarn_help_syntax": "Usage: fwarn help <subcommand>",
"fwarn_add_syntax": "Usage: fwarn add <nick[!user@host]|=account> [@]<points> [~expiry] [sanctions] <:reason> [| notes]",
"fwarn_page_invalid": "Invalid page, must be a number 1 or greater.",
"fwarn_points_invalid": "Invalid points, must be a number above 0.",
"fwarn_expiry_invalid_suffix": "Invalid expiration suffix, must use either d, h, or m.",
"fwarn_cannot_add": "Cannot add warning, double-check your parameters (the nick might be wrong or you are not joined to the channel).",
"fwarn_added": "Added warning {0}.",
"fwarn_done": "Done.",
"fwarn_sanction_invalid": "Invalid sanction, can be either deny or stasis.",
"fwarn_stasis_invalid": "Invalid stasis amount, specify sanction as stasis=number.",
"fwarn_deny_invalid": "Invalid denied commands, specify sanction as deny=command,command,command without spaces.",
"fwarn_deny_invalid_command": "Invalid command \"{0}\", specify sanction as deny=command,command,command without spaces.",
"fwarn_list_header": "{0} has {1} active warning points.",
"fwarn_list": "{0}{1}[#{2} {3}] {4} by {5} - {6} ({7}, {8}){9}",
"fwarn_list": "{0}{1}[#{2} {3}] to {4} by {5} - {6} ({7} points, {8}){9}",
"fwarn_deleted": "deleted",
"fwarn_expired": "expired",
"fwarn_never_expires": "never expires",
"fwarn_list_footer": "More results are available, use fwarn list {0} to view them.",
"fwarn_list_empty": "No results.",
"fwarn_invalid_warning": "The specified warning id does not exist or you do not have permission to view it.",
"fwarn_view_header": "Warning #{0}, given to {1} on {2} by {3}. {4} points. {5}.",
"fwarn_view_active": "Currently active, {0}",
"fwarn_view_expires": "expires on {0}",
"fwarn_view_expired": "Expired on {0}",
"fwarn_view_deleted": "Deleted on {0} by {1}",
"fwarn_view_ack": "Warning has not yet been acknowledged.",
"fwarn_view_sanctions": "Sanctions:",
"fwarn_view_stasis": "{0} games of stasis.",
"fwarn_view_deny": "denied {0}.",
"fwarn_reason_required": "A public warning reason is required.",
"_": " vim: set sw=4 expandtab:"
}

118
src/db.py
View File

@ -1,3 +1,4 @@
import botconfig
import src.settings as var
import sqlite3
import os
@ -265,6 +266,8 @@ def get_flags(acc, hostmask):
ON at.id = a.template
WHERE a.person = ?""", (peid,))
row = c.fetchone()
if row is None:
return ""
return row[0]
def get_denied_commands(acc, hostmask):
@ -312,17 +315,18 @@ def list_all_warnings(list_all=False, skip=0, show=0):
warning.issued,
warning.expires,
CASE WHEN warning.expires IS NULL OR warning.expires > datetime('now')
THEN 1 ELSE 0 END AS expired,
THEN 0 ELSE 1 END AS expired,
warning.acknowledged,
warning.deleted,
warning.reason
FROM warning
JOIN person pet
ON pet.id = warning.target
JOIN player plt
ON plt.id = pet.primary_player
LEFT JOIN pes
LEFT JOIN person pes
ON pes.id = warning.sender
LEFT JOIN pls
LEFT JOIN player pls
ON pls.id = pes.primary_player
"""
if not list_all:
@ -348,8 +352,8 @@ def list_all_warnings(list_all=False, skip=0, show=0):
"expires": row[5],
"expired": row[6],
"ack": row[7],
"deleted": row[8]},
"reason": row[9])
"deleted": row[8],
"reason": row[9]})
return warnings
def list_warnings(acc, hostmask, list_all=False, skip=0, show=0):
@ -363,17 +367,18 @@ def list_warnings(acc, hostmask, list_all=False, skip=0, show=0):
warning.issued,
warning.expires,
CASE WHEN warning.expires IS NULL OR warning.expires > datetime('now')
THEN 1 ELSE 0 END AS expired,
THEN 0 ELSE 1 END AS expired,
warning.acknowledged,
warning.deleted,
warning.reason
FROM warning
JOIN person pet
ON pet.id = warning.target
JOIN player plt
ON plt.id = pet.primary_player
LEFT JOIN pes
LEFT JOIN person pes
ON pes.id = warning.sender
LEFT JOIN pls
LEFT JOIN player pls
ON pls.id = pes.primary_player
WHERE
warning.target = ?
@ -404,9 +409,84 @@ def list_warnings(acc, hostmask, list_all=False, skip=0, show=0):
"reason": row[9]})
return warnings
def get_warning(warn_id, acc=None, hm=None):
pe, pl = _get_ids(acc, hm)
c = conn.cursor()
sql = """SELECT
warning.id,
COALESCE(plt.account, plt.hostmask) AS target,
COALESCE(pls.account, pls.hostmask, ?) AS sender,
warning.amount,
warning.issued,
warning.expires,
CASE WHEN warning.expires IS NULL OR warning.expires > datetime('now')
THEN 0 ELSE 1 END AS expired,
warning.acknowledged,
warning.deleted,
warning.reason,
warning.notes,
COALESCE(pld.account, pld.hostmask) AS deleted_by,
warning.deleted_on
FROM warning
JOIN person pet
ON pet.id = warning.target
JOIN player plt
ON plt.id = pet.primary_player
LEFT JOIN person pes
ON pes.id = warning.sender
LEFT JOIN player pls
ON pls.id = pes.primary_player
LEFT JOIN person ped
ON ped.id = warning.deleted_by
LEFT JOIN player pld
ON pld.id = ped.primary_player
WHERE
warning.id = ?
"""
params = (botconfig.NICK, warn_id)
if acc is not None and hm is not None:
sql += """ AND warning.target = ?
AND warning.deleted = 0"""
params = (botconfig.NICK, warn_id, peid)
c.execute(sql, params)
row = c.fetchone()
if not row:
return None
return {"id": row[0],
"target": row[1],
"sender": row[2],
"amount": row[3],
"issued": row[4],
"expires": row[5],
"expired": row[6],
"ack": row[7],
"deleted": row[8],
"reason": row[9],
"notes": row[10],
"deleted_by": row[11],
"deleted_on": row[12],
"sanctions": get_warning_sanctions(warn_id)}
def get_warning_sanctions(warn_id):
c = conn.cursor()
c.execute("SELECT sanction, data FROM warning_sanction WHERE warning=?", (warn_id,))
sanctions = {}
for sanc, data in c:
if sanc == "stasis":
sanctions["stasis"] = int(data)
elif sanc == "deny command":
if "deny" not in sanctions:
sanctions["deny"] = set()
sanctions["deny"].add(data)
return sanctions
def add_warning(tacc, thm, sacc, shm, amount, reason, notes, expires, need_ack):
teid, tlid = _get_ids(tacc, thm)
seid, slid = _get_ids(sacc, shm)
with conn:
c = conn.cursor()
c.execute("""INSERT INTO warning
(
@ -425,12 +505,34 @@ def add_warning(tacc, thm, sacc, shm, amount, reason, notes, expires, need_ack):
return c.lastrowid
def add_warning_sanction(warning, sanction, data):
with conn:
c = conn.cursor()
c.execute("""INSERT INTO warning_sanction
(warning, sanction, data)
VALUES
(?, ?, ?)""", (warning, sanction, data))
def del_warning(warning, acc, hm):
peid, plid = _get_ids(acc, hm)
with conn:
c = conn.cursor()
c.execute("""UPDATE warning
SET
acknowledged = 1,
deleted = 1,
deleted_on = datetime('now'),
deleted_by = ?
WHERE
id = ?
AND deleted = 0""", (peid, warning))
def set_warning(warning, reason, notes):
with conn:
c = conn.cursor()
c.execute("""UPDATE warning
SET reason = ?, notes = ?
WHERE id = ?""", (reason, notes, warning))
def _upgrade():
# no upgrades yet, once there are some, add methods like _add_table(), _add_column(), etc.
# that check for the existence of that table/column/whatever and adds/drops/whatevers them

View File

@ -10,7 +10,7 @@ from oyoyo.parse import parse_nick
import botconfig
import src.settings as var
from src.utilities import *
from src import logger
from src import logger, db
from src.messages import messages
adminlog = logger("audit.log")
@ -176,8 +176,9 @@ class cmd:
forced_owner_only = True
break
is_owner = var.is_owner(nick, ident, host)
if self.owner_only or forced_owner_only:
if var.is_owner(nick, ident, host):
if is_owner:
adminlog(chan, rawnick, self.name, rest)
return self.func(*largs)
@ -190,13 +191,14 @@ class cmd:
# TODO: cache flags and cmds (below) on init, possibly store in var.USERS
# that would greatly reduce our db calls
flags = db.get_flags(acc, hostmask)
if self.flag and self.flag in flags:
is_full_admin = "F" in flags
if self.flag and (is_full_admin or is_owner):
adminlog(chan, rawnick, self.name, rest)
return self.func(*largs)
denied_cmds = db.get_denied_commands(acc, hostmask)
for command in self.cmds:
if command in denied_commands:
if command in denied_cmds:
if chan == nick:
pm(cli, nick, messages["invalid_permissions"])
else:
@ -204,7 +206,10 @@ class cmd:
return
if self.flag:
if chan == nick:
if self.flag in flags:
adminlog(chan, rawnick, self.name, rest)
return self.func(*largs)
elif chan == nick:
pm(cli, nick, messages["not_an_admin"])
else:
cli.notice(nick, messages["not_an_admin"])
@ -240,3 +245,5 @@ class hook:
HOOKS[each].remove(inner)
if not HOOKS[each]:
del HOOKS[each]
# vim: set sw=4 expandtab:

View File

@ -8018,9 +8018,10 @@ def fwarn(cli, nick, chan, rest):
# is not online, interpreted as an account name. To specify an account if nick is online,
# use =account. If not specified, shows all warnings on the bot.
# !fwarn view <id> - views details on warning id
# !fwarn del <id> <reason> - deletes warning id
# !fwarn del <id> - deletes warning id
# !fwarn set <id> <reason> [| notes]
# !fwarn add <nick> [@]<points> [~expiry] [sanctions] <:reason> [| notes]
# e.g. !fwarn add lykos @1 ~30d deny=goat,stats stasis=5 :Spamming|I secretly just hate him
# e.g. !fwarn add lykos @1 ~30d deny=goat,gstats stasis=5 :Spamming | I secretly just hate him
# nick => nick to warn. Can also be a hostmask in nick!user@host form. If nick is not online,
# interpreted as an account name. To specify an account if nick is online, use =account.
# @ => warning requires acknowledgement before user can !join again
@ -8035,7 +8036,7 @@ def fwarn(cli, nick, chan, rest):
# in reasons (no escaping is performed).
params = re.split(" +", rest)
nick = None
target = None
points = None
need_ack = False
expiry = None
@ -8055,8 +8056,8 @@ def fwarn(cli, nick, chan, rest):
except IndexError:
reply(cli, nick, chan, messages["fwarn_help_syntax"])
return
if subcommand not in ("list", "view", "add", "del", "help"):
reply(cli, nick, chan, messages["fwarn_invalid_subcommand"])
if subcommand not in ("list", "view", "add", "del", "set", "help"):
reply(cli, nick, chan, messages["fwarn_usage"])
return
reply(cli, nick, chan, messages["fwarn_{0}_syntax".format(subcommand)])
return
@ -8066,12 +8067,12 @@ def fwarn(cli, nick, chan, rest):
page = 1
try:
list_all = params.pop(0)
nick = params.pop(0)
target = params.pop(0)
page = int(params.pop(0))
if list_all and list_all != "-all":
if nick is not None:
page = int(nick)
nick = list_all
if target is not None:
page = int(target)
target = list_all
list_all = False
elif show_all == "-all":
list_all = True
@ -8080,14 +8081,14 @@ def fwarn(cli, nick, chan, rest):
except ValueError:
reply(cli, nick, chan, messages["fwarn_page_invalid"])
return
if nick is not None:
acc, hm = parse_warning_target(nick)
if target is not None:
acc, hm = parse_warning_target(target)
if acc is None and hm is None:
reply(cli, nick, chan, messages["fwarn_nick_invalid"])
return
warnings = db.list_warnings(acc, hm, list_all=list_all, skip=(page-1)*10, show=11)
points = db.get_warning_points(acc, hm)
reply(cli, nick, chan, messages["fwarn_list_header"].format(nick, points))
reply(cli, nick, chan, messages["fwarn_list_header"].format(target, points))
else:
warnings = db.list_all_warnings(list_all=list_all, skip=(page-1)*10, show=11)
@ -8098,8 +8099,8 @@ def fwarn(cli, nick, chan, rest):
parts = []
if list_all:
parts.append("-all")
if nick is not None:
parts.append(nick)
if target is not None:
parts.append(target)
parts.append(str(page + 1))
reply(cli, nick, chan, messages["fwarn_list_footer"].format(" ".join(parts)))
break
@ -8109,29 +8110,123 @@ def fwarn(cli, nick, chan, rest):
expires = warn["expires"] if warn["expires"] is not None else messages["fwarn_never_expires"]
if warn["deleted"]:
start = "\u000314"
end = " [\u00033{0}\u000314]\u0003".format(messages["fwarn_deleted"])
end = " [\u00034{0}\u000314]\u0003".format(messages["fwarn_deleted"])
elif warn["expired"]:
start = "\u000314"
end = " [\u00037{1}\u000314]\u0003".format(messages["fwarn_expired"])
if not warn["acknowledged"]:
end = " [\u00037{0}\u000314]\u0003".format(messages["fwarn_expired"])
if not warn["ack"]:
ack = "\u0002!\u0002 "
reply(cli, nick, chan, messages["fwarn_list"].format(
start, ack, warn["id"], warn["issued"], warn["target"],
warn["sender"], warn["reason"], warn["points"], expires, end))
warn["sender"], warn["reason"], warn["amount"], expires, end))
if i == 0:
reply(cli, nick, chan, messages["fwarn_list_empty"])
return
if command == "view":
try:
warn_id = int(params.pop(0))
except (IndexError, ValueError):
reply(cli, nick, chan, messages["fwarn_view_syntax"])
return
warning = db.get_warning(warn_id)
if warning is None:
reply(cli, nick, chan, messages["fwarn_invalid_warning"])
return
if warning["deleted"]:
expires = messages["fwarn_view_deleted"].format(warning["deleted_on"], warning["deleted_by"])
elif warning["expired"]:
expires = messages["fwarn_view_expired"].format(warning["expires"])
elif warning["expires"] is None:
expires = messages["fwarn_view_active"].format(messages["fwarn_never_expires"])
else:
expires = messages["fwarn_view_active"].format(messages["fwarn_view_expires"].format(warning["expires"]))
reply(cli, nick, chan, messages["fwarn_view_header"].format(
warning["id"], warning["target"], warning["issued"], warning["sender"],
warning["amount"], expires))
reason = [warning["reason"]]
if warning["notes"] is not None:
reason.append(warning["notes"])
reply(cli, nick, chan, " | ".join(reason))
sanctions = []
if not warning["ack"]:
sanctions.append(messages["fwarn_view_ack"])
if warning["sanctions"]:
sanctions.append(messages["fwarn_view_sanctions"])
if "stasis" in warning["sanctions"]:
sanctions.append(messages["fwarn_view_stasis"].format(warning["sanctions"]["stasis"]))
if "deny" in warning["sanctions"]:
sanctions.append(messages["fwarn_view_deny"].format(", ".join(warning["sanctions"]["deny"])))
if sanctions:
reply(cli, nick, chan, " ".join(sanctions))
return
if command == "del":
try:
warn_id = int(params.pop(0))
except (IndexError, ValueError):
reply(cli, nick, chan, messages["fwarn_del_syntax"])
return
warning = db.get_warning(warn_id)
if warning is None:
reply(cli, nick, chan, messages["fwarn_invalid_warning"])
return
acc, hm = parse_warning_target(nick)
db.del_warning(warn_id, acc, hm)
reply(cli, nick, chan, messages["fwarn_done"])
return
if command == "set":
try:
warn_id = int(params.pop(0))
except (IndexError, ValueError):
reply(cli, nick, chan, messages["fwarn_del_syntax"])
return
warning = db.get_warning(warn_id)
if warning is None:
reply(cli, nick, chan, messages["fwarn_invalid_warning"])
return
rsp = " ".join(params).split("|", 1)
if len(rsp) == 1:
rsp.append(None)
reason, notes = rsp
reason = reason.strip()
if not reason:
reply(cli, nick, chan, messages["fwarn_reason_required"])
return
# maintain existing notes if none were specified
if notes is not None:
notes = notes.strip()
if not notes:
notes = None
else:
notes = warning["notes"]
db.set_warning(warn_id, reason, notes)
reply(cli, nick, chan, messages["fwarn_done"])
return
if command != "add":
reply(cli, nick, chan, messages["fwarn_invalid_subcommand"])
reply(cli, nick, chan, messages["fwarn_usage"])
return
# command == "add"
while params:
p = params.pop(0)
if nick is None:
# figuring out what nick actually is is handled in add_warning
nick = p
if target is None:
# figuring out what target actually is is handled in add_warning
target = p
elif points is None:
points = p
if points[0] == "@":
@ -8148,13 +8243,10 @@ def fwarn(cli, nick, chan, rest):
elif notes is not None:
notes += " " + p
elif reason is not None:
if p[0] == "|":
if p == "|":
notes = ""
else:
notes = p[1:]
continue
reason += " " + p
rsp = p.split("|", 1)
if len(rsp) > 1:
notes = rsp[1]
reason += " " + rsp[0]
elif p[0] == ":":
if p == ":":
reason = ""
@ -8167,7 +8259,7 @@ def fwarn(cli, nick, chan, rest):
expiry = p[1:]
else:
# sanctions are the only thing left here
sanc = p.split("=", 2)
sanc = p.split("=", 1)
if sanc[0] == "deny":
try:
cmds = sanc[1].split(",")
@ -8193,15 +8285,15 @@ def fwarn(cli, nick, chan, rest):
elif sanc[0] == "stasis":
try:
sanctions["stasis"] = int(sanc[1])
except IndexError, ValueError:
except (IndexError, ValueError):
reply(cli, nick, messages["fwarn_stasis_invalid"])
return
else:
reply(cli, nick, chan, messages["fwarn_sanction_invalid"])
return
if nick is None or points is None or reason is None:
cli.notice(nick, messages["fwarn_syntax"])
if target is None or points is None or reason is None:
reply(cli, nick, chan, messages["fwarn_add_syntax"])
return
reason = reason.strip()
@ -8221,6 +8313,12 @@ def fwarn(cli, nick, chan, rest):
reply(cli, nick, chan, messages["fwarn_expiry_invalid_suffix"])
return
warn_id = add_warning(target, amount, nick, reason, notes, expires, need_ack, sanctions)
if warn_id is False:
reply(cli, nick, chan, messages["fwarn_cannot_add"])
else:
reply(cli, nick, chan, messages["fwarn_added"].format(warn_id))
@cmd("wait", "w", playing=True, phases=("join",))
def wait(cli, nick, chan, rest):
"""Increases the wait time until !start can be used."""