Skip to content

Commit c0d8ffc

Browse files
author
Matthias
committed
Changelog fragment
1 parent d71a6e8 commit c0d8ffc

File tree

2 files changed

+68
-74
lines changed

2 files changed

+68
-74
lines changed

changelogs/fragments/slack.yml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
minor_changes:
2+
- Slack upload file - feature added support for uploading files to Slack (https://github.com/ansible-collections/community.general/pull/9472).

plugins/modules/slack.py

+66-74
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@
148148
type: dict
149149
description:
150150
- Specify details to upload a file to Slack. The file can include metadata such as an initial comment, alt text, snipped and title.
151-
- See Slack's file upload API for details at U(https://api.slack.com/methods/files.getUploadURLExternal) and U(https://api.slack.com/methods/files.completeUploadExternal).
151+
- See Slack's file upload API for details at U(https://api.slack.com/methods/files.getUploadURLExternal).
152+
- See Slack's file upload API for details at U(https://api.slack.com/methods/files.completeUploadExternal).
152153
suboptions:
153154
path:
154155
type: str
@@ -171,6 +172,10 @@
171172
type: str
172173
description:
173174
- Optional title for the uploaded file.
175+
thread_ts:
176+
type: str
177+
description:
178+
- Optional timestamp of parent message to thread this message, see U(https://api.slack.com/docs/message-threading).
174179
"""
175180

176181
EXAMPLES = r"""
@@ -293,6 +298,7 @@
293298
alt_text: ''
294299
snippet_type: ''
295300
title: ''
301+
thread_ts: ''
296302
"""
297303

298304
import re
@@ -474,9 +480,10 @@ def do_notify_slack(module, domain, token, payload):
474480
else:
475481
return {'webhook': 'ok'}
476482

483+
477484
def get_channel_id(module, token, channel_name):
478485
url = SLACK_CONVERSATIONS_LIST_WEBAPI
479-
headers = {"Authorization": f"Bearer {token}"}
486+
headers = {"Authorization": "Bearer " + token}
480487
params = {
481488
"types": "public_channel,private_channel,mpim,im",
482489
"limit": 1000,
@@ -487,22 +494,22 @@ def get_channel_id(module, token, channel_name):
487494
if cursor:
488495
params["cursor"] = cursor
489496
query = urlencode(params)
490-
full_url = f"{url}?{query}"
497+
full_url = "%s?%s" % (url, query)
491498
response, info = fetch_url(module, full_url, headers=headers, method="GET")
492499
status = info.get("status")
493500
if status != 200:
494501
error_msg = info.get("msg", "Unknown error")
495502
module.fail_json(
496-
msg=f"Failed to retrieve channels: {error_msg} (HTTP {status})"
503+
msg="Failed to retrieve channels: %s (HTTP %s)" % (error_msg, status)
497504
)
498505
try:
499506
response_body = response.read().decode("utf-8") if response else ""
500507
data = json.loads(response_body)
501-
except json.JSONDecodeError as e:
502-
module.fail_json(msg=f"JSON decode error: {e}")
508+
except ValueError as e:
509+
module.fail_json(msg="JSON decode error: %s" % str(e))
503510
if not data.get("ok"):
504511
error = data.get("error", "Unknown error")
505-
module.fail_json(msg=f"Slack API error: {error}")
512+
module.fail_json(msg="Slack API error: %s" % error)
506513
channels = data.get("channels", [])
507514
for channel in channels:
508515
if channel.get("name") == channel_name:
@@ -511,52 +518,45 @@ def get_channel_id(module, token, channel_name):
511518
cursor = data.get("response_metadata", {}).get("next_cursor")
512519
if not cursor:
513520
break
514-
module.fail_json(msg=f"Channel named '{channel_name}' not found.")
521+
module.fail_json(msg="Channel named '%s' not found." % channel_name)
515522

516523

517524
def upload_file_to_slack(module, token, channel, file_upload):
518525
try:
519526
file_path = file_upload["path"]
520527
if not os.path.exists(file_path):
521-
module.fail_json(msg=f"File not found: {file_path}")
528+
module.fail_json(msg="File not found: %s" % file_path)
522529
# Step 1: Get upload URL
523530
url = SLACK_GET_UPLOAD_URL_EXTERNAL
524531
headers = {
525-
"Authorization": f"Bearer {token}",
532+
"Authorization": "Bearer " + token,
526533
"Content-Type": "application/x-www-form-urlencoded",
527534
}
528-
params = urlencode(
529-
{
530-
"filename": file_upload.get("filename", os.path.basename(file_path)),
531-
"length": os.path.getsize(file_path),
532-
**(
533-
{"alt_text": file_upload.get("alt_text")}
534-
if file_upload.get("alt_text")
535-
else {}
536-
),
537-
**(
538-
{"snippet_type": file_upload.get("snippet_type")}
539-
if file_upload.get("snippet_type")
540-
else {}
541-
),
542-
}
543-
)
535+
params = {
536+
"filename": file_upload.get("filename", os.path.basename(file_path)),
537+
"length": os.path.getsize(file_path),
538+
}
539+
if file_upload.get("alt_text"):
540+
params["alt_text"] = file_upload.get("alt_text")
541+
if file_upload.get("snippet_type"):
542+
params["snippet_type"] = file_upload.get("snippet_type")
543+
params = urlencode(params)
544544
response, info = fetch_url(
545-
module, f"{url}?{params}", headers=headers, method="GET"
545+
module, "%s?%s" % (url, params), headers=headers, method="GET"
546546
)
547547
if info["status"] != 200:
548548
module.fail_json(
549-
msg=f"Error retrieving upload URL: {info['msg']} (HTTP {info['status']})"
549+
msg="Error retrieving upload URL: %s (HTTP %s)" % (info['msg'], info['status'])
550550
)
551551
try:
552552
upload_url_data = json.load(response)
553-
except json.JSONDecodeError:
553+
except ValueError:
554554
module.fail_json(
555-
msg=f"The Slack API response is not valid JSON: {response.read()}"
555+
msg="The Slack API response is not valid JSON: %s" % response.read()
556556
)
557557
if not upload_url_data.get("ok"):
558558
module.fail_json(
559-
msg=f"Failed to retrieve upload URL: {upload_url_data.get('error')}"
559+
msg="Failed to retrieve upload URL: %s" % upload_url_data.get('error')
560560
)
561561
upload_url = upload_url_data["upload_url"]
562562
file_id = upload_url_data["file_id"]
@@ -573,39 +573,29 @@ def upload_file_to_slack(module, token, channel, file_upload):
573573
)
574574
if info["status"] != 200:
575575
module.fail_json(
576-
msg=f"Error during file upload: {info['msg']} (HTTP {info['status']})"
576+
msg="Error during file upload: %s (HTTP %s)" % (info['msg'], info['status'])
577577
)
578-
except FileNotFoundError:
579-
module.fail_json(msg=f"The file {file_path} is not found.")
578+
except IOError:
579+
module.fail_json(msg="The file %s is not found." % file_path)
580580
# Step 3: Complete upload
581581
complete_url = SLACK_COMPLETE_UPLOAD_EXTERNAL
582-
files_data = json.dumps(
583-
{
584-
"files": [
585-
{
586-
"id": file_id,
587-
**(
588-
{"title": file_upload.get("title")}
589-
if file_upload.get("title")
590-
else {}
591-
),
592-
}
593-
],
594-
**(
595-
{"initial_comment": file_upload.get("initial_comment")}
596-
if file_upload.get("initial_comment")
597-
else {}
598-
),
599-
**(
600-
{"thread_ts": file_upload.get("thread_ts")}
601-
if file_upload.get("thread_ts")
602-
else {}
603-
),
604-
"channel_id": get_channel_id(module, token, channel),
605-
}
606-
)
582+
files_dict = {
583+
"files": [
584+
{
585+
"id": file_id,
586+
}
587+
],
588+
"channel_id": get_channel_id(module, token, channel),
589+
}
590+
if file_upload.get("title"):
591+
files_dict["files"][0]["title"] = file_upload.get("title")
592+
if file_upload.get("initial_comment"):
593+
files_dict["initial_comment"] = file_upload.get("initial_comment")
594+
if file_upload.get("thread_ts"):
595+
files_dict["thread_ts"] = file_upload.get("thread_ts")
596+
files_data = json.dumps(files_dict)
607597
headers = {
608-
"Authorization": f"Bearer {token}",
598+
"Authorization": "Bearer " + token,
609599
"Content-Type": "application/json",
610600
}
611601
try:
@@ -614,18 +604,18 @@ def upload_file_to_slack(module, token, channel, file_upload):
614604
)
615605
if info["status"] != 200:
616606
module.fail_json(
617-
msg=f"Error during upload completion: {info['msg']} (HTTP {info['status']})"
607+
msg="Error during upload completion: %s (HTTP %s)" % (info['msg'], info['status'])
618608
)
619609
upload_url_data = json.load(response)
620-
except json.JSONDecodeError:
610+
except ValueError:
621611
module.fail_json(
622-
msg=f"The Slack API response is not valid JSON: {response.read()}"
612+
msg="The Slack API response is not valid JSON: %s" % response.read()
623613
)
624614
if not upload_url_data.get("ok"):
625-
module.fail_json(msg=f"Failed to complete the upload: {upload_url_data}")
615+
module.fail_json(msg="Failed to complete the upload: %s" % upload_url_data)
626616
return upload_url_data
627617
except Exception as e:
628-
module.fail_json(msg=f"Error uploading file: {str(e)}")
618+
module.fail_json(msg="Error uploading file: %s" % str(e))
629619

630620

631621
def main():
@@ -647,14 +637,16 @@ def main():
647637
blocks=dict(type='list', elements='dict'),
648638
message_id=dict(type='str'),
649639
prepend_hash=dict(type='str', choices=['always', 'never', 'auto']),
650-
upload_file=dict(type="dict", options=dict(
651-
path=dict(type="str", required=True),
652-
alt_text=dict(type="str"),
653-
snippet_type=dict(type="str"),
654-
initial_comment=dict(type="str"),
655-
thread_ts=dict(type="str"),
656-
title=dict(type="str")
657-
)
640+
upload_file=dict(
641+
type="dict",
642+
options=dict(
643+
path=dict(type="str", required=True),
644+
alt_text=dict(type="str"),
645+
snippet_type=dict(type="str"),
646+
initial_comment=dict(type="str"),
647+
thread_ts=dict(type="str"),
648+
title=dict(type="str"),
649+
)
658650
),
659651
),
660652
supports_check_mode=True,
@@ -688,7 +680,7 @@ def main():
688680
upload_response=upload_response,
689681
)
690682
except Exception as e:
691-
module.fail_json(msg=f"Failed to upload file: {str(e)}")
683+
module.fail_json(msg="Failed to upload file: %s" % str(e))
692684

693685
if prepend_hash is None:
694686
module.deprecate(

0 commit comments

Comments
 (0)