Skip to content

Commit 6eefe66

Browse files
authored
Bridge files slack to zulip (#15)
* Fix a time zone sensitivity issue in the reformat test. * Very basic support for mirroring files from slack to zulip. - Only minimal error checking, and on any failure will revert to just saying there was a file there with no link. - No tests. - Does not do any clever caching -- editing without replacing the file just uploads another copy.
1 parent 7b54049 commit 6eefe66

File tree

3 files changed

+37
-5
lines changed

3 files changed

+37
-5
lines changed

__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ async def receive_slack_msg(**payload):
249249
needs_leading_newline = \
250250
(len(msg) > 0 or len(formatted_attachments['markdown']) > 0)
251251
formatted_files = slack_reformat.format_files_from_slack(
252-
files, needs_leading_newline)
252+
files, needs_leading_newline, SLACK_TOKEN, self.zulip_client)
253253

254254
zulip_message_text = \
255255
msg + formatted_attachments['markdown'] + formatted_files['markdown']
@@ -327,6 +327,7 @@ async def receive_slack_msg(**payload):
327327

328328
def send_from_zulip(self, msg):
329329
_LOGGER.debug('caught zulip message')
330+
_LOGGER.debug('JSON: %s' % json.dumps(msg))
330331
try:
331332
if (msg['subject'] in PUBLIC_TWO_WAY and
332333
msg['sender_short_name'] != ZULIP_BOT_NAME):

slack_reformat.py

+26-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
import logging
66
import re
77
import sys
8+
import requests
89
import traceback
910

11+
from io import BytesIO
12+
1013
_LOGGER = logging.getLogger(__name__)
1114

1215
# These are module-private regular expressions used by the reformatter
@@ -151,10 +154,14 @@ async def replace_markdown_link(m):
151154
replace_markdown_link)
152155

153156

154-
def format_files_from_slack(files, needs_leading_newline):
157+
def format_files_from_slack(files, needs_leading_newline,
158+
slack_bearer_token=None, zulip_client=None):
155159
'''Given a list of files from the slack API, return both a markdown and plaintext
156160
string representation of those files.
157161
162+
Assuming a bearer token and zulip client are provided, the files are mirrored to zulip
163+
and those links are included in the markdown result.
164+
158165
This method only uses the passed in message text to determine how to format its output
159166
caller must append as appropriate.'''
160167
if files == None:
@@ -174,7 +181,24 @@ def format_files_from_slack(files, needs_leading_newline):
174181
first_file = False
175182

176183
if 'name' in file and file['name']:
177-
output['markdown'] += f"*(Bridged Message included file: {file['name']}"
184+
rendered_markdown_name = file['name']
185+
if slack_bearer_token and zulip_client and 'url_private' in file and file['url_private']:
186+
file_private_url = file['url_private']
187+
r = requests.get(file_private_url,
188+
headers={"Authorization": f"Bearer {slack_bearer_token}"})
189+
if r.status_code == 200:
190+
uploadable_file = BytesIO(r.content)
191+
uploadable_file.name = file['name']
192+
193+
response = zulip_client.upload_file(uploadable_file)
194+
if 'uri' in response and response['uri']:
195+
rendered_markdown_name = f"[{file['name']}]({response['uri']})"
196+
else:
197+
_LOGGER.info('Got bad response when uploading to zulip: {}'.format(response))
198+
else:
199+
_LOGGER.info(f"Got code {r.status_code} when fetching {file_private_url} from slack.")
200+
201+
output['markdown'] += f"*(Bridged Message included file: {rendered_markdown_name}"
178202
output['plaintext'] += f"(Bridged Message included file: {file['name']}"
179203
if 'title' in file and file['title'] and file['name'] != file['title']:
180204
output['markdown'] += f": '{file['title']}'"

slack_reformat_test.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ def test_markdown_links(self):
194194

195195
def test_format_files_from_slack(self):
196196
# Note: This test is _not_ exhaustive!
197+
#
198+
# TODO: Figure out some way to mock out the pieces necessary to allow us to test the download/upload
199+
# path for files.
197200

198201
# None case
199202
output = slack_reformat.format_files_from_slack(None, False)
@@ -331,13 +334,17 @@ def test_format_attachments_from_slack(self):
331334
}
332335
output = do_await(slack_reformat.format_attachments_from_slack(
333336
'message', [github_app_attachment], False, _trivial_user_formatter))
337+
338+
# TODO This test (really, the formatting itself) is time zone sensitive to the TZ of the machine
339+
# you are on! Currently assumes Eastern time.
340+
334341
self.assertEqual(
335342
output['markdown'],
336-
'\n\n```quote\n**ABTech/zulip_slack_integration**\n**Stars**\n1\n**Language**\nPython\n*[ABTech/zulip_slack_integration](https://github.com/ABTech/zulip_slack_integration)* | *Thu May 23 14:35:12 2019*\n```'
343+
'\n\n```quote\n**ABTech/zulip_slack_integration**\n**Stars**\n1\n**Language**\nPython\n*[ABTech/zulip_slack_integration](https://github.com/ABTech/zulip_slack_integration)* | *Thu May 23 17:35:12 2019*\n```'
337344
)
338345
self.assertEqual(
339346
output['plaintext'],
340-
'\n\nABTech/zulip_slack_integration\nStars\n1\nLanguage\nPython\n[ABTech/zulip_slack_integration](https://github.com/ABTech/zulip_slack_integration) | Thu May 23 14:35:12 2019\n'
347+
'\n\nABTech/zulip_slack_integration\nStars\n1\nLanguage\nPython\n[ABTech/zulip_slack_integration](https://github.com/ABTech/zulip_slack_integration) | Thu May 23 17:35:12 2019\n'
341348
)
342349

343350
if __name__ == '__main__':

0 commit comments

Comments
 (0)