def expiry(self): """Utility function to get a string like "expires in 10 minutes".""" if self.deleted: return _('lifted %s') % str_from_timediff(int(itime())-self.deleted) elif not self.length: return _('permanent') elif self.length + self.start < itime(): return _('expired %s') % str_from_timediff(int(itime())-self.length-self.start) else: return _("expires %s") % str_from_timediff(self.length+self.start-int(itime()), future=True)
def _check_update(args, contents): author, channel_, set, modes, args = args if channel_ != channel: return admin = author.split('!')[0] changes = [] for mode, arg in zip(modes, args): if mode == 'b': if set: t = itime() else: t = None for mask_, admin_, t_ in contents: if mask_ == arg: t = t_ admin = admin_ if t == None: continue changes.append((arg, admin, t)) if set: return (changes, []) else: return ([], changes)
def _insertGame(txn): txn.execute(""" INSERT INTO pickup_games(game, time, players, captains) VALUES(:game, :time, :players, :captains) """, { 'game': game.nick, 'time': itime(), 'players': json.dumps(players, separators=(',',':')), 'captains': json.dumps(captains, separators=(',',':')), }) txn.execute("SELECT last_insert_rowid() AS id") result = txn.fetchall() id_ = result[0][0] def _insertPlayers(playerlist): for player in playerlist: if isinstance(player, StringTypes): db.runOperation("""INSERT INTO pickup_players_games(game_id, name, game, time) VALUES(?, ?, ?, ?) """, (id_, player, game.nick, itime())) else: _insertPlayers(player) _insertPlayers(players) return id_
def _printResult(r): if len(r) < 1: if args and args[0].startswith('#'): call.reply(_("No record for game #{0}").format(id)) else: call.reply(_("No game played yet in mode(s): {0}").format(' '.join(games))) return gamenick, gtime, players_, captains_, id_ = r[0] if ',' in players_: players = json.loads(players_) captains = json.loads(captains_) else: players = players_.split() captains = captains_.split() try: game = self.pickup.get_game(call, [gamenick]) gamename = game.name teamnameFactory = game.teamname except InputError: gamename = _("Unknown(%s)") % gamenick teamnameFactory = lambda i: _("Team {0}").format(i + 1) timestr = str_from_timediff(itime()-gtime) if captains: call.reply(config.get('Pickup player tracking', 'lastgame').decode('string-escape') % \ { 'name': gamename, 'nick': gamenick, 'id': id_, 'when': timestr, 'playerlist': ', '.join(players), 'captainlist': ', '.join(captains) }) elif not isinstance(players[0], StringTypes): call.reply(config.get('Pickup player tracking', 'lastgame autopick').decode('string-escape') % \ { 'name': gamename, 'nick': gamenick, 'id': id_, 'when': timestr, 'teamslist': ', '.join([ config.get('Pickup messages', 'game ready autopick team').decode('string-escape')% { 'name': teamnameFactory(i), 'players': ', '.join(team) } for i, team in enumerate(players)]) }) else: call.reply(config.get('Pickup player tracking', 'lastgame nocaptains').decode('string-escape') % \ { 'name': gamename, 'nick': gamenick, 'id': id_, 'when': timestr, 'playerlist': ', '.join(players), })
def _insertPlayers(playerlist): for player in playerlist: if isinstance(player, StringTypes): db.runOperation("""INSERT INTO pickup_players_games(game_id, name, game, time) VALUES(?, ?, ?, ?) """, (id_, player, game.nick, itime())) else: _insertPlayers(player)
def _confirmed(confirmed): if not confirmed: call.reply(_("Cancelled.")) else: for item in r: item.meta['deleted_by'] = call.user item.deleted = itime() call.reply(_("{item} lifted.").format(item=item).capitalize()) self.periodic_check()
def __init__(self, tracker, meta, start=0, length=0, deleted=0, applied=True, id=None): self.tracker = tracker self.id = id self.meta = meta if start: self.start = start else: self.start = itime() self.length = length self.applied = applied self.deleted = deleted
def _purge(self, keep=0): """used by clearGames and purgeGames""" res = defer.gatherResults([ db.runOperation(""" DELETE FROM """ + table + """ WHERE time < ? """, (itime() - keep,)) for table in ['pickup_games', 'pickup_players_games'] ]) def onErr(failure): log.err(failure, "purge games, keep = {0}".format(keep)) return failure res.addErrback(onErr) return res
def listCmd(self, call, args): """!%(name)slist [#id|search] Shows/searches the active %(name)ss list, or give detailled info about one %(name)s.""" r = self.search( ' '.join(args), self.search_keys, self.get_cmp_funcs(), lambda item: not item.expired() or (item.deleted and item.deleted + 86400 > itime() )\ or not item.deleted and item.start + item.length + 86400 > itime()) if not r: raise InputError(_("No matches.")) if len(r) == 1: call.reply(r[0].long_str(), config.getescaped('Tracker', 'list separator')) else: call.reply( config.getescaped('Tracker', 'list separator')\ .join((item.short_str() for item in r)), config.getescaped('Tracker', 'list separator') )
def _doTransaction(txn): params = dict(zip([str(i) for i in range(len(games))], games)) params.update({'time': itime()-config.getduration("Pickup player tracking", "top10 spread")}) txn.execute(""" SELECT name FROM pickup_players_games WHERE (""" + \ ' OR '.join(['game=:%d' % i for i in range(len(games))]) \ + """) AND time>:time""", params ) players = {} for (player,) in txn.fetchall(): try: players[player] += 1 except KeyError: players[player] = 1 ordered = players.items() ordered.sort(None, lambda x: x[1], True) return ordered[:10]
def sync_with_real(self): if self.expired() == self.applied: if not self.expired(): self.deleted = itime() self.update_db()
def from_call(cls, tracker, call, args): nick = None user = None if not args: if tracker.lastKicked and tracker.lastKickedTime + 120 > itime(): user = tracker.lastKicked reason = tracker.lastKickedReason else: raise InputError( _("No kick issued recently, so please specify a user or mask to ban.")) else: if '$' == args[0][0]: # that's a server-custom mask # the user surely knows what they're # doing there user = args.pop(0) elif '@' not in args[0] \ and '!' not in args[0] \ and '*' not in args[0] \ and '?' not in args[0]: if is_ipv4(args[0]) or is_ipv6(args[0]): user = '******' + args.pop(0) # TODO ban a subnet for # ivp6 addresses else: nick = args.pop(0) else: if '@' not in args[0] \ and '!' not in args[0]: user = args.pop(0)+'!*@*' else: if not banmaskRe.match(args[0]): raise InputError(_("Invalid hostmask '%s'")%args[0]) elif hostmaskRe.match(args[0]): # full hostmask user = cls.find_banmask(args.pop(0)) else: # already a banmask user = args.pop(0) if user: user_d = defer.succeed([user]) else: def _gotUserList(l): for nick_, ident, host, flags in l: if nick == nick_: user = "******" % (nick_, ident, host) return cls.find_banmask(user) else: return ['%s!*@*' % nick] user_d = FetchedList.get_users( tracker.pypickupbot, tracker.pypickupbot.channel ).get().addCallback(_gotUserList) def _gotMasks(masks): def _gotUserList(userlist): meta = { 'ban_masks': masks, 'seen_masks': [], 'seen_nicks': [], } if user: meta['seen_masks'].append(user) if nick: meta['seen_nicks'].append(nick) to_kick = [] for nick_, ident, host, flags in userlist: mask_ = '%s!%s@%s' % (nick_, ident, host) if tracker.cmp_masks( mask_, masks ): to_kick.append(nick_) if nick_ not in meta['seen_nicks']: meta['seen_nicks'].append(nick_) if mask_ not in meta['seen_masks']: meta['seen_masks'].append(mask_) if tracker.pypickupbot.nickname in to_kick: raise InputError(_("Ain't gonna ban myself.")) if len(to_kick) > 1: confirm = call.confirm(_("More than 1 client(%s) is affected with this ban, proceed?") % ' '.join(to_kick)) else: confirm = defer.succeed(True) def _confirmed(confirmed): if not confirmed: raise InputError(_("Cancelled.")) return cls( tracker, meta ) return confirm.addCallback(_confirmed) return FetchedList.get_users( tracker.pypickupbot, tracker.pypickupbot.channel ).get(_gotUserList).addCallback(_gotUserList) return user_d.addCallback(_gotMasks)
def expired(self): return bool(self.deleted) or (bool(self.length) and self.start + self.length < itime())
def mainCmd(self, call, args): """!%(name)s [#id|hostmask|user [length [reason]]] Sets a new %(name)s or edits an existing one.""" length = None needle = None if args: needle = args.pop(0) r = self.search( needle, self.search_keys, self.get_cmp_funcs(), lambda item: not self.ItemClass.expired(item) ) else: r = [] if r: new = False if len(r) > 1: call.reply( _("More than one match: please specify the id of the item to edit")) return else: item_ = r[0] if 'edited_by' not in item_.meta: item_.meta['edited_by'] = [] item_.meta['edited_by'].append(call.user) try: newlen = timediff_from_str(args[0]) except IndexError: raise InputError(_("Please specify a new {type} length or reason.").format(type=self.name)) except InvalidTimeDiffString: length = item_.length # assume it's a new reason for the ban else: # apply the new length as if the ban started now without changing start time length = itime() - item_.start + newlen args.pop(0) item = defer.succeed(item_) else: new = True if args or needle: args.insert(0, needle) try: length = timediff_from_str(args[1]) except (InvalidTimeDiffString, IndexError): # Ignore error and let subclass decide the default value for this pass else: del args[1] def _newItem(item): item.meta['author'] = call.user return item item = self.ItemClass.from_call(self, call, args) item.addCallback(_newItem) def _gotItem(item, length): if args and length == None: try: length = timediff_from_str(args.pop(0)) except InvalidTimeDiffString as e: raise InputError(str(e)) elif length == None: length = config.getduration( self.name.capitalize(), 'default duration') item.length = length if args: item.meta['reason'] = ' '.join(args) applied = self.retrieve_real_list().addCallback(item.check_applied) def _applied(applied): if new: self.listed.append(item) synced = item.sync_with_self() else: synced = item.update_db() def _reply(self): if new: call.reply(_("{item} created.").format(item=item).capitalize()) else: call.reply(_("{item} edited.").format(item=item).capitalize()) synced.addCallback(_reply) applied.addCallback(_applied) return item return item.addCallback(_gotItem, length)