-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathholidaybot.py
200 lines (178 loc) · 7.78 KB
/
holidaybot.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
import configparser
import imp
import json
import os
import re
import requests
import string
from collections import namedtuple
from errbot import BotPlugin, botcmd, re_botcmd
from os.path import join, realpath
bhr_client_source = join(realpath(os.path.dirname(__file__)), './bhr_client.py')
bhr_client = imp.load_source('bhr_client', bhr_client_source)
whosout_source = join(realpath(os.path.dirname(__file__)), './whosout.py')
whosout = imp.load_source('whosout', whosout_source)
WHERES_X_PATTERN = r"^where('?s| is) (@?[^?]+?)( today)?(\?|$)"
IS_X_IN_PATTERN = r"""^is (@?.*) (in|out|here|away|at work|on holiday|on
vacation|on leave)( today)?(\?)?$"""
BAMBOOHR_APIKEY_KEY = 'BAMBOOHR_APIKEY'
BAMBOOHR_COMPANY_KEY = 'BAMBOOHR_COMPANY'
BAMBOOHR_HOST_KEY = 'BAMBOOHR_HOST'
CONFIGURATION_TEMPLATE = {BAMBOOHR_APIKEY_KEY: 'changeme',
BAMBOOHR_COMPANY_KEY: 'changeme',
BAMBOOHR_HOST_KEY: 'https://api.bamboohr.com'}
NO_CREDENTIALS_RESPONSE = "Unable to check. An admin needs to configure credentials"
BambooHRConfig = namedtuple("BambooConfig", "host company api_key")
HipchatConfig = namedtuple("HipchatConfig", "host token")
class HolidayBot(BotPlugin):
"""Plugin for querying who is on leave right now"""
def activate(self):
super().activate()
config = configparser.ConfigParser()
print("environment var = " + os.getenv('HOLIDAY_BOT_TEST_RUN', 'False'))
if os.getenv('HOLIDAY_BOT_TEST_RUN') == 'True':
path = './test_credentials.cfg'
print("Test run detected - loading test credentials")
else:
path = './holidaybot_credentials.cfg'
if (os.path.isfile(path)):
with open(path) as f:
bamboo_config = self.parse_bamboo_credentials(f)
try:
config = CONFIGURATION_TEMPLATE
config[BAMBOOHR_APIKEY_KEY] = bamboo_config.api_key
config[BAMBOOHR_COMPANY_KEY] = bamboo_config.company
config[BAMBOOHR_HOST_KEY] = bamboo_config.host
self.configure(config)
except requests.exceptions.HTTPError:
print("Got an http error with given bamboo hr config")
self.checker = None
with open(path) as f:
hipchat_config = self.parse_hipchat_credentials(f)
if hipchat_config is not None:
try:
self.people = self.get_hipchat_users(
hipchat_config.host,
hipchat_config.token)
except requests.exceptions.HTTPError:
print("Got an http error with given hipchat hr config")
else:
print ("Could not locate credentials file at " + path)
self.people = {}
self.checker = None
def parse_bamboo_credentials(self, f):
config = configparser.ConfigParser()
config.read_file(f)
host = config.get('BambooHR', 'Host')
company = config.get('BambooHR', 'Company')
api_key = config.get('BambooHR', 'ApiKey')
return BambooHRConfig(host, company, api_key)
def parse_hipchat_credentials(self, f):
config = configparser.ConfigParser()
config.read_file(f)
host = config.get('HipChat', 'Host')
token = config.get('HipChat', 'Token')
return HipchatConfig(host, token)
def get_hipchat_users(self, hipchat_host, hipchat_token):
url = hipchat_host + "/v2/user?auth_token=" + hipchat_token
response = requests.get(url)
if response.status_code != 200:
response.raise_for_status()
return json.loads(response.text)
def get_name_from_mention(self, mention):
for person in self.people['items']:
if person['mention_name'].lower() == mention.lower():
return person['name']
def get_configuration_template(self):
return CONFIGURATION_TEMPLATE
def configure(self, configuration):
super(HolidayBot, self).configure(configuration)
self.initialise_checker_from_config_if_possible()
def initialise_checker_from_config_if_possible(self):
if self.config is None:
# self.checker = None
return
# Check it has been changed from default
# if self.config == CONFIGURATION_TEMPLATE:
# return
print("initialising to config: ", self.config)
self.initialise_checker_from_config(self.config)
def initialise_checker_from_config(self, config):
try:
self.checker = whosout.WhosOutChecker(
config[BAMBOOHR_APIKEY_KEY],
config[BAMBOOHR_COMPANY_KEY],
config[BAMBOOHR_HOST_KEY])
except requests.exceptions.HTTPError:
print("Got an http error with given config")
self.checker = None
@botcmd
def hello(self, msg, args):
"""Say hello to HolidayBot"""
return """Hello! Ask me \"who's out\" or \"is NAME in?\" to check up on
your colleagues"""
@re_botcmd(pattern=WHERES_X_PATTERN, prefixed=False, flags=re.IGNORECASE)
def wheres_x(self, msg, match):
'''Reply to variants of "where is X?"'''
name = match.group(2)
for x in self.where_is(name):
yield x
@re_botcmd(pattern=IS_X_IN_PATTERN, prefixed=False, flags=re.IGNORECASE)
def is_x_in(self, msg, match):
"""Reply to variants of 'is so-and-so in?'"""
name = match.group(1)
for x in self.where_is(name):
yield x
def where_is(self, name, debug=False):
"""Query if a specific person is here or on holiday"""
if debug:
yield "where_is called with args: " + name
if self.checker is None:
self.initialise_checker_from_config_if_possible()
if self.checker is None:
yield NO_CREDENTIALS_RESPONSE
return
if name.startswith('@'):
emp_name = self.get_name_from_mention(name.lstrip('@'))
if emp_name is None:
# no matching employee
yield whosout.build_whereis_reply(name, [])
return
else:
name = emp_name
where_is_results = self.checker.where_is(name)
yield whosout.build_whereis_reply(name, where_is_results)
@re_botcmd(pattern=r"^who('?s| is)[ ]?(out|away|around|on leave|on vaction|on holiday)( today)?(\?)?$", prefixed=False, flags=re.IGNORECASE)
def whos_out(self, msg, match):
"""Say who is away today"""
if self.checker is None:
self.initialise_checker_from_config_if_possible()
if self.checker is None:
return NO_CREDENTIALS_RESPONSE
return whosout.build_whosout_reply(self.checker.get_whos_out())
@re_botcmd(pattern=r"(?u)@([\w]+)([^\w]|$)",
matchall=True,
prefixed=False)
def listen_for_at_mentions(self, msg, matches):
"heard an @mention - i'll tell you if they're out"
if self.checker is None:
return
if re.match(IS_X_IN_PATTERN, msg.body) is not None \
or re.match(WHERES_X_PATTERN, msg.body) is not None:
return
reply = ''
for match in matches:
mention_name = match.group(1)
name = self.get_name_from_mention(mention_name)
if name is None:
continue
all_results = self.checker.where_is(name)
on_leave = [(emp, leave) for (emp, leave) in all_results
if leave is not None]
if len(on_leave) == 0:
continue
reply += whosout.build_whereis_reply(mention_name, on_leave) + '\n'
if reply == '':
return
else:
return reply