Esempio n. 1
0
    def normalize_incoming_event(self, event):
        logging.debug("hipchat: normalize_incoming_event - %s" % event)
        if event["type"] in ("chat", "normal",
                             "groupchat") and ("from_jid" in event
                                               or "from" in event):

            sender = self.get_user_from_message(event)
            interpolated_handle = "@%s" % self.me.handle
            will_is_mentioned = False
            will_said_it = False
            channel = None
            if "xmpp_jid" in event and event["xmpp_jid"]:
                channel = clean_for_pickling(self.channels[event["xmpp_jid"]])
                is_private_chat = False
            else:
                if event["type"] in ("chat", "normal"):
                    is_private_chat = True

            is_direct = False
            if is_private_chat or event["body"].startswith(
                    interpolated_handle):
                is_direct = True

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

            if interpolated_handle in event["body"]:
                will_is_mentioned = True

            if sender and self.me and sender.id == self.me.id:
                will_said_it = True

            m = Message(
                content=event["body"],
                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,
                will_is_mentioned=will_is_mentioned,
                will_said_it=will_said_it,
                backend_supports_acl=True,
                original_incoming_event=clean_for_pickling(event),
            )
            # print("normalized:")
            # print(m.__dict__)
            return m

        else:
            # print("Unknown event type")
            # print(event)
            return None
Esempio n. 2
0
    def _update_channels(self, client=None):
        "Updates our internal list of channels.  Kind of expensive."
        channels = {}
        if client:
            for page in client.conversations_list(
                    limit=self.PAGE_LIMIT,
                    exclude_archived=True,
                    types="public_channel,private_channel,mpim,im",
            ):
                for channel in page["channels"]:
                    members = {}
                    for m in channel.get("members", list()):
                        if m in self.people:
                            members[m] = self.people[m]

                    channels[channel["id"]] = Channel(
                        id=channel["id"],
                        name=channel.get("name", channel["id"]),
                        source=clean_for_pickling(channel),
                        members=members,
                    )
        if len(channels.keys()) == 0:
            # Server isn't set up yet, and we're likely in a processing thread,
            if self.load("slack_channel_cache", None):
                self._channels = self.load("slack_channel_cache", None)
        else:
            self._channels = channels
            self.save("slack_channel_cache", channels)
Esempio n. 3
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)
Esempio n. 4
0
    def _rest_channels_list(self):
        logging.debug('Getting channel 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

        channels = {}

        while fetched <= total:
            r = requests.get('{}channels.list'.format(self.rocketchat_api_url),
                             headers=headers)
            resp_json = r.json()

            total = resp_json['total']

            for channel in resp_json['channels']:
                members = {}
                for username in channel['usernames']:
                    userid = self._get_userid_from_username(username)
                    members[userid] = self.people[userid]

                channels[channel['_id']] = Channel(
                    id=channel['_id'],
                    name=channel['name'],
                    source=clean_for_pickling(channel),
                    members=members)

            passes += 1
            fetched = count * passes

        self.channels = channels
Esempio n. 5
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)
Esempio n. 6
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
Esempio n. 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
Esempio n. 8
0
    def channels(self):
        if not hasattr(self, "_channels"):
            all_rooms = {}

            # Grab the first roster page, and populate all_rooms
            url = ALL_ROOMS_URL % {
                "server": settings.HIPCHAT_SERVER,
                "token": settings.HIPCHAT_V2_TOKEN,
                "start_index": 0,
                "max_results": 1000
            }
            r = requests.get(url, **settings.REQUESTS_OPTIONS)
            for room in r.json()['items']:
                # print(room)
                all_rooms["%s" % (room['xmpp_jid'], )] = Channel(
                    id=room["id"],
                    name=room["name"],
                    source=clean_for_pickling(room),
                    members={},
                )

            # 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 room in r.json()['items']:
                    all_rooms["%s" % (room['xmpp_jid'], )] = Channel(
                        id=room["id"],
                        name=room["name"],
                        source=clean_for_pickling(room),
                        members={})

            self._channels = all_rooms
        return self._channels
Esempio n. 9
0
    def _update_channels(self):
        channels = {}
        for c in self.client.server.channels:
            members = {}
            for m in c.members:
                members[m] = self.people[m]

            channels[c.id] = Channel(id=c.id,
                                     name=c.name,
                                     source=clean_for_pickling(c),
                                     members=members)
        if len(channels.keys()) == 0:
            # Server isn't set up yet, and we're likely in a processing thread,
            if self.load("slack_channel_cache", None):
                self._channels = self.load("slack_channel_cache", None)
        else:
            self._channels = channels
            self.save("slack_channel_cache", channels)
Esempio n. 10
0
    def normalize_incoming_event(self, event):
        "Makes a Slack event look like all the other events we handle"
        event_type = event.get("type")
        event_subtype = event.get("subtype")
        logging.debug("event type: %s, subtype: %s", event_type, event_subtype)
        if ((event_subtype is None
             and event_type not in ["message_changed", "message.incoming"])
                # Ignore thread summary events (for now.)
                and
            (event_subtype is None or
             ("message" in event and "thread_ts" not in event["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'}
            logging.debug("we like that event!")
            sender = self.people[event["user"]]
            channel = self.get_channel_from_name(event["channel"])
            is_private_chat = getattr(channel, "is_private", False)
            is_direct = getattr(getattr(channel, "source", None), 'is_im',
                                False)
            channel = clean_for_pickling(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

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

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

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

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

            # sometimes autocomplete adds a : to the usename, but it's certainly extraneous.
            if will_is_mentioned and event["text"][0] == ":":
                event["text"] = event["text"][1:]

            if event["user"] == self.me.id:
                will_said_it = True

            m = Message(
                content=event["text"].strip(),
                type=event_type,
                is_direct=is_direct or will_is_mentioned,
                is_private_chat=is_private_chat,
                is_group_chat=not (is_private_chat or is_direct),
                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
        # An event type the slack ba has no idea how to handle.
        return None
Esempio n. 11
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")
            # Ignore thread summary events (for now.)
            # TODO: We should stack these into the history.
            and ("subtype" not in event or ("message" in event and "thread_ts" not in event["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'}

            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["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
Esempio n. 12
0
    def normalize_incoming_event(self, event):
        logging.info('Normalizing incoming Rocket.Chat event')
        logging.debug('event: {}'.format(self.pp.pformat(event)))
        if event["type"] == "message":

            # Were we mentioned?
            will_is_mentioned = False
            for mention in event['mentions']:
                if mention['username'] == self.me.handle:
                    will_is_mentioned = True
                    break

            # Handle direct messages, which in Rocket.Chat are a rid
            # made up of both users' _ids.
            is_private_chat = False
            if self.me.id in event["rid"]:
                is_private_chat = True

                # Create a "Channel" to align with Rocket.Chat DM
                # paradigm. There might well be a better way of doing
                # this. See TODO in _rest_channels_list.
                sender_id = event['u']['_id']
                ids = [sender_id, self.me.id]
                ids.sort()
                channel_id = '{}{}'.format(*ids)
                sender = self.people[sender_id]
                channel_members = {}
                channel_members[sender_id] = sender
                channel_members[self.me.id] = self.me
                channel = Channel(id=channel_id,
                                  name=channel_id,
                                  source=clean_for_pickling(channel_id),
                                  members=channel_members)
            else:
                if "rid" in event and event["rid"] in self.channels:
                    channel = clean_for_pickling(self.channels[event["rid"]])
                else:
                    # Private channel, unknown members.  Just do our best and try to route it.
                    if "rid" in event:
                        channel = Channel(id=event["rid"],
                                          name=event["rid"],
                                          source=clean_for_pickling(
                                              event["rid"]),
                                          members={})
            logging.debug('channel: {}'.format(channel))

            # Set various variables depending on whether @handle was
            # part of the message.
            interpolated_handle = "@%s " % self.handle
            logging.debug(
                'interpolated_handle: {}'.format(interpolated_handle))
            is_direct = False
            if is_private_chat or event['msg'].startswith(interpolated_handle):
                is_direct = True

            # Strip my handle from the start. NB Won't strip it from
            # elsewhere in the text, and won't strip other mentions.
            # This will stop regexes from working, not sure if it's a
            # feature or a bug.
            if event['msg'].startswith(interpolated_handle):
                event['msg'] = event['msg'][len(interpolated_handle):].strip()

            if interpolated_handle in event['msg']:
                will_is_mentioned = True

            # Determine if Will said it.
            logging.debug('self.people: {}'.format(self.pp.pformat(
                self.people)))
            sender = self.people[event['u']['_id']]
            logging.debug('sender: {}'.format(sender))
            if sender['handle'] == self.me.handle:
                logging.debug('Will said it')
                will_said_it = True
            else:
                logging.debug('Will didnt say it')
                will_said_it = False

            m = Message(content=event['msg'],
                        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,
                        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:
            logging.debug(
                'Passing, I dont know how to normalize this event of type ',
                event["type"])
            pass