mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-27 05:09:23 +01:00
Aka: Add lock support.
This commit is contained in:
parent
b7a9569f72
commit
c49e088879
@ -31,6 +31,7 @@
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import datetime
|
||||||
|
|
||||||
import supybot.utils as utils
|
import supybot.utils as utils
|
||||||
from supybot.commands import *
|
from supybot.commands import *
|
||||||
@ -54,17 +55,22 @@ if sqlalchemy:
|
|||||||
__tablename__ = 'aliases'
|
__tablename__ = 'aliases'
|
||||||
|
|
||||||
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
|
id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
|
||||||
name = sqlalchemy.Column(sqlalchemy.String, unique=True)
|
name = sqlalchemy.Column(sqlalchemy.String, unique=True, nullable=False)
|
||||||
alias = sqlalchemy.Column(sqlalchemy.String)
|
alias = sqlalchemy.Column(sqlalchemy.String, nullable=False)
|
||||||
|
|
||||||
|
locked = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
|
||||||
|
locked_by = sqlalchemy.Column(sqlalchemy.String, nullable=True)
|
||||||
|
locked_at = sqlalchemy.Column(sqlalchemy.DateTime, nullable=True)
|
||||||
|
|
||||||
def __init__(self, name, alias):
|
def __init__(self, name, alias):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.alias = alias
|
self.alias = alias
|
||||||
|
self.locked = False
|
||||||
|
self.locked_by = None
|
||||||
|
self.locked_at = None
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Alias('%r', '%r')>" % (self.name, self.alias)
|
return "<Alias('%r', '%r')>" % (self.name, self.alias)
|
||||||
|
|
||||||
# TODO: Add table for locks
|
|
||||||
# TODO: Add table for usage statistics
|
# TODO: Add table for usage statistics
|
||||||
|
|
||||||
class SqlAlchemyAkaDB(object):
|
class SqlAlchemyAkaDB(object):
|
||||||
@ -110,7 +116,7 @@ if sqlalchemy:
|
|||||||
|
|
||||||
def add_aka(self, channel, name, alias):
|
def add_aka(self, channel, name, alias):
|
||||||
if self.has_aka(channel, name):
|
if self.has_aka(channel, name):
|
||||||
raise AliasError(_('This Aka already exists.'))
|
raise AkaError(_('This Aka already exists.'))
|
||||||
if sys.version_info[0] < 3:
|
if sys.version_info[0] < 3:
|
||||||
if isinstance(name, str):
|
if isinstance(name, str):
|
||||||
name = name.decode('utf8')
|
name = name.decode('utf8')
|
||||||
@ -125,6 +131,43 @@ if sqlalchemy:
|
|||||||
db.query(Alias).filter(Alias.name == name).delete()
|
db.query(Alias).filter(Alias.name == name).delete()
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
def lock_aka(self, channel, name, by):
|
||||||
|
db = self.get_db(channel)
|
||||||
|
try:
|
||||||
|
aka = db.query(Alias) \
|
||||||
|
.filter(Alias.name == name).one()
|
||||||
|
except sqlalchemy.orm.exc.NoResultFound:
|
||||||
|
raise AkaError(_('This Aka does not exist'))
|
||||||
|
if aka.locked:
|
||||||
|
raise AkaError(_('This Aka is already locked.'))
|
||||||
|
aka.locked = True
|
||||||
|
aka.locked_by = by
|
||||||
|
aka.locked_at = datetime.datetime.now()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def unlock_aka(self, channel, name, by):
|
||||||
|
db = self.get_db(channel)
|
||||||
|
try:
|
||||||
|
aka = db.query(Alias.alias) \
|
||||||
|
.filter(Alias.name == name).one()
|
||||||
|
except sqlalchemy.orm.exc.NoResultFound:
|
||||||
|
raise AkaError(_('This Aka does not exist'))
|
||||||
|
if aka.locked:
|
||||||
|
raise AkaError(_('This Aka is already unlocked.'))
|
||||||
|
aka.locked = False
|
||||||
|
aka.locked_by = by
|
||||||
|
aka.locked_at = datetime.datetime.now()
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
def get_aka_lock(self, channel, name):
|
||||||
|
try:
|
||||||
|
return self.get_db(channel) \
|
||||||
|
.query(Alias.locked, Alias.locked_by, Alias.locked_at)\
|
||||||
|
.filter(Alias.name == name).one()
|
||||||
|
except sqlalchemy.orm.exc.NoResultFound:
|
||||||
|
raise AkaError(_('This Aka does not exist'))
|
||||||
|
|
||||||
|
|
||||||
def getArgs(args, required=1, optional=0, wildcard=0):
|
def getArgs(args, required=1, optional=0, wildcard=0):
|
||||||
if len(args) < required:
|
if len(args) < required:
|
||||||
raise callbacks.ArgumentError
|
raise callbacks.ArgumentError
|
||||||
@ -138,10 +181,10 @@ def getArgs(args, required=1, optional=0, wildcard=0):
|
|||||||
ret = list(args)
|
ret = list(args)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
class AliasError(Exception):
|
class AkaError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class RecursiveAlias(AliasError):
|
class RecursiveAlias(AkaError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
dollarRe = re.compile(r'\$(\d+)')
|
dollarRe = re.compile(r'\$(\d+)')
|
||||||
@ -253,20 +296,24 @@ class Aka(callbacks.Plugin):
|
|||||||
|
|
||||||
def _add_aka(self, channel, name, alias):
|
def _add_aka(self, channel, name, alias):
|
||||||
if self.__parent.isCommandMethod(name):
|
if self.__parent.isCommandMethod(name):
|
||||||
raise AliasError(_('You can\'t overwrite commands in '
|
raise AkaError(_('You can\'t overwrite commands in '
|
||||||
'this plugin.'))
|
'this plugin.'))
|
||||||
if self._db.has_aka(channel, name):
|
if self._db.has_aka(channel, name):
|
||||||
raise AliasError(_('This Aka already exists.'))
|
raise AkaError(_('This Aka already exists.'))
|
||||||
biggestDollar = findBiggestDollar(alias)
|
biggestDollar = findBiggestDollar(alias)
|
||||||
biggestAt = findBiggestAt(alias)
|
biggestAt = findBiggestAt(alias)
|
||||||
wildcard = '$*' in alias
|
wildcard = '$*' in alias
|
||||||
if biggestAt and wildcard:
|
if biggestAt and wildcard:
|
||||||
raise AliasError(_('Can\'t mix $* and optional args (@1, etc.)'))
|
raise AkaError(_('Can\'t mix $* and optional args (@1, etc.)'))
|
||||||
if alias.count('$*') > 1:
|
if alias.count('$*') > 1:
|
||||||
raise AliasError(_('There can be only one $* in an alias.'))
|
raise AkaError(_('There can be only one $* in an alias.'))
|
||||||
self._db.add_aka(channel, name, alias)
|
self._db.add_aka(channel, name, alias)
|
||||||
|
|
||||||
def _remove_aka(self, channel, name):
|
def _remove_aka(self, channel, name, evenIfLocked=False):
|
||||||
|
if not evenIfLocked:
|
||||||
|
(locked, by, at) = self._db.get_aka_lock(channel, name)
|
||||||
|
if locked:
|
||||||
|
raise AkaError(_('This Aka is locked.'))
|
||||||
self._db.remove_aka(channel, name)
|
self._db.remove_aka(channel, name)
|
||||||
|
|
||||||
def add(self, irc, msg, args, optlist, name, alias):
|
def add(self, irc, msg, args, optlist, name, alias):
|
||||||
@ -294,27 +341,75 @@ class Aka(callbacks.Plugin):
|
|||||||
self.log.info('Adding Aka %q for %q (from %s)',
|
self.log.info('Adding Aka %q for %q (from %s)',
|
||||||
name, alias, msg.prefix)
|
name, alias, msg.prefix)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
except AliasError as e:
|
except AkaError as e:
|
||||||
irc.error(str(e))
|
irc.error(str(e))
|
||||||
add = wrap(add, [getopts({
|
add = wrap(add, [getopts({
|
||||||
'channel': 'somethingWithoutSpaces',
|
'channel': 'somethingWithoutSpaces',
|
||||||
}), 'commandName', 'text'])
|
}), 'commandName', 'text'])
|
||||||
|
|
||||||
def remove(self, irc, msg, args, channel, name):
|
def remove(self, irc, msg, args, optlist, name):
|
||||||
"""[<#channel|global>] <name>
|
"""[--channel <#channel>] <name>
|
||||||
|
|
||||||
Removes the given alias, if unlocked.
|
Removes the given alias, if unlocked.
|
||||||
"""
|
"""
|
||||||
|
channel = 'global'
|
||||||
|
for (option, arg) in optlist:
|
||||||
|
if option == 'channel':
|
||||||
|
if not ircutils.isChannel(arg):
|
||||||
|
irc.error(_('%r is not a valid channel.') % arg,
|
||||||
|
Raise=True)
|
||||||
|
channel = arg
|
||||||
try:
|
try:
|
||||||
self._remove_aka(channel, name)
|
self._remove_aka(channel, name)
|
||||||
self.log.info('Removing Aka %q (from %s)', name, msg.prefix)
|
self.log.info('Removing Aka %q (from %s)', name, msg.prefix)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
except AliasError as e:
|
except AkaError as e:
|
||||||
irc.error(str(e))
|
irc.error(str(e))
|
||||||
remove = wrap(remove, [first(('literal', 'global'), 'channel'),
|
remove = wrap(remove, [getopts({
|
||||||
'commandName'])
|
'channel': 'somethingWithoutSpaces',
|
||||||
|
}), 'commandName'])
|
||||||
|
|
||||||
|
|
||||||
|
def lock(self, irc, msg, args, optlist, user, name):
|
||||||
|
"""[--channel <#channel>] <alias>
|
||||||
|
|
||||||
|
Locks an alias so that no one else can change it.
|
||||||
|
"""
|
||||||
|
channel = 'global'
|
||||||
|
for (option, arg) in optlist:
|
||||||
|
if option == 'channel':
|
||||||
|
if not ircutils.isChannel(arg):
|
||||||
|
irc.error(_('%r is not a valid channel.') % arg,
|
||||||
|
Raise=True)
|
||||||
|
channel = arg
|
||||||
|
try:
|
||||||
|
self._db.lock_aka(channel, name, user)
|
||||||
|
except AkaError as e:
|
||||||
|
irc.error(str(e))
|
||||||
|
lock = wrap(lock, [getopts({
|
||||||
|
'channel': 'somethingWithoutSpaces',
|
||||||
|
}), 'admin', 'commandName'])
|
||||||
|
|
||||||
|
def unlock(self, irc, msg, args, optlist, user, name):
|
||||||
|
"""[--channel <#channel>] <alias>
|
||||||
|
|
||||||
|
Unlocks an alias so that people can define new aliases over it.
|
||||||
|
"""
|
||||||
|
channel = 'global'
|
||||||
|
for (option, arg) in optlist:
|
||||||
|
if option == 'channel':
|
||||||
|
if not ircutils.isChannel(arg):
|
||||||
|
irc.error(_('%r is not a valid channel.') % arg,
|
||||||
|
Raise=True)
|
||||||
|
channel = arg
|
||||||
|
try:
|
||||||
|
self._db.lock_aka(channel, name, user)
|
||||||
|
except AkaError as e:
|
||||||
|
irc.error(str(e))
|
||||||
|
unlock = wrap(unlock, [getopts({
|
||||||
|
'channel': 'somethingWithoutSpaces',
|
||||||
|
}), 'admin', 'commandName'])
|
||||||
|
|
||||||
Class = Aka
|
Class = Aka
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,11 +103,12 @@ class AkaTestCase(ChannelPluginTestCase):
|
|||||||
|
|
||||||
def testAddRemoveAka(self):
|
def testAddRemoveAka(self):
|
||||||
cb = self.irc.getCallback('Aka')
|
cb = self.irc.getCallback('Aka')
|
||||||
cb._add_aka(None, 'foobar', 'echo sbbone', lock=True)
|
cb._add_aka('global', 'foobar', 'echo sbbone')
|
||||||
|
cb._db.lock_aka('global', 'foobar', 'evil_admin')
|
||||||
self.assertResponse('foobar', 'sbbone')
|
self.assertResponse('foobar', 'sbbone')
|
||||||
self.assertRaises(Aka.AkaError, cb.removeAka, 'foobar')
|
self.assertRaises(Aka.AkaError, cb._remove_aka, 'global', 'foobar')
|
||||||
cb._remove_aka(None, 'foobar', evenIfLocked=True)
|
cb._remove_aka('global', 'foobar', evenIfLocked=True)
|
||||||
self.failIf('foobar' in cb.akaes)
|
self.assertNotRegexp('list Aka', 'foobar')
|
||||||
self.assertError('foobar')
|
self.assertError('foobar')
|
||||||
|
|
||||||
def testOptionalArgs(self):
|
def testOptionalArgs(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user