From 27a23ce47e3ec11b94f3355c2d2ee94c1958679c Mon Sep 17 00:00:00 2001 From: Evelyn Osman Date: Tue, 13 Apr 2021 12:31:26 +0200 Subject: [PATCH] Support unsolicitied direct file uploads (#440) * Support sending files directly to user via direct message * Cleaning filenames caused files to lose extension * Update Authors, added @BrianGallew --- AUTHORS | 5 ++-- will/backends/io_adapters/slack.py | 47 ++++++++++++++++++++++++++---- will/plugin.py | 4 +-- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3bbe2109..7212b4f2 100644 --- a/AUTHORS +++ b/AUTHORS @@ -51,8 +51,9 @@ acommasplice, https://github.com/acommasplice TaunoTinits, https://github.com/TaunoTinits ostracon, https://github.com/ostracon mattcl, https://github.com/mattcl -Ahmed Osman, https://github.com/Ashex +Evelyn Osman, https://github.com/Ashex Boris Peterbarg, https://github.com/reist unicolet, https://github.com/unicolet Rob Salmond, https://github.com/rsalmond -Jeremy Logan, https://github.com/fixedd \ No newline at end of file +Jeremy Logan, https://github.com/fixedd +Brian Gallew, https://github.com/BrianGallew \ No newline at end of file diff --git a/will/backends/io_adapters/slack.py b/will/backends/io_adapters/slack.py index a2f69c06..46cad3d9 100644 --- a/will/backends/io_adapters/slack.py +++ b/will/backends/io_adapters/slack.py @@ -78,6 +78,10 @@ def get_channel_from_name(self, name): for c in self.channels.values(): if c.name.lower() == name.lower() or c.id.lower() == name.lower(): return c + # We need to check if a user id was passed as a channel + # and get the correct IM channel if it was. + elif name.startswith('U') or name.startswith('W'): + return self.open_direct_message(name) webclient = self.client._web_client # pylint: disable=protected-access try: channel_info = webclient.conversations_info(channel=name)["channel"] @@ -103,6 +107,11 @@ def get_channel_from_name(self, name): is_private=True, ) + def get_channel_name_from_id(self, name): + for k, c in self.channels.items(): + if c.name.lower() == name.lower() or c.id.lower() == name.lower(): + return c.name + def normalize_incoming_event(self, event): "Makes a Slack event look like all the other events we handle" event_type = event.get("type") @@ -141,8 +150,21 @@ def normalize_incoming_event(self, event): # 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"]) + if event_subtype == "bot_message": + sender = Person( + id=event["bot_id"], + mention_handle="<@%s>" % event["bot_id"], + handle=event["username"], + source=event, + name=event["username"], + ) + else: + sender = self.people[event["user"]] + try: + channel = self.get_channel_from_name(event["channel"]) + except KeyError: + self._update_channels() + 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) @@ -169,7 +191,7 @@ def normalize_incoming_event(self, event): if will_is_mentioned and event["text"][0] == ":": event["text"] = event["text"][1:] - if event["user"] == self.me.id: + if event.get("user") == self.me.id: will_said_it = True m = Message( @@ -206,10 +228,14 @@ def send_file(self, event): try: logging.info('EVENT: %s', str(event)) - data = { + data = {} + if hasattr(event, "kwargs"): + data.update(event.kwargs) + + data.update({ 'filename': event.filename, 'filetype': event.filetype - } + }) self.set_data_channel_and_thread(event, data) # This is just *silly* if 'thread_ts' in data: @@ -303,6 +329,10 @@ def handle_outgoing_event(self, event, retry=5): @staticmethod def set_data_channel_and_thread(event, data=None): "Update data with the channel/thread information from event" + if event.type == "file.upload": + # We already know what to do when it's a file DM + if event.kwargs.get("is_direct") is True: + return if data is None: data = dict() if "channel" in event: @@ -489,6 +519,13 @@ def send_message(self, event): "chat.postMessage", data=data ) + def open_direct_message(self, user_id): + """Opens a DM channel.""" + return self.client._web_client.api_call( # pylint: disable=protected-access + "conversations.open", + users=[user_id] + )['channel']['id'] + def update_message(self, event): "Update a Slack message" if event.content == "" or event.content is None: diff --git a/will/plugin.py b/will/plugin.py index 438229af..c0c2f643 100644 --- a/will/plugin.py +++ b/will/plugin.py @@ -10,8 +10,6 @@ from will.mixins import NaturalTimeMixin, ScheduleMixin, StorageMixin, SettingsMixin, \ EmailMixin, PubSubMixin -FILENAME_CLEANER = re.compile(r'[^-_0-9a-zA-Z]+') - class WillPlugin(EmailMixin, StorageMixin, NaturalTimeMixin, ScheduleMixin, SettingsMixin, PubSubMixin): @@ -114,7 +112,7 @@ def send_file(self, message, content, filename, text=None, filetype='text', e = Event( type="file.upload", file=content, - filename=FILENAME_CLEANER.sub('_', filename), + filename=filename, filetype=filetype, source_message=message, title=text,