-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbot.py
226 lines (197 loc) · 7.48 KB
/
bot.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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
import datetime
import os
import time
import requests
from slackclient import SlackClient
from menu import Menu
from votebox import VoteBox
slack_client = SlackClient(os.environ.get('SLACK_BOT_TOKEN'))
voteBox = None
index_restaurant = {}
cached_menu = None
def get_bot_id():
bot_name = 'lunchbot'
api_call = slack_client.api_call("users.list")
if api_call.get('ok'):
# retrieve all users so we can find our bot
users = api_call.get('members')
for user in users:
if 'name' in user and user.get('name') == bot_name:
print("Bot ID for '" + user['name'] + "' is " + user.get('id'))
return user.get('id')
else:
print("could not find bot user with the name " + bot_name)
return None
def parse_slack_output(slack_rtm_output, bot_id):
at_bot = "<@" + bot_id + ">"
output_list = slack_rtm_output
if output_list and len(output_list) > 0:
for output in output_list:
if output and 'text' in output and at_bot in output['text']:
return output['text'].split(at_bot)[1].strip().lower(), output['channel'], output['user']
return None, None, None
def find_menu():
global cached_menu
if cached_menu is not None and cached_menu.is_menu_valid(datetime.date.today()):
return cached_menu
today = datetime.date.today()
tomorrow = today + datetime.timedelta(days=1)
if today.weekday() == 5 or today.weekday() == 6:
return None
json_obj = {
"where": {
"date": {
"$gte": {
"__type": "Date",
"iso": today.isoformat()
},
"$lte": {
"__type": "Date",
"iso": tomorrow.isoformat()
}
}
},
"_method": "get"
}
headers = {
"X-Parse-Application-Id": "nAixMGyDvVeNfeWEectyJrvtqSeKregQs2gLh9Aw"
}
res = requests.post("http://lunch-menu.herokuapp.com/parse/classes/Menu", json=json_obj, headers=headers)
cached_menu = Menu.from_json(res.json())
return cached_menu
def is_int(input):
if input is None:
return False
try:
int(input)
return True
except ValueError:
return False
def handle_command(command, channel, user):
global voteBox
attachments = []
if "lunch" in command:
attachments = create_menu_message(attachments)
elif "vote" in command:
selection = split_vote_command(command)
#in case vote is not initialized, or if it's not valid for today (could be initialized yesterday), initialize it
if (voteBox is None or not voteBox.is_valid_for(datetime.date.today())):
attachments = initialize_voting(attachments, False)
elif voteBox is not None and selection == "reset":
print('Voting reseted by user {}'.format(user))
attachments = initialize_voting(attachments, True)
else:
attachments = add_vote(attachments, command, user, voteBox, selection=selection)
elif "show results" in command:
if (voteBox is None or not voteBox.is_valid_for(datetime.date.today())):
print("Votebox not initialized for today...")
else:
show_vote_stats(attachments,voteBox)
elif "blame" in command:
if (voteBox is None or not voteBox.is_valid_for(datetime.date.today())):
print("Votebox not initialized for today...")
else:
show_blame(attachments,voteBox)
else:
create_default_message(attachments)
slack_client.api_call("chat.postMessage", channel=channel, as_user=True, attachments=attachments)
def create_menu_message(attachments):
menus = find_menu()
if menus is None:
attachments.append({
"title": "NO LUNCH IN THE WEEKEND, FOOL!",
"text": "Stupid...",
"fallback": "There's no lunch on weekends, stupid",
"color": "danger"
})
else:
for menu_item in menus.get_menu():
attachments.append({
"title": menu_item.itemName,
"text": menu_item.itemValue,
"fallback": menu_item.itemName + " - " + menu_item.itemValue,
"color": "good"
})
return attachments
def initialize_voting(attachments, reset):
global voteBox
menus = find_menu()
i = 0
text = ""
for menu_item in menus.get_menu():
text += "\n" + menu_item.itemName + "(" + str(i) + "): 0"
index_restaurant[i] = menu_item.itemName
i += 1
voteBox = VoteBox(index_restaurant)
title = "Restarting the vote (by <@{}>)".format(user) if reset else "Starting vote..."
attachments.append({
"title": title,
"text": "Tag me with 'vote #', and I'll register your vote!\nExample: @lunchbot vote 1" + text,
"fallback": "Vote for lunch started",
"color": "good"
})
return attachments
def add_vote(attachments, command, user, voteBox, selection):
is_proper_selection_value = False
if is_int(selection):
selection = int(selection)
if selection >= -1 and selection < len(find_menu().get_menu()):
is_proper_selection_value = True
if not is_proper_selection_value:
# prepare the message for the fucker that sent this
message = "<@{}> tried to kill me! He/She is a botkiller and likes Fresh4You restaurant!".format(
user)
attachments.append({
"title": "Veggie lover!",
"text": message,
"fallback": "Smartass",
"color": "danger"
})
else:
if voteBox.vote(selection, user):
show_vote_stats(attachments, voteBox)
return attachments
def show_vote_stats(attachments, voteBox):
text = voteBox.votes_to_string()
print(text)
attachments.append({
"title": "Vote",
"text": text,
"fallback": "Votes are in"
})
def show_blame(attachments, voteBox):
attachments.append({
"title": "Votes in detail",
"text": voteBox.blame_to_string(),
"fallback": "Everyone that voted"
})
def split_vote_command(command):
selection = command.split('vote')[1].strip()
if selection != '':
selection = selection.split()[0].strip()
else:
selection = None
return selection
def create_default_message(attachments):
attachments.append({
"title": "Too dumb",
"text": "I'm not smart enough to understand that. Try something with lunch",
"fallback": "That's not a command"
})
if __name__ == "__main__":
bot_id = get_bot_id()
if bot_id is not None:
if slack_client.rtm_connect():
print("lunchbot connected and running!")
while True:
try:
command, channel, user = parse_slack_output(slack_client.rtm_read(), bot_id)
# Fuck it, gotta catch 'em all
except Exception as e:
print("Caught an exception while trying to read:\nReconnecting...", e)
slack_client.rtm_connect()
if command and channel and user:
handle_command(command, channel, user)
time.sleep(1)
else:
print("Connection failed. Invalid Slack token or bot ID?")