Пример #1
0
 def sendHookah(self, uid):
     """ Send a set of hookah parts to a user """
     with InventoryLock.lock:
         oos = self.outOfStock(self._saveLast)
         if len(oos) > 0:
             print(str(oos))
             return "Not enough hookah parts."
         self.removeHookahFromDisplay(0)
         hookahItems = [4510, 4511, 4515, 4516, 4512, 4513]
         items = dict((iid, 1) for iid in hookahItems)
         k = Kmail(uid=uid,
                   text="Hookah override. DO NOT FORGET TO COOK THE "
                   "NOODLES AND VIAL.\n\nSeriously, don't forget.")
         k.addItems(items)
         self.sendKmail(k)
         return "Hookah sent to >>{}".format(uid)
Пример #2
0
 def _sendHelpMessage(self, message):
     uid = message.uid
     helptext = []
     for m in self._modules:
         mod = m.module
         clanOnly = m.clanOnly
         permission = m.permission
         no_permissions = (permission in _noPermissions)
         if not clanOnly or self.checkClan(uid):
             if (no_permissions
                     or permission in self.properties.getPermissions(uid)):
                 newTxt = mod.extendedCall('kmail_description')
                 if newTxt is not None:
                     if newTxt not in helptext:
                         if not no_permissions:
                             newTxt = "[ADMIN] " + newTxt
                         print newTxt
                         print permission
                         helptext.append(newTxt)
     if not helptext:
         txt = "Sorry, I don't have any help available."
     if self._showChatHelpMessage:
         helptext.append(
             "CHAT HELP: If you want a list of chat commands, "
             "send me a PM with the text '!help' for all "
             "available commands. You can also use "
             "'!help COMMAND_NAME' to get detailed information on "
             "a specific command.")
         txt = '\n\n'.join(helptext)
     return [KmailResponse(self, self, Kmail(uid, txt))]
Пример #3
0
 def _heartbeat(self):
     now = time.time()
     if (self._lastCheck is None or now - self._lastCheck > 60 * 60 * 24):
         self._checkNew()
     if _versionGreater(self._lastAvailableVersion, self.properties.version,
                        self._notifyOn):
         if self._chatEvery > 0:
             if now - self._lastChatNotify > self._chatEvery:
                 self.chat("New version available: {}".format(_url))
                 self._lastChatNotify = now
         if self._firstcheck:
             self._firstcheck = False
             updateAdmins = self.properties.getAdmins('update_notify')
             for uid in updateAdmins:
                 lastKmail = self._kmailed.get(uid, 0)
                 if now - lastKmail >= 14 * 24 * 60 * 60:
                     k = Kmail(
                         uid, "New cwbot version ({}) available: {}".format(
                             self._lastAvailableVersion, _url))
                     self.sendKmail(k)
                     self._kmailed[uid] = now
                 else:
                     self.log(
                         'Already kmailed {} about update.'.format(uid))
                 lastPm = self._privateMessaged.get(uid, 0)
                 if now - lastPm >= 7 * 24 * 60 * 60:
                     self.whisper(
                         uid,
                         "New cwbot version available: {}".format(_url))
                     self._privateMessaged[uid] = now
                 else:
                     self.log('Already pm\'ed {} about update.'.format(uid))
Пример #4
0
 def _boot(self, uid):
     r1 = RemovePlayerFromClanWhitelistRequest(self.session, uid)
     self.tryRequest(r1)
     r2 = BootClanMemberRequest(self.session, uid)
     self.tryRequest(r2)
     if self._bootMessage is not None:
         self.sendKmail(Kmail(uid, self._bootMessage))
Пример #5
0
 def sendHookah(self, uid):
     """ Send a set of hookah parts to a user """
     with InventoryLock.lock:
         oos = self.outOfStock(self._saveLast)
         if len(oos) > 0:
             print(str(oos))
             return "Not enough hookah parts."
         self.removeHookahFromDisplay(0)
         hookahItems = [4510,4511,4515,4516,4512,4513]
         items = dict((iid, 1) for iid in hookahItems)
         k = Kmail(uid=uid, 
                   text="Hookah override. DO NOT FORGET TO COOK THE "
                        "NOODLES AND VIAL.\n\nSeriously, don't forget.")
         k.addItems(items)
         self.sendKmail(k)
         return "Hookah sent to >>{}".format(uid)
Пример #6
0
    def processNewCommunications(self):
        """ This function is called every second or two (as specified in
        modules.ini) and downloads and processes new chats/kmails. """
        msgs = self._c.getNewChatMessages()
        self._processChat(msgs)

        # check for mail handler issues
        if self._mailHandler.exception.is_set():
            self._mailHandler.join()
        # get new mail
        newKmail = Kmail.fromPyKol(self._mailHandler.getNextKmail())
        while newKmail is not None:
            responses = self._processKmail(newKmail)
            try:
                # send responses to MailHandler
                kmails = [r.kmail for r in responses]
                self._mailHandler.respondToKmail(newKmail.info['id'],
                                                 map(Kmail.toPyKol, kmails))
            except Exception as e:
                for r in responses:
                    r.manager.kmailFailed(r.module, r.kmail, e)
                raise
            newKmail = Kmail.fromPyKol(self._mailHandler.getNextKmail())
Пример #7
0
    def processNewCommunications(self):
        """ This function is called every second or two (as specified in
        modules.ini) and downloads and processes new chats/kmails. """
        msgs = self._c.getNewChatMessages()
        self._processChat(msgs)

        # check for mail handler issues
        if self._mailHandler.exception.is_set():
            self._mailHandler.join()
        # get new mail
        newKmail = Kmail.fromPyKol(self._mailHandler.getNextKmail())
        while newKmail is not None:
            responses = self._processKmail(newKmail)
            try:
                # send responses to MailHandler
                kmails = [r.kmail for r in responses]
                self._mailHandler.respondToKmail(newKmail.info['id'],  
                                                 map(Kmail.toPyKol, kmails))
            except Exception as e:
                for r in responses:
                    r.manager.kmailFailed(r.module, r.kmail, e)
                raise
            newKmail = Kmail.fromPyKol(self._mailHandler.getNextKmail())
Пример #8
0
    def dispatchKmail(self, uid, dailyDigest=False, noThrow=False):
        with self._lock:
            now_ = datetime.datetime.now(utc)
            txt = ("Hobopolis chat monitor violations for {} "
                   "(* indicates player in clan chat):\n\n".format(
                       utcToArizona(now_, '%x')))
            tf1 = "%d %b %I:%M %p"
            tf2 = "%I:%M %p"

            violators = [
                u for u, v in self._violations.items()
                if numViolations(v) > self.numWarnings
            ]
            if len(violators) == 0 and not dailyDigest:
                return
            if len(violators) > 0:
                violateStrs = []
                self.log("Violators: {}".format(violators))
                for uname in violators:
                    vList = self._violations[uname]
                    timeRanges = [[
                        utcToArizona(rBegin, tf1),
                        utcToArizona(rEnd, tf2)
                    ] for rBegin, rEnd in violationTimeRanges(vList)]
                    s = uname + " in time range(s): "
                    s += ", ".join("({0[0]} - {0[1]})".format(range_)
                                   for range_ in timeRanges)

                    # mark players in clan chat (but not in hobopolis)
                    if any(v.violation and v.data.get('inClan', False)
                           for v in vList):
                        s = "*" + s

                    # note if they joined /hobopolis
                    timeJoin = next((v.time for v in vList if not v.violation),
                                    None)
                    if timeJoin is not None:
                        s += ("; joined /hobopolis at {}".format(
                            utcToArizona(timeJoin, tf1)))

                    violateStrs.append(s)
                txt += "\n".join(violateStrs)
            else:
                txt += "No users were in violation of Hobopolis chat rules."
            k = Kmail(uid=uid, text=txt)
            self.log("Sending HoboChatMon kmail to {}...".format(uid))
            self.sendKmail(k)
            return True
Пример #9
0
 def registerViolation(self, userName, inClanChat):
     with self._lock:
         violations = self._violations.get(userName, [])
         violations.append(
                         ChatEvent(userName, True, {'inClan': inClanChat}))
         numV = numViolations(violations)
         r = SearchPlayerRequest(self.session, userName)
         ul = self.tryRequest(r)
         uid = ul["players"][0]["userId"]
         txt = ('Hi there! You\'ve been detected adventuring in hobopolis without listening to the '
                'hobopolis chat channel! Please type "/l hobopolis" into chat before continuing '
                'to adventure in hobopolis. Thanks!')
         k = Kmail(uid=uid, text=txt)
         self.debugLog("Warning {} about chat violation".format(userName))
         self.sendKmail(k)
         self.log("Detected {} adventuring in hobopolis without being "
                  "in channel (violation number #{})!"
                  .format(userName, numV))
         self._violations[userName] = violations 
Пример #10
0
 def sendChatLog(self, channel, uid):
     chars = 0
     messages = []
     with self._lock:
         self.reduceChatLog()
         for msg in (m for m in reversed(self._chatlog) 
                     if m['channel'] == channel):
             spacer = "" if msg['type'] == "emote" else ":"
             line = ("[{}] {}{} {}"
                     .format(msg['time'].strftime("%I:%M:%S"), 
                             msg['user'], spacer, msg['text']))
             chars += len(line) + 1
             if chars <= MAX_KMAIL:
                 messages.append(line)
             else:
                 break
     msgText = '\n'.join(reversed(messages))
     self.sendKmail(Kmail(uid=uid, text=msgText))
     return True
Пример #11
0
 def _doBooting(self, simulate):
     bootedMembers = []
     if self._daysUntilBoot <= 0:
         return
     self.log("Running bootings...")
     self._refreshClanMembers()
     checkSeconds = _daysToSecs(self._daysUntilBoot)
     curTime = time.time()
     numRecords = len(self._userDb)
     i = 0
     for uid_s, record in self._userDb.items():
         i += 1
         if self._stopNow.is_set():
             break
         if not record.get('updated', False):
             continue
         nextCheckTime = record.get('lastActiveCheck', 0) + checkSeconds
         if curTime >= nextCheckTime:
             prefix = "[{}/{}] ".format(i, numRecords)
             booted = self._bootIfInactive(int(uid_s), simulate, prefix)
             if booted:
                 bootedMembers.append(uid_s)
         else:
             nextCheckDays = 1 + _secsToDays(nextCheckTime - curTime)
             self.debugLog("[{}/{}] Skipping boot check for {}; will "
                           "check in {} days.".format(
                               i, numRecords, record['userName'],
                               nextCheckDays))
     self.log("Done running bootings.")
     if bootedMembers:
         bootedList = [
             "{} (#{}) [{}]".format(record['userName'], record['userId'],
                                    record['rank']['rankName'])
             for key, record in self._userDb.items() if key in bootedMembers
         ]
         txt = ("The following users have been booted and/or "
                "removed from the clan whitelist:\n\n{}\n".format(
                    "\n".join(bootedList)))
         self.log("Booted members: {}".format(", ".join(bootedList)))
         for uid in self.properties.getAdmins("boot_clan_member_notify"):
             self.sendKmail(Kmail(uid, txt))
Пример #12
0
 def _processCommand(self, message, cmd, args):
     if cmd == "timeline":
         dvid = self._lastRaidlog.get('dvid')
         if (self._dungeonActive() or dvid is None
                 or str(dvid) not in self._pastes):
             return ("You can't get the timeline while the dungeon is "
                     "active.")
         data = self._pastes[str(dvid)]
         if data['error']:
             return ("Error with timeline: {}".format(data['url']))
         return "Timeline for current instance: {}".format(data['url'])
     elif cmd == "timelines":
         timelines = self._pastes.values()
         timelines.sort(key=lambda x: x['time'], reverse=True)
         strings = []
         for item in timelines:
             urlText = item['url'] if not item['error'] else "ERROR"
             dvidText = item['dvid']
             dt_utc = datetime.datetime.fromtimestamp(
                 item['time'], pytz.utc)
             dt_az = dt_utc.astimezone(_tz)
             timeText = dt_az.strftime("%a %d %b %y")
             kisses = item['kisses']
             strings.append("{} - {} [{} kisses]: {}".format(
                 timeText, dvidText, kisses, urlText))
         sendString = ""
         for string in strings:
             if len(string) + len(sendString) > 1500:
                 break
             sendString += string + "\n"
         if sendString == "":
             return "No timelines in memory."
         self.sendKmail(
             Kmail(
                 message['userId'],
                 "Here are the most recent Dreadsylvania "
                 "instances:\n\n{}".format(sendString)))
         return "Timelines sent."
Пример #13
0
    def _processCommand(self, message, cmd, args):
        if cmd == "die":
            args = args.strip()
            if args == "":
                args = "0"
            try:
                t = int(args)
                e = kol.Error.Error("Manual crash")
                e.timeToWait = t * 60 + 1
                self.chat("Coming online in {} minutes.".format(t))
                raise e
            except kol.Error.Error:
                raise
            except:
                pass
            return "Invalid argument to !die '{}'".format(args)
        elif cmd == "simulate":
            self.parent.director._processChat([{
                'text': args,
                'userName': "******",
                'userId': -2,
                'channel': "hobopolis",
                'type': "normal",
                'simulate': True
            }])
            return "Simulated message: {}".format(args)
        elif cmd == "spam":
            return "\n".join(["SPAM"] * 15)
        elif cmd == "restart":
            self._raiseEvent("RESTART", "__system__")
        elif cmd == "raise_event":
            r = self._raiseEvent(args)
            return "Reply to event '{}': {}".format(args, r)
        elif cmd == "kmail_test":
            n = 1000
            try:
                n = int(args)
            except Exception:
                pass

            text = ""
            count = 0
            startChar = "A"
            while n >= 100:
                count += 100
                n -= 100
                newText = "A" * 100 + "{}".format(count)
                newText = startChar + newText[-99:]
                text += newText
                startChar = " "
            k = Kmail(message['userId'], text)
            self.sendKmail(k)
        elif cmd == "bot_status":
            r = StatusRequest(self.session)
            d = self.tryRequest(r)
            return "\n".join("{}: {}".format(k, v) for k, v in d.items()
                             if k not in ["pwd", "eleronkey"])
        elif cmd == "inclan":
            tf = self.parent.checkClan(int(args))
            return str(tf)
        elif cmd == "plist":
            return str(self.properties.getPermissions(int(args)))
        elif cmd == "say":
            txtMatch = re.search(r"^\s*(?:/(\w+))?\s*(.*)", args)
            if txtMatch:
                self.chat(txtMatch.group(2), channel=txtMatch.group(1))
                return None
            return "Error matching text"
        return None
Пример #14
0
 def newMessage(self, uid, text="", meat=0):
     """ Create a new Kmail object. """
     return Kmail(uid, text, meat)
Пример #15
0
    def _refreshClanMembers(self):
        self.debugLog("Fetching clan member list...")

        curTime = int(time.time())
        newUserDb = copy.deepcopy(self._userDb)
        for record in newUserDb.values():
            record['updated'] = False

        # member info comes from two sources: members in the clan right
        # now are in the detailed roster; members who are whitelisted to a
        # different clan are on the whitelist. Sadly, the information
        # contained in each is different. It's impossible to find the karma
        # of a user who is away on whitelist, and you can't find the
        # title of a user in the detailed roster.
        members = defaultdict(dict)
        r1 = ClanWhitelistRequest(self.session)
        d1 = self.tryRequest(r1)
        r2 = ClanDetailedMemberRequest(self.session)
        d2 = self.tryRequest(r2)
        if len(d2['members']) == 0:
            raise RuntimeError("Could not detect any members of clan!")

        self.debugLog("{} members on whitelist".format(len(d1['members'])))
        self.debugLog("{} members in clan".format(len(d2['members'])))
        for record in d1['members']:
            uid = int(record['userId'])
            entry = {
                'userId':
                uid,
                'userName':
                record['userName'],
                'rank':
                self._ranks.get(_rankTransform(record['rankName']),
                                _unknownRank),
                'whitelist':
                True,
                'updated':
                True
            }
            self._titles[uid] = record['clanTitle']
            members[uid] = entry
        for record in d2['members']:
            uid = int(record['userId'])
            entry = {
                'userId':
                uid,
                'userName':
                record['userName'],
                'rank':
                self._ranks.get(_rankTransform(record['rankName']),
                                _unknownRank),
                'inClan':
                True,
                'karma':
                record['karma'],
                'updated':
                True
            }
            members[uid].update(entry)

        self.debugLog("{} members total".format(len(members)))

        newMembers = []
        # add some default values and put these in the database
        for uid, record in members.items():
            record.setdefault('karma', 0)
            record.setdefault('inClan', False)
            record.setdefault('whitelist', False)
            record['lastData'] = curTime

            key = str(uid)
            if key not in newUserDb:
                newUserDb[key] = {
                    'lastPromotion': self._rolloverTime,
                    'entryCreated': self._rolloverTime,
                    'lastActiveCheck': 0
                }
                newMembers.append(key)
            newUserDb[key].update(record)

        # delete old users from database
        deleteAfterSeconds = _daysToSecs(90)
        newUserDb = {
            k: v
            for k, v in newUserDb.items()
            if v.get('lastData') >= curTime - deleteAfterSeconds
        }

        # remove deleted users from _inactiveAstrals
        for k in self._inactiveAstrals.keys():
            if k not in newUserDb:
                del self._inactiveAstrals[k]

        if newMembers:
            newMemberList = [
                "{} (#{}){}".format(
                    record['userName'], record['userId'],
                    "" if record['inClan'] else " [whitelist only]")
                for key, record in newUserDb.items() if key in newMembers
            ]
            txt = ("The following users are new clan members:\n\n{}\n".format(
                "\n".join(newMemberList)))
            self.log("New members: {}".format(", ".join(newMemberList)))
            for uid in self.properties.getAdmins("new_clan_member_notify"):
                self.sendKmail(Kmail(uid, txt))

        self._userDb = newUserDb
        self.debugLog("UserDb updated to {} entries".format(len(newUserDb)))
Пример #16
0
    def _processCommand(self, msg, cmd, args):
        if cmd in ["points", "score"]:
            hasPermission = "dread_points" in self.properties.getPermissions(
                msg['userId'])

            txt = "Current Dreadsylvania scores:\n\n"
            sortedUsers = list(self._userPoints.items())
            sortedUsers.sort(key=lambda x: -x[1])

            for user, points in sortedUsers:
                events = self._userEvents[user]
                if not events:
                    continue
                userName = self._properUserNames[user]
                userId = self._userIds[user]
                userTxt = ("[{}] {} (#{}): ".format(
                    intOrFloatToString(points, 2), userName, userId))
                userEventTxt = []
                for e, num in events.items():
                    value = self._eventValue[e]
                    userEventTxt.append("{} x {} ({:+})".format(
                        num, e, value * num))
                userTxt += ", ".join(userEventTxt)
                txt += userTxt + "\n"

            if hasPermission and not self._dungeonActive():
                txt += "(use '!points official' to run drawing)\n"

            if args.lower().strip() in ["official", "test"]:
                if hasPermission:
                    if (self._dungeonActive()
                            and args.lower().strip() != "test"):
                        return ("I can't perform the drawing until the "
                                "instance is done.")
                    else:
                        self._performDrawing()
                else:
                    return "You don't have permission to distribute loot."
            elif args and args.lower().strip().split()[0] in ["give", "grant"]:
                if not hasPermission:
                    return "You don't have permission to do that."
                isPM = (msg['type'] == "private")
                if isPM:
                    return "You can't grant points in a PM."
                match = re.search(r'(-?\d+)(?: points?)? to (.*)',
                                  args,
                                  flags=re.IGNORECASE)
                if not match:
                    return "Invalid format."
                pointAmount = int(match.group(1))
                user = _nameKey(match.group(2))
                if user not in self._userPoints:
                    return "No such user {}.".format(match.group(2))
                self._grantedPoints.setdefault(user, 0)
                self._grantedPoints[user] += pointAmount
                self._processLog(self._lastRaidlog)
                return ("Granted {} points to {}".format(
                    pointAmount, self._properUserNames[user]))
            else:
                self.sendKmail(Kmail(msg['userId'], txt))
                return "Kmail sent."
        return None
Пример #17
0
 def _sendMonsterList(self, uid):
     text = ("Available monsters:\n\n" +
             "\n".join(sorted(self._monsters.keys())))
     self.sendKmail(Kmail(uid, text))
     return "Monster list sent."