-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsend_timeoff_reminders.py
225 lines (162 loc) · 8.21 KB
/
send_timeoff_reminders.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
import argparse
import configparser
import os
import json
import re
import smtplib
from datetime import datetime
from dateutil.relativedelta import relativedelta
from rx import Observable
from bamboo_hr_api import BambooHRApi
from email_util import EmailUtil, SMTPConfig
from employee import Employee
from project_team import ProjectTeam
from tempo_api import TempoApi
from time_off_reminder import TimeOffReminder
from time_off import TimeOff, STATUS_ALLOWED
from logger import get_logger
REG_PATTERN_PROJECT_TEAM = re.compile("PT\s(.*)")
REG_PATTERN_FUNCTIONAL_TEAM = re.compile("FT\s((.+)-(\d+))")
log = get_logger()
time_off_cache = {}
def read_and_populate_project_teams(project_team_folder):
project_teams = []
for team in os.listdir(project_team_folder):
project_team = ProjectTeam(team)
with open(os.path.join(project_team_folder, team)) as f:
for line in f:
if line.find("=") != -1:
fields = line[line.index("=") + 1:].split(',')
if line.startswith("team"):
project_team.set_working_members(fields)
elif line.startswith("report"):
project_team.set_reporting_members(fields)
project_teams.append(project_team)
return project_teams
def append_employee_info(employee: Employee, employee_directory):
for item in employee_directory:
if item['workEmail'] == employee.email:
employee.id = item['id']
employee.fullname = item['displayName']
employee.photoUrl = item['photoUrl']
break
def append_employee_time_offs(employee: Employee, api: BambooHRApi):
if employee.id != -1:
time_offs = get_employee_time_offs(api, employee.id)
for time_off_data in time_offs:
employee.add_time_off(TimeOff(time_off_data, employee.photoUrl, employee.id))
else:
log.debug("Timeoff data not fetched for {}; employee id not set!".format(employee.email))
def get_employee_time_offs(api: BambooHRApi, employee_id):
if employee_id not in time_off_cache.keys():
time_off_cache[employee_id] = fetch_employee_time_offs(api, employee_id)
return time_off_cache.get(employee_id)
def fetch_employee_time_offs(api: BambooHRApi, employee_id):
now = datetime.now()
two_months_from_now_on = now + relativedelta(months=2)
return api.get_employee_time_offs(employee_id, now, two_months_from_now_on, STATUS_ALLOWED)
def send_reminder(project_team, smtp_config, recipients=None):
log.info("reminding \"{}\" timeoffs to \"{}\"".format(project_team.name,
project_team.reports if not recipients else recipients))
EmailUtil.send(TimeOffReminder(project_team).as_email(), smtp_config, recipients)
def read_project_team_files_and_remind(smtp_config, bamboo_api, recipients=None):
project_teams = read_and_populate_project_teams(project_team_folder)
if project_teams:
employee_directory = bamboo_api.get_list_of_employees()
for team in project_teams:
for employee in team.members:
append_employee_info(employee, employee_directory)
append_employee_time_offs(employee, bamboo_api)
send_reminder(team, smtp_config, recipients.get(team.name))
else:
log.debug("No project team found.")
def is_team_member_active(member):
return member["member"]["activeInJira"]
def get_email(member_full_name):
return "{}@commencis.com".format(member_full_name)
def append_team_members(team: ProjectTeam, tempo_api):
team_members = tempo_api.get_team_members(team.id)
team_member_emails = list(filter(is_team_member_active, team_members))
team_member_emails = list(map(lambda member: get_email(member["member"]["name"]), team_member_emails))
team.set_working_members(team_member_emails)
return Observable.create(lambda obs: obs.on_next(team))
def append_team_member_details(team: ProjectTeam, employee_directory):
for employee in team.members:
append_employee_info(employee, employee_directory)
return team
def append_team_time_offs(team: ProjectTeam, bamboo_api):
for employee in team.members:
if employee.id != -1:
time_offs = get_employee_time_offs(bamboo_api, employee.id)
log.debug(time_offs)
for time_off_data in time_offs:
employee.add_time_off(TimeOff(time_off_data, employee.photoUrl, employee.id))
return team
def filter_teams(team):
return REG_PATTERN_FUNCTIONAL_TEAM.match(team["name"]) or REG_PATTERN_PROJECT_TEAM.match(team["name"])
def fetch_project_teams_and_remind(smtp_config, bamboo_api, tempo_api, recipients=None):
try:
employee_directory = bamboo_api.get_list_of_employees()
Observable.from_list(tempo_api.get_all_teams()) \
.filter(filter_teams) \
.flat_map(lambda team: Observable.create(lambda obs: obs.on_next(ProjectTeam(team["name"],
get_email(team["lead"]),
team["id"])))) \
.flat_map(lambda team: append_team_members(team, tempo_api)) \
.map(lambda team: append_team_member_details(team, employee_directory)) \
.map(lambda team: append_team_time_offs(team, bamboo_api)) \
.subscribe(lambda team: send_reminder(team, smtp_config, recipients.get(team.name)))
except smtplib.SMTPException:
log.exception('SMTP error occurred!')
pass
except Exception:
log.exception("Something went wrong!")
def remind_time_offs(config_smtp, config_bamboo, recipients=None, **kwargs):
smtp_config = SMTPConfig(config_smtp['host'],
config_smtp['from'],
config_smtp['port'])
bamboo_api = BambooHRApi(config_bamboo['sub_domain'],
config_bamboo['api_key'])
if "tempo_api" in kwargs.keys():
fetch_project_teams_and_remind(smtp_config,
bamboo_api,
TempoApi(kwargs.get("tempo_api")["url"], kwargs.get("tempo_api")["token"]),
recipients)
else:
read_project_team_files_and_remind(smtp_config, bamboo_api, recipients)
def read_recipients(extras_file):
try:
with open(extras_file, mode='r', encoding='utf-8') as file:
return json.load(file)
finally:
file.close()
def execute():
arg_parser = argparse.ArgumentParser(description="BambooHR Time Off Reminder CLI")
arg_parser.add_argument("--config", help="configuration file", required=True)
arg_parser.add_argument("--teams", help="project teams folder path", required=False)
arg_parser.add_argument("--recipients", help="Recipients json file. By default project lead is the only recipient",
required=False)
args = arg_parser.parse_args()
config_parser = configparser.ConfigParser()
config_parser.read(args.config)
if 'bamboo' not in config_parser.sections():
raise KeyError("'bamboo' section missing. Make sure to set 'api_key' and 'sub_domain'.")
if 'smtp' not in config_parser.sections():
raise KeyError("'smtp' section missing. Make sure to set 'host', 'port' and 'from'.")
recipients = None if not args.recipients else read_recipients(args.recipients)
if "tempo" in config_parser.sections():
if "url" not in config_parser["tempo"]:
raise KeyError("'url' missing under 'tempo' section. Please check configuration file.")
if "token" not in config_parser["tempo"]:
raise KeyError("'token' missing under 'tempo' section. Please check configuration file.")
remind_time_offs(config_parser["smtp"],
config_parser["bamboo"],
recipients,
tempo_api=config_parser["tempo"])
else:
remind_time_offs(config_parser['smtp'],
config_parser["bamboo"],
recipients,
teams=args.teams)
if __name__ == "__main__":
execute()