From 69a19eae35eac1e9960b7a33c589cf22cd7d4aea Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Fri, 27 Oct 2017 00:02:57 -0700 Subject: Add support for shared channels Since shared channels only work with the new conversations API, a new class of SlackChannel and API type were added to support them. Also `rtm.start` doesn't include external users so their information needs to be fetched individually when getting the channel history. To distinguish external users from team members their nicks get appended with an asterisk, which can be changed with a new setting. They also appear in a new "External" group in the nicklist since their presences can't be fetched with `users.getPresence`. Unfortunately `conversations.history` doesn't include thread messages so threads won't show up in shared channels. --- _pytest/data/http/rtm.start.json | 8 +++ wee_slack.py | 117 ++++++++++++++++++++++++++++++++++----- 2 files changed, 111 insertions(+), 14 deletions(-) diff --git a/_pytest/data/http/rtm.start.json b/_pytest/data/http/rtm.start.json index d9cc464..34d875a 100644 --- a/_pytest/data/http/rtm.start.json +++ b/_pytest/data/http/rtm.start.json @@ -307,6 +307,8 @@ "creator": "U407ABLLW", "is_archived": false, "is_general": true, + "is_shared": false, + "is_org_shared": false, "has_pins": false, "is_member": true, "last_read": "1485976236.000019", @@ -392,6 +394,8 @@ "creator": "U407ABLLW", "is_archived": false, "is_general": false, + "is_shared": false, + "is_org_shared": false, "has_pins": false, "is_member": false, "previous_names": [] @@ -404,6 +408,8 @@ "creator": "U407ABLLW", "is_archived": false, "is_general": false, + "is_shared": false, + "is_org_shared": false, "has_pins": false, "is_member": true, "last_read": "1485969592.000002", @@ -441,6 +447,8 @@ "creator": "U407ABLLW", "is_archived": false, "is_general": false, + "is_shared": false, + "is_org_shared": false, "has_pins": false, "is_member": false, "previous_names": [ diff --git a/wee_slack.py b/wee_slack.py index 9262e7f..f6448ce 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -72,6 +72,13 @@ SLACK_API_TRANSLATOR = { "mark": "groups.mark", "info": "groups.info" }, + "shared": { + "history": "conversations.history", + "join": "conversations.join", + "leave": "conversations.leave", + "mark": "channels.mark", + "info": "conversations.info", + }, "thread": { "history": None, "join": None, @@ -122,6 +129,7 @@ def utf8_decode(f): NICK_GROUP_HERE = "0|Here" NICK_GROUP_AWAY = "1|Away" +NICK_GROUP_EXTERNAL = "2|External" sslopt_ca_certs = {} if hasattr(ssl, "get_default_verify_paths") and callable(ssl.get_default_verify_paths): @@ -981,6 +989,7 @@ class SlackTeam(object): except: self.channels = channels self.users = users + self.external_users = {} self.bots = bots self.team_hash = SlackTeam.generate_team_hash(self.nick, self.subdomain) self.name = self.domain @@ -1071,6 +1080,12 @@ class SlackTeam(object): def get_username_map(self): return {v.name: k for k, v in self.users.iteritems()} + def get_user(self, user_id): + if user_id in self.users: + return self.users[user_id] + elif user_id in self.external_users: + return self.external_users[user_id] + def get_team_hash(self): return self.team_hash @@ -1248,6 +1263,8 @@ class SlackChannel(object): prepend = ">" elif self.type == "group": prepend = config.group_name_prefix + elif self.type == "shared": + prepend = config.shared_name_prefix else: prepend = "#" select = { @@ -1552,7 +1569,7 @@ class SlackChannel(object): def update_nicklist(self, user=None): if not self.channel_buffer: return - if self.type not in ["channel", "group", "mpim"]: + if self.type not in ["channel", "group", "mpim", "shared"]: return w.buffer_set(self.channel_buffer, "nicklist", "1") # create nicklists for the current channel if they don't exist @@ -1564,16 +1581,25 @@ class SlackChannel(object): if not afk: afk = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_AWAY, "weechat.color.nicklist_group", 1) + # Add External nicklist group only for shared channels + if self.type == 'shared': + external = w.nicklist_search_group(self.channel_buffer, '', NICK_GROUP_EXTERNAL) + if not external: + external = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_EXTERNAL, 'weechat.color.nicklist_group', 2) + if user and len(self.members) < 1000: - user = self.team.users[user] - if user.deleted: + user = self.team.get_user(user) + # External users that have left shared channels won't exist + if not user or user.deleted: return nick = w.nicklist_search_nick(self.channel_buffer, "", user.name) # since this is a change just remove it regardless of where it is w.nicklist_remove_nick(self.channel_buffer, nick) # now add it back in to whichever.. nick_group = afk - if self.team.is_user_present(user.identifier): + if user.is_external: + nick_group = external + elif self.team.is_user_present(user.identifier): nick_group = here if user.identifier in self.members: w.nicklist_add_nick(self.channel_buffer, nick_group, user.name, user.color_name, "", "", 1) @@ -1583,11 +1609,13 @@ class SlackChannel(object): if len(self.members) < 1000: try: for user in self.members: - user = self.team.users[user] + user = self.team.get_user(user) if user.deleted: continue nick_group = afk - if self.team.is_user_present(user.identifier): + if user.is_external: + nick_group = external + elif self.team.is_user_present(user.identifier): nick_group = here w.nicklist_add_nick(self.channel_buffer, nick_group, user.name, user.color_name, "", "", 1) except Exception as e: @@ -1770,6 +1798,30 @@ class SlackMPDMChannel(SlackChannel): pass +class SlackSharedChannel(SlackChannel): + def __init__(self, eventrouter, **kwargs): + super(SlackSharedChannel, self).__init__(eventrouter, **kwargs) + self.type = 'shared' + + def set_related_server(self, team): + super(SlackSharedChannel, self).set_related_server(team) + # Fetch members here (after the team is known) since they aren't + # included in rtm.start + s = SlackRequest(team.token, 'conversations.members', {'channel': self.identifier}, team_hash=team.team_hash, channel_identifier=self.identifier) + self.eventrouter.receive(s) + + def get_history(self, slow_queue=False): + # Get info for external users in the channel + all_users = set(self.team.users.keys()) | set(self.team.external_users.keys()) + for user in self.members - all_users: + s = SlackRequest(self.team.token, 'users.info', {'user': user}, team_hash=self.team.team_hash, channel_identifier=self.identifier) + self.eventrouter.receive(s) + super(SlackSharedChannel, self).get_history(slow_queue) + + def set_name(self, slack_name): + self.name = config.shared_name_prefix + slack_name + + class SlackThreadChannel(object): """ A thread channel is a virtual channel. We don't inherit from @@ -1923,6 +1975,7 @@ class SlackUser(object): # the rest we can just learn from slack self.identifier = kwargs["id"] self.profile = {} # in case it's not in kwargs + self.is_external = False for key, value in kwargs.items(): setattr(self, key, value) @@ -2020,10 +2073,13 @@ class SlackMessage(object): if 'user' in self.message_json: if self.message_json['user'] == self.team.myidentifier: u = self.team.users[self.team.myidentifier] - elif self.message_json['user'] in self.team.users: - u = self.team.users[self.message_json['user']] + else: + u = self.team.get_user(self.message_json['user']) name = "{}".format(u.formatted_name()) name_plain = "{}".format(u.formatted_name(enable_color=False)) + if u.is_external: + name += config.external_user_suffix + name_plain += config.external_user_suffix elif 'username' in self.message_json: u = self.message_json["username"] if self.message_json.get("subtype") == "bot_message": @@ -2163,7 +2219,10 @@ def handle_rtmstart(login_data, eventrouter): channels = {} for item in login_data["channels"]: - channels[item["id"]] = SlackChannel(eventrouter, **item) + if item["is_shared"]: + channels[item["id"]] = SlackSharedChannel(eventrouter, **item) + else: + channels[item["id"]] = SlackChannel(eventrouter, **item) for item in login_data["ims"]: channels[item["id"]] = SlackDMChannel(eventrouter, users, **item) @@ -2260,6 +2319,10 @@ def handle_mpimhistory(message_json, eventrouter, **kwargs): handle_history(message_json, eventrouter, **kwargs) +def handle_conversationshistory(message_json, eventrouter, **kwargs): + handle_history(message_json, eventrouter, **kwargs) + + def handle_history(message_json, eventrouter, **kwargs): request_metadata = pickle.loads(message_json["wee_slack_request_metadata"]) kwargs['team'] = eventrouter.teams[request_metadata.team_hash] @@ -2276,6 +2339,23 @@ def handle_history(message_json, eventrouter, **kwargs): process_message(message, eventrouter, **kwargs) +def handle_conversationsmembers(members_json, eventrouter, **kwargs): + request_metadata = pickle.loads(members_json['wee_slack_request_metadata']) + team = eventrouter.teams[request_metadata.team_hash] + channel = team.channels[request_metadata.channel_identifier] + channel.members = set(members_json['members']) + + +def handle_usersinfo(user_json, eventrouter, **kwargs): + request_metadata = pickle.loads(user_json['wee_slack_request_metadata']) + team = eventrouter.teams[request_metadata.team_hash] + channel = team.channels[request_metadata.channel_identifier] + user_info = user_json['user'] + user_info.update(is_external=True, deleted=False) + team.external_users[user_info['id']] = SlackUser(**user_info) + channel.update_nicklist(user_info['id']) + + ###### New/converted process_ and subprocess_ methods def process_hello(message_json, eventrouter, **kwargs): kwargs['team'].subscribe_users_presence() @@ -2834,11 +2914,12 @@ def resolve_ref(ref): e = EVENTROUTER if ref.startswith('@U') or ref.startswith('@W'): for t in e.teams.keys(): - if ref[1:] in e.teams[t].users: - # try: - return "@{}".format(e.teams[t].users[ref[1:]].name) - # except: - # dbg("NAME: {}".format(ref)) + user = e.teams[t].get_user(ref[1:]) + if user: + name = '@{}'.format(user.name) + if user.is_external: + name += config.external_user_suffix + return name elif ref.startswith('#C'): for t in e.teams.keys(): if ref[1:] in e.teams[t].channels: @@ -3666,6 +3747,9 @@ class PluginConfig(object): 'distracting_channels': Setting( default='', desc='List of channels to hide.'), + 'external_user_suffix': Setting( + default='*', + desc='The suffix appended to nicks to indicate external users.'), 'group_name_prefix': Setting( default='&', desc='The prefix of buffer names for groups (private channels).'), @@ -3697,6 +3781,9 @@ class PluginConfig(object): ' will be used instead of the actual name of the slack (in buffer' ' names, logging, etc). E.g `work:no_fun_allowed` would make your' ' work slack show up as `no_fun_allowed` rather than `work.slack.com`.'), + 'shared_name_prefix': Setting( + default='%', + desc='The prefix of buffer names for shared channels.'), 'short_buffer_names': Setting( default='false', desc='Use `foo.#channel` rather than `foo.slack.com.#channel` as the' @@ -3796,10 +3883,12 @@ class PluginConfig(object): return w.config_get_plugin(key) == default get_debug_level = get_int + get_external_user_suffix = get_string get_group_name_prefix = get_string get_map_underline_to = get_string get_render_bold_as = get_string get_render_italic_as = get_string + get_shared_name_prefix = get_string get_slack_timeout = get_int get_thread_suffix_color = get_string get_unfurl_auto_link_display = get_string -- cgit From 54a61626cc438287f00bcd209571619562538ccd Mon Sep 17 00:00:00 2001 From: Eric Wang Date: Tue, 3 Apr 2018 11:22:11 -0700 Subject: Replace Slack links with direct links to shared files The current links in shared file messages only show a thumbnail and require an extra click to get to the actual shared file, which is a minor annoyance. Links from external members in shared channels are also from their team's Slack subdomain, so they're inaccessible if you're not a member of their team. The direct links are from the files.slack.com subdomain though and visible to all, and the official Slack client uses them to show those files. --- wee_slack.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wee_slack.py b/wee_slack.py index f6448ce..7ba22ab 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -2051,6 +2051,15 @@ class SlackMessage(object): if message_json.get('subtype') == 'me_message' and not message_json['text'].startswith(self.sender): message_json['text'] = self.sender + ' ' + self.message_json['text'] + # Replace Slack link with direct link to shared file (required if + # shared by an external user since only the direct link is accessible) + if message_json.get('subtype') == 'file_share': + message_json['text'] = re.sub( + r' Date: Wed, 9 May 2018 00:34:03 -0700 Subject: Add support for DMs with external users --- wee_slack.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index 7ba22ab..a78794a 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -1661,12 +1661,21 @@ class SlackDMChannel(SlackChannel): def __init__(self, eventrouter, users, **kwargs): dmuser = kwargs["user"] - kwargs["name"] = users[dmuser].name + kwargs["name"] = users[dmuser].name if dmuser in users else dmuser super(SlackDMChannel, self).__init__(eventrouter, **kwargs) self.type = 'im' self.update_color() self.set_name(self.slack_name) - self.topic = create_user_status_string(users[dmuser].profile) + if dmuser in users: + self.topic = create_user_status_string(users[dmuser].profile) + + def set_related_server(self, team): + super(SlackDMChannel, self).set_related_server(team) + # If the topic hasn't been set then the user is external and needs to + # be fetched + if not self.topic: + s = SlackRequest(self.team.token, 'users.info', {'user': self.slack_name}, team_hash=self.team.team_hash, channel_identifier=self.identifier) + self.eventrouter.receive(s) def set_name(self, slack_name): self.name = slack_name @@ -2361,8 +2370,15 @@ def handle_usersinfo(user_json, eventrouter, **kwargs): channel = team.channels[request_metadata.channel_identifier] user_info = user_json['user'] user_info.update(is_external=True, deleted=False) - team.external_users[user_info['id']] = SlackUser(**user_info) - channel.update_nicklist(user_info['id']) + user = SlackUser(**user_info) + team.external_users[user_info['id']] = user + + if channel.type == 'shared': + channel.update_nicklist(user_info['id']) + elif channel.type == 'im': + channel.slack_name = user.name + channel.set_topic(create_user_status_string(user.profile)) + ###### New/converted process_ and subprocess_ methods -- cgit From 7c9afee412a0c328578faa9b1120e453ec5a1f1a Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Thu, 7 Jun 2018 13:12:08 +0200 Subject: Combine users and external_users list Since we have an is_external attribute on the users, it's simpler to just have them all in a single list. The documentation says that the user id is not necessarily unique across teams, but I talked to Slack and they said it's unlikely to be a collision. If you refer to a user in a message, you only use the id without a team id, so you will have problems with collisions there anyway. I'm waiting to hear from Slack how to handle that. --- wee_slack.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index a78794a..95b11dd 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -989,7 +989,6 @@ class SlackTeam(object): except: self.channels = channels self.users = users - self.external_users = {} self.bots = bots self.team_hash = SlackTeam.generate_team_hash(self.nick, self.subdomain) self.name = self.domain @@ -1080,12 +1079,6 @@ class SlackTeam(object): def get_username_map(self): return {v.name: k for k, v in self.users.iteritems()} - def get_user(self, user_id): - if user_id in self.users: - return self.users[user_id] - elif user_id in self.external_users: - return self.external_users[user_id] - def get_team_hash(self): return self.team_hash @@ -1588,7 +1581,7 @@ class SlackChannel(object): external = w.nicklist_add_group(self.channel_buffer, '', NICK_GROUP_EXTERNAL, 'weechat.color.nicklist_group', 2) if user and len(self.members) < 1000: - user = self.team.get_user(user) + user = self.team.users.get(user) # External users that have left shared channels won't exist if not user or user.deleted: return @@ -1609,7 +1602,7 @@ class SlackChannel(object): if len(self.members) < 1000: try: for user in self.members: - user = self.team.get_user(user) + user = self.team.users.get(user) if user.deleted: continue nick_group = afk @@ -1821,8 +1814,7 @@ class SlackSharedChannel(SlackChannel): def get_history(self, slow_queue=False): # Get info for external users in the channel - all_users = set(self.team.users.keys()) | set(self.team.external_users.keys()) - for user in self.members - all_users: + for user in self.members - set(self.team.users.keys()): s = SlackRequest(self.team.token, 'users.info', {'user': user}, team_hash=self.team.team_hash, channel_identifier=self.identifier) self.eventrouter.receive(s) super(SlackSharedChannel, self).get_history(slow_queue) @@ -2092,7 +2084,7 @@ class SlackMessage(object): if self.message_json['user'] == self.team.myidentifier: u = self.team.users[self.team.myidentifier] else: - u = self.team.get_user(self.message_json['user']) + u = self.team.users.get(self.message_json['user']) name = "{}".format(u.formatted_name()) name_plain = "{}".format(u.formatted_name(enable_color=False)) if u.is_external: @@ -2371,7 +2363,7 @@ def handle_usersinfo(user_json, eventrouter, **kwargs): user_info = user_json['user'] user_info.update(is_external=True, deleted=False) user = SlackUser(**user_info) - team.external_users[user_info['id']] = user + team.users[user_info['id']] = user if channel.type == 'shared': channel.update_nicklist(user_info['id']) @@ -2939,7 +2931,7 @@ def resolve_ref(ref): e = EVENTROUTER if ref.startswith('@U') or ref.startswith('@W'): for t in e.teams.keys(): - user = e.teams[t].get_user(ref[1:]) + user = e.teams[t].users.get(ref[1:]) if user: name = '@{}'.format(user.name) if user.is_external: -- cgit From 9b89a5188a8658f91d325947f231b98d08348bce Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Thu, 7 Jun 2018 13:12:42 +0200 Subject: Use users list to check if user info should be fetched This is probably more reliable than depending on the topic not being set. --- wee_slack.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index 95b11dd..f61168e 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -1664,9 +1664,7 @@ class SlackDMChannel(SlackChannel): def set_related_server(self, team): super(SlackDMChannel, self).set_related_server(team) - # If the topic hasn't been set then the user is external and needs to - # be fetched - if not self.topic: + if self.user not in self.team.users: s = SlackRequest(self.team.token, 'users.info', {'user': self.slack_name}, team_hash=self.team.team_hash, channel_identifier=self.identifier) self.eventrouter.receive(s) -- cgit From bee8c87e680795b953ea6bfaee5740ad99833b1a Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Thu, 7 Jun 2018 13:31:25 +0200 Subject: Check if user exists in is_user_present This method may be called before an external user is fetched, so it doesn't exist yet. --- wee_slack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wee_slack.py b/wee_slack.py index f61168e..f4e3786 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -1097,7 +1097,7 @@ class SlackTeam(object): def is_user_present(self, user_id): user = self.users.get(user_id) - if user.presence == 'active': + if user and user.presence == 'active': return True else: return False -- cgit From 164443ab9de3033aa3738dd34ea068053d6bf7fa Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Thu, 7 Jun 2018 13:33:52 +0200 Subject: Ensure presence is always set on SlackUser The presence attribute is missing in the response for external users, so we just set it to unknown. --- wee_slack.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index f4e3786..edc33ec 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -1970,10 +1970,11 @@ class SlackUser(object): """ def __init__(self, **kwargs): - # We require these two things for a valid object, - # the rest we can just learn from slack self.identifier = kwargs["id"] - self.profile = {} # in case it's not in kwargs + # These attributes may be missing in the response, so we have to make + # sure they're set + self.profile = {} + self.presence = kwargs.get("presence", "unknown") self.is_external = False for key, value in kwargs.items(): setattr(self, key, value) -- cgit From eb9a1b306a0df2410ace180178c6c9737d03d73d Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Thu, 7 Jun 2018 13:56:29 +0200 Subject: Don't assume all users.info responses are for external users We might want to use this request for other users as well in the future, so we shouldn't assume that all of the users received by it are external. --- wee_slack.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index edc33ec..b0516d8 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -1975,7 +1975,8 @@ class SlackUser(object): # sure they're set self.profile = {} self.presence = kwargs.get("presence", "unknown") - self.is_external = False + self.deleted = kwargs.get("deleted", False) + self.is_external = "is_stranger" in kwargs for key, value in kwargs.items(): setattr(self, key, value) @@ -2360,7 +2361,6 @@ def handle_usersinfo(user_json, eventrouter, **kwargs): team = eventrouter.teams[request_metadata.team_hash] channel = team.channels[request_metadata.channel_identifier] user_info = user_json['user'] - user_info.update(is_external=True, deleted=False) user = SlackUser(**user_info) team.users[user_info['id']] = user -- cgit From 3cd3d096d6ca8bd4963b41f8ec5eb7fec201516d Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Thu, 7 Jun 2018 14:25:45 +0200 Subject: Handle get_sender being called before users.info When messages were loaded before the user info were fetched for an external user, this would crash. --- wee_slack.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index b0516d8..62719a4 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -2080,33 +2080,27 @@ class SlackMessage(object): def get_sender(self): name = "" name_plain = "" - if 'user' in self.message_json: - if self.message_json['user'] == self.team.myidentifier: - u = self.team.users[self.team.myidentifier] - else: - u = self.team.users.get(self.message_json['user']) - name = "{}".format(u.formatted_name()) - name_plain = "{}".format(u.formatted_name(enable_color=False)) - if u.is_external: + user = self.team.users.get(self.message_json.get('user')) + if user: + name = "{}".format(user.formatted_name()) + name_plain = "{}".format(user.formatted_name(enable_color=False)) + if user.is_external: name += config.external_user_suffix name_plain += config.external_user_suffix elif 'username' in self.message_json: - u = self.message_json["username"] + username = self.message_json["username"] if self.message_json.get("subtype") == "bot_message": - name = "{} :]".format(u) - name_plain = "{}".format(u) + name = "{} :]".format(username) + name_plain = "{}".format(username) else: - name = "-{}-".format(u) - name_plain = "{}".format(u) + name = "-{}-".format(username) + name_plain = "{}".format(username) elif 'service_name' in self.message_json: name = "-{}-".format(self.message_json["service_name"]) name_plain = "{}".format(self.message_json["service_name"]) elif self.message_json.get('bot_id') in self.team.bots: name = "{} :]".format(self.team.bots[self.message_json["bot_id"]].formatted_name()) name_plain = "{}".format(self.team.bots[self.message_json["bot_id"]].formatted_name(enable_color=False)) - else: - name = "" - name_plain = "" return (name, name_plain) def add_reaction(self, reaction, user): -- cgit From b6d9e04bc0aa47545f46fc468c8ccc7d39ddd256 Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Thu, 7 Jun 2018 16:56:12 +0200 Subject: Use team id to determine if user is external The is_stranger attribute isn't clearly documented, so it's safer to check if the team_id of the user matches the team_id of the team we request the user in. --- wee_slack.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/wee_slack.py b/wee_slack.py index 62719a4..2682ea9 100644 --- a/wee_slack.py +++ b/wee_slack.py @@ -966,7 +966,8 @@ class SlackTeam(object): Team object under which users and channels live.. Does lots. """ - def __init__(self, eventrouter, token, websocket_url, subdomain, nick, myidentifier, users, bots, channels, **kwargs): + def __init__(self, eventrouter, token, websocket_url, team_info, nick, myidentifier, users, bots, channels, **kwargs): + self.identifier = team_info["id"] self.ws_url = websocket_url self.connected = False self.connecting = False @@ -976,8 +977,8 @@ class SlackTeam(object): self.eventrouter = eventrouter self.token = token self.team = self - self.subdomain = subdomain - self.domain = subdomain + ".slack.com" + self.subdomain = team_info["domain"] + self.domain = self.subdomain + ".slack.com" self.preferred_name = self.domain self.nick = nick self.myidentifier = myidentifier @@ -1969,14 +1970,15 @@ class SlackUser(object): Represends an individual slack user. Also where you set their name formatting. """ - def __init__(self, **kwargs): + def __init__(self, originating_team_id, **kwargs): self.identifier = kwargs["id"] # These attributes may be missing in the response, so we have to make # sure they're set self.profile = {} self.presence = kwargs.get("presence", "unknown") self.deleted = kwargs.get("deleted", False) - self.is_external = "is_stranger" in kwargs + self.is_external = (not kwargs.get("is_bot") and + kwargs.get("team_id") != originating_team_id) for key, value in kwargs.items(): setattr(self, key, value) @@ -2018,8 +2020,8 @@ class SlackBot(SlackUser): Basically the same as a user, but split out to identify and for future needs """ - def __init__(self, **kwargs): - super(SlackBot, self).__init__(**kwargs) + def __init__(self, originating_team_id, **kwargs): + super(SlackBot, self).__init__(originating_team_id, is_bot=True, **kwargs) class SlackMessage(object): @@ -2215,11 +2217,11 @@ def handle_rtmstart(login_data, eventrouter): users = {} for item in login_data["users"]: - users[item["id"]] = SlackUser(**item) + users[item["id"]] = SlackUser(login_data['team']['id'], **item) bots = {} for item in login_data["bots"]: - bots[item["id"]] = SlackBot(**item) + bots[item["id"]] = SlackBot(login_data['team']['id'], **item) channels = {} for item in login_data["channels"]: @@ -2241,7 +2243,7 @@ def handle_rtmstart(login_data, eventrouter): eventrouter, metadata.token, login_data['url'], - login_data["team"]["domain"], + login_data["team"], login_data["self"]["name"], login_data["self"]["id"], users, @@ -2355,7 +2357,7 @@ def handle_usersinfo(user_json, eventrouter, **kwargs): team = eventrouter.teams[request_metadata.team_hash] channel = team.channels[request_metadata.channel_identifier] user_info = user_json['user'] - user = SlackUser(**user_info) + user = SlackUser(team.identifier, **user_info) team.users[user_info['id']] = user if channel.type == 'shared': @@ -2426,7 +2428,7 @@ def process_user_typing(message_json, eventrouter, **kwargs): def process_team_join(message_json, eventrouter, **kwargs): user = message_json['user'] team = kwargs["team"] - team.users[user["id"]] = SlackUser(**user) + team.users[user["id"]] = SlackUser(team.identifier, **user) def process_pong(message_json, eventrouter, **kwargs): -- cgit