Roundup Tracker

This is an example of adding an about page that provides info about how the system is configured. All of these changes are done in the tracker home directory. You might not have a lib subdirectory. If you don't, just make the directory with the same owner, group, and permissions as the other directories like html or extensions.

Add an html template.

In html/home.about.html put:

   1 <tal:block metal:use-macro="templates/page/macros/icing">
   2 
   3 <title metal:fill-slot="head_title" i18n:translate="" >                         
   4  About this Tracker                                                             
   5 </title>
   6 <tal:block metal:fill-slot="body_title" i18n:translate="">
   7   About this Tracker
   8 </tal:block>
   9 
  10 <div class="content" metal:fill-slot="content">
  11   
  12   <span tal:condition="not:python:request.user.hasRole('Admin')"
  13         tal:omit-tag="python:1" i18n:translate="">
  14     Please login with your username and password to find out about
  15     this tracker.
  16   </span>
  17 
  18   <div tal:condition="python:request.user.hasRole('Admin')"
  19        tal:omit-tag="python:1" i18n:translate="">
  20 
  21     <div tal:replace="structure python:utils.AboutPage(db)"></div>
  22 
  23   </div>
  24 </div>
  25 
  26 </tal:block>

in lib/tracker_version.py you can put:

   1 '''                                                                             
   2 Define the version of this tracker.                        
   3 Manually maintained incremented at release.                                     
   4 '''
   5   
   6 __version__ = "0.9"

this is optional as a missing tracker_version.py is ignored. But it may be useful to set as part of a deployment script of you use version control.

Put the following in extensions/about.py:

Download about.py

   1 try:
   2   import tracker_version
   3   t_version = tracker_version.__version__
   4 except ImportError:
   5   t_version = "Not set"
   6 
   7 import sys
   8 from roundup import __version__ as roundup_version
   9 
  10 def AboutPage(db):
  11     "report useful info about this tracker"
  12 
  13     def is_module_loaded(module):
  14         modules = list(sys.modules.keys())
  15         return module in modules
  16 
  17     def get_status_of_module(module, prefix=None, version=True):
  18         modules = list(sys.modules.keys())
  19         is_enabled = module in modules
  20         if is_enabled:
  21             if module == 'MySQLdb':
  22                 from MySQLdb import version_info
  23                 version="version %s"%".".join([str(v) for v in version_info])
  24             elif module == 'pychart':
  25                 from pychart import version
  26                 version="version %s"%version.version
  27             elif module == 'pyme':
  28                 from pyme import version
  29                 version="version %s"%version.versionstr
  30             elif module == 'sqlite3':
  31                 from sqlite3 import version
  32                 version="version %s"%version
  33             elif module == "whoosh":
  34                 from whoosh import versionstring
  35                 version="version %s"%versionstring()
  36             elif module == 'xapian':
  37                 from xapian import version_string
  38                 version="version %s"%version_string()
  39             else:
  40                 if version:
  41                     m = __import__(module)
  42                     try:
  43                         version="version %s"%m.__version__
  44                     except AttributeError:
  45                         version="version unavailable - exception thrown"
  46                 else:
  47                     version="version unavailable"
  48 
  49             if prefix:
  50                 return "%s %s %s enabled: %s"%(prefix, module, version, is_enabled)
  51             else:
  52                 return "Module: %s %s enabled: %s"%(module, version, is_enabled)
  53         else:
  54             if prefix:
  55                 return "%s %s enabled: %s"%(prefix, module, is_enabled)
  56             else:
  57                 return "Module: %s enabled: %s"%(module, is_enabled)
  58 
  59     info = []
  60 
  61     info.append("Tracker name: %s<br>"%db.config['TRACKER_NAME'])
  62     info.append("Tracker base version: %s"%t_version)
  63 
  64     info.append("<h2>Operating environment</h2>")
  65     info.append('<a href="http://roundup.sourceforge.net/">Roundup</a> version: %s<br>'%roundup_version)
  66     info.append("Python Version: %s<br>"%sys.version)
  67 
  68     info.append("<h2>Configuration</h2>")
  69 
  70     backend = db.config['RDBMS_BACKEND']
  71     info.append("Roundup backend: %s<br>"%backend)
  72     if backend != 'anydbm':
  73         info.append("Roundup db cache: %s<br>"%db.config['RDBMS_CACHE_SIZE'])
  74         info.append("Roundup isolation_level: %s<br>"%db.config['RDBMS_ISOLATION_LEVEL'])
  75 
  76     info.append("Roundup template: %s<br>"%db.config['TEMPLATE_ENGINE'])
  77 
  78     info.append("<h2>Database modules</h2>")
  79     info.append(get_status_of_module('anydbm', version=False) + "<br>")
  80     info.append(get_status_of_module('dbm', version=False) + "<br>")
  81     info.append(get_status_of_module('sqlite3') + "<br>")
  82     info.append(get_status_of_module('MySQLdb') + "<br>")
  83     info.append(get_status_of_module('psycopg2') + "<br>")
  84 
  85     info.append("<h2>Other modules</h2>")
  86 
  87     indexer = db.config['INDEXER']
  88     if not indexer:
  89         if is_module_loaded('xapian'):
  90             indexer="unset using xapian"
  91         elif is_module_loaded('whoosh'):
  92             indexer="unset using woosh"
  93         else:
  94             indexer="unset using native"
  95     else:
  96         indexer="set to " + indexer
  97 
  98     info.append("Indexer used for full-text: %s<br>"%indexer)
  99 
 100     info.append("Available indexers:<br><ul>")
 101     if is_module_loaded('xapian'):
 102         info.append("<li>%s</li>"%get_status_of_module('xapian', prefix="Indexer loaded:"))
 103     if is_module_loaded('whoosh'):
 104         info.append("<li>%s</li>"%get_status_of_module('whoosh', prefix="Indexer loaded:"))
 105     info.append("<li>Indexer loaded: native: True</li>")
 106     info.append("</ul>")
 107     info.append(get_status_of_module('pytz') + "<br>")
 108     info.append(get_status_of_module('pyme') + "<br>")
 109     info.append(get_status_of_module('OpenSSL') + "<br>")
 110     info.append(get_status_of_module('pychart') + "<br>")
 111     info.append(get_status_of_module('pygal') + "<br>")
 112 
 113     info.append(get_status_of_module('jinja2') + "<br>")
 114 
 115     uid = db._db.getuid()
 116     if uid == "1" or \
 117        db._db.security.hasPermission("SeeAboutPrivDetails", uid) or \
 118        db._db.user.has_role(uid,"Admin"):
 119         info.append("<h2>Python Environment</h2>")
 120         #may leak sensitive info about system, directory paths etc.
 121         #so require more that just SeeAbout privs.
 122         info.append("")
 123         info.append("sys.path: %r"%sys.path)
 124 
 125         info.append("<h2>Environment Variables</h2>")
 126         info.append("<pre>") # include pre to prevent wrapping of values
 127         for key in list(db._client.env.keys()):
 128             info.append("%s=%s"%(key,db._client.env[key]) + "<br>")
 129         info.append("</pre>")
 130 
 131         info.append("<h2>Runtime state</h2>")
 132         info.append("<pre>js enabled on client: %s</pre>" % \
 133                     str('jsdisabled' not in db._client.cookie))
 134         info.append('')
 135         for key in db._client.cookie:
 136             info.append("<pre>Cookie: %s = %s</pre>" % (key,
 137                                  db._client.cookie[key].value))
 138     return "\n".join(info)
 139 
 140 def init(instance):
 141     instance.registerUtil('AboutPage', AboutPage)
about.py

To view the page go to the url: http://host/tracker/?@template=about I.E. append "?@template=about" to the base url of your tracker.

The page looks something like:

about.png

Hopefully I got all the important bits as I extracted this from my tracker.