-
Notifications
You must be signed in to change notification settings - Fork 0
/
my_app.py
185 lines (152 loc) · 6.3 KB
/
my_app.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
from flask import Flask, jsonify, request, make_response
import requests as r
from collections import Counter
import os
from tabulate import tabulate
from datetime import datetime, timedelta
import re
try:
from passwords import BEARER, SLACK_TOKEN, SLACK_OAUTH_ACESS_TOKEN
except:
BEARER = os.environ['BEARER']
SLACK_TOKEN = os.environ['SLACK_TOKEN']
SLACK_OAUTH_ACESS_TOKEN = os.environ['SLACK_OAUTH_ACESS_TOKEN']
class Airtable(object):
def __init__(self):
self.headers = {'Authorization': BEARER,
'Content-Type': 'application/json'}
self.base_url = "https://api.airtable.com/v0/apphBP3YhZKaBIYti/donuts"
self.update_entries()
def update_entries(self):
params = {'view': 'sorted'}
self.entries = r.get(self.base_url, headers=self.headers, params=params).json()['records']
def last_entry_per_donut(self):
latest = {}
self.update_entries()
for entry in self.entries:
donut = entry['fields']['donut']
try:
latest[donut]
except KeyError:
latest[donut] = entry
return latest
def get_owe(self):
owes = []
for entry in self.last_entry_per_donut().values():
fields = entry['fields']
if fields['event_type'] == 'donutted':
owes += [(fields['donut'], fields['user_name'], fields['created'])]
return owes
def create_entry(self, donut, user_name='', event_type='donutted'):
"""
event_type can be either 'donutted' or 'brought' everything else will error from Airtable
"""
self.update_entries()
self._validate_entry(donut, user_name, event_type)
payload = {
"records": [{'fields': {'donut': donut, 'user_name': user_name, 'event_type': event_type}}]
}
resp = r.post(self.base_url, headers=self.headers, json=payload).json()
return resp
def donuts(self):
names = [entry['fields']['display_name'] for entry in self.entries if
entry['fields']['event_type'] == 'donutted']
return names
def latest(self):
names = self.donuts()
return names[0]
def hall_of_shame(self):
names = self.donuts()
return Counter(names).most_common()
def _validate_entry(self, donut, user_name, event_type):
if event_type == 'donutted':
match_time = False
for d in self.entries:
if d['fields']['donut'] == donut:
match_time = datetime.fromisoformat(d['createdTime'][:-1])
break
if match_time:
acceptable_start = datetime.utcnow() - timedelta(minutes=5)
if match_time > acceptable_start:
raise ValueError('User donutted too soon')
elif event_type == 'brought':
for owe_donut, owe_user_name, _ in self.get_owe():
if (donut == owe_donut) and (user_name == owe_user_name):
break
else:
raise ValueError('Person reported does not seem to owe donuts')
else:
raise Exception('Invalid event_type')
a = Airtable()
app = Flask(__name__)
@app.route("/")
def home():
return 'hello from the app'
@app.route("/donut", methods=['GET', 'POST'])
def donut_api():
if request.headers['Authorization'] != a.headers['Authorization']:
return jsonify({"message": "No"}), 401
if request.method == 'GET':
response = a.get_owe()
elif request.method == 'POST':
body = request.get_json()
try:
response = a.create_entry(**body)
except ValueError:
response = {'message': 'Nah'}
else:
response = a.hall_of_shame()
return jsonify(response)
@app.route("/slack", methods=['POST'])
def donut():
if request.form['token'] != SLACK_TOKEN:
return jsonify({'message': 'Nope'}), 401
text = request.form['text']
user_id = f'<@{request.form["user_id"]}>'
user_name = request.form["user_name"]
bringer_id = re.search(r'<@[^|>]*|$', text).group()
if bringer_id:
bringer_id += '>'
bringer_name = re.search(r'\|[^>]*>|$', text).group()[1:-1]
if text == 'me':
try:
a.create_entry(user_id, user_name)
out = f'''{":doughnut:" * 11}\n:doughnut:{user_id} has been donutted!!:doughnut:\n{":doughnut:" * 11}'''
except ValueError:
out = 'Please wait a bit before donutting again'
elif text == 'shame':
a.update_entries()
latest_string = f"\n\nThe last person to get donutted was {a.latest()}."
owe = [owe_user_name for (_, owe_user_name, _) in a.get_owe()]
owe_string = f"\n\nThese people still owe donuts: {', '.join(owe)}." if owe else "Nobody owes donuts right now!"
shame = a.hall_of_shame()
table = tabulate(shame, tablefmt="simple", headers=['Donut', '#'])
out = f'''```Welcome to the Hall of Shame!{latest_string}{owe_string}\n\n{table}```'''
elif bringer_id:
if request.form['user_id'] in bringer_id:
out = "Are you sure that you brought donuts? Maybe ask someone else to vouch for you :p"
else:
try:
a.create_entry(bringer_id, bringer_name, 'brought')
owe = [owe_user_name for (_, owe_user_name, _) in a.get_owe()]
owe_string = f"\n\nThese people still owe donuts: {', '.join(owe)}." if owe else "Nobody owes donuts right now!"
out = f'''{user_id} reports that {bringer_id} has brought donuts!\n{owe_string}'''
except ValueError:
out = 'It doesnt seem like that person owes donuts'
else:
out = ''':wave: Hi there, here is how you can use Donut Bot\n>`/donut me` to donut someone\n>`/donut shame` to see the Donut Hall of Shame\n`/donut @someone` when someone brings in donuts'''
payload = {
"channel": "C0B6XTPC5",
"text": out
}
url = "https://slack.com/api/chat.postMessage"
headers = {
"Content-type": "application/json",
"Authorization": f"Bearer {SLACK_OAUTH_ACESS_TOKEN}"
}
r.post(url, headers=headers, json=payload)
response = {
"response_type": "ephemeral",
"text": "check #random for response"
}
return jsonify(response)