Пример #1
0
 def _update_people(self, client=None):
     "Updates our internal list of Slack users.  Kind of expensive."
     people = {}
     if client:
         for page in client.users_list(limit=self.PAGE_LIMIT):
             for member in page["members"]:
                 if member["deleted"]:
                     continue
                 member_id = member["id"]
                 user_timezone = member.get("tz")
                 people[member_id] = Person(
                     id=member_id,
                     mention_handle=member.get("mention_handle", ""),
                     handle=member["name"],
                     source=clean_for_pickling(member),
                     name=member.get("real_name", ""),
                 )
                 if member["name"] == self.handle:
                     self.me = people[member_id]
                 if user_timezone and user_timezone != "unknown":
                     people[member_id].timezone = user_timezone
     if len(people.keys()) == 0:
         # Server isn't set up yet, and we're likely in a processing thread,
         if self.load("slack_people_cache", None):
             self._people = self.load("slack_people_cache", None)
         if self.me is None:
             self.me = self.load("slack_me_cache", None)
         if self.handle is None:
             self.handle = self.load("slack_handle_cache", None)
     else:
         self._people = people
         self.save("slack_people_cache", people)
         self.save("slack_me_cache", self.me)
         self.save("slack_handle_cache", self.handle)
Пример #2
0
    def bootstrap(self):
        # Bootstrap must provide a way to to have:
        # a) self.normalize_incoming_event fired, or incoming events put into self.incoming_queue
        # b) any necessary threads running for a)
        # c) self.me (Person) defined, with Will's info
        # d) self.people (dict of People) defined, with everyone in an organization/backend
        # e) self.channels (dict of Channels) defined, with all available channels/rooms.
        #    Note that Channel asks for members, a list of People.
        # f) A way for self.handle, self.me, self.people, and self.channels to be kept accurate,
        #    with a maximum lag of 60 seconds.
        self.people = {}
        self.channels = {}
        self.me = Person(
            id="will",
            handle="will",
            mention_handle="@will",
            source=Bunch(),
            name="William T. Botterton",
        )

        # Do this to get the first "you" prompt.
        self.pubsub.publish('message.incoming.stdin',
                            (Message(content="",
                                     type="message.incoming",
                                     is_direct=True,
                                     is_private_chat=True,
                                     is_group_chat=False,
                                     backend=self.internal_name,
                                     sender=self.partner,
                                     will_is_mentioned=False,
                                     will_said_it=False,
                                     backend_supports_acl=False,
                                     original_incoming_event={})))
Пример #3
0
    def _update_people(self):
        people = {}

        self.handle = self.client.server.username

        for k, v in self.client.server.users.items():
            user_timezone = None
            if v.tz:
                user_timezone = v.tz
            people[k] = Person(
                id=v.id,
                mention_handle="<@%s>" % v.id,
                handle=v.name,
                source=clean_for_pickling(v),
                name=v.real_name,
            )
            if v.name == self.handle:
                self.me = Person(
                    id=v.id,
                    mention_handle="<@%s>" % v.id,
                    handle=v.name,
                    source=clean_for_pickling(v),
                    name=v.real_name,
                )
            if user_timezone and user_timezone != 'unknown':
                people[k].timezone = user_timezone
                if v.name == self.handle:
                    self.me.timezone = user_timezone
        if len(people.keys()) == 0:
            # Server isn't set up yet, and we're likely in a processing thread,
            if self.load("slack_people_cache", None):
                self._people = self.load("slack_people_cache", None)
            if not hasattr(self, "me") or not self.me:
                self.me = self.load("slack_me_cache", None)
            if not hasattr(self, "handle") or not self.handle:
                self.handle = self.load("slack_handle_cache", None)
        else:
            self._people = people
            self.save("slack_people_cache", people)
            self.save("slack_me_cache", self.me)
            self.save("slack_handle_cache", self.handle)
Пример #4
0
    def _person(fields):
        required_fields = {
            "id": "TBD",
            "mention_handle": "TBD",
            "source": "TBD",
            "handle": "TBD",
            "name": "TBD",
            "first_name": "TDB"
        }
        required_fields.update(fields)

        return Person(**required_fields)
Пример #5
0
    def people(self):
        if not hasattr(self, "_people"):
            full_roster = {}

            # Grab the first roster page, and populate full_roster
            url = ALL_USERS_URL % {
                "server": settings.HIPCHAT_SERVER,
                "token": settings.HIPCHAT_V2_TOKEN,
                "start_index": 0,
                "max_results": 1000
            }
            r = requests.get(url, **settings.REQUESTS_OPTIONS)
            for user in r.json()['items']:
                full_roster["%s" % (user['id'], )] = Person(
                    id=user["id"],
                    handle=user["mention_name"],
                    mention_handle="@%s" % user["mention_name"],
                    source=clean_for_pickling(user),
                    name=user["name"],
                )
            # Keep going through the next pages until we're out of pages.
            while 'next' in r.json()['links']:
                url = "%s&auth_token=%s" % (r.json()['links']['next'],
                                            settings.HIPCHAT_V2_TOKEN)
                r = requests.get(url, **settings.REQUESTS_OPTIONS)

                for user in r.json()['items']:
                    full_roster["%s" % (user['id'], )] = Person(
                        id=user["id"],
                        handle=user["mention_name"],
                        mention_handle="@%s" % user["mention_name"],
                        source=clean_for_pickling(user),
                        name=user["name"],
                    )

            self._people = full_roster
            for k, u in full_roster.items():
                if u.handle == settings.HIPCHAT_HANDLE:
                    self.me = u
        return self._people
Пример #6
0
    def update_will_roster_and_rooms(self):
        people = self.load('will_hipchat_people', {})

        # Loop through the connected rooms (self.roster comes from ClientXMPP)
        for roster_id in self.roster:

            cur_roster = self.roster[roster_id]
            # Loop through the users in a given room
            for user_id in cur_roster:
                user_data = cur_roster[user_id]
                if user_data["name"] != "":
                    # If we don't have this user in the people, add them.
                    if not user_id in people:
                        people[user_id] = Person()

                    hipchat_id = user_id.split("@")[0].split("_")[1]
                    # Update their info
                    people[user_id].update({
                        "name": user_data["name"],
                        "jid": user_id,
                        "hipchat_id": hipchat_id,
                    })

                    # If we don't have a nick yet, pull it and mention_name off the master user list.
                    if not hasattr(people[user_id],
                                   "nick") and hipchat_id in self.people:
                        user_data = self.get_user_list[hipchat_id]
                        people[user_id].nick = user_data["mention_name"]
                        people[user_id].mention_name = user_data[
                            "mention_name"]

                    # If it's me, save that info!
                    if people[user_id].get("name", "") == self.nick:
                        self.me = people[user_id]

        self.save("will_hipchat_people", people)

        self.update_available_rooms()
Пример #7
0
    def _rest_users_list(self):
        logging.debug('Getting users list from Rocket.Chat')

        # Remember to paginate. ;)
        count = 50
        passes = 0
        headers = {'X-Auth-Token': self.token,
                   'X-User-Id': self.userid}
        fetched = 0
        total = 0

        self.handle = settings.ROCKETCHAT_USERNAME
        self.mention_handle = "@%s" % settings.ROCKETCHAT_USERNAME

        people = {}

        while fetched <= total:
            params = {'count': count,
                      'offset': fetched}
            r = requests.get('{}users.list'.format(self.rocketchat_api_url),
                             headers=headers,
                             params=params)
            resp_json = r.json()
            if resp_json['success'] is False:
                logging.exception('resp_json: {}'.format(resp_json))
            total = resp_json['total']

            for user in resp_json['users']:
                # TODO: Unlike slack.py, no timezone support at present.
                # RC returns utcOffset, but this isn't enough to
                # determine timezone.
                # TODO: Pickle error if timezone set to UTC, and I didn't
                # have a chance to report it. Using GMT as a poor substitute.
                person = Person(
                    id=user['_id'],
                    handle=user['username'],
                    mention_handle="@%s" % user["username"],
                    source=clean_for_pickling(user)['username'],
                    name=user['name'],
                    timezone='GMT'
                )

                people[user['_id']] = person
                if user['username'] == self.handle:
                    self.me = person

            passes += 1
            fetched = count * passes

        self.people = people
Пример #8
0
class ShellBackend(StdInOutIOBackend):
    friendly_name = "Interactive Shell"
    internal_name = "will.backends.io_adapters.shell"
    partner = Person(
        id="you",
        handle="shelluser",
        mention_handle="@shelluser",
        source=Bunch(),
        name="Friend",
    )

    def send_direct_message(self, message_body, **kwargs):
        print("Will: %s" % html_to_text(message_body))

    def send_room_message(self,
                          room_id,
                          message_body,
                          html=False,
                          color="green",
                          notify=False,
                          **kwargs):
        print("Will: %s" % html_to_text(message_body))

    def set_room_topic(self, topic):
        print("Will: Let's talk about %s" % (topic, ))

    def normalize_incoming_event(self, event):
        if event["type"] == "message.incoming.stdin":
            m = Message(content=event.data.content.strip(),
                        type=event.type,
                        is_direct=True,
                        is_private_chat=True,
                        is_group_chat=False,
                        backend=self.internal_name,
                        sender=self.partner,
                        will_is_mentioned=False,
                        will_said_it=False,
                        backend_supports_acl=False,
                        original_incoming_event=event)
            return m
        else:
            # An event type the shell has no idea how to handle.
            return None

    def handle_outgoing_event(self, event):
        # Print any replies.
        if event.type in ["say", "reply"]:
            self.send_direct_message(event.content)
        if event.type in [
                "topic_change",
        ]:
            self.set_room_topic(event.content)

        elif event.type == "message.no_response":
            if event.data and hasattr(
                    event.data, "original_incoming_event") and len(
                        event.data.original_incoming_event.data.content) > 0:
                self.send_direct_message(random.choice(UNSURE_REPLIES))

        # Regardless of whether or not we had something to say,
        # give the user a new prompt.
        sys.stdout.write("You:  ")
        sys.stdout.flush()

    def bootstrap(self):
        # Bootstrap must provide a way to to have:
        # a) self.normalize_incoming_event fired, or incoming events put into self.incoming_queue
        # b) any necessary threads running for a)
        # c) self.me (Person) defined, with Will's info
        # d) self.people (dict of People) defined, with everyone in an organization/backend
        # e) self.channels (dict of Channels) defined, with all available channels/rooms.
        #    Note that Channel asks for members, a list of People.
        # f) A way for self.handle, self.me, self.people, and self.channels to be kept accurate,
        #    with a maximum lag of 60 seconds.
        self.people = {}
        self.channels = {}
        self.me = Person(
            id="will",
            handle="will",
            mention_handle="@will",
            source=Bunch(),
            name="William T. Botterton",
        )

        # Do this to get the first "you" prompt.
        self.pubsub.publish('message.incoming.stdin',
                            (Message(content="",
                                     type="message.incoming",
                                     is_direct=True,
                                     is_private_chat=True,
                                     is_group_chat=False,
                                     backend=self.internal_name,
                                     sender=self.partner,
                                     will_is_mentioned=False,
                                     will_said_it=False,
                                     backend_supports_acl=False,
                                     original_incoming_event={})))
Пример #9
0
    def normalize_incoming_event(self, event):

        if ("type" in event and event["type"] == "message" and
            ("subtype" not in event or event["subtype"] != "message_changed")
                and
                # Ignore thread summary events (for now.)
                # TODO: We should stack these into the history.
            ("subtype" not in event or
             ("message" in event and "thread_ts" not in event["message"])
             or event["subtype"] == "bot_message")):
            # print("slack: normalize_incoming_event - %s" % event)
            # Sample of group message
            # {u'source_team': u'T5ACF70KV', u'text': u'test',
            # u'ts': u'1495661121.838366', u'user': u'U5ACF70RH',
            # u'team': u'T5ACF70KV', u'type': u'message', u'channel': u'C5JDAR2S3'}

            # Sample of 1-1 message
            # {u'source_team': u'T5ACF70KV', u'text': u'test',
            # u'ts': u'1495662397.335424', u'user': u'U5ACF70RH',
            # u'team': u'T5ACF70KV', u'type': u'message', u'channel': u'D5HGP0YE7'}

            # Threaded message
            # {u'event_ts': u'1507601477.000073', u'ts': u'1507601477.000073',
            # u'subtype': u'message_replied', u'message':
            # {u'thread_ts': u'1507414046.000010', u'text': u'hello!',
            # u'ts': u'1507414046.000010', u'unread_count': 2,
            # u'reply_count': 2, u'user': u'U5GUL9D9N', u'replies':
            # [{u'user': u'U5ACF70RH', u'ts': u'1507601449.000007'}, {
            # u'user': u'U5ACF70RH', u'ts': u'1507601477.000063'}],
            # u'type': u'message', u'bot_id': u'B5HL9ABFE'},
            # u'type': u'message', u'hidden': True, u'channel': u'D5HGP0YE7'}

            if event.get("subtype") == "bot_message":
                bot = self.get_bot(event["bot_id"])

                sender = Person(id=event["bot_id"],
                                mention_handle="<@%s>" % event["bot_id"],
                                name=bot['name'],
                                handle=bot['name'],
                                source=event)

                event["text"] = event["attachments"][0]["fallback"]
            else:
                sender = self.people[event["user"]]

            channel = clean_for_pickling(self.channels[event["channel"]])
            # print "channel: %s" % channel
            interpolated_handle = "<@%s>" % self.me.id
            real_handle = "@%s" % self.me.handle
            will_is_mentioned = False
            will_said_it = False

            is_private_chat = False

            thread = None
            if "thread_ts" in event:
                thread = event["thread_ts"]

            # If the parent thread is a 1-1 between Will and I, also treat that as direct.
            # Since members[] still comes in on the thread event, we can trust this, even if we're
            # in a thread.
            if channel.id == channel.name:
                is_private_chat = True

            # <@U5GUL9D9N> hi
            # TODO: if there's a thread with just will and I on it, treat that as direct.
            is_direct = False
            if is_private_chat or event["text"].startswith(
                    interpolated_handle) or event["text"].startswith(
                        real_handle):
                is_direct = True

            if event["text"].startswith(interpolated_handle):
                event["text"] = event["text"][len(interpolated_handle):].strip(
                )

            if event["text"].startswith(real_handle):
                event["text"] = event["text"][len(real_handle):].strip()

            if interpolated_handle in event["text"] or real_handle in event[
                    "text"]:
                will_is_mentioned = True

            if event.get("user") == self.me.id:
                will_said_it = True

            m = Message(
                content=event["text"],
                type=event["type"],
                is_direct=is_direct,
                is_private_chat=is_private_chat,
                is_group_chat=not is_private_chat,
                backend=self.internal_name,
                sender=sender,
                channel=channel,
                thread=thread,
                will_is_mentioned=will_is_mentioned,
                will_said_it=will_said_it,
                backend_supports_acl=True,
                original_incoming_event=clean_for_pickling(event),
            )
            return m
        else:
            # An event type the slack ba has no idea how to handle.
            pass