1""" 2Library for interacting with Slack API 3 4.. versionadded:: 2016.3.0 5 6:configuration: This module can be used by specifying the name of a 7 configuration profile in the minion config, minion pillar, or master 8 config. 9 10 For example: 11 12 .. code-block:: yaml 13 14 slack: 15 api_key: peWcBiMOS9HrZG15peWcBiMOS9HrZG15 16""" 17 18import http.client 19import logging 20import urllib.parse 21 22import salt.utils.http 23 24log = logging.getLogger(__name__) 25 26 27def query( 28 function, 29 api_key=None, 30 args=None, 31 method="GET", 32 header_dict=None, 33 data=None, 34 opts=None, 35): 36 """ 37 Slack object method function to construct and execute on the API URL. 38 39 :param api_key: The Slack api key. 40 :param function: The Slack api function to perform. 41 :param method: The HTTP method, e.g. GET or POST. 42 :param data: The data to be sent for POST method. 43 :return: The json response from the API call or False. 44 """ 45 46 ret = {"message": "", "res": True} 47 48 slack_functions = { 49 "rooms": {"request": "channels.list", "response": "channels"}, 50 "users": {"request": "users.list", "response": "members"}, 51 "message": {"request": "chat.postMessage", "response": "channel"}, 52 } 53 54 if not api_key: 55 api_key = __salt__["config.get"]("slack.api_key") or __salt__["config.get"]( 56 "slack:api_key" 57 ) 58 59 if not api_key: 60 log.error("No Slack api key found.") 61 ret["message"] = "No Slack api key found." 62 ret["res"] = False 63 return ret 64 65 api_url = "https://slack.com" 66 base_url = urllib.parse.urljoin(api_url, "/api/") 67 path = slack_functions.get(function).get("request") 68 url = urllib.parse.urljoin(base_url, path, False) 69 70 if not isinstance(args, dict): 71 query_params = {} 72 else: 73 query_params = args.copy() 74 75 if header_dict is None: 76 header_dict = {} 77 78 if method != "POST": 79 header_dict["Accept"] = "application/json" 80 81 # https://api.slack.com/changelog/2020-11-no-more-tokens-in-querystrings-for 82 # -newly-created-apps 83 # Apps created after February 24, 2021 may no longer send tokens as query 84 # parameters and must instead use an HTTP authorization header or 85 # send the token in an HTTP POST body. 86 # Apps created before February 24, 2021 will continue functioning no 87 # matter which way you pass your token. 88 header_dict["Authorization"] = "Bearer {}".format(api_key) 89 result = salt.utils.http.query( 90 url, 91 method, 92 params=query_params, 93 data=data, 94 decode=True, 95 status=True, 96 header_dict=header_dict, 97 opts=opts, 98 ) 99 100 if result.get("status", None) == http.client.OK: 101 _result = result["dict"] 102 response = slack_functions.get(function).get("response") 103 if "error" in _result: 104 ret["message"] = _result["error"] 105 ret["res"] = False 106 return ret 107 ret["message"] = _result.get(response) 108 return ret 109 elif result.get("status", None) == http.client.NO_CONTENT: 110 return True 111 else: 112 log.debug(url) 113 log.debug(query_params) 114 log.debug(data) 115 log.debug(result) 116 if "dict" in result: 117 _result = result["dict"] 118 if "error" in _result: 119 ret["message"] = result["error"] 120 ret["res"] = False 121 return ret 122 ret["message"] = "Unknown response" 123 ret["res"] = False 124 else: 125 ret["message"] = "invalid_auth" 126 ret["res"] = False 127 return ret 128