set ban duration with @comment command, also allow multiple ban ids

example:
 @comment 1,2 this is a comment, 1 week
This commit is contained in:
Elián Hanisch 2012-07-27 00:50:25 -03:00
parent 3c7eff0f70
commit 2f1a087faf
2 changed files with 138 additions and 66 deletions

View File

@ -119,8 +119,11 @@ def readTimeDelta(s):
# completed an unit, add to seconds # completed an unit, add to seconds
string = string.strip() string = string.strip()
if string: if string:
mult = timeUnits[string] try:
seconds += number * mult unit = timeUnits[string]
except KeyError:
raise ValueError(string)
seconds += number * unit
string = '' string = ''
string += c string += c
else: else:
@ -139,8 +142,11 @@ def readTimeDelta(s):
else: else:
string = string.strip() string = string.strip()
if string: if string:
mult = timeUnits[string] try:
seconds += number * mult unit = timeUnits[string]
except KeyError:
raise ValueError(string)
seconds += number * unit
return seconds return seconds
@ -1466,12 +1472,54 @@ class Bantracker(callbacks.Plugin):
updatebt = wrap(updatebt, [optional('anything', default=None)]) updatebt = wrap(updatebt, [optional('anything', default=None)])
def comment(self, irc, msg, args, id, kickmsg): def _getBan(self, id):
"""<id> [<comment>] """gets mask, channel and removal date of ban"""
L = self.db_run("SELECT mask, channel, removal FROM bans WHERE id = %s",
id, expect_result=True)
if not L:
raise ValueError
return L[0]
def _setBanDuration(self, id, duration):
# check if ban has already a duration time
for idx, br in enumerate(self.managedBans):
if id == br.ban.id:
ban = br.ban
del self.managedBans.shelf[idx]
break
else:
# ban obj ins't in self.managedBans
try:
mask, channel, removal = self._getBan(id)
except ValueError:
raise Exception("unknow id")
type = guessBanType(mask)
if type not in ('ban', 'quiet'):
raise Exception("not a ban or quiet")
if removal:
raise Exception("ban was removed")
for ban in self.bans[channel]:
if mask == ban.mask:
if ban.id is None:
ban.id = id
break
else:
# ban not in sync it seems, shouldn't happen normally.
raise Exception("bans not in sync")
# add ban duration
self.managedBans.add(BanRemoval(ban, duration))
def comment(self, irc, msg, args, ids, kickmsg):
"""<id>[,<id> ...] [<comment>][, <duration>]
Reads or adds the <comment> for the ban with <id>, Reads or adds the <comment> for the ban with <id>,
use @bansearch to find the id of a ban use @bansearch to find the id of a ban
""" """
def addComment(id, nick, msg): def addComment(id, nick, msg):
n = now() n = now()
self.db_run("INSERT INTO comments (ban_id, who, comment, time) values(%s,%s,%s,%s)", (id, nick, msg, n)) self.db_run("INSERT INTO comments (ban_id, who, comment, time) values(%s,%s,%s,%s)", (id, nick, msg, n))
@ -1479,74 +1527,74 @@ class Bantracker(callbacks.Plugin):
return self.db_run("SELECT who, comment, time FROM comments WHERE ban_id=%i", (id,), True) return self.db_run("SELECT who, comment, time FROM comments WHERE ban_id=%i", (id,), True)
nick = msg.nick nick = msg.nick
if kickmsg: duration, banset = None, []
addComment(id, nick, kickmsg) if kickmsg and ',' in kickmsg:
irc.replySuccess() s = kickmsg[kickmsg.rfind(','):]
else: try:
data = readComment(id) duration = readTimeDelta(s)
if data: except ValueError:
for c in data: pass
irc.reply("%s %s: %s" % (cPickle.loads(c[2]).astimezone(pytz.timezone('UTC')).strftime("%b %d %Y %H:%M:%S"), c[0], c[1].strip()) )
for id in [ int(i) for i in ids.split(',') if i.isdigit() and int(i) > 0 ]:
try:
mask, channel, removal = self._getBan(id)
except ValueError:
irc.reply("I don't know any ban with id %s." % id)
continue
if kickmsg:
addComment(id, nick, kickmsg)
if duration is not None:
# set duration time
type = guessBanType(mask)
if type not in ('ban', 'quiet'):
continue
try:
self._setBanDuration(id, duration)
banset.append(str(id))
except Exception as exc:
irc.reply("Failed to set duration time on ban %s (%s)" % (id, exc))
else: else:
irc.error("No comments recorded for ban %i" % id) data = readComment(id)
comment = wrap(comment, ['id', optional('text')]) if data:
for c in data:
date = cPickle.loads(c[2]).astimezone(pytz.timezone('UTC')).strftime("%b %d %Y %H:%M")
irc.reply("%s %s: %s" % (date, c[0], c[1].strip()))
else:
irc.reply("No comments recorded for ban %s" % id)
# success reply. If duration time used, say which ones.
if kickmsg:
if duration is not None:
if banset:
irc.reply("Ban set for auto removal: %s" % ', '.join(banset))
else:
irc.replySuccess()
comment = wrap(comment, ['something', optional('text')])
def banremove(self, irc, msg, args, ids, timespec): def banremove(self, irc, msg, args, ids, timespec):
"""<id>[,<id> ...] <time> """<id>[,<id> ...] <duration>
Sets expiration time. Sets expiration time.
""" """
try: try:
seconds = readTimeDelta(timespec) seconds = readTimeDelta(timespec)
except KeyError: except ValueError:
irc.error("bad time format.") irc.error("bad time format.")
return return
ids = [ int(i) for i in ids.split(',') if i.isdigit() and int(i) > 0 ] banset = []
for id in [ int(i) for i in ids.split(',') if i.isdigit() and int(i) > 0 ]:
try:
self._setBanDuration(id, seconds)
banset.append(str(id))
except Exception as exc:
irc.reply("Failed to set duration time on ban %s (%s)" % (id, exc))
for id in ids: if banset:
# lets check if is already managed first irc.reply("Ban set for auto removal: %s" % ', '.join(banset))
for idx, remove in enumerate(self.managedBans):
if id == remove.ban.id:
ban = remove.ban
del self.managedBans.shelf[idx]
break
else:
L = self.db_run("SELECT mask, channel, removal FROM bans WHERE id = %s",
id, expect_result=True)
if not L:
irc.reply("I don't know any ban with id %s." % id)
continue
mask, channel, removal = L[0]
type = guessBanType(mask)
if type not in ('ban', 'quiet'):
irc.reply("Id %s is a %s, only bans or quiets can be autoremoved." % (id, type))
continue
if removal:
irc.reply("Ban %s (%s) was already removed in %s." % (id, mask, channel))
continue
for ban in self.bans[channel]:
if mask == ban.mask:
if ban.id is None:
ban.id = id
break
else:
# ban not in sync it seems, shouldn't happen normally.
irc.reply("Ban %s (%s) isn't active in %s." % (id, mask, channel))
continue
self.managedBans.add(BanRemoval(ban, seconds))
# check bans set
done = []
for br in self.managedBans:
if br.ban.id in ids:
done.append(str(br.ban.id))
if done:
irc.reply("Ban set for auto removal: %s" % ', '.join(done))
banremove = wrap(banremove, ['something', 'text']) banremove = wrap(banremove, ['something', 'text'])

View File

@ -125,6 +125,30 @@ class BantrackerTestCase(ChannelPluginTestCase):
return ban return ban
def testComment(self): def testComment(self):
self.assertResponse('comment 1', "I don't know any ban with id 1.")
self.feedBan('asd!*@*')
self.assertResponse('comment 1', 'No comments recorded for ban 1')
self.assertResponse('comment 1 this is a test', 'The operation succeeded.')
self.assertRegexp('comment 1', 'test: this is a test$')
def testMultiComment(self):
self.feedBan('asd!*@*')
self.feedBan('qwe!*@*')
self.assertResponse('comment 1,2,3 this is a test',
"I don't know any ban with id 3.")
msg = self.irc.takeMsg()
self.assertEqual(msg.args[1], "test: The operation succeeded.")
self.assertRegexp('comment 1,2', 'test: this is a test$')
msg = self.irc.takeMsg()
self.assertTrue(msg.args[1].endswith("test: this is a test"))
def testCommentDuration(self):
self.feedBan('asd!*@*')
self.assertResponse('comment 1 this is a test, 1 week 10', 'Ban set for auto removal: 1')
self.assertRegexp('comment 1', 'test: this is a test, 1 week 10$')
self.assertRegexp('baninfo 1', 'expires in 1 week$')
def testCommentRequest(self):
pluginConf.request.setValue(True) pluginConf.request.setValue(True)
# test bans # test bans
self.feedBan('asd!*@*') self.feedBan('asd!*@*')
@ -382,7 +406,7 @@ class BantrackerTestCase(ChannelPluginTestCase):
def testBanremoveMultiSet(self): def testBanremoveMultiSet(self):
self.feedBan('asd!*@*') self.feedBan('asd!*@*')
self.assertResponse('banremove 1,2 10', self.assertResponse('banremove 1,2 10',
"I don't know any ban with id 2.") "Failed to set duration time on ban 2 (unknow id)")
msg = self.irc.takeMsg() msg = self.irc.takeMsg()
self.assertEqual(msg.args[1], "test: Ban set for auto removal: 1") self.assertEqual(msg.args[1], "test: Ban set for auto removal: 1")
@ -400,19 +424,19 @@ class BantrackerTestCase(ChannelPluginTestCase):
def testBanremoveBadType(self): def testBanremoveBadType(self):
self.feedBan('nick', mode='k') self.feedBan('nick', mode='k')
self.assertResponse('banremove 1 0', self.assertResponse('banremove 1 0',
"Id 1 is a removal, only bans or quiets can be autoremoved.") "Failed to set duration time on ban 1 (not a ban or quiet)")
self.feedBan('$a:nick') self.feedBan('$a:nick')
self.assertResponse('banremove 2 0', 'Ban set for auto removal: 2') self.assertResponse('banremove 2 0', 'Ban set for auto removal: 2')
def testBanremoveBadId(self): def testBanremoveBadId(self):
self.assertResponse('banremove 1 0', "I don't know any ban with id 1.") self.assertResponse('banremove 1 0', "Failed to set duration time on ban 1 (unknow id)")
def testBanremoveInactiveBan(self): def testBanremoveInactiveBan(self):
self.feedBan('asd!*@*') self.feedBan('asd!*@*')
self.irc.feedMsg(ircmsgs.unban(self.channel, 'asd!*@*', self.irc.feedMsg(ircmsgs.unban(self.channel, 'asd!*@*',
'op!user@host.net')) 'op!user@host.net'))
self.assertResponse('banremove 1 0', self.assertResponse('banremove 1 0',
"Ban 1 (asd!*@*) was already removed in #test.") "Failed to set duration time on ban 1 (ban was removed)")
def testBanremoveTimeFormat(self): def testBanremoveTimeFormat(self):
cb = self.getCallback() cb = self.getCallback()