Attachment 'TaskTable.py'

Download

   1 """
   2     MoinMoin - TaskTable Macro
   3     Version 0.9
   4 
   5     This macro is the corresponding user interface for the TaskPlanner action.
   6     
   7     Usage:
   8        [[TaskTable]]
   9        Display tasks for current page
  10        
  11        [[TaskTable(page=SomeWikiPage)]]
  12        Display tasks for page 'SomeWikiPage'
  13 
  14        [[TaskTable(assign=UserName)]]
  15        Display tasks assigned to 'UserName'
  16        
  17        [[TaskTable(page=SomeWikiPage, assign=UserName)]]
  18        Display tasks assigned to 'UserName' for page 'SomeWikiPage'
  19 
  20        [[TaskTable(sort=status)]]
  21        [[TaskTable(sort=date)]]
  22        Display tasks sorted by given criteria
  23 
  24        [[TaskTable(readonly=1, closed=1)]]
  25        
  26     args:
  27        @page=string: display tasks appended to an other page (default=CurrentPage)
  28        @assign=string: display only tasks for a specific user (default=None)
  29        @sort=string: sort task by either by status or date (default=sort by prio, then date)
  30        @closed=bool: display the table in a closed/open state overriding the default cfg value 'task_table_compact'
  31        @readonly=bool: display the table without the 'remove task' option
  32 
  33     TaskTable is heavily based on AttachTable.
  34     AttachTable
  35     @copyright: 2006 Erick Martin
  36     
  37     TaskTable
  38     @copyright: 2007 Oliver Siemoneit
  39     @license: GNU GPL, see COPYING for details.
  40 
  41 """
  42 
  43 import os, random
  44 from MoinMoin import config, wikiutil
  45 from MoinMoin.Page import Page
  46 
  47 
  48 def _get_tasks(request, pagename, assign):
  49     tasks = []
  50     databaseFile = os.path.join(request.cfg.data_dir, "task-db")
  51     if os.path.isfile(databaseFile):
  52         for line in open(databaseFile).readlines():
  53             tmp = line.split("\t")
  54             # we have a pagename to search for
  55             if pagename:
  56                 if tmp[12].find(pagename) != -1:
  57                     # do we also have some restrictions concerning assign?
  58                     if assign:
  59                         if tmp[6].find(assign) != -1:
  60                             tasks.append(tmp)
  61                     else:
  62                         tasks.append(tmp)
  63             # we only have an assign to search for
  64             elif assign:
  65                  if tmp[6].find(assign) != -1:
  66                      tasks.append(tmp)
  67         return tasks
  68 
  69     return []
  70 
  71 
  72 def _sort_tasks_default(task1, task2):
  73 
  74     result = _sort_tasks_by_prio(task1, task2)
  75 
  76     # if tasks are not equal, return result
  77     if result != 0:
  78         return result
  79     # tasks are equal, sort them by date
  80     return _sort_tasks_by_date(task1, task2)
  81 
  82 
  83 def _sort_tasks_by_prio(task1, task2):
  84     prio = { 'none'     : 4,
  85              'low'      : 3,
  86              'medium'   : 2,
  87              'high'     : 1,
  88              'critical' : 0 }
  89 
  90     task1_prio_str = task1[8]
  91     if task1_prio_str == '':
  92         task1_prio_str = 'none'
  93     task1_prio = prio[task1_prio_str]
  94 
  95     task2_prio_str = task2[8]
  96     if task2_prio_str == '':
  97         task2_prio_str = 'none'
  98     task2_prio = prio[task2_prio_str]
  99 
 100     return cmp(task1_prio, task2_prio)
 101 
 102 
 103 def _sort_tasks_by_date(task1, task2):
 104     from time import strptime
 105     time1 = task1[7].strip(' ')
 106     if time1 != "":
 107         try:
 108             time_struct_1 = strptime(time1, "%d.%m.%y")
 109         except ValueError:
 110             try:
 111                 time_struct_1 = strptime(time1, "%d.%m.%y %H:%M")
 112             except ValueError:
 113                 pass # this should never happen since only valid datetime objects are saved in the database
 114     else:
 115         return 1
 116 
 117     time2 = task2[7].strip(' ')
 118     if time2 != "":
 119         try:
 120             time_struct_2 = strptime(time2, "%d.%m.%y")
 121         except ValueError:
 122             try:
 123                 time_struct_2 = strptime(time2, "%d.%m.%y %H:%M")
 124             except ValueError:
 125                 pass # this should never happen since only valid datetime objects are saved in the database
 126     else:
 127         return -1
 128 
 129     return cmp(time_struct_1, time_struct_2)
 130 
 131 
 132 def _sort_tasks_by_status(task1, task2):
 133     status = { 'to do'       : 0,
 134                'in progress' : 1,
 135                'pending'     : 2,
 136                'done'        : 3,
 137                'failed'      : 4,
 138                'closed'      : 5,
 139                'remove me'   : 6 }
 140 
 141     task1_status_str = task1[9]
 142     task1_status = status[task1_status_str]
 143 
 144     task2_status_str = task2[9]
 145     task2_status = status[task2_status_str]
 146 
 147     return cmp(task1_status, task2_status)
 148         
 149 
 150 def _table_row(d):
 151     row = ('   <tr style="display:">\n'
 152            '      <td> %(data_1)s </td>\n'
 153            '      <td> %(data_2)s </td>\n'
 154            '      <td> %(data_3)s </td>\n'
 155            '      <td> %(data_4)s </td>\n'
 156            '      <td> %(data_5)s </td>\n'
 157            '      <td> %(data_6)s </td>\n'
 158            '      <td> %(data_7)s </td>\n'
 159            '   </tr>\n') % d
 160     return row
 161 
 162 
 163 def file_table(request, pagename, assign, sort_by=None, display_table_closed=0, readonly=0):
 164     _ = request.getText
 165     action = 'TaskPlanner'
 166     page_url = wikiutil.quoteWikinameURL(request.page.page_name)
 167 
 168     # if we have an assign or a page different than the current page forward this information
 169     # to the task planner user interface
 170     url_ext_page = url_ext_assign = ""
 171     if pagename and (request.page.page_name != pagename):
 172         pagename = wikiutil.escape(pagename, 1)
 173         pagename = pagename.replace(' ', '%20')
 174         url_ext_page = "&page=%s" % pagename
 175     if assign:
 176         assign = wikiutil.escape(assign, 1)
 177         assign = assign.replace(' ', '%20')
 178         url_ext_assign = "&assign=%s" % assign        
 179 
 180     manage_url = '<a href="%(baseurl)s/%(page_url)s?action=%(action)s%(ext1)s%(ext2)s" title="%(title)s" alt="%(title)s">%(text)s</a>' % {
 181         'baseurl': request.getScriptname(),
 182         'page_url': page_url,
 183         'action': action,
 184         'ext1': url_ext_page,
 185         'ext2': url_ext_assign,
 186         'title': _('Add/Manage tasks'),
 187         'text': _('Add/Manage'), }
 188 
 189     tasks = _get_tasks(request, pagename, assign)
 190 
 191     page_text = assign_text = ""
 192     if pagename:
 193         page_text = " " + _("for the '''%(pagename)s''' page") % {'pagename': pagename, }
 194     if assign:
 195         assign_text = " " + _("for user '''%(assign)s'''") % {'assign': assign, }
 196 
 197     if not tasks:
 198         if pagename and Page(request, pagename).exists() == False:
 199             return _("\n%(icon)s %(manage_url)s tasks %(assign_text)s%(page_text)s %(error)s\n ") % {
 200                 'icon': request.theme.make_icon('table-null'),
 201                 'manage_url': manage_url,
 202                 'assign_text': assign_text,
 203                 'page_text': page_text,
 204                 'error': _("''[No such page]''"), }
 205         else:
 206             return _("\n%(icon)s %(manage_url)s tasks %(assign_text)s %(page_text)s \n") % {
 207                 'icon': request.theme.make_icon('table-null'),
 208                 'manage_url': manage_url,
 209                 'assign_text': assign_text,
 210                 'page_text': page_text, }
 211             
 212 
 213     table_closed_file_name = 'table-open.png'
 214     table_open_file_name = 'table-close.png'
 215 
 216     open_image = request.theme.img_url(table_open_file_name)
 217     closed_image = request.theme.img_url(table_closed_file_name)
 218 
 219     javascript_function = """
 220 // Toggle display of a folder's contents.
 221 function showHideContents ( idnum ) {
 222    the_table = document.getElementById( 't' + idnum );
 223 
 224    arrowObj  = document.getElementById( 'a' + idnum );
 225    // we use the image to determine if the table is open or closed
 226    if (arrowObj.src.indexOf('%(table_open_file_name)s') > -1) {
 227       arrowObj.src = '%(closed_image)s';
 228       display      = 'none';
 229    } else {
 230       arrowObj.src = '%(open_image)s';
 231       display      = '';
 232    }
 233 
 234    // change the open/closed state of the rows for the table
 235    for (var i = 0; i < the_table.rows.length; i++) {
 236       the_table.rows[i].style.display = display;
 237    }
 238 }
 239 """ % {'closed_image': closed_image,
 240        'open_image': open_image,
 241        'table_open_file_name' : table_open_file_name, }
 242 
 243     html = ("\n"
 244             '<script type="text/javascript">' "\n"
 245             "<!--\n"
 246             "%(javascript_function)s\n"
 247             "--> </script>\n"
 248             "\n" ) % { 'javascript_function' : javascript_function, }
 249 
 250     file_id = random.randint(1, 99999999999)
 251 
 252     html = html + '\n<div class="attachmentTable" >\n'
 253 
 254     table_caption1 = ('<a onClick="showHideContents(%(file_id)s);" title="%(alt_title)s">'
 255                       '<img id="a%(file_id)s" align="middle" border=0 src="%(open_image)s"'
 256                       'alt="%(alt_title)s"></a>\n') % {
 257                       'file_id':  file_id,
 258                       'alt_title': _("Click to open/close table"),
 259                       'open_image': open_image, }                              
 260     
 261     table_caption2 = _("%(manage_url)s tasks%(assign_text)s%(page_text)s ''[%(num_files)s task(s)]''") % {
 262                          'num_files':  len(tasks),
 263                          'page_text': page_text,
 264                          'assign_text': assign_text,
 265                          'manage_url': manage_url, }
 266 
 267     table_caption = table_caption1 + table_caption2
 268 
 269     html = html + ('<br>\n'
 270                    '%(table_caption)s\n'
 271                    '<table id="t%(file_id)s" >\n'
 272                    '   <tr style="display:">\n'
 273                    '     <th>%(id)s</th>\n'
 274                    '     <th>%(name)s</th>\n'
 275                    '     <th>%(assign)s</th>\n'
 276                    '     <th>%(priority)s</th>\n'
 277                    '     <th>%(status)s</th>\n'
 278                    '     <th>%(date)s</th>\n'
 279                    '     <th>%(action)s</th>\n'
 280                    '   </tr>\n') % {
 281                       'file_id':  file_id,
 282                       'table_caption':  table_caption,
 283                       'id': _('ID'),
 284                       'name': _('Name'),
 285                       'assign': _('Assign'),
 286                       'priority': _('Priority'),
 287                       'status': _('Status'),
 288                       'date': _('Date'),
 289                       'action': _('Information'), }
 290 
 291     # if user is not superuser, force readonly mode
 292     if not request.user.isSuperUser():
 293         readonly = 1
 294 
 295     # sort tasks
 296     if sort_by == 'date':
 297         tasks.sort(_sort_tasks_by_date)
 298     elif sort_by == 'status':
 299         tasks.sort(_sort_tasks_by_status)
 300     else:
 301         tasks.sort(_sort_tasks_default)
 302 
 303 
 304     # output tasks
 305     for task in tasks:
 306         # build icon
 307         task_prio_status = "task-%(prio)s-%(status)s" % {'prio': task[8].lower().replace(' ', ''),
 308                                                          'status': task[9].lower().replace(' ', ''), }
 309         if task_prio_status in request.theme.icons:
 310             image = request.theme.make_icon(task_prio_status)
 311         else:
 312             if task[9] == "closed":
 313                 image = request.theme.make_icon('task-closed')
 314             elif task[9] == "remove me":
 315                 image = request.theme.make_icon('task-removeme')
 316             else:
 317                 image = request.theme.make_icon('task--inprogress')
 318                 
 319         # create link to task's homepage
 320         if task[11].replace(' ', '') != "":
 321             task_homepage = request.formatter.pagelink(1, task[11]) + request.formatter.text(task[0]) + request.formatter.pagelink(0, task[11])
 322         else:
 323             task_homepage = "<strong>%(id)s<strong>" % {'id': task[0], }
 324 
 325         # create 'edit task' link
 326         ticket = wikiutil.createTicket(request)
 327         edit_link = '<a class="smallText" href="%(baseurl)s/%(page_url)s?action=TaskPlanner&edit=%(task_id)s&ticket=%(ticket)s">%(text)s</a>' % {
 328         'baseurl': request.getScriptname(),
 329         'page_url': page_url,
 330         'task_id': task[0],
 331         'ticket': ticket,
 332         'text': _('[Edit task]'), }
 333 
 334         # create 'remove task' link
 335         if readonly == 0:
 336             remove_link = '<a class="smallText" href="%(baseurl)s/%(page_url)s?action=TaskPlanner&remove=%(task_id)s&ticket=%(ticket)s">%(text)s</a>' % {
 337             'baseurl': request.getScriptname(),
 338             'page_url': page_url,
 339             'task_id': task[0],
 340             'ticket': ticket,
 341             'text': _('[Remove task]'), }
 342         else:
 343             remove_link=""
 344 
 345         data_1 = "<strong>%(image)s %(task_id)s</strong>" % {'image': image, 'task_id': task_homepage, }
 346         data_2 = "%(task_name)s" % {'task_name': task[5], }
 347         data_3 = "%(assign)s" % {'assign': task[6], }
 348         data_4 = "%(priority)s" % {'priority': _(task[8]), }
 349         data_5 = "%(status)s" % {'status': _(task[9]), }
 350         data_6 = "%(time_frame)s" % {'time_frame': task[7], }
 351         data_7 = "%(desc)s <p>" % { 'desc': task[10], }
 352         if task[3] == 'unknown':
 353             data_7 += '<p class="smallText"> %(label1)s %(created_by)s %(label2)s</p><p>' % {'label1': _('Task created by'),
 354                                                                                              'created_by': task[1],
 355                                                                                              'label2': _('on'), }
 356             data_7 += '<p class="smallText">%(created_at)s</p><p>' % {'created_at': task[2], }
 357         else:
 358             data_7 += '<p class="smallText"> %(label1)s %(closed_by)s %(label2)s</p><p>' % {'label1': _('Task closed by'),
 359                                                                                             'closed_by': task[3],
 360                                                                                             'label2': _('on'), }
 361             data_7 += '<p class="smallText">%(closed_at)s</p><p>' % {'closed_at': task[4], }
 362         data_7 += '<p class="smallText">%(edit)s %(remove)s</p>' % {'edit': edit_link, 'remove': remove_link, }
 363     
 364         html = html + _table_row( { 
 365                                     'data_1' : data_1,
 366                                     'data_2' : data_2,
 367                                     'data_3' : data_3,
 368                                     'data_4' : data_4,
 369                                     'data_5' : data_5,
 370                                     'data_6' : data_6,
 371                                     'data_7' : data_7,
 372                                     } )
 373 
 374     html = html + '\n</table>\n</div>\n'
 375 
 376     if display_table_closed:
 377         close_str = ('\n<script type="text/javascript">\n'
 378                      '<!--\nshowHideContents(%(file_id)s);\n-->\n'
 379                      '</script>\n' ) % {'file_id':  file_id, }
 380         html = html + close_str
 381 
 382     return html
 383 
 384 
 385 def getArgs(given_arguments, allowed_arguments):
 386     if not given_arguments:
 387         return {}
 388     args = {}
 389     for s in given_arguments.split(','):
 390         if s and s.find('=') > 0:
 391             key, value = s.split('=', 1)
 392             if key and value:
 393                 key = key.strip()
 394                 if key in allowed_arguments:
 395                     args[key] = value.strip()
 396     return args
 397 
 398 
 399 def execute(macro, options):
 400     request = macro.request
 401     
 402     arguments = ['page', 'assign', 'sort', 'closed', 'readonly']
 403     args = getArgs(options, arguments)
 404 
 405     assign = args.get('assign', None)
 406 
 407     pagename = args.get('page', None)
 408     if not pagename and not assign:
 409         pagename = request.page.page_name
 410 
 411     default_table_closed = 0
 412     if hasattr(request.cfg, 'task_table_compact'):
 413         default_table_closed = request.cfg.task_table_compact
 414 
 415     table_closed = int(args.get('closed', default_table_closed))
 416     table_readonly = int(args.get('readonly', 0))
 417 
 418     sort_by = args.get('sort', None)
 419     if sort_by not in ['date', 'status']:
 420         sort_by = None
 421 
 422     return file_table(request, pagename, assign, sort_by, table_closed, table_readonly)

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.