Attachment 'TaskPlanner-1.9.1.py'
Download 1 # -*- coding: utf-8 -*-
2 """
3 MoinMoin - TaskPlanner Action
4 Version 0.9
5
6 A task planner plugin for Moin.
7
8 General information:
9 * The task database file "task-db" is located in the wiki's data dir and is
10 a plain text file.
11 * The total number of tasks is currently restricted to 999.999 tasks. However
12 a plain text database doesn't scale very well. So try to keep the database
13 small and do remove task not needed anymore.
14 * Note: Removing a task from the database does also mean: deleting the task's wiki
15 homepage.
16 * Note: You have to be superuser to be able to remove tasks. Normal users can mark
17 a completed task with the label "remove me" so superuser get to know which tasks to
18 remove.
19
20 @copyright: 2007 by Oliver Siemoneit
21 @license: GNU GPL, see COPYING for details.
22 Adapted for version 1.9.1 by JV
23
24 """
25
26 import os, time
27 from MoinMoin import config, wikiutil, user
28 from MoinMoin.Page import Page
29 from MoinMoin.util import timefuncs
30 from MoinMoin.mail.sendmail import sendmail
31
32
33 def _make_unique_task_id(request):
34 """
35 Make unique task id
36
37 @param request: request object
38 @return: 6-digit id (string)
39 """
40 from random import randint
41 databaseFile = os.path.join(request.cfg.data_dir, "task-db")
42 if os.path.isfile(databaseFile):
43 existing_id = task_id = 0
44 while task_id == existing_id:
45 task_id = "%06d" % randint(1, 999999)
46 for line in open(databaseFile).readlines():
47 tmp = line.split("\t")
48 existing_id = tmp[0]
49 if existing_id == task_id:
50 break
51 else:
52 task_id = "%06d" % randint(1, 999999)
53
54 return task_id
55
56
57 def _make_local_timestamp(request):
58 """
59 Make a timestamp for creation/closing of task
60
61 @param request: request object
62 @return: timestamp (string)
63 """
64 now = time.time()
65 user = request.user
66
67 if user.valid and user.tz_offset:
68 tz = user.tz_offset
69 tz -= tz % 60
70 minutes = tz / 60
71 hours = minutes / 60
72 minutes -= hours * 60
73 now += tz
74
75 return time.strftime("%Y.%m.%dT%H:%M:%S", timefuncs.tmtuple(now))
76
77
78 def do_mainform(request, actname, msg=None):
79 """
80 Build the main form
81
82 @param request: request object
83 @param actname: actname object
84 @param msg: message to display
85 @return: html form (string)
86 """
87 _ = request.getText
88 ticket = wikiutil.createTicket(request)
89 querytext = _('TaskPlanner User Interface')
90 button1 = _('Add Task')
91 button2 = _('Edit Task')
92 button3 = _('Remove Task')
93 button4 = _('Close')
94
95 formhtml1 = '''
96 <form method="post" action="">
97 <strong>%s <br></strong>''' % querytext
98
99 if msg:
100 formhtml2 = "<br> %s <br>" % msg
101 else:
102 formhtml2 = ""
103
104 formhtml3 = '''
105 <br>
106 <input type="hidden" name="action" value="%(actname)s">
107 <input type="hidden" name="ticket" value="%(ticket)s">
108 <input class="buttons" type="submit" name="button_add" value="%(button1)s">
109 <input class="buttons" type="submit" name="button_edit" value="%(button2)s"> ''' % {
110 'actname' : actname,
111 'ticket' : ticket,
112 'button1' : button1,
113 'button2' : button2, }
114
115 if request.user.isSuperUser():
116 formhtml4 = '''
117 <input class="buttons" type="submit" name="button_remove" value="%(button3)s">''' % {
118 'button3' : button3, }
119
120 else:
121 formhtml4 = ""
122
123 formhtml5 = '''
124 <input class="buttons" type="submit" name="button_cancel" value="%(button4)s">
125 </form>''' % {
126 'button4' : button4, }
127
128 formhtml = formhtml1 + formhtml2 + formhtml3 + formhtml4 + formhtml5
129 return formhtml
130
131
132 def do_addform(request, actname, page, msg=None, assoc_page=None, assign=None):
133 """
134 Build the 'add task' form
135
136 @param request: request object
137 @param actname: actname object
138 @param page: page object
139 @param msg: message to display
140 @param assoc_page: preset page association (by TaskTable macro)
141 @param assign: preset assign (by TaskTable macro)
142 @return: html form (string)
143 """
144 _ = request.getText
145 ticket = wikiutil.createTicket(request)
146 task_id = _make_unique_task_id(request)
147 querytext = _('Add Task')
148 button1 = _('Add')
149 button2 = _('Cancel')
150 label1 = _('Task ID')
151 value1 = task_id
152 label2 = _('Created by')
153 value2 = request.user.name
154 label3 = _('Created on')
155 value3 = _make_local_timestamp(request)
156 label4 = _('Task name')
157 value4 = ""
158 label5 = _('Assigned to')
159 if assign:
160 value5 = assign.replace('%20', ' ')
161 else:
162 value5 = ""
163 label6 = _('Time-frame')
164 value6 = ""
165 label7 = _('Priority')
166 value7 = ""
167 label8 = _('Status')
168 value8 = _('to do')
169 label9 = _('Task description')
170 value9 = ""
171 label10 = _('Task\'s wiki homepage')
172 value10 = "ToDos/%s" % task_id
173 label11 = _('Task associated with page')
174 label12 = _('Notify assignee by email?')
175 value12= "Yes"
176 if assoc_page:
177 value11 = assoc_page.replace('%20', ' ')
178 else:
179 value11 = page.page_name
180
181 formhtml1 = '''
182 <form method="post" action="">
183 <div class="userpref">
184 <strong>%s <br></strong>''' % querytext
185
186 if msg:
187 formhtml2 = "%s" % msg
188 else:
189 formhtml2 = ""
190
191 formhtml3 = '''
192 <br>
193 <input type="hidden" name="action" value="%(actname)s">
194 <input type="hidden" name="ticket" value="%(ticket)s">
195 <input type="hidden" name="closed_by" value="unknown">
196 <input type="hidden" name="closed_at" value="unknown">
197 <table border="0">
198 <tr>
199 <td class="label"><label>%(label1)s</label></td>
200 <td class="content">
201 <input type="text" name="task_id" value="%(value1)s" size="6" readonly="readonly">
202 </td>
203 </tr>
204 <tr>
205 <td class="label"><label>%(label2)s</label></td>
206 <td class="content">
207 <input type="text" name="created_by" value="%(value2)s" size="36" readonly="readonly">
208 </td>
209 </tr>
210 <tr>
211 <td class="label"><label>%(label3)s</label></td>
212 <td class="content">
213 <input type="text" name="created_at" value="%(value3)s" size="36" readonly="readonly">
214 </td>
215 </tr>
216 <tr>
217 <td class="label"><label>%(label4)s</label></td>
218 <td class="content">
219 <input type="text" name="task_name" value="%(value4)s" size="36" maxlength="50">
220 </td>
221 </tr>
222 <tr>
223 <td class="label"><label>%(label5)s</label></td>
224 <td class="content">
225 <input type="text" name="assigned_to" value="%(value5)s" size="36" maxlength="100">
226 </td>
227 </tr>
228 <tr>
229 <td class="label"><label>%(label6)s</label></td>
230 <td class="content">
231 <input type="text" name="time_frame" value="%(value6)s" size="36" maxlength="20">
232 </td>
233 </tr>
234 <tr>
235 <td class="label"><label>%(label7)s</label></td>
236 <td class="content">
237 <select name="priority" size="1">
238 <option selected value=""> </option>
239 <option value="low">%(low)s</option>
240 <option value="medium">%(medium)s</option>
241 <option value="high">%(high)s</option>
242 <option value="critical">%(critical)s</option>
243 </select>
244 </td>
245 </tr>
246 <tr>
247 <td class="label"><label>%(label8)s</label></td>
248 <td class="content">
249 <select name="status" size="1">
250 <option selected value="to do">%(ToDo)s</option>
251 <option value="in progress">%(InProgress)s</option>
252 <option value="pending">%(Pending)s</option>
253 </select>
254 </td>
255 </tr>
256 <tr>
257 <td class="label"><label>%(label9)s</label></td>
258 <td class="content">
259 <input type="text" name="task_desc" value="%(value9)s" size="80" maxlength="100">
260 </td>
261 </tr>
262 <tr>
263 <td class="label"><label>%(label10)s</label></td>
264 <td class="content">
265 <input type="text" name="task_disc_page" value="%(value10)s" size="80" maxlength="100">
266 </td>
267 </tr>
268 <tr>
269 <td class="label"><label>%(label11)s</label></td>
270 <td class="content">
271 <input type="text" name="task_assoc" value="%(value11)s" size="80" maxlength="100">
272 </td>
273 </tr>
274 <tr>
275 <td class="label"><label>%(label12)s</label></td>
276 <td class="content">
277 <input type="checkbox" name="email_notification" value="%(value12)s">
278 </td>
279 </tr>
280 <tr>
281 <td> </td>
282 <td>
283 <input class="buttons" type="submit" name="button_add_a" value="%(button1)s">
284 <input class="buttons" type="submit" name="button_back" value="%(button2)s">
285 </td>
286 </tr>
287 </table>
288 </div>
289 </form>''' % {
290 'actname' : actname,
291 'ticket' : ticket,
292 'label1' : label1,
293 'value1' : value1,
294 'label2' : label2,
295 'value2' : value2,
296 'label3' : label3,
297 'value3' : value3,
298 'label4' : label4,
299 'value4' : value4,
300 'label5' : label5,
301 'value5' : value5,
302 'label6' : label6,
303 'value6' : value6,
304 'label7' : label7,
305 'low' : _('low'),
306 'medium' : _('medium'),
307 'high' : _('high'),
308 'critical' : _('critical'),
309 'label8' : label8,
310 'ToDo' : _('to do'),
311 'Pending' : _('pending'),
312 'InProgress' : _('in progress'),
313 'label9' : label9,
314 'value9' : value9,
315 'label10' : label10,
316 'value10' : value10,
317 'label11' : label11,
318 'value11' : value11,
319 'label12' : label12,
320 'value12' : value12,
321 'button1' : button1,
322 'button2' : button2
323 }
324 formhtml = formhtml1 + formhtml2 + formhtml3
325 return formhtml
326
327
328 def _check_form_input(request):
329 """
330 Check for valid input in 'add task' and 'edit task' form
331
332 @param request: request object
333 @result: result (string)
334 """
335 _ = request.getText
336 task_name = request.form.get('task_name', [""])
337 task_name = task_name.strip(' ')
338 if task_name == "":
339 return (_('You have to specify a task name.'), "warning")
340
341 assigned_to = request.form.get('assigned_to', [""])
342 assigned_to = assigned_to.strip(' ')
343 if assigned_to == "":
344 return (_('You have to assign the task to someone.'), "warning")
345 else:
346 assignee_id=user.getUserId(request, assigned_to)
347 if assignee_id==None:
348 return (_('You can only assign the task to a user.'), "warning")
349
350 time_frame = request.form.get('time_frame', [""])
351 time_frame = time_frame.strip(' ')
352 if time_frame != "":
353 from time import strptime
354 try:
355 time_struct = strptime(time_frame, "%d.%m.%y")
356 except ValueError:
357 try:
358 time_struct = strptime(time_frame, "%d.%m.%y %H:%M")
359 except ValueError:
360 return (_('Valid time-frame formats are either dd.mm.yy or dd.mm.yy hh:mm.'),"warning")
361 return ""
362
363
364 def _save_task(request):
365 """
366 Save task data to disc
367
368 @param request: request object
369 @return: result (string)
370 """
371 _ = request.getText
372 task_id = request.form.get('task_id', [""])
373 created_by = request.form.get('created_by', [""])
374 created_at = request.form.get('created_at', [""])
375 closed_by = request.form.get('closed_by', [""])
376 closed_at = request.form.get('closed_at', [""])
377 task_name = request.form.get('task_name', [""])
378 task_name = wikiutil.escape(task_name, 1)
379 task_name = wikiutil.clean_input(task_name)
380 assigned_to = request.form.get('assigned_to', [""])
381 assigned_to = wikiutil.escape(assigned_to, 1)
382 assigned_to = wikiutil.clean_input(assigned_to)
383 time_frame = request.form.get('time_frame', [""])
384 priority = request.form.get('priority', [""])
385 status = request.form.get('status', [""])
386 task_desc = request.form.get('task_desc', [""])
387 email_notification = request.form.get('email_notification',[""])
388 if task_desc != "":
389 task_desc = wikiutil.escape(task_desc, 1)
390 task_desc = wikiutil.clean_input(task_desc)
391 task_disc_page = request.form.get('task_disc_page', [""])
392 if task_disc_page != "":
393 task_disc_page = wikiutil.escape(task_disc_page, 1)
394 task_disc_page = wikiutil.clean_input(task_disc_page)
395 task_assoc = request.form.get('task_assoc', [""])
396 if task_assoc != "":
397 task_assoc = wikiutil.escape(task_assoc, 1)
398 task_assoc = wikiutil.clean_input(task_assoc)
399
400 try:
401 databaseFile = os.path.join(request.cfg.data_dir, "task-db")
402 db = open(databaseFile,"a")
403 db.write("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % (task_id,
404 created_by,
405 created_at,
406 closed_by,
407 closed_at,
408 task_name,
409 assigned_to,
410 time_frame,
411 priority,
412 status,
413 task_desc,
414 task_disc_page,
415 task_assoc))
416 db.close()
417 except IOError:
418 return (_('Error while trying to save task data.'), "error")
419 if email_notification=="Yes":
420 #here must the notify by email function call appear
421 #make the email body
422 txtbody =u'''
423 Hi,
424 You have been assigned a new task.
425 The task details are:
426 Created by: %(1)s
427 Created at: %(2)s
428 Task_name: %(3)s
429 Finish before: %(4)s
430 Priority: %(5)s
431 Status: %(6)s
432 Task description: %(7)s
433 Have a good day!
434 ''' % {
435 '1': created_by,
436 '2': created_at,
437 '3': task_name,
438 '4': time_frame,
439 '5': priority,
440 '6': status,
441 '7': task_desc,
442 }
443 # get email address
444 # first make a user
445 assignee=user.User(request,id=user.getUserId(request, assigned_to))
446 # then load the data from disk so that its email adress becomes available
447 assignee.load_from_id()
448 # then we can send
449 sendok=sendmail(request, [assignee.email], u'New task: '+task_name, txtbody)[0]
450 if sendok:
451 return (_('Task succesfully saved and assignee notified succesfully.'),"ok")
452 else:
453 return (_('Task successfully saved but assignee could not be notified.'), "warning")
454 return (_('Task successfully saved.'), "ok")
455
456 def do_edit_search_form(request, actname, msg=None):
457 """
458 Build the 'search task for editing' form
459
460 @param request: request object
461 @param actname: actname object
462 @param msg: message to display
463 @return: html form (string)
464 """
465 _ = request.getText
466 ticket = wikiutil.createTicket(request)
467 querytext = _('Edit Task')
468 button1 = _('Edit')
469 button2 = _('Cancel')
470 label1 = _('Task ID')
471 value1 = ""
472
473 formhtml1 = '''
474 <form method="post" action="">
475 <div class="userpref">
476 <strong>%s <br></strong>''' % querytext
477
478 if msg:
479 formhtml2 = "%s" % msg
480 else:
481 formhtml2 = ""
482
483 formhtml3 = '''
484 <br>
485 <input type="hidden" name="action" value="%(actname)s">
486 <input type="hidden" name="ticket" value="%(ticket)s">
487 <table border="0">
488 <tr>
489 <td class="label"><label>%(label1)s</label></td>
490 <td class="content">
491 <input type="text" name="task_id" value="%(value1)s" size="6" maxlength="6">
492 </td>
493 </tr>
494 <tr>
495 <td> </td>
496 <td>
497 <input class="buttons" type="submit" name="button_search_id" value="%(button1)s">
498 <input class="buttons" type="submit" name="button_back" value="%(button2)s">
499 </td>
500 </tr>
501 </table>
502 </div>
503 </form>''' % {
504 'actname': actname,
505 'ticket' : ticket,
506 'label1' : label1,
507 'value1' : value1,
508 'button1': button1,
509 'button2': button2
510 }
511 formhtml = formhtml1 + formhtml2 + formhtml3
512 return formhtml
513
514
515 def do_editform(request, actname, page, task, msg=None):
516 """
517 Build the 'edit task' form
518
519 @param request: request object
520 @param actname: actname object
521 @param page: page object
522 @param task: task to edit
523 @param msg: message to display
524 @return: html form (string)
525 """
526 _ = request.getText
527 ticket = wikiutil.createTicket(request)
528 querytext = _('Edit Task')
529 button1 = _('Save')
530 button2 = _('Cancel')
531 label1 = _('Task ID')
532 value1 = task[0]
533 label2 = _('Created by')
534 value2 = task[1]
535 label3 = _('Created on')
536 value3 = task[2]
537 label4 = _('Closed by')
538 value4 = task[3]
539 label5 = _('Closed at')
540 value5 = task[4]
541 label6 = _('Task name')
542 value6 = task[5]
543 label7 = _('Assigned to')
544 value7 = task[6]
545 label8 = _('Time-frame')
546 value8 = task[7]
547 label9 = _('Priority')
548 value9 = task[8]
549 label10 = _('Status')
550 value10 = task[9]
551 label11 = _('Task description')
552 value11 = task[10]
553 label12 = _('Task\'s wiki homepage')
554 value12 = task[11]
555 label13 = _('Task associated with page')
556 value13 = task[12]
557 label14 = _('Notify assignee?')
558 value14 ="Yes"
559
560 formhtml1 = '''
561 <form method="post" action="">
562 <div class="userpref">
563 <strong>%s <br></strong>''' % querytext
564
565 if msg:
566 formhtml2 = "%s" % msg
567 else:
568 formhtml2 = ""
569
570 formhtml3 = '''
571 <br>
572 <input type="hidden" name="action" value="%(actname)s">
573 <input type="hidden" name="ticket" value="%(ticket)s">
574 <table border="0">
575 <tr>
576 <td class="label"><label>%(label1)s</label></td>
577 <td class="content">
578 <input type="text" name="task_id" value="%(value1)s" size="6" readonly="readonly">
579 </td>
580 </tr>
581 <tr>
582 <td class="label"><label>%(label2)s</label></td>
583 <td class="content">
584 <input type="text" name="created_by" value="%(value2)s" size="36" readonly="readonly">
585 </td>
586 </tr>
587 <tr>
588 <td class="label"><label>%(label3)s</label></td>
589 <td class="content">
590 <input type="text" name="created_at" value="%(value3)s" size="36" readonly="readonly">
591 </td>
592 </tr> ''' % {
593 'actname': actname,
594 'ticket' : ticket,
595 'label1' : label1,
596 'value1' : value1,
597 'label2' : label2,
598 'value2' : value2,
599 'label3' : label3,
600 'value3' : value3
601 }
602
603 if value4 != "unknown":
604 formhtml4 = '''
605 <tr>
606 <td class="label"><label>%(label4)s</label></td>
607 <td class="content">
608 <input type="text" name="closed_by" value="%(value4)s" size="36" readonly="readonly">
609 </td>
610 </tr>
611 <tr>
612 <td class="label"><label>%(label5)s</label></td>
613 <td class="content">
614 <input type="text" name="closed_at" value="%(value5)s" size="36" readonly="readonly">
615 </td>
616 </tr> ''' % {
617 'label4' : label4,
618 'value4' : value4,
619 'label5' : label5,
620 'value5' : value5
621 }
622 else:
623 formhtml4 = '''
624 <input type="hidden" name="closed_by" value="%(value4)s">
625 <input type="hidden" name="closed_at" value="%(value5)s"> ''' % {
626 'value4' : value4,
627 'value5' : value5
628 }
629
630 formhtml5 = '''
631 <tr>
632 <td class="label"><label>%(label6)s</label></td>
633 <td class="content">
634 <input type="text" name="task_name" value="%(value6)s" size="36" maxlength="50">
635 </td>
636 </tr>
637 <tr>
638 <td class="label"><label>%(label7)s</label></td>
639 <td class="content">
640 <input type="text" name="assigned_to" value="%(value7)s" size="36" maxlength="100">
641 </td>
642 </tr>
643 <tr>
644 <td class="label"><label>%(label8)s</label></td>
645 <td class="content">
646 <input type="text" name="time_frame" value="%(value8)s" size="36" maxlength="20">
647 </td>
648 </tr>
649 <tr>
650 <td class="label"><label>%(label9)s</label></td>
651 <td class="content">
652 <select name="priority" size="1"> ''' % {
653 'label6' : label6,
654 'value6' : value6,
655 'label7' : label7,
656 'value7' : value7,
657 'label8' : label8,
658 'value8' : value8,
659 'label9' : label9
660 }
661 # ToDo: Make code more compact. Don't use if value9 = ..
662 if value9 == "":
663 formhtml6 = '''
664 <option selected value=""> </option>
665 <option value="low">%(low)s</option>
666 <option value="medium">%(medium)s</option>
667 <option value="high">%(high)s</option>
668 <option value="critical">%(critical)s</option>
669 </select>''' % { 'low' : _('low'),
670 'medium' : _('medium'),
671 'high' : _('high'),
672 'critical' : _('critical') }
673
674 if value9 == "low":
675 formhtml6 = '''
676 <option value=""> </option>
677 <option selected value="low">%(low)s</option>
678 <option value="medium">%(medium)s</option>
679 <option value="high">%(high)s</option>
680 <option value="critical">%(critical)s</option>
681 </select>''' % { 'low' : _('low'),
682 'medium' : _('medium'),
683 'high' : _('high'),
684 'critical' : _('critical') }
685
686 if value9 == "medium":
687 formhtml6 = '''
688 <option value=""> </option>
689 <option value="low">%(low)s</option>
690 <option selected value="medium">%(medium)s</option>
691 <option value="high">%(high)s</option>
692 <option value="critical">%(critical)s</option>
693 </select>''' % { 'low' : _('low'),
694 'medium' : _('medium'),
695 'high' : _('high'),
696 'critical' : _('critical') }
697
698 if value9 == "high":
699 formhtml6 = '''
700 <option value=""> </option>
701 <option value="low">%(low)s</option>
702 <option value="medium">%(medium)s</option>
703 <option selected value="high">%(high)s</option>
704 <option value="critical">%(critical)s</option>
705 </select>''' % { 'low' : _('low'),
706 'medium' : _('medium'),
707 'high' : _('high'),
708 'critical' : _('critical') }
709
710 if value9 == "critical":
711 formhtml6 = '''
712 <option value=""> </option>
713 <option value="low">%(low)s</option>
714 <option value="medium">%(medium)s</option>
715 <option value="high">%(high)s</option>
716 <option selected value="critical">%(critical)s</option>
717 </select>''' % { 'low' : _('low'),
718 'medium' : _('medium'),
719 'high' : _('high'),
720 'critical' : _('critical') }
721
722 formhtml7 = '''
723 </td>
724 </tr>
725 <tr>
726 <td class="label"><label>%(label10)s</label></td>
727 <td class="content">
728 <select name="status" size="1"> ''' % {
729 'label10' : label10 }
730
731 # ToDo: Make code more compact. Don't use if value10 = ..
732 if value10 == "to do":
733 formhtml8 = '''
734 <option selected value="to do">%(ToDo)s</option>
735 <option value="in progress">%(InProgress)s</option>
736 <option value="pending">%(Pending)s</option>
737 <option value="done">%(Done)s</option>
738 <option value="failed">%(Undone)s</option>
739 <option value="closed">%(Closed)s</option>
740 <option value="remove me">%(RemoveMe)s</option>''' % { 'ToDo' : _('to do'),
741 'InProgress' : _('in progress'),
742 'Pending' : _('pending'),
743 'Done' : _('done'),
744 'Undone' : _('failed'),
745 'Closed' : _('closed'),
746 'RemoveMe' : _('remove me') }
747
748 if value10 == "in progress":
749 formhtml8 = '''
750 <option value="to do">%(ToDo)s</option>
751 <option selected value="in progress">%(InProgress)s</option>
752 <option value="pending">%(Pending)s</option>
753 <option value="done">%(Done)s</option>
754 <option value="failed">%(Undone)s</option>
755 <option value="closed">%(Closed)s</option>
756 <option value="remove me">%(RemoveMe)s</option>''' % { 'ToDo' : _('to do'),
757 'InProgress' : _('in progress'),
758 'Pending' : _('pending'),
759 'Done' : _('done'),
760 'Undone' : _('failed'),
761 'Closed' : _('closed'),
762 'RemoveMe' : _('remove me') }
763
764 if value10 == "pending":
765 formhtml8 = '''
766 <option value="to do">%(ToDo)s</option>
767 <option value="in progress">%(InProgress)s</option>
768 <option selected value="pending">%(Pending)s</option>
769 <option value="done">%(Done)s</option>
770 <option value="failed">%(Undone)s</option>
771 <option value="closed">%(Closed)s</option>
772 <option value="remove me">%(RemoveMe)s</option>''' % { 'ToDo' : _('to do'),
773 'InProgress' : _('in progress'),
774 'Pending' : _('pending'),
775 'Done' : _('done'),
776 'Undone' : _('failed'),
777 'Closed' : _('closed'),
778 'RemoveMe' : _('remove me') }
779
780 if value10 == "done":
781 formhtml8 = '''
782 <option value="to do">%(ToDo)s</option>
783 <option value="in progress">%(InProgress)s</option>
784 <option value="pending">%(Pending)s</option>
785 <option selected value="done">%(Done)s</option>
786 <option value="failed">%(Undone)s</option>
787 <option value="closed">%(Closed)s</option>
788 <option value="remove me">%(RemoveMe)s</option>''' % { 'ToDo' : _('to do'),
789 'InProgress' : _('in progress'),
790 'Pending' : _('pending'),
791 'Done' : _('done'),
792 'Undone' : _('failed'),
793 'Closed' : _('closed'),
794 'RemoveMe' : _('remove me') }
795
796 if value10 == "failed":
797 formhtml8 = '''
798 <option value="to do">%(ToDo)s</option>
799 <option value="in progress">%(InProgress)s</option>
800 <option value="pending">%(Pending)s</option>
801 <option value="done">%(Done)s</option>
802 <option selected value="failed">%(Undone)s</option>
803 <option value="closed">%(Closed)s</option>
804 <option value="remove me">%(RemoveMe)s</option>''' % { 'ToDo' : _('to do'),
805 'InProgress' : _('in progress'),
806 'Pending' : _('pending'),
807 'Done' : _('done'),
808 'Undone' : _('failed'),
809 'Closed' : _('closed'),
810 'RemoveMe' : _('remove me') }
811
812 if value10 == "closed":
813 formhtml8 = '''
814 <option value="to do">%(ToDo)s</option>
815 <option value="in progress">%(InProgress)s</option>
816 <option value="pending">%(Pending)s</option>
817 <option value="done">%(Done)s</option>
818 <option value="failed">%(Undone)s</option>
819 <option selected value="closed">%(Closed)s</option>
820 <option value="remove me">%(RemoveMe)s</option>''' % { 'ToDo' : _('to do'),
821 'InProgress' : _('in progress'),
822 'Pending' : _('pending'),
823 'Done' : _('done'),
824 'Undone' : _('failed'),
825 'Closed' : _('closed'),
826 'RemoveMe' : _('remove me') }
827
828 if value10 == "remove me":
829 formhtml8 = '''
830 <option value="to do">%(ToDo)s</option>
831 <option value="in progress">%(InProgress)s</option>
832 <option value="pending">%(Pending)s</option>
833 <option value="done">%(Done)s</option>
834 <option value="failed">%(Undone)s</option>
835 <option value="closed">%(Closed)s</option>
836 <option selected value="remove me">%(RemoveMe)s</option>''' % { 'ToDo' : _('to do'),
837 'InProgress' : _('in progress'),
838 'Pending' : _('pending'),
839 'Done' : _('done'),
840 'Undone' : _('failed'),
841 'Closed' : _('closed'),
842 'RemoveMe' : _('remove me') }
843
844 formhtml9 = '''
845 </select>
846 </td>
847 </tr>
848 <tr>
849 <td class="label"><label>%(label11)s</label></td>
850 <td class="content">
851 <input type="text" name="task_desc" value="%(value11)s" size="80" maxlength="100">
852 </td>
853 </tr>
854 <tr>
855 <td class="label"><label>%(label12)s</label></td>
856 <td class="content">
857 <input type="text" name="task_disc_page" value="%(value12)s" size="80" maxlength="100">
858 </td>
859 </tr>
860 <tr>
861 <td class="label"><label>%(label13)s</label></td>
862 <td class="content">
863 <input type="text" name="task_assoc" value="%(value13)s" size="80" maxlength="100">
864 </td>
865 </tr>
866 <tr>
867 <td class="label"><label>%(label14)s</label></td>
868 <td class="content">
869 <input type="checkbox" name="email_notification" value="%(value14)s">
870 </td>
871 </tr>
872 <tr>
873 <td> </td>
874 <td>
875 <input class="buttons" type="submit" name="button_save_edit" value="%(button1)s">
876 <input class="buttons" type="submit" name="button_back_search" value="%(button2)s">
877 </td>
878 </tr>
879 </table>
880 </div>
881 </form>''' % {
882 'label11' : label11,
883 'value11' : value11,
884 'label12' : label12,
885 'value12' : value12,
886 'label13' : label13,
887 'value13' : value13,
888 'label14' : label14,
889 'value14' : value14,
890 'button1' : button1,
891 'button2' : button2
892 }
893 formhtml = formhtml1 + formhtml2 + formhtml3 + formhtml4 + formhtml5 + formhtml6 + formhtml7 + formhtml8 + formhtml9
894 return formhtml
895
896
897 def _save_changed_task(request, page):
898 """
899 Save changed task data to disc
900
901 @param request: request object
902 @param page: page object
903 @return: result (string)
904
905 """
906 _ = request.getText
907 task_id = request.form.get('task_id', [""])
908 created_by = request.form.get('created_by', [""])
909 created_at = request.form.get('created_at', [""])
910 closed_by = request.form.get('closed_by', [""])
911 closed_at = request.form.get('closed_at', [""])
912 task_name = request.form.get('task_name', [""])
913 task_name = wikiutil.escape(task_name, 1)
914 task_name = wikiutil.clean_input(task_name)
915 assigned_to = request.form.get('assigned_to', [""])
916 assigned_to = wikiutil.escape(assigned_to, 1)
917 assigned_to = wikiutil.clean_input(assigned_to)
918 time_frame = request.form.get('time_frame', [""])
919 priority = request.form.get('priority', [""])
920 status = request.form.get('status', [""])
921 task_desc = request.form.get('task_desc', [""])
922 email_notification = request.form.get('email_notification', [""])
923 if task_desc != "":
924 task_desc = wikiutil.escape(task_desc, 1)
925 task_desc = wikiutil.clean_input(task_desc)
926 task_disc_page = request.form.get('task_disc_page', [""])
927 if task_disc_page != "":
928 task_disc_page = wikiutil.escape(task_disc_page, 1)
929 task_disc_page = wikiutil.clean_input(task_disc_page)
930 task_assoc = request.form.get('task_assoc', [""])
931 if task_assoc != "":
932 task_assoc = wikiutil.escape(task_assoc, 1)
933 task_assoc = wikiutil.clean_input(task_assoc)
934
935 databaseFile = os.path.join(request.cfg.data_dir, "task-db")
936 try:
937 db = open(databaseFile,"r")
938 taskdata = db.readlines()
939 db.close()
940 except IOError:
941 return (_('Error while trying to read task data.'), "error")
942
943 new_taskdata = []
944 for line in taskdata:
945 tmp = line.split("\t")
946 if tmp[0] == task_id:
947 # task closed
948 if (status == "closed" or status == "remove me") and (tmp[9] != "closed" or tmp[9] != "remove me"):
949 tmp[3] = request.user.name
950 tmp[4] = _make_local_timestamp(request)
951 # task reopend
952 if status in ["to do", "in progress", "pending", "done", "failed"] and (tmp[9] == "closed" or tmp[9] == "remove me"):
953 tmp[3] = "unknown"
954 tmp[4] = "unknown"
955 tmp[5] = task_name
956 tmp[6] = assigned_to
957 tmp[7] = time_frame
958 tmp[8] = priority
959 tmp[9] = status
960 tmp[10] = task_desc
961 tmp[11] = task_disc_page
962 tmp[12] = task_assoc
963 newline = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" % (tmp[0],
964 tmp[1],
965 tmp[2],
966 tmp[3],
967 tmp[4],
968 tmp[5],
969 tmp[6],
970 tmp[7],
971 tmp[8],
972 tmp[9],
973 tmp[10],
974 tmp[11],
975 tmp[12])
976 new_taskdata += newline
977 else:
978 new_taskdata += line
979
980 try:
981 db = open(databaseFile,"w")
982 db.writelines(new_taskdata)
983 db.close()
984 except IOError:
985 return (_('Error while trying to save task data.'),"error")
986 if email_notification=="Yes":
987 #here must the notify by email function call appear
988 #make the email body
989 txtbody =u'''
990 Hi,
991 A task previously assigned to you has been modified.
992 The new task details are:
993 Created by: %(1)s
994 Created at: %(2)s
995 Task_name: %(3)s
996 Finish before: %(4)s
997 Priority: %(5)s
998 Status: %(6)s
999 Task description: %(7)s
1000 Have a good day!
1001 ''' % {
1002 '1': created_by,
1003 '2': created_at,
1004 '3': task_name,
1005 '4': time_frame,
1006 '5': priority,
1007 '6': status,
1008 '7': task_desc,
1009 }
1010 # get email address
1011 # first make a user
1012 assignee=user.User(request,id=user.getUserId(request, assigned_to))
1013 # then load the data from disk so that its email adress becomes available
1014 assignee.load_from_id()
1015 # then we can send
1016 sendok=sendmail(request, [assignee.email], u'Modified task: '+task_name, txtbody)[0]
1017 if sendok:
1018 return (_('Task succesfully saved and assignee notified succesfully.'),"ok")
1019 else:
1020 return (_('Task successfully saved but assignee could not be notified.'), "warning")
1021
1022 return (_('Task successfully saved.'),"ok")
1023
1024
1025 def do_removeform(request, actname, msg=None):
1026 """
1027 Build the 'remove task' form
1028
1029 @param request: request object
1030 @param actname: actname object
1031 @param msg: message to display
1032 @return: html form (string)
1033 """
1034 _ = request.getText
1035 ticket = wikiutil.createTicket(request)
1036 querytext = _('Remove Task')
1037 button1 = _('Remove')
1038 button2 = _('Cancel')
1039 label1 = _('Task ID')
1040 value1 = ""
1041
1042 formhtml1 = '''
1043 <form method="post" action="">
1044 <div class="userpref">
1045 <strong>%s <br></strong>''' % querytext
1046
1047 if msg:
1048 formhtml2 = "%s" % msg
1049 else:
1050 formhtml2 = ""
1051
1052 formhtml3 = '''
1053 <br>
1054 <input type="hidden" name="action" value="%(actname)s">
1055 <input type="hidden" name="ticket" value="%(ticket)s">
1056 <table border="0">
1057 <tr>
1058 <td class="label"><label>%(label1)s</label></td>
1059 <td class="content">
1060 <input type="text" name="task_id" value="%(value1)s" size="6" maxlength="6">
1061 </td>
1062 </tr>
1063 <tr>
1064 <td> </td>
1065 <td>
1066 <input class="buttons" type="submit" name="button_remove_id" value="%(button1)s">
1067 <input class="buttons" type="submit" name="button_back" value="%(button2)s">
1068 </td>
1069 </tr>
1070 </table>
1071 </div>
1072 </form>''' % {
1073 'actname': actname,
1074 'ticket' : ticket,
1075 'label1' : label1,
1076 'value1' : value1,
1077 'button1': button1,
1078 'button2': button2
1079 }
1080 formhtml = formhtml1 + formhtml2 + formhtml3
1081 return formhtml
1082
1083
1084 def _remove_task(request, task_to_remove=None):
1085 """
1086 Remove task from database
1087
1088 @param request: request object
1089 @param task_to_remove: id of task to remove
1090 @return: tuple result, message (bool, string)
1091 """
1092 _ = request.getText
1093 if task_to_remove == None:
1094 task_id = request.form['task_id']
1095 else:
1096 task_id = task_to_remove
1097 databaseFile = os.path.join(request.cfg.data_dir, "task-db")
1098 if os.path.isfile(databaseFile):
1099 try:
1100 db = open(databaseFile, "r")
1101 database = db.readlines()
1102 db.close()
1103 except:
1104 return (False, (_('Error while trying to remove task from database.'), "error"))
1105 found = False
1106 task_homepage = ""
1107 new_database = []
1108 for line in database:
1109 tmp = line.split("\t")
1110 if tmp[0] == task_id:
1111 found = True
1112 task_homepage = tmp[11]
1113 else:
1114 new_database += line
1115
1116 if found == True:
1117 try:
1118 db = open(databaseFile, "w")
1119 db.writelines(new_database)
1120 db.close()
1121 except:
1122 return (False, (_('Error while trying to remove task from database.'), "error"))
1123 if Page(request, task_homepage).exists():
1124 if request.user.may.delete(task_homepage):
1125 page = PageEditor(request, task_homepage, do_editor_backup=0)
1126 success, msg = page.deletePage()
1127 if success:
1128 return (True, (_("Task and task's wiki homepage successfully removed."),"ok"))
1129 else:
1130 return (True, (_("Task successfully removed from database. Error while trying to delete task's wiki homepage."),"warning"))
1131 else:
1132 return (True, (_("Task successfully removed from database. Error while trying to delete task's wiki homepage: You are not allowed to delete this page."),"warning"))
1133 return (True, (_('Task successfully removed.'),"ok"))
1134 else:
1135 return (False, (_('Task not found.'),"error"))
1136 else:
1137 return (False, (_('Database not found.'),"error"))
1138
1139
1140 def execute(pagename, request):
1141 _ = request.getText
1142 actname = __name__.split('.')[-1]
1143 page = Page(request, pagename)
1144
1145 # check whether user is logged in
1146 if request.user.valid == 0:
1147 request.theme.add_msg(_('Please log in first.'),'error')
1148 return page.send_page()
1149
1150 # ckeck whether action is allowed
1151 if actname in request.cfg.actions_excluded:
1152 request.theme.add_msg(_('You are not allowed to perform this action.'),"warning")
1153 return page.send_page()
1154
1155 # check whether page does really exist
1156 if not page.exists():
1157 request.theme.add_msg(_('This page is already deleted or was never created!'),"error")
1158 return page.send_page()
1159
1160 #
1161 # 'add task' called from outside by the macro via "?action=TaskPlanner&add" (currently not used)
1162 #
1163 if request.form.has_key('action') and request.form.has_key('add'):
1164 # check whether this is a valid request (make outside
1165 # attacks harder by requiring two full HTTP transactions)
1166 if not request.form.has_key('ticket'):
1167 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1168 return page.send_page()
1169
1170 if not wikiutil.checkTicket(request, request.form['ticket']):
1171 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1172 return page.send_page()
1173
1174 if request.form.has_key('button_back'):
1175 return page.send_page()
1176
1177 # check whether TaskTable macro has forwarded information on page and assign
1178 assoc_page = assign = None
1179 if request.form.has_key('page'):
1180 assoc_page = request.form.get('page', [None])
1181 if request.form.has_key('assign'):
1182 assign = request.form.get('assign', [None])
1183
1184 if request.form.has_key('button_add_a'):
1185 result = _check_form_input(request)
1186 if result =="":
1187 result = _save_task(request)
1188 request.theme.add_msg(*result)
1189 return page.send_page()
1190 else:
1191 request.theme.add_msg(_(do_addform(request, actname, page, msg=result[0], assoc_page=assoc_page, assign=assign)),result[1])
1192 return page.send_page()
1193
1194 request.theme.add_msg(_(do_addform(request, actname, page, assoc_page=assoc_page, assign=assign)))
1195 return page.send_page()
1196
1197 #
1198 # 'edit task' called from outside by the macro via "?action=TaskPlanner&edit=[task_id]"
1199 #
1200 elif request.form.has_key('action') and request.form.has_key('edit'):
1201 # check whether this is a valid request (make outside
1202 # attacks harder by requiring two full HTTP transactions)
1203 if not request.form.has_key('ticket'):
1204 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1205 return page.send_page()
1206
1207 if not wikiutil.checkTicket(request, request.form['ticket']):
1208 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1209 return page.send_page()
1210
1211 if request.form.has_key('button_back_search'):
1212 return page.send_page()
1213
1214 task_id = request.form.get('edit', [""])
1215 databaseFile = os.path.join(request.cfg.data_dir, "task-db")
1216 if os.path.isfile(databaseFile):
1217 existing_id = 0
1218 found = False
1219 for line in open(databaseFile).readlines():
1220 tmp = line.split("\t")
1221 existing_id = tmp[0]
1222 if existing_id == task_id:
1223 found = True
1224 break
1225 else:
1226 request.theme.add_msg(_('Database not found. '),"error")
1227 return page.send_page()
1228
1229 if request.form.has_key('button_save_edit'):
1230 result = _check_form_input(request)
1231 if result =="":
1232 result = _save_changed_task(request, page)
1233 request.theme.add_msg(*result)
1234 return page.send_page()
1235 else:
1236 request.theme.add_msg(do_editform(request, actname, page, tmp, msg=result[0]))
1237 return page.send_page()
1238
1239 if found == True:
1240 request.theme.add_msg(_(do_editform(request, actname, page, tmp)))
1241 return page.send_page()
1242
1243 else:
1244 request.theme.add_msg(_('Task not found. '),"error")
1245 return page.send_page()
1246
1247 #
1248 # 'remove task' called from outside by the macro via "?action=TaskPlanner&remove=[task_id]"
1249 #
1250 elif request.form.has_key('action') and request.form.has_key('remove'):
1251 # check whether this is a valid request (make outside
1252 # attacks harder by requiring two full HTTP transactions)
1253 if not request.form.has_key('ticket'):
1254 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1255 return page.send_page()
1256
1257 if not wikiutil.checkTicket(request, request.form['ticket']):
1258 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1259 return page.send_page()
1260
1261 if not request.user.isSuperUser():
1262 request.theme.add_msg(_('You have to be superuser to remove items from the task list database.'),"warning")
1263 return page.send_page()
1264
1265 task_id = request.form.get('remove', [""])
1266 success, msg = _remove_task(request, task_id)
1267 # return page.send_page(msg=msg)
1268 request.theme.add_msg(*msg)
1269 return page.send_page()
1270
1271 #
1272 # Event handling for TaskPlanner user interface
1273 #
1274 elif request.form.has_key('action') and request.form.has_key('ticket'):
1275 # check whether ticket is valid (make outside attacks harder
1276 # by requiring two full HTTP transactions)
1277 if not request.form.has_key('ticket'):
1278 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1279 return page.send_page()
1280
1281 if not wikiutil.checkTicket(request, request.form['ticket']):
1282 request.theme.add_msg(_('Please use the interactive user interface for adding, editing and removing tasks.'),"warning")
1283 return page.send_page()
1284 #
1285 # 'add task' stuff
1286 #
1287
1288 # check whether TaskTable macro has forwarded information on page and assign
1289 assoc_page = assign = None
1290 if request.form.has_key('page'):
1291 assoc_page = request.form.get('page', [None])
1292 if request.form.has_key('assign'):
1293 assign = request.form.get('assign', [None])
1294
1295 # display menu for adding tasks
1296 if request.form.has_key('button_add'):
1297 request.theme.add_msg(do_addform(request, actname, page, assoc_page=assoc_page, assign=assign))
1298 return page.send_page()
1299
1300 # user pressed button 'add task'
1301 if request.form.has_key('button_add_a'):
1302 result = _check_form_input(request)
1303 if result != "":
1304 request.theme.add_msg(_(do_addform(request, actname, page, msg=result[0], assoc_page=assoc_page, assign=assign)),result[1])
1305 return page.send_page()
1306 else:
1307 result = _save_task(request)
1308 request.theme.add_msg(_(do_mainform(request, actname, msg=result[0])),result[1])
1309 return page.send_page()
1310
1311 #
1312 # 'edit task' stuff
1313 #
1314
1315 # display menu for searching task to edit
1316 if request.form.has_key('button_edit'):
1317 request.theme.add_msg(_(do_edit_search_form(request, actname)))
1318 return page.send_page()
1319
1320 # user pressed button 'edit task' in the search task form
1321 if request.form.has_key('button_search_id'):
1322 task_id = request.form['task_id']
1323 databaseFile = os.path.join(request.cfg.data_dir, "task-db")
1324 if os.path.isfile(databaseFile):
1325 existing_id = 0
1326 found = False
1327 for line in open(databaseFile).readlines():
1328 tmp = line.split("\t")
1329 existing_id = tmp[0]
1330 if existing_id == task_id:
1331 found = True
1332 break
1333 else:
1334 request.theme.add_msg(_('Database not found. '),"error")
1335 return page.send_page()
1336
1337 if found == True:
1338 request.theme.add_msg(do_editform(request, actname, page, tmp))
1339 return page.send_page()
1340 else:
1341 request.theme.add_msg(_('Task not found. '),"warning")
1342 return page.send_page()
1343
1344 # user pressed button 'save edited' task
1345 if request.form.has_key('button_save_edit'):
1346 result = _check_form_input(request)
1347 # if we have invalid input, reload task data and display edit form again
1348 if result != "":
1349 task_id = request.form['task_id']
1350 databaseFile = os.path.join(request.cfg.data_dir, "task-db")
1351 if os.path.isfile(databaseFile):
1352 existing_id = 0
1353 found = False
1354 for line in open(databaseFile).readlines():
1355 tmp = line.split("\t")
1356 existing_id = tmp[0]
1357 if existing_id == task_id:
1358 found = True
1359 break
1360 else:
1361 request.theme.add_msg(_('Database not found. '),"error")
1362 return page.send_page()
1363 request.theme.add_msg(do_editform(request, actname, page, tmp, msg=result[0]),result[1])
1364 return page.send_page()
1365
1366 else:
1367 result = _save_changed_task(request, page)
1368 request.theme.add_msg(do_mainform(request, actname, msg=result[0]),result[1])
1369 return page.send_page()
1370
1371 # user pressed button cancel editing task
1372 if request.form.has_key('button_back_search'):
1373 request.theme.add_msg(do_mainform(request, actname))
1374 return page.send_page()
1375
1376 #
1377 # 'remove task' stuff
1378 #
1379
1380 # display menu for removing tasks
1381 if request.form.has_key('button_remove'):
1382 if not request.user.isSuperUser():
1383 request.theme.add_msg(do_mainform(request, actname, msg=_('You have to be superuser to remove items from the task list database.')),"warning")
1384 return page.send_page()
1385 request.theme.add_msg(do_removeform(request, actname))
1386 return page.send_page()
1387
1388
1389
1390 # user pressed button 'remove task'
1391 if request.form.has_key('button_remove_id'):
1392 if not request.user.isSuperUser():
1393 request.theme.add_msg(do_mainform(request, actname, msg= _('You have to be superuser to remove items from the task list database.')),"warning")
1394 return page.send_page()
1395
1396 success, msg = _remove_task(request)
1397 if success:
1398 request.theme.add_msg(do_mainform(request, actname, msg=msg[0]),msg[1])
1399 return page.send_page()
1400 else:
1401 request.theme.add_msg(do_removeform(request, actname, msg=msg[0]),msg[1])
1402 return page.send_page()
1403
1404 # user pressed button 'cancel' in the main form
1405 if request.form.has_key('button_cancel'):
1406 return page.send_page()
1407
1408 # either no button was pressed (i.e. just display TaskPlanner user interface after calling the action
1409 # or 'button_back' was pressed (then show main form again)
1410 # return page.send_page(msg=do_mainform(request, actname))
1411 request.theme.add_msg(do_mainform(request, actname))
1412 return page.send_page()
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.