Roundup Tracker

This has the same functionality as the default csv export in roundup 2.0 and newer. So it is not needed if you are running 2.0 or newer.

Also this patch was changed to add: quoting=csv.QUOTE_NONNUMERIC to the csv.writer invocation to quote all lines to impove security if the csv is imported into some versions of Excel.

Here is a patch that enables exporting csv with actual names of linked items instead of their ids. It adds a new action, "export_csv_names" to the "extensions" directory in your tracker.

The action works like export_csv except on columns with the Link type. The action tries to find a column called name in the linked class, or username if the class is user. If it is found, it prints this column instead of the id. Simply change the lines in the desired html pages from export_csv to export_csv_names, copy this file to the extensions directory, and that's it.

This action has been evaluated on Roundup 0.8.2 only, and was updated from the original version that ran under 0.7.

[BEWARE: get the patch from the wiki page source, not from the html display, since the wiki software removes quotes. Any suggestions of a better way to put this patch online are welcome.]

Code is also posted to this pastebin URL: http://pastebin.com/f4f6ad0c0 .

ExportCSVNamesAction.py:

   1 from roundup.cgi.actions import Action
   2 from roundup.cgi import templating
   3 from roundup import hyperdb
   4 
   5 import csv
   6 
   7 class ExportCSVNamesAction(Action):
   8     name = 'export'
   9     permissionType = 'View'
  10 
  11     def handle(self):
  12         ''' Export the specified search query as CSV. '''
  13         # figure the request
  14         request = templating.HTMLRequest(self.client)
  15         filterspec = request.filterspec
  16         sort = request.sort
  17         group = request.group
  18         columns = request.columns
  19         klass = self.db.getclass(request.classname)
  20 
  21         # full-text search
  22         if request.search_text:
  23             matches = self.db.indexer.search(
  24                 re.findall(r'\b\w{2,25}\b', request.search_text), klass)
  25         else:
  26             matches = None
  27 
  28         h = self.client.additional_headers
  29         h['Content-Type'] = 'text/csv; charset=%s' % self.client.charset
  30         # some browsers will honor the filename here...
  31         h['Content-Disposition'] = 'inline; filename=query.csv'
  32 
  33         self.client.header()
  34 
  35         if self.client.env['REQUEST_METHOD'] == 'HEAD':
  36             # all done, return a dummy string
  37             return 'dummy'
  38 
  39         wfile = self.client.request.wfile
  40         if self.client.charset != self.client.STORAGE_CHARSET:
  41             wfile = codecs.EncodedFile(wfile,
  42                 self.client.STORAGE_CHARSET, self.client.charset, 'replace')
  43 
  44         writer = csv.writer(wfile, quoting=csv.QUOTE_NONNUMERIC)
  45         self.client._socket_op(writer.writerow, columns)
  46 
  47         # Figure out Link columns
  48         represent = {}
  49 
  50         def repr_link(cls,col):
  51             def f(x):
  52                 if x==None:
  53                     return ""
  54                 else:
  55                     return str(cls.get(x,col))
  56             return f
  57 
  58         props = klass.getprops()
  59 
  60         for col in columns:
  61             represent[col] = str
  62             if isinstance(props[col], hyperdb.Link):
  63                 cn = props[col].classname
  64                 cl = self.db.getclass(cn)
  65                 if cl.getprops().has_key('name'):
  66                     represent[col] = repr_link(cl, 'name')
  67                 elif cn == 'user':
  68                     represent[col] = repr_link(cl, 'username')
  69 
  70         # and search
  71         for itemid in klass.filter(matches, filterspec, sort, group):
  72             self.client._socket_op(writer.writerow, [represent[col](klass.get(itemid, col)) for col in columns])
  73 
  74         return '\n'
  75 
  76 def init(instance):
  77           instance.registerAction('export_csv_names', ExportCSVNamesAction)
  78 
  79 
  80 # vim: set filetype=python sts=4 sw=4 et si


CategoryActions