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.
  • [get | view] (2006-12-29 15:02:33, 14.7 KB) [[attachment:AttachTable.py]]
  • [get | view] (2009-08-11 07:04:46, 53.6 KB) [[attachment:TaskPlanner-1.8.4.py]]
  • [get | view] (2010-01-23 14:17:02, 52.7 KB) [[attachment:TaskPlanner-1.9.1.py]]
  • [get | view] (2007-04-14 15:35:39, 49.1 KB) [[attachment:TaskPlanner.py]]
  • [get | view] (2007-02-01 07:00:31, 243.0 KB) [[attachment:TaskPlanner.zip]]
  • [get | view] (2009-08-11 07:05:54, 56.5 KB) [[attachment:TaskPlanner1.8.4plusEmail.py]]
  • [get | view] (2006-12-29 19:46:46, 146.4 KB) [[attachment:TaskPlannerAttachTableIcons.zip]]
  • [get | view] (2007-08-24 20:11:02, 244.6 KB) [[attachment:TaskPlanner_LlubNek.zip]]
  • [get | view] (2007-04-02 14:42:44, 15.3 KB) [[attachment:TaskTable.py]]
  • [get | view] (2006-12-29 19:45:58, 66.9 KB) [[attachment:__init__.py]]
  • [get | view] (2006-12-29 19:45:29, 5.0 KB) [[attachment:_init_.diff]]
  • [get | view] (2006-12-26 16:49:56, 63.8 KB) [[attachment:addtask.jpg]]
  • [get | view] (2007-01-01 22:27:54, 3.8 KB) [[attachment:classic_theme.jpg]]
  • [get | view] (2008-05-07 16:42:25, 201.5 KB) [[attachment:clickingerror.jpg]]
  • [get | view] (2006-12-26 16:55:30, 9.7 KB) [[attachment:common.css]]
  • [get | view] (2006-12-26 16:55:03, 1.1 KB) [[attachment:common.diff]]
  • [get | view] (2007-01-01 22:27:36, 13.8 KB) [[attachment:common_icons.jpg]]
  • [get | view] (2006-12-26 16:53:07, 3.1 KB) [[attachment:de.AttachTable.po]]
  • [get | view] (2006-12-26 16:52:44, 7.4 KB) [[attachment:de.TaskPlanner.po]]
  • [get | view] (2006-12-26 16:50:48, 72.5 KB) [[attachment:imagepreview.jpg]]
  • [get | view] (2006-12-26 16:50:21, 78.2 KB) [[attachment:tasktable.jpg]]
  • [get | view] (2008-05-07 16:42:29, 8.4 KB) [[attachment:traceback_taskplanner.html]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.