banned/src/decorators.py

195 lines
6.3 KiB
Python

import fnmatch
from collections import defaultdict
import botconfig
from oyoyo.parse import parse_nick
from src import settings as var
from src import logger
adminlog = logger(None)
COMMANDS = defaultdict(list)
HOOKS = defaultdict(list)
class cmd:
def __init__(self, *cmds, raw_nick=False, admin_only=False, owner_only=False,
chan=True, pm=False, playing=False, silenced=False, phases=(), roles=()):
self.cmds = cmds
self.raw_nick = raw_nick
self.admin_only = admin_only
self.owner_only = owner_only
self.chan = chan
self.pm = pm
self.playing = playing
self.silenced = silenced
self.phases = phases
self.roles = roles
self.func = None
self.aftergame = False
self.name = cmds[0]
alias = False
self.aliases = []
for name in cmds:
for func in COMMANDS[name]:
if (func.owner_only != owner_only or
func.admin_only != admin_only):
raise ValueError("unmatching protection levels for " + func.name)
COMMANDS[name].append(self)
if alias:
self.aliases.append(self)
alias = True
def __call__(self, func):
self.func = func
self.__doc__ = self.func.__doc__
return self
def caller(self, *args):
largs = list(args)
cli, rawnick, chan, rest = largs
nick, mode, user, cloak = parse_nick(rawnick)
if cloak is None:
cloak = ""
if not self.raw_nick:
largs[1] = nick
if not self.pm and chan == nick:
return # PM command, not allowed
if not self.chan and chan != nick:
return # channel command, not allowed
if chan.startswith("#") and chan != botconfig.CHANNEL and not (admin_only or owner_only):
if "" in self.cmds:
return # don't have empty commands triggering in other channels
for command in self.cmds:
if command in botconfig.ALLOWED_ALT_CHANNELS_COMMANDS:
break
else:
return
if nick in var.USERS and var.USERS[nick]["account"] != "*":
acc = var.USERS[nick]["account"]
else:
acc = None
if "" in self.cmds:
return self.func(*largs)
if self.phases and var.PHASE not in self.phases:
return
if self.playing and (nick not in var.list_players() or nick in var.DISCONNECTED):
if chan == nick:
pm(cli, nick, "You're not currently playing.")
else:
cli.notice(nick, "You're not currently playing.")
return
if self.silenced and nick in var.SILENCED:
if chan == nick:
pm(cli, nick, "You have been silenced, and are unable to use any special powers.")
else:
cli.notice(nick, "You have been silenced, and are unable to use any special powers.")
return
if self.roles:
for role in self.roles:
if nick in var.ROLES[role]:
break
else:
return
return self.func(*largs) # don't check restrictions for role commands
if self.owner_only:
if var.is_owner(nick, cloak):
adminlog(chan, rawnick, self.name, rest)
return self.func(*largs)
if chan == nick:
pm(cli, nick, "You are not the owner.")
else:
cli.notice(nick, "You are not the owner.")
return
if not self.admin_only:
return self.func(*largs)
if var.is_admin(nick, cloak):
adminlog(chan, rawnick, self.name, rest)
return self.func(*largs)
if acc:
for pattern in var.DENY_ACCOUNTS:
if fnmatch.fnmatch(acc.lower(), pattern.lower()):
for command in self.cmds:
if command in var.DENY_ACCOUNTS[pattern]:
if chan == nick:
pm(cli, nick, "You do not have permission to use that command.")
else:
cli.notice(nick, "You do not have permission to use that command.")
return
for pattern in var.ALLOW_ACCOUNTS:
if fnmatch.fnmatch(acc.lower(), pattern.lower()):
for command in self.cmds:
if command in var.ALLOW_ACCOUNTS[pattern]:
adminlog(chan, rawnick, self.name, rest)
return self.func(*largs)
if not var.ACCOUNTS_ONLY and cloak:
for pattern in var.DENY:
if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
for command in self.cmds:
if command in var.DENY[pattern]:
if chan == nick:
pm(cli, nick, "You do not have permission to use that command.")
else:
cli.notice(nick, "You do not have permission to use that command.")
return
for pattern in var.ALLOW:
if fnmatch.fnmatch(cloak.lower(), pattern.lower()):
for command in self.cmds:
if command in var.ALLOW[pattern]:
adminlog(chan, rawnick, self.name, rest)
return self.func(*largs)
if chan == nick:
pm(cli, nick, "You are not an admin.")
else:
cli.notice(nick, "You are not an admin.")
return
class hook:
def __init__(self, name, hookid=-1):
self.name = name
self.hookid = hookid
self.func = None
HOOKS[name].append(self)
def __call__(self, func):
self.func = func
self.__doc__ = self.func.__doc__
return self
def caller(self, *args):
return self.func(*args)
@staticmethod
def unhook(hookid):
for each in list(HOOKS):
for inner in list(HOOKS[each]):
if inner.hookid == hookid:
HOOKS[each].remove(inner)
if not HOOKS[each]:
del HOOKS[each]