-
Notifications
You must be signed in to change notification settings - Fork 0
/
slacker.py
executable file
·102 lines (88 loc) · 3.71 KB
/
slacker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#! /usr/bin/env python2.7
import json
import time
import requests
class Slacker(object):
def __init__(self, slack, token):
self.slack = slack
self.token = token
def user_post(self, message, id):
# annoyingly, we first need to create a DM channel, then get its ID, then do the needful
# print "Trying to create IM channel to {}".format(id)
payload = self.api_call("im.open?user={}".format(id), requests.post)
# print json.dumps(payload)
channel_id = payload['channel']['id']
self.channel_post(message, channel_id)
def channel_post(self, message, channel_id, link_names=True, ts=None):
"""
posts a message; unless ts is given, in which case we'll *update* the message with the given
ts instead
"""
post = {'channel': channel_id, 'text': message, 'as_user': True, 'link_names': True}
method = "chat.postMessage"
if ts:
post['ts'] = ts
method = "chat.update"
self.api_call(method, method=requests.post, json=post, header_for_token=True)
def paginated_lister(self, api_call, element_name, limit=200):
start = time.time()
done = False
cursor = None
results = []
separator = self.use_separator(api_call)
api_call = api_call + separator + "limit={}".format(limit)
while not done:
interim_api_call = api_call
if cursor:
interim_api_call += "&cursor={}".format(cursor)
interim_results = self.api_call(interim_api_call)
results += interim_results[element_name]
cursor = interim_results.get("response_metadata", {}).get("next_cursor", "")
if not cursor:
done = True
end = time.time()
diff = end - start
print "Loaded {} {} in {:.1f} seconds".format(len(results), element_name, diff)
return results
def use_separator(self, url):
"""
if url already has '?', use &; otherwise, use '?'
"""
separator = "?"
if '?' in url:
separator = "&"
return separator
def retry_api_call(self, method, url, json, headers, delay=1, increment=2, max_delay=120):
while True:
try:
payload = method(url, json=json, headers=headers)
return payload
except Exception, e:
print "Failed to retrieve {} : {} / {}. Sleeping {} seconds".format(url, Exception, e, delay)
time.sleep(delay)
if delay < max_delay:
delay += increment
print "Incrementing delay to {}".format(delay)
def api_call(self, api_endpoint, method=requests.get, json=None, header_for_token=False):
url = "https://{}.slack.com/api/{}".format(self.slack, api_endpoint)
headers = {}
if header_for_token:
headers['Authorization'] = "Bearer {}".format(self.token)
else:
separator = self.use_separator(url)
url += "{}token={}".format(separator, self.token)
if json:
headers['Content-Type'] = "application/json"
# print "url: {}".format(url)
done = False
while not done:
response = self.retry_api_call(method, url, json=json, headers=headers)
if response.status_code == 200:
done = True
if response.status_code == 429:
retry_after = int(response['Retry-After']) + 1
time.sleep(retry_after)
payload = response.json()
# print "json: {} headers: {}".format(json, headers)
# print "status code: {} payload: {}".format(response.status_code, payload)
return payload