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