forked from ccarruitero/MozReminder
/
reminder.py
301 lines (271 loc) · 13.3 KB
/
reminder.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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
#!/env/bin/python
# -*- coding: utf-8 -*-
import urllib
import urllib2
import json
import smtplib
import string
import re
import argparse
from email.mime.text import MIMEText
from collections import defaultdict
from datetime import datetime, timedelta
from local_config import *
TASKS_URL = 'https://www.mozilla-hispano.org/documentacion/Especial:Ask/-5B-5BCategor%C3%ADa:Tarea-5D-5D-5B-5Bestado::!Finalizado-5D-5D/-3FResponsable%3DRespon./-3FArea/-3FProyecto/-3FEstado/-3FFechafin%3DL%C3%ADmite/mainlabel%3D/order%3DASC,ASC/sort%3DFechafin,Estado/format%3Djson/limit%3D1000'
COLLABORATORS_URL = 'https://www.mozilla-hispano.org/documentacion/Especial:Ask/-5B-5BCategoría:Colaborador-5D-5D/-3FCorreo/mainlabel%3D/format%3Djson/limit%3D1000'
AREA_OWNER_URL = 'https://www.mozilla-hispano.org/documentacion/index.php?title=Especial%3AAsk&po=%3FResponsable%0D%0A&p[format]=json&q='
MEETINGS_URL = 'https://www.mozilla-hispano.org/documentacion/Especial:Ask/-5B-5BCategor%C3%ADa:Reuniones-5D-5D/-3FFechainicio/-3FArea/-3FAsistentes/-3FProyecto/mainlabel%3D/order%3DDESC,DESC/sort%3DFechainicio/format%3Djson/limit%3D100'
# Dictionary that maps areas to an array of owner email addresses.
areaOwners = {}
def convertToEmailAddress(emailString):
'''
Converts the email string into a valid email address. This is necessary
because addresses can be obfuscated (name ARROBA server PUNTO com).
'''
email = emailString.strip()
# The spaces around the 'at' are intentional. It avoids picking up names
# with 'at' in them. Why algarrobo? Ask StripTM :|
pattern = re.compile('\s?(arroba| at |@|algarrobo)\s?', re.IGNORECASE)
email = pattern.sub('@', emailString, 1)
pattern = re.compile('\s?(punto|dot)\s?', re.IGNORECASE)
email = pattern.sub('.', email)
# MediaWiki doesn't handle underscores well (issue #17).
email = email.replace(' ', '_')
return email
def getAreaOwners(area, collab_new):
'''
Gets the user information of the owners of the given focus area.
'''
owners = []
if len(area) != 0:
quotedArea = urllib.quote_plus(area.encode('utf-8'))
if quotedArea not in areaOwners:
ownerURL = AREA_OWNER_URL + '[[' + quotedArea + ']]'
ownerJSON = urllib2.urlopen(ownerURL).read()
ownerObj = json.loads(ownerJSON)
for ownerList in ownerObj['items']:
for owner in ownerList['responsable']:
userString = 'Usuario:' + owner
if userString in collab_new:
owners.append(owner)
# Save locally for future use.
areaOwners[quotedArea] = owners
else:
# Use saved copy instead of fetching it again.
owners = areaOwners[quotedArea]
return owners
def collaborators(collab_new):
'''
we get json from media wiki with this structure:
colab['items'][n]['label']
colab['items'][n]['correo']
but this is not usable and mails isn't in mail format, this is for solve that.
'''
json_collab = urllib2.urlopen(COLLABORATORS_URL).read()
collab = json.loads(json_collab)
n = len(collab["items"])
for var in range(n):
'''
for each collaborator we get a dictionary with collaborators name (ncollab) and collaborators mail (mcollab)
'''
ncollab = collab['items'][int(var)]['label']
try:
mcollab = convertToEmailAddress(collab['items'][int(var)]['correo'][0])
except KeyError:
mcollab = ''
collab_new.update({ncollab:mcollab})
return collab_new
def getTasks():
'''
Like json collab, tasks json structure is:
tasks['items'][n]['respon.']
tasks['items'][n]['label']
tasks['items'][n][u'límite']
this is to append collaborator mail with this data and separate tasks according to date limit: if is overdue (tasks_overdue),
that mature in three days (tasks_threedays) and that mature today (tasks_onday)
'''
json_tasks = urllib2.urlopen(TASKS_URL).read()
tasks = json.loads(json_tasks)
tasks_onday = []
tasks_threedays = []
tasks_overdue =[]
collab_new = {}
collaborators(collab_new)
for task in tasks['items']:
dueToday = False
dueInThreeDays = False
overdue = False
# Get the date limit and figure out if we need to do anything.
if u'límite' in task:
limit = task[u'límite'][0]
datelimit = datetime.strptime(limit, '%Y-%m-%d %H:%M:%S')
if timedelta(hours = 1) < (datelimit - datetime.now()) <= timedelta(hours = 24):
dueToday = True
elif timedelta(days = 1) < (datelimit -datetime.now()) <= timedelta(days = 3):
dueInThreeDays = True
elif (datetime.now() - datelimit) > timedelta (hours = 1) :
overdue = True
# Figure out who to send the message to.
if (dueToday or dueInThreeDays or overdue):
assignees = []
# Get assignees from task.
if 'respon.' in task:
for user in task['respon.']:
userString = 'Usuario:' + user
if userString in collab_new:
assignees.append(user)
# If there are none, get area owners.
if len(assignees) == 0:
if 'area' in task:
assignees = getAreaOwners(task['area'][0],collab_new)
if len(assignees) == 0:
print 'Due task "' + task['label'] + '" has no one responsible for it.'
for assignee in assignees:
email = collab_new['Usuario:' + assignee]
if dueToday:
tasks_onday.append([assignee, email, task['label'], limit])
elif dueInThreeDays:
tasks_threedays.append([assignee, email, task['label'], limit])
elif overdue:
tasks_overdue.append([assignee, email, task['label'], limit])
taskoverdue(tasks_overdue)
taskthreedays(tasks_threedays)
taskonday(tasks_onday)
def send_mail(txtmessage, txtsubject, tasks_new):
'''
send mails for each collaborator
'''
d = defaultdict(list)
for resp,mailresp,label,limit in tasks_new:
'''
for order tasks (label) for each collaborator, result a dict with 2 items
'''
d[resp,mailresp].append(label)
for k,v in d.items():
'''
lines before, we get a dict (d) with 2 items. Now I parse this items (k,v) in mail message
'''
toAddress = k[1]
if (toAddress != ''):
try:
respon = k[0]
numtasks = len(v)
text = txtmessage % (respon, numtasks)
for i in range(numtasks):
b = [w.replace(' ','_') for w in [v[int(i)]]]
text = text + '\n' + v[int(i)] + ' https://www.mozilla-hispano.org/documentacion/'+ b[0]
text = text + '\n\nSaludos'
msg = MIMEText(unicode(text).encode('utf-8'))
msg['Subject'] = txtsubject % numtasks
msg['From'] = MAIL_FROM
msg['To'] = toAddress
msg.set_charset('utf-8')
server = smtplib.SMTP(HOST)
server.starttls()
server.login(username,password)
server.sendmail(MAIL_FROM, toAddress, msg.as_string())
server.quit()
except Exception:
pass
else:
# TODO: show a 'no email address for user X' error.
pass
def taskoverdue(tasks_overdue):
'''
text for message and subject for overdue tasks
'''
tasks_new = tasks_overdue
txtmessage = u"Hola %s, \n\nActualmente tienes %s tarea(s) asignada(s) a ti que están caducadas. Por favor revisa su estado y marcalas como finalizadas o amplia su fecha límite \n"
txtsubject = '[Mozilla Hispano] Tienes %s tareas caducadas'
send_mail(txtmessage, txtsubject, tasks_new)
def taskthreedays(tasks_threedays):
'''
text for message and subject for tasks that mature in three days
'''
tasks_new = tasks_threedays
txtmessage = u"Hola %s, \n\nActualmente tienes %s tarea(s) asignada(s) a ti que están a punto de caducar. \n"
txtsubject = '[Mozilla Hispano] Tienes %s tareas a punto de caducar'
send_mail(txtmessage, txtsubject,tasks_new)
def taskonday(tasks_onday):
'''
text for message and subject for tasks that mature today
'''
tasks_new = tasks_onday
txtmessage = u"Hola %s, \n\nActualmente tienes %s tarea(s) asignada(s) a ti que caducan hoy. Por favor revisa su estado y actualizalas acordemente \n"
txtsubject = '[Mozilla Hispano] Tienes %s tareas que caducan hoy'
send_mail(txtmessage, txtsubject, tasks_new)
# meetings reminder
class Meetings(object):
def __init__(self):
self.collab_new = {}
collaborators(self.collab_new)
json_meeting = urllib2.urlopen(MEETINGS_URL).read()
self.meetings = json.loads(json_meeting)
def meetingmail(self, txtmessage, txtsubject, json):
try:
address = json[1]
text = txtmessage % (json[0],json[2],json[3],json[5])
msg = MIMEText(unicode(text).encode('utf-8'))
msg['Subject'] = txtsubject % unicode(json[4]).encode('utf-8')
msg['From'] = MAIL_FROM
msg['To'] = address
msg.set_charset('utf-8')
server = smtplib.SMTP(HOST)
server.starttls()
server.login(username,password)
server.sendmail(MAIL_FROM, address, msg.as_string())
server.quit
except Exception:
pass
def meetingsthreedays(self):
for meeting in self.meetings['items']:
fecha = meeting['fechainicio'][0]
fechareal = datetime.strptime(fecha, '%Y-%m-%d %H:%M:%S')
fecha = fechareal + timedelta(hours=localtime)
if timedelta(days = 2) < (fecha - datetime.now()) <= timedelta(days=3):
for user in meeting['asistentes']:
email = self.collab_new['Usuario:' + user]
meeting_three_days = []
try:
meeting_three_days.append([user, email, meeting['proyecto'][0],fechareal.strftime('%d de %b a las %H:%M UTC'),meeting['area'][0],meeting['label']])
except KeyError:
meeting_three_days.append([user, email, meeting['area'][0],fechareal.strftime('%d de %b a las %H:%M UTC'),meeting['area'][0],meeting['label']])
meeting_three_days = meeting_three_days[0]
txtmessage = u"""Hola %s, \n\n Te recordamos que estas registrado para asistir a la reunión de %s, el próximo %s.
\nPuedes ver más información acerca de la reunión en: https://www.mozilla-hispano.org/documentacion/%s
\nRevisa tu hora local en http://www.timeanddate.com/worldclock/fixedtime.html?iso="""+ fechareal.strftime('%Y%m%dT%H%M')
txtsubject = '[MozillaHispano]Reunión de %s en unos días'
Meetings().meetingmail(txtmessage,txtsubject,meeting_three_days)
def meetingstoday(self):
for meeting in self.meetings['items']:
fecha = meeting['fechainicio'][0]
fechareal = datetime.strptime(fecha, '%Y-%m-%d %H:%M:%S')
fecha = fechareal + timedelta(hours=localtime)
if timedelta(hours = 2) < (fecha - datetime.now()) <= timedelta(hours=3):
for user in meeting['asistentes']:
email = self.collab_new['Usuario:' + user]
meeting_today = []
try:
meeting_today.append([user, email, meeting['proyecto'][0],fechareal.strftime('%d de %b a las %H:%M UTC'),meeting['area'][0],meeting['label']])
except KeyError:
meeting_today.append([user, email, meeting['area'][0],fechareal.strftime('%d de %b a las %H:%M UTC'),meeting['area'][0],meeting['label']])
meeting_today = meeting_today[0]
txtmessage = u"""Hola %s, \n\n Te recordamos que estas registrado para asistir a la reunión de %s, hoy %s.
\n Puedes ver más información acerca de la reunión en: https://www.mozilla-hispano.org/documentacion/%s
\nRevisa tu hora local en http://www.timeanddate.com/worldclock/fixedtime.html?iso="""+ fechareal.strftime('%Y%m%dT%H%M')
txtsubject = '[MozillaHispano]Reunión de %s en unas horas'
Meetings().meetingmail(txtmessage,txtsubject,meeting_today)
def tasks(parsed_args):
getTasks()
def meeting_threedays(parsed_args):
Meetings().meetingsthreedays()
def meeting_today(parsed_args):
Meetings().meetingstoday()
parser=argparse.ArgumentParser()
parser.add_argument('--tasks', dest='action', action='store_const', const=tasks, help='reminder for tasks')
parser.add_argument('--meetings-threedays', dest='action', action='store_const', const=meeting_threedays, help='reminder for meetings into three days')
parser.add_argument('--meetings-today', dest='action', action='store_const', const=meeting_today, help= 'reminder for meetings today')
parsed_args = parser.parse_args()
if parsed_args.action is None:
parser.parse_args(['-h'])
parsed_args.action(parsed_args)