"Fossies" - the Fresh Open Source Software Archive

Member "roundup-2.0.0/share/doc/roundup/html/customizing.html" (13 Jul 2020, 544083 Bytes) of package /linux/www/roundup-2.0.0.tar.gz:


The requested HTML page contains a <FORM> tag that is unusable on "Fossies" in "automatic" (rendered) mode so that page is shown as HTML source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    2   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    3 
    4 <html xmlns="http://www.w3.org/1999/xhtml">
    5   <head>
    6     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    7     
    8     <title>Customising Roundup &mdash; Roundup 2.0.0 documentation</title>
    9     
   10     <link rel="stylesheet" href="_static/basic.css" type="text/css" />
   11     <link rel="stylesheet" href="_static/style.css" type="text/css" />
   12     <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
   13     <script type="text/javascript">
   14       var DOCUMENTATION_OPTIONS = {
   15           URL_ROOT:    './',
   16           VERSION:     '2.0.0',
   17           COLLAPSE_MODINDEX: false,
   18           FILE_SUFFIX: '.html'
   19       };
   20     </script>
   21     <script type="text/javascript" src="_static/jquery.js"></script>
   22     <script type="text/javascript" src="_static/underscore.js"></script>
   23     <script type="text/javascript" src="_static/doctools.js"></script>
   24     <link rel="index" title="Index" href="genindex.html" />
   25     <link rel="search" title="Search" href="search.html" />
   26     <link rel="top" title="Roundup 2.0.0 documentation" href="index.html" />
   27     <link rel="next" title="Administration Guide" href="admin_guide.html" />
   28     <link rel="prev" title="User Guide" href="user_guide.html" /> 
   29   </head>
   30   <body>
   31     <div class="header"><h1>Roundup</h1>
   32         <div id="searchbox" style="display: none">
   33           <form class="search" action="search.html" method="get">
   34             <input type="text" name="q" size="18" />
   35             <input type="submit" value="Search" />
   36             <input type="hidden" name="check_keywords" value="yes" />
   37             <input type="hidden" name="area" value="default" />
   38           </form>
   39         </div>
   40         <script type="text/javascript">$('#searchbox').show(0);</script>
   41     </div>
   42     <div class="navigation">
   43       <div class="menu">
   44        
   45     <h3><a href="index.html">Table Of Contents</a></h3>
   46     <ul>
   47 <li><a class="reference internal" href="#">Customising Roundup</a><ul>
   48 <li><a class="reference internal" href="#what-you-can-do">What You Can Do</a></li>
   49 <li><a class="reference internal" href="#trackers-in-a-nutshell">Trackers in a Nutshell</a></li>
   50 <li><a class="reference internal" href="#tracker-configuration">Tracker Configuration</a></li>
   51 <li><a class="reference internal" href="#tracker-schema">Tracker Schema</a></li>
   52 <li><a class="reference internal" href="#detectors-adding-behaviour-to-your-tracker">Detectors - adding behaviour to your tracker</a></li>
   53 <li><a class="reference internal" href="#extensions-adding-capabilities-to-your-tracker">Extensions - adding capabilities to your tracker</a></li>
   54 <li><a class="reference internal" href="#interfaces-py-hooking-into-the-core-of-roundup">interfaces.py - hooking into the core of roundup</a></li>
   55 <li><a class="reference internal" href="#database-content">Database Content</a></li>
   56 <li><a class="reference internal" href="#security-access-controls">Security / Access Controls</a></li>
   57 <li><a class="reference internal" href="#web-interface">Web Interface</a></li>
   58 <li><a class="reference internal" href="#examples">Examples</a></li>
   59 <li><a class="reference internal" href="#debugging-trackers">Debugging Trackers</a></li>
   60 </ul>
   61 </li>
   62 </ul>
   63 
   64     <h4>Previous topic</h4>
   65     <p class="topless"><a href="user_guide.html"
   66                           title="previous chapter">User Guide</a></p>
   67     <h4>Next topic</h4>
   68     <p class="topless"><a href="admin_guide.html"
   69                           title="next chapter">Administration Guide</a></p>
   70     <h3>This Page</h3>
   71     <ul class="this-page-menu">
   72       <li><a href="_sources/customizing.txt"
   73              rel="nofollow">Show Source</a></li>
   74     </ul>
   75   <div id="searchbox" style="display: none">
   76     <h3>Quick search</h3>
   77       <form class="search" action="search.html" method="get">
   78         <input type="text" name="q" size="18" />
   79         <input type="submit" value="Go" />
   80         <input type="hidden" name="check_keywords" value="yes" />
   81         <input type="hidden" name="area" value="default" />
   82       </form>
   83       <p style="font-size: 90%">Enter search terms or a module, class or function name.</p>
   84   </div>
   85   <script type="text/javascript">$('#searchbox').show(0);</script>
   86       </div>
   87     </div>
   88     <div class="content">
   89        
   90     <div class="related related-top">
   91       <ul>
   92         <li class="right" style="margin-right: 10px">
   93           <a href="genindex.html" title="General Index"
   94              accesskey="I">index</a></li>
   95         <li class="right" >
   96           <a href="admin_guide.html" title="Administration Guide"
   97              accesskey="N">next</a></li>
   98         <li class="right" >
   99           <a href="user_guide.html" title="User Guide"
  100              accesskey="P">previous</a></li>
  101         <li><a href="index.html">Roundup 2.0.0 documentation</a></li> 
  102       </ul>
  103     </div>
  104        
  105   <div class="section" id="customising-roundup">
  106 <h1>Customising Roundup<a class="headerlink" href="#customising-roundup" title="Permalink to this headline"></a></h1>
  107 <div class="contents local topic" id="contents">
  108 <ul class="simple">
  109 <li><a class="reference internal" href="#what-you-can-do" id="id7">What You Can Do</a></li>
  110 <li><a class="reference internal" href="#trackers-in-a-nutshell" id="id8">Trackers in a Nutshell</a></li>
  111 <li><a class="reference internal" href="#tracker-configuration" id="id9">Tracker Configuration</a><ul>
  112 <li><a class="reference internal" href="#extending-the-configuration-file" id="id10">Extending the configuration file</a></li>
  113 </ul>
  114 </li>
  115 <li><a class="reference internal" href="#tracker-schema" id="id11">Tracker Schema</a><ul>
  116 <li><a class="reference internal" href="#the-schema-py-and-initial-data-py-modules" id="id12">The <code class="docutils literal"><span class="pre">schema.py</span></code> and <code class="docutils literal"><span class="pre">initial_data.py</span></code> modules</a></li>
  117 <li><a class="reference internal" href="#the-classic-schema" id="id13">The “classic” schema</a></li>
  118 <li><a class="reference internal" href="#what-you-can-t-do-to-the-schema" id="id14">What you can’t do to the schema</a></li>
  119 <li><a class="reference internal" href="#what-you-can-do-to-the-schema" id="id15">What you can do to the schema</a></li>
  120 <li><a class="reference internal" href="#classes-and-properties-creating-a-new-information-store" id="id16">Classes and Properties - creating a new information store</a></li>
  121 <li><a class="reference internal" href="#examples-of-adding-to-your-schema" id="id17">Examples of adding to your schema</a></li>
  122 </ul>
  123 </li>
  124 <li><a class="reference internal" href="#detectors-adding-behaviour-to-your-tracker" id="id18">Detectors - adding behaviour to your tracker</a><ul>
  125 <li><a class="reference internal" href="#detector-api" id="id19">Detector API</a></li>
  126 <li><a class="reference internal" href="#additional-detectors-ready-for-use" id="id20">Additional Detectors Ready For Use</a></li>
  127 <li><a class="reference internal" href="#auditor-or-reactor" id="id21">Auditor or Reactor?</a></li>
  128 <li><a class="reference internal" href="#vetoing-creation-of-or-changes-to-items" id="id22">Vetoing creation of or changes to items</a></li>
  129 <li><a class="reference internal" href="#generating-email-from-roundup" id="id23">Generating email from Roundup</a></li>
  130 </ul>
  131 </li>
  132 <li><a class="reference internal" href="#extensions-adding-capabilities-to-your-tracker" id="id24">Extensions - adding capabilities to your tracker</a></li>
  133 <li><a class="reference internal" href="#interfaces-py-hooking-into-the-core-of-roundup" id="id25">interfaces.py - hooking into the core of roundup</a><ul>
  134 <li><a class="reference internal" href="#example-changing-cache-control-headers" id="id26">Example: Changing Cache-Control headers</a></li>
  135 <li><a class="reference internal" href="#example-implement-password-complexity-checking" id="id27">Example: Implement password complexity checking</a></li>
  136 <li><a class="reference internal" href="#example-enhance-time-intervals" id="id28">Example: Enhance time intervals</a></li>
  137 <li><a class="reference internal" href="#example-modifying-the-mail-gateway" id="id29">Example: Modifying the mail gateway</a></li>
  138 <li><a class="reference internal" href="#other-examples" id="id30">Other Examples</a></li>
  139 </ul>
  140 </li>
  141 <li><a class="reference internal" href="#database-content" id="id31">Database Content</a></li>
  142 <li><a class="reference internal" href="#security-access-controls" id="id32">Security / Access Controls</a><ul>
  143 <li><a class="reference internal" href="#automatic-permission-checks" id="id33">Automatic Permission Checks</a></li>
  144 <li><a class="reference internal" href="#new-user-roles" id="id34">New User Roles</a></li>
  145 <li><a class="reference internal" href="#changing-access-controls" id="id35">Changing Access Controls</a></li>
  146 </ul>
  147 </li>
  148 <li><a class="reference internal" href="#web-interface" id="id36">Web Interface</a><ul>
  149 <li><a class="reference internal" href="#repercussions-of-changing-the-tracker-schema" id="id37">Repercussions of changing the tracker schema</a></li>
  150 <li><a class="reference internal" href="#how-requests-are-processed" id="id38">How requests are processed</a></li>
  151 <li><a class="reference internal" href="#roundup-url-design" id="id39">Roundup URL design</a></li>
  152 <li><a class="reference internal" href="#determining-web-context" id="id40">Determining web context</a></li>
  153 <li><a class="reference internal" href="#the-home-context" id="id41">The “home” Context</a></li>
  154 <li><a class="reference internal" href="#serving-static-content" id="id42">Serving static content</a></li>
  155 <li><a class="reference internal" href="#performing-actions-in-web-requests" id="id43">Performing actions in web requests</a></li>
  156 <li><a class="reference internal" href="#protecting-users-from-web-application-attacks" id="id44">Protecting users from web application attacks</a></li>
  157 <li><a class="reference internal" href="#special-form-variables" id="id45">Special form variables</a></li>
  158 <li><a class="reference internal" href="#default-templates" id="id46">Default templates</a></li>
  159 <li><a class="reference internal" href="#implementing-modal-editing-using-template" id="id47">Implementing Modal Editing Using &#64;template</a></li>
  160 <li><a class="reference internal" href="#how-the-templates-work" id="id48">How the templates work</a></li>
  161 <li><a class="reference internal" href="#information-available-to-templates" id="id49">Information available to templates</a></li>
  162 <li><a class="reference internal" href="#displaying-properties" id="id50">Displaying Properties</a></li>
  163 <li><a class="reference internal" href="#index-views" id="id51">Index Views</a></li>
  164 <li><a class="reference internal" href="#searching-views" id="id52">Searching Views</a></li>
  165 <li><a class="reference internal" href="#item-views" id="id53">Item Views</a></li>
  166 <li><a class="reference internal" href="#defining-new-web-actions" id="id54">Defining new web actions</a></li>
  167 <li><a class="reference internal" href="#bit-character-set-support-in-web-interface" id="id55">8-bit character set support in Web interface</a></li>
  168 </ul>
  169 </li>
  170 <li><a class="reference internal" href="#examples" id="id56">Examples</a><ul>
  171 <li><a class="reference internal" href="#changing-what-s-stored-in-the-database" id="id57">Changing what’s stored in the database</a></li>
  172 <li><a class="reference internal" href="#using-external-user-databases" id="id58">Using External User Databases</a></li>
  173 <li><a class="reference internal" href="#changes-to-tracker-behaviour" id="id59">Changes to Tracker Behaviour</a></li>
  174 <li><a class="reference internal" href="#changes-to-security-and-permissions" id="id60">Changes to Security and Permissions</a></li>
  175 <li><a class="reference internal" href="#changes-to-the-web-user-interface" id="id61">Changes to the Web User Interface</a></li>
  176 </ul>
  177 </li>
  178 <li><a class="reference internal" href="#debugging-trackers" id="id62">Debugging Trackers</a></li>
  179 </ul>
  180 </div>
  181 <div class="section" id="what-you-can-do">
  182 <h2><a class="toc-backref" href="#id7">What You Can Do</a><a class="headerlink" href="#what-you-can-do" title="Permalink to this headline"></a></h2>
  183 <p>Before you get too far, it’s probably worth having a quick read of the Roundup
  184 <a class="reference external" href="design.html">design documentation</a>.</p>
  185 <p>Customisation of Roundup can take one of six forms:</p>
  186 <ol class="arabic simple">
  187 <li><a class="reference internal" href="#tracker-configuration">tracker configuration</a> changes</li>
  188 <li>database, or <a class="reference internal" href="#tracker-schema">tracker schema</a> changes</li>
  189 <li>“definition” class <a class="reference internal" href="#database-content">database content</a> changes</li>
  190 <li>behavioural changes through <a class="reference internal" href="#detectors">detectors</a>, <a class="reference internal" href="#extensions">extensions</a> and <a class="reference internal" href="#interfaces-py">interfaces.py</a></li>
  191 <li><a class="reference internal" href="#security-access-controls">security / access controls</a></li>
  192 <li>change the <a class="reference internal" href="#web-interface">web interface</a></li>
  193 </ol>
  194 <p>The third case is special because it takes two distinctly different forms
  195 depending upon whether the tracker has been initialised or not. The other two
  196 may be done at any time, before or after tracker initialisation. Yes, this
  197 includes adding or removing properties from classes.</p>
  198 </div>
  199 <div class="section" id="trackers-in-a-nutshell">
  200 <h2><a class="toc-backref" href="#id8">Trackers in a Nutshell</a><a class="headerlink" href="#trackers-in-a-nutshell" title="Permalink to this headline"></a></h2>
  201 <p>Trackers have the following structure:</p>
  202 <table border="1" class="docutils" id="index-0">
  203 <colgroup>
  204 <col width="25%" />
  205 <col width="75%" />
  206 </colgroup>
  207 <thead valign="bottom">
  208 <tr class="row-odd"><th class="head">Tracker File</th>
  209 <th class="head">Description</th>
  210 </tr>
  211 </thead>
  212 <tbody valign="top">
  213 <tr class="row-even"><td>config.ini</td>
  214 <td>Holds the basic <a class="reference internal" href="#tracker-configuration">tracker configuration</a></td>
  215 </tr>
  216 <tr class="row-odd"><td>schema.py</td>
  217 <td>Holds the <a class="reference internal" href="#tracker-schema">tracker schema</a></td>
  218 </tr>
  219 <tr class="row-even"><td>initial_data.py</td>
  220 <td>Holds any data to be entered into the database when the
  221 tracker is initialised.</td>
  222 </tr>
  223 <tr class="row-odd"><td>db/</td>
  224 <td>Holds the tracker’s database</td>
  225 </tr>
  226 <tr class="row-even"><td>db/files/</td>
  227 <td>Holds the tracker’s upload files and messages</td>
  228 </tr>
  229 <tr class="row-odd"><td>db/backend_name</td>
  230 <td>Names the database back-end for the tracker (obsolete).
  231 Current way uses the <code class="docutils literal"><span class="pre">backend</span></code> setting in the rdbms
  232 section of config.ini.</td>
  233 </tr>
  234 <tr class="row-even"><td>detectors/</td>
  235 <td>Auditors and reactors for this tracker</td>
  236 </tr>
  237 <tr class="row-odd"><td>extensions/</td>
  238 <td>Additional actions and <a class="reference internal" href="#templating-utilities">templating utilities</a></td>
  239 </tr>
  240 <tr class="row-even"><td>html/</td>
  241 <td>Web interface templates, images and style sheets</td>
  242 </tr>
  243 <tr class="row-odd"><td>lib/</td>
  244 <td>optional common imports for detectors and extensions</td>
  245 </tr>
  246 </tbody>
  247 </table>
  248 <span class="target" id="index-1"></span></div>
  249 <div class="section" id="tracker-configuration">
  250 <span id="index-2"></span><h2><a class="toc-backref" href="#id9">Tracker Configuration</a><a class="headerlink" href="#tracker-configuration" title="Permalink to this headline"></a></h2>
  251 <p>The <code class="docutils literal"><span class="pre">config.ini</span></code> located in your tracker home contains the basic
  252 configuration for the web and e-mail components of roundup’s interfaces.</p>
  253 <p>Changes to the data captured by your tracker is controlled by the <a class="reference internal" href="#tracker-schema">tracker
  254 schema</a>.  Some configuration is also performed using permissions - see the
  255 <a class="reference internal" href="#security-access-controls">security / access controls</a> section. For example, to allow users to
  256 automatically register through the email interface, you must grant the
  257 “Anonymous” Role the “Email Access” Permission.</p>
  258 <p id="index-3">The following is taken from the <a class="reference external" href="https://docs.python.org/2/library/configparser.html">Python Library Reference</a> (July 18, 2018)
  259 section “ConfigParser – Configuration file parser”:</p>
  260 <blockquote>
  261 <div><p>The configuration file consists of sections, led by a [section] header
  262 and followed by name: value entries, with continuations in the style
  263 of RFC 822 (see section 3.1.1, “LONG HEADER FIELDS”); name=value is
  264 also accepted. Note that leading whitespace is removed from
  265 values. The optional values can contain format strings which refer to
  266 other values in the same section, or values in a special DEFAULT
  267 section. Additional defaults can be provided on initialization and
  268 retrieval. Lines beginning with ‘#’ or ‘;’ are ignored and may be
  269 used to provide comments.</p>
  270 <p>For example:</p>
  271 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">My</span> <span class="n">Section</span><span class="p">]</span>
  272 <span class="n">foodir</span> <span class="o">=</span> <span class="o">%</span><span class="p">(</span><span class="nb">dir</span><span class="p">)</span><span class="n">s</span><span class="o">/</span><span class="n">whatever</span>
  273 <span class="nb">dir</span> <span class="o">=</span> <span class="n">frob</span>
  274 </pre></div>
  275 </div>
  276 <p>would resolve the “%(dir)s” to the value of “dir” (“frob” in this case)
  277 resulting in “foodir” being “frob/whatever”.</p>
  278 </div></blockquote>
  279 <p>Example configuration settings are below. This is a partial
  280 list. Documentation on all the settings is included in the
  281 <code class="docutils literal"><span class="pre">config.ini</span></code> file.</p>
  282 <dl class="docutils" id="index-4">
  283 <dt>Section <strong>main</strong></dt>
  284 <dd><dl class="first last docutils">
  285 <dt>database – <code class="docutils literal"><span class="pre">db</span></code></dt>
  286 <dd>Database directory path. The path may be either absolute or relative
  287 to the directory containig this config file.</dd>
  288 <dt>templates – <code class="docutils literal"><span class="pre">html</span></code></dt>
  289 <dd>Path to the HTML templates directory. The path may be either absolute
  290 or relative to the directory containing this config file.</dd>
  291 <dt>static_files – default <em>blank</em></dt>
  292 <dd>A list of space separated directory paths (or a single directory).
  293 These directories hold additional static files available via Web UI.
  294 These directories may contain sitewide images, CSS stylesheets etc. If
  295 a ‘-‘ is included, the list processing ends and the TEMPLATES
  296 directory is not searched after the specified directories.  If this
  297 option is not set, all static files are taken from the TEMPLATES
  298 directory.</dd>
  299 <dt>admin_email – <code class="docutils literal"><span class="pre">roundup-admin</span></code></dt>
  300 <dd>Email address that roundup will complain to if it runs into trouble. If
  301 the email address doesn’t contain an <code class="docutils literal"><span class="pre">&#64;</span></code> part, the MAIL_DOMAIN defined
  302 below is used.</dd>
  303 <dt>dispatcher_email – <code class="docutils literal"><span class="pre">roundup-admin</span></code></dt>
  304 <dd>The ‘dispatcher’ is a role that can get notified of new items to the
  305 database. It is used by the ERROR_MESSAGES_TO config setting. If the
  306 email address doesn’t contain an <code class="docutils literal"><span class="pre">&#64;</span></code> part, the MAIL_DOMAIN defined
  307 below is used.</dd>
  308 <dt>email_from_tag – default <em>blank</em></dt>
  309 <dd>Additional text to include in the “name” part of the From: address used
  310 in nosy messages. If the sending user is “Foo Bar”, the From: line
  311 is usually: <code class="docutils literal"><span class="pre">&quot;Foo</span> <span class="pre">Bar&quot;</span> <span class="pre">&lt;issue_tracker&#64;tracker.example&gt;</span></code>
  312 the EMAIL_FROM_TAG goes inside the “Foo Bar” quotes like so:
  313 <code class="docutils literal"><span class="pre">&quot;Foo</span> <span class="pre">Bar</span> <span class="pre">EMAIL_FROM_TAG&quot;</span> <span class="pre">&lt;issue_tracker&#64;tracker.example&gt;</span></code></dd>
  314 <dt>new_web_user_roles – <code class="docutils literal"><span class="pre">User</span></code></dt>
  315 <dd>Roles that a user gets when they register with Web User Interface.
  316 This is a comma-separated list of role names (e.g. <code class="docutils literal"><span class="pre">Admin,User</span></code>).</dd>
  317 <dt>new_email_user_roles – <code class="docutils literal"><span class="pre">User</span></code></dt>
  318 <dd>Roles that a user gets when they register with Email Gateway.
  319 This is a comma-separated string of role names (e.g. <code class="docutils literal"><span class="pre">Admin,User</span></code>).</dd>
  320 <dt>error_messages_to – <code class="docutils literal"><span class="pre">user</span></code></dt>
  321 <dd>Send error message emails to the <code class="docutils literal"><span class="pre">dispatcher</span></code>, <code class="docutils literal"><span class="pre">user</span></code>, or <code class="docutils literal"><span class="pre">both</span></code>?
  322 The dispatcher is configured using the DISPATCHER_EMAIL setting.
  323 Allowed values: <code class="docutils literal"><span class="pre">dispatcher</span></code>, <code class="docutils literal"><span class="pre">user</span></code>, or <code class="docutils literal"><span class="pre">both</span></code></dd>
  324 <dt>html_version – <code class="docutils literal"><span class="pre">html4</span></code></dt>
  325 <dd>HTML version to generate. The templates are <code class="docutils literal"><span class="pre">html4</span></code> by default.
  326 If you wish to make them xhtml, then you’ll need to change this
  327 var to <code class="docutils literal"><span class="pre">xhtml</span></code> too so all auto-generated HTML is compliant.
  328 Allowed values: <code class="docutils literal"><span class="pre">html4</span></code>, <code class="docutils literal"><span class="pre">xhtml</span></code></dd>
  329 <dt>timezone – <code class="docutils literal"><span class="pre">0</span></code></dt>
  330 <dd>Numeric timezone offset used when users do not choose their own
  331 in their settings.</dd>
  332 <dt>instant_registration – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  333 <dd>Register new users instantly, or require confirmation via
  334 email?
  335 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code></dd>
  336 <dt>email_registration_confirmation – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  337 <dd>Offer registration confirmation by email or only through the web?
  338 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code></dd>
  339 <dt>indexer_stopwords – default <em>blank</em></dt>
  340 <dd>Additional stop-words for the full-text indexer specific to
  341 your tracker. See the indexer source for the default list of
  342 stop-words (e.g. <code class="docutils literal"><span class="pre">A,AND,ARE,AS,AT,BE,BUT,BY,</span> <span class="pre">...</span></code>).</dd>
  343 <dt>umask – <code class="docutils literal"><span class="pre">02</span></code></dt>
  344 <dd>Defines the file creation mode mask.</dd>
  345 <dt>csv_field_size – <code class="docutils literal"><span class="pre">131072</span></code></dt>
  346 <dd>Maximum size of a csv-field during import. Roundups export
  347 format is a csv (comma separated values) variant. The csv
  348 reader has a limit on the size of individual fields
  349 starting with python 2.5. Set this to a higher value if you
  350 get the error ‘Error: field larger than field limit’ during
  351 import.</dd>
  352 </dl>
  353 </dd>
  354 </dl>
  355 <dl class="docutils" id="index-5">
  356 <dt>Section <strong>tracker</strong></dt>
  357 <dd><dl class="first last docutils">
  358 <dt>name – <code class="docutils literal"><span class="pre">Roundup</span> <span class="pre">issue</span> <span class="pre">tracker</span></code></dt>
  359 <dd>A descriptive name for your roundup instance.</dd>
  360 <dt>web – <code class="docutils literal"><span class="pre">http://host.example/demo/</span></code></dt>
  361 <dd>The web address that the tracker is viewable at.
  362 This will be included in information sent to users of the tracker.
  363 The URL MUST include the cgi-bin part or anything else
  364 that is required to get to the home page of the tracker.
  365 You MUST include a trailing ‘/’ in the URL.</dd>
  366 <dt>email – <code class="docutils literal"><span class="pre">issue_tracker</span></code></dt>
  367 <dd>Email address that mail to roundup should go to.</dd>
  368 <dt>language – default <em>blank</em></dt>
  369 <dd>Default locale name for this tracker. If this option is not set, the
  370 language is determined by the environment variable LANGUAGE, LC_ALL,
  371 LC_MESSAGES, or LANG, in that order of preference.</dd>
  372 </dl>
  373 </dd>
  374 </dl>
  375 <dl class="docutils" id="index-6">
  376 <dt>Section <strong>web</strong></dt>
  377 <dd><dl class="first last docutils">
  378 <dt>allow_html_file – <code class="docutils literal"><span class="pre">no</span></code></dt>
  379 <dd>Setting this option enables Roundup to serve uploaded HTML
  380 file content <em>as HTML</em>. This is a potential security risk
  381 and is therefore disabled by default. Set to ‘yes’ if you
  382 trust <em>all</em> users uploading content to your tracker.</dd>
  383 <dt>http_auth – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  384 <dd>Whether to use HTTP Basic Authentication, if present.
  385 Roundup will use either the REMOTE_USER or HTTP_AUTHORIZATION
  386 variables supplied by your web server (in that order).
  387 Set this option to ‘no’ if you do not wish to use HTTP Basic
  388 Authentication in your web interface.</dd>
  389 <dt>use_browser_language – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  390 <dd>Whether to use HTTP Accept-Language, if present.
  391 Browsers send a language-region preference list.
  392 It’s usually set in the client’s browser or in their
  393 Operating System.
  394 Set this option to ‘no’ if you want to ignore it.</dd>
  395 <dt>debug – <code class="docutils literal"><span class="pre">no</span></code></dt>
  396 <dd>Setting this option makes Roundup display error tracebacks
  397 in the user’s browser rather than emailing them to the
  398 tracker admin.”),</dd>
  399 </dl>
  400 </dd>
  401 </dl>
  402 <dl class="docutils" id="index-7">
  403 <dt>Section <strong>rdbms</strong></dt>
  404 <dd><p class="first">Settings in this section are used to set the backend and configure
  405 addition settings needed by RDBMs like SQLite, Postgresql and
  406 MySQL backends.</p>
  407 <dl class="docutils" id="index-8">
  408 <dt>backend – set to value by init</dt>
  409 <dd>The database backend such as anydbm, sqlite, mysql or postgres.</dd>
  410 <dt>name – <code class="docutils literal"><span class="pre">roundup</span></code></dt>
  411 <dd>Name of the database to use.</dd>
  412 <dt>host – <code class="docutils literal"><span class="pre">localhost</span></code></dt>
  413 <dd>Database server host.</dd>
  414 <dt>port – default <em>blank</em></dt>
  415 <dd>TCP port number of the database server. Postgresql usually resides on
  416 port 5432 (if any), for MySQL default port number is 3306. Leave this
  417 option empty to use backend default.</dd>
  418 <dt>user – <code class="docutils literal"><span class="pre">roundup</span></code></dt>
  419 <dd>Database user name that Roundup should use.</dd>
  420 <dt>password – <code class="docutils literal"><span class="pre">roundup</span></code></dt>
  421 <dd>Database user password.</dd>
  422 <dt>read_default_file – <code class="docutils literal"><span class="pre">~/.my.cnf</span></code></dt>
  423 <dd>Name of the MySQL defaults file. Only used in MySQL connections.</dd>
  424 <dt>read_default_group – <code class="docutils literal"><span class="pre">roundup</span></code></dt>
  425 <dd>Name of the group to use in the MySQL defaults file. Only used in
  426 MySQL connections.</dd>
  427 </dl>
  428 <dl class="last docutils" id="index-9">
  429 <dt>sqlite_timeout – <code class="docutils literal"><span class="pre">30</span></code></dt>
  430 <dd>Number of seconds to wait when the SQLite database is locked.
  431 Used only for SQLite.</dd>
  432 <dt>cache_size – <cite>100</cite></dt>
  433 <dd>Size of the node cache (in elements) used to keep most recently used
  434 data in memory.</dd>
  435 </dl>
  436 </dd>
  437 </dl>
  438 <dl class="docutils" id="index-10">
  439 <dt>Section <strong>logging</strong></dt>
  440 <dd><dl class="first last docutils">
  441 <dt>config – default <em>blank</em></dt>
  442 <dd>Path to configuration file for standard Python logging module. If this
  443 option is set, logging configuration is loaded from specified file;
  444 options ‘filename’ and ‘level’ in this section are ignored. The path may
  445 be either absolute or relative to the directory containig this config file.</dd>
  446 <dt>filename – default <em>blank</em></dt>
  447 <dd>Log file name for minimal logging facility built into Roundup.  If no file
  448 name specified, log messages are written on stderr. If above ‘config’
  449 option is set, this option has no effect. The path may be either absolute
  450 or relative to the directory containig this config file.</dd>
  451 <dt>level – <code class="docutils literal"><span class="pre">ERROR</span></code></dt>
  452 <dd>Minimal severity level of messages written to log file. If above ‘config’
  453 option is set, this option has no effect.
  454 Allowed values: <code class="docutils literal"><span class="pre">DEBUG</span></code>, <code class="docutils literal"><span class="pre">INFO</span></code>, <code class="docutils literal"><span class="pre">WARNING</span></code>, <code class="docutils literal"><span class="pre">ERROR</span></code></dd>
  455 </dl>
  456 </dd>
  457 </dl>
  458 <dl class="docutils" id="index-11">
  459 <dt>Section <strong>mail</strong></dt>
  460 <dd><p class="first">Outgoing email options. Used for nosy messages, password reset and
  461 registration approval requests.</p>
  462 <dl class="last docutils">
  463 <dt>domain – <code class="docutils literal"><span class="pre">localhost</span></code></dt>
  464 <dd>Domain name used for email addresses.</dd>
  465 <dt>host – default <em>blank</em></dt>
  466 <dd>SMTP mail host that roundup will use to send mail</dd>
  467 <dt>username – default <em>blank</em></dt>
  468 <dd>SMTP login name. Set this if your mail host requires authenticated access.
  469 If username is not empty, password (below) MUST be set!</dd>
  470 <dt>password – default <em>blank</em></dt>
  471 <dd>SMTP login password.
  472 Set this if your mail host requires authenticated access.</dd>
  473 <dt>port – default <em>25</em></dt>
  474 <dd>SMTP port on mail host.
  475 Set this if your mail host runs on a different port.</dd>
  476 <dt>local_hostname – default <em>blank</em></dt>
  477 <dd>The fully qualified domain name (FQDN) to use during SMTP sessions. If left
  478 blank, the underlying SMTP library will attempt to detect your FQDN. If your
  479 mail host requires something specific, specify the FQDN to use.</dd>
  480 <dt>tls – <code class="docutils literal"><span class="pre">no</span></code></dt>
  481 <dd>If your SMTP mail host provides or requires TLS (Transport Layer Security)
  482 then you may set this option to ‘yes’.
  483 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code></dd>
  484 <dt>tls_keyfile – default <em>blank</em></dt>
  485 <dd>If TLS is used, you may set this option to the name of a PEM formatted
  486 file that contains your private key. The path may be either absolute or
  487 relative to the directory containig this config file.</dd>
  488 <dt>tls_certfile – default <em>blank</em></dt>
  489 <dd>If TLS is used, you may set this option to the name of a PEM formatted
  490 certificate chain file. The path may be either absolute or relative
  491 to the directory containig this config file.</dd>
  492 <dt>charset – utf-8</dt>
  493 <dd>Character set to encode email headers with. We use utf-8 by default, as
  494 it’s the most flexible. Some mail readers (eg. Eudora) can’t cope with
  495 that, so you might need to specify a more limited character set
  496 (eg. iso-8859-1).</dd>
  497 <dt>debug – default <em>blank</em></dt>
  498 <dd>Setting this option makes Roundup to write all outgoing email messages
  499 to this file <em>instead</em> of sending them. This option has the same effect
  500 as environment variable SENDMAILDEBUG. Environment variable takes
  501 precedence. The path may be either absolute or relative to the directory
  502 containig this config file.</dd>
  503 <dt>add_authorinfo – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  504 <dd>Add a line with author information at top of all messages send by
  505 roundup.</dd>
  506 <dt>add_authoremail – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  507 <dd>Add the mail address of the author to the author information at the
  508 top of all messages.  If this is false but add_authorinfo is true,
  509 only the name of the actor is added which protects the mail address
  510 of the actor from being exposed at mail archives, etc.</dd>
  511 </dl>
  512 </dd>
  513 </dl>
  514 <dl class="docutils" id="index-12">
  515 <dt>Section <strong>mailgw</strong></dt>
  516 <dd><p class="first">Roundup Mail Gateway options</p>
  517 <dl class="last docutils">
  518 <dt>keep_quoted_text – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  519 <dd>Keep email citations when accepting messages. Setting this to <code class="docutils literal"><span class="pre">no</span></code> strips
  520 out “quoted” text from the message. Signatures are also stripped.
  521 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code></dd>
  522 <dt>leave_body_unchanged – <code class="docutils literal"><span class="pre">no</span></code></dt>
  523 <dd>Preserve the email body as is - that is, keep the citations <em>and</em>
  524 signatures.
  525 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code></dd>
  526 <dt>default_class – <code class="docutils literal"><span class="pre">issue</span></code></dt>
  527 <dd>Default class to use in the mailgw if one isn’t supplied in email subjects.
  528 To disable, leave the value blank.</dd>
  529 <dt>language – default <em>blank</em></dt>
  530 <dd>Default locale name for the tracker mail gateway.  If this option is
  531 not set, mail gateway will use the language of the tracker instance.</dd>
  532 <dt>subject_prefix_parsing – <code class="docutils literal"><span class="pre">strict</span></code></dt>
  533 <dd>Controls the parsing of the [prefix] on subject lines in incoming emails.
  534 <code class="docutils literal"><span class="pre">strict</span></code> will return an error to the sender if the [prefix] is not
  535 recognised. <code class="docutils literal"><span class="pre">loose</span></code> will attempt to parse the [prefix] but just
  536 pass it through as part of the issue title if not recognised. <code class="docutils literal"><span class="pre">none</span></code>
  537 will always pass any [prefix] through as part of the issue title.</dd>
  538 <dt>subject_suffix_parsing – <code class="docutils literal"><span class="pre">strict</span></code></dt>
  539 <dd>Controls the parsing of the [suffix] on subject lines in incoming emails.
  540 <code class="docutils literal"><span class="pre">strict</span></code> will return an error to the sender if the [suffix] is not
  541 recognised. <code class="docutils literal"><span class="pre">loose</span></code> will attempt to parse the [suffix] but just
  542 pass it through as part of the issue title if not recognised. <code class="docutils literal"><span class="pre">none</span></code>
  543 will always pass any [suffix] through as part of the issue title.</dd>
  544 <dt>subject_suffix_delimiters – <code class="docutils literal"><span class="pre">[]</span></code></dt>
  545 <dd>Defines the brackets used for delimiting the commands suffix in a subject
  546 line.</dd>
  547 <dt>subject_content_match – <code class="docutils literal"><span class="pre">always</span></code></dt>
  548 <dd>Controls matching of the incoming email subject line against issue titles
  549 in the case where there is no designator [prefix]. <code class="docutils literal"><span class="pre">never</span></code> turns off
  550 matching. <code class="docutils literal"><span class="pre">creation</span> <span class="pre">+</span> <span class="pre">interval</span></code> or <code class="docutils literal"><span class="pre">activity</span> <span class="pre">+</span> <span class="pre">interval</span></code> will match
  551 an issue for the interval after the issue’s creation or last activity.
  552 The interval is a standard Roundup interval.</dd>
  553 <dt>subject_updates_title – <code class="docutils literal"><span class="pre">yes</span></code></dt>
  554 <dd>Update issue title if incoming subject of email is different.
  555 Setting this to <code class="docutils literal"><span class="pre">no</span></code> will ignore the title part of
  556 the subject of incoming email messages.</dd>
  557 <dt>refwd_re – <code class="docutils literal"><span class="pre">(\s*\W?\s*(fw|fwd|re|aw|sv|ang)\W)+</span></code></dt>
  558 <dd>Regular expression matching a single reply or forward prefix
  559 prepended by the mailer. This is explicitly stripped from the
  560 subject during parsing.  Value is Python Regular Expression
  561 (UTF8-encoded).</dd>
  562 <dt>origmsg_re – `` ^[&gt;|s]*—–s?Original Messages?—–$``</dt>
  563 <dd>Regular expression matching start of an original message if quoted
  564 in the body.  Value is Python Regular Expression (UTF8-encoded).</dd>
  565 <dt>sign_re – <code class="docutils literal"><span class="pre">^[&gt;|\s]*--</span> <span class="pre">?$</span></code></dt>
  566 <dd>Regular expression matching the start of a signature in the message
  567 body.  Value is Python Regular Expression (UTF8-encoded).</dd>
  568 <dt>eol_re – <code class="docutils literal"><span class="pre">[\r\n]+</span></code></dt>
  569 <dd>Regular expression matching end of line.  Value is Python Regular
  570 Expression (UTF8-encoded).</dd>
  571 <dt>blankline_re – <code class="docutils literal"><span class="pre">[\r\n]+\s*[\r\n]+</span></code></dt>
  572 <dd>Regular expression matching a blank line.  Value is Python Regular
  573 Expression (UTF8-encoded).</dd>
  574 <dt>ignore_alternatives – <code class="docutils literal"><span class="pre">no</span></code></dt>
  575 <dd>When parsing incoming mails, roundup uses the first
  576 text/plain part it finds. If this part is inside a
  577 multipart/alternative, and this option is set, all other
  578 parts of the multipart/alternative are ignored. The default
  579 is to keep all parts and attach them to the issue.</dd>
  580 </dl>
  581 </dd>
  582 </dl>
  583 <dl class="docutils" id="index-13">
  584 <dt>Section <strong>pgp</strong></dt>
  585 <dd><p class="first">OpenPGP mail processing options</p>
  586 <dl class="last docutils">
  587 <dt>enable – <code class="docutils literal"><span class="pre">no</span></code></dt>
  588 <dd>Enable PGP processing. Requires gpg.</dd>
  589 <dt>roles – default <em>blank</em></dt>
  590 <dd>If specified, a comma-separated list of roles to perform PGP
  591 processing on. If not specified, it happens for all users.</dd>
  592 <dt>homedir – default <em>blank</em></dt>
  593 <dd>Location of PGP directory. Defaults to $HOME/.gnupg if not
  594 specified.</dd>
  595 </dl>
  596 </dd>
  597 </dl>
  598 <dl class="docutils" id="index-14">
  599 <dt>Section <strong>nosy</strong></dt>
  600 <dd><p class="first">Nosy messages sending</p>
  601 <dl class="last docutils">
  602 <dt>messages_to_author – <code class="docutils literal"><span class="pre">no</span></code></dt>
  603 <dd>Send nosy messages to the author of the message.
  604 If <code class="docutils literal"><span class="pre">yes</span></code> is used, then messages are sent to the author
  605 even if not on the nosy list, same for <code class="docutils literal"><span class="pre">new</span></code> (but only for new messages).
  606 When set to <code class="docutils literal"><span class="pre">nosy</span></code>, the nosy list controls sending messages to the author.
  607 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code>, <code class="docutils literal"><span class="pre">new</span></code>, <code class="docutils literal"><span class="pre">nosy</span></code></dd>
  608 <dt>signature_position – <code class="docutils literal"><span class="pre">bottom</span></code></dt>
  609 <dd>Where to place the email signature.
  610 Allowed values: <code class="docutils literal"><span class="pre">top</span></code>, <code class="docutils literal"><span class="pre">bottom</span></code>, <code class="docutils literal"><span class="pre">none</span></code></dd>
  611 <dt>add_author – <code class="docutils literal"><span class="pre">new</span></code></dt>
  612 <dd>Does the author of a message get placed on the nosy list automatically?
  613 If <code class="docutils literal"><span class="pre">new</span></code> is used, then the author will only be added when a message
  614 creates a new issue. If <code class="docutils literal"><span class="pre">yes</span></code>, then the author will be added on
  615 followups too. If <code class="docutils literal"><span class="pre">no</span></code>, they’re never added to the nosy.
  616 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code>, <code class="docutils literal"><span class="pre">new</span></code></dd>
  617 <dt>add_recipients – <code class="docutils literal"><span class="pre">new</span></code></dt>
  618 <dd>Do the recipients (<code class="docutils literal"><span class="pre">To:</span></code>, <code class="docutils literal"><span class="pre">Cc:</span></code>) of a message get placed on the nosy
  619 list?  If <code class="docutils literal"><span class="pre">new</span></code> is used, then the recipients will only be added when a
  620 message creates a new issue. If <code class="docutils literal"><span class="pre">yes</span></code>, then the recipients will be added
  621 on followups too. If <code class="docutils literal"><span class="pre">no</span></code>, they’re never added to the nosy.
  622 Allowed values: <code class="docutils literal"><span class="pre">yes</span></code>, <code class="docutils literal"><span class="pre">no</span></code>, <code class="docutils literal"><span class="pre">new</span></code></dd>
  623 <dt>email_sending – <code class="docutils literal"><span class="pre">single</span></code></dt>
  624 <dd>Controls the email sending from the nosy reactor. If <code class="docutils literal"><span class="pre">multiple</span></code> then
  625 a separate email is sent to each recipient. If <code class="docutils literal"><span class="pre">single</span></code> then a single
  626 email is sent with each recipient as a CC address.</dd>
  627 <dt>max_attachment_size – <code class="docutils literal"><span class="pre">2147483647</span></code></dt>
  628 <dd>Attachments larger than the given number of bytes won’t be attached
  629 to nosy mails. They will be replaced by a link to the tracker’s
  630 download page for the file.</dd>
  631 </dl>
  632 </dd>
  633 </dl>
  634 <p id="index-15">You may generate a new default config file using the <code class="docutils literal"><span class="pre">roundup-admin</span>
  635 <span class="pre">genconfig</span></code> command. You can generate a new config file merging in
  636 existing settings using the <code class="docutils literal"><span class="pre">roundup-admin</span> <span class="pre">updateconfig</span></code> command.</p>
  637 <p>Configuration variables may be referred to in lower or upper case. In code,
  638 variables not in the “main” section are referred to using their section and
  639 name, so “domain” in the section “mail” becomes MAIL_DOMAIN.</p>
  640 <div class="section" id="extending-the-configuration-file">
  641 <span id="index-16"></span><h3><a class="toc-backref" href="#id10">Extending the configuration file</a><a class="headerlink" href="#extending-the-configuration-file" title="Permalink to this headline"></a></h3>
  642 <p>You can’t add new variables to the config.ini file in the tracker home but
  643 you can add two new config.ini files:</p>
  644 <ul class="simple">
  645 <li>a config.ini in the <code class="docutils literal"><span class="pre">extensions</span></code> directory will be loaded and attached
  646 to the config variable as “ext”.</li>
  647 <li>a config.ini in the <code class="docutils literal"><span class="pre">detectors</span></code> directory will be loaded and attached
  648 to the config variable as “detectors”.</li>
  649 </ul>
  650 <p>For example, the following in <code class="docutils literal"><span class="pre">detectors/config.ini</span></code>:</p>
  651 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">main</span><span class="p">]</span>
  652 <span class="n">qa_recipients</span> <span class="o">=</span> <span class="n">email</span><span class="nd">@example</span><span class="o">.</span><span class="n">com</span>
  653 </pre></div>
  654 </div>
  655 <p>is accessible as:</p>
  656 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">db</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">detectors</span><span class="p">[</span><span class="s1">&#39;QA_RECIPIENTS&#39;</span><span class="p">]</span>
  657 </pre></div>
  658 </div>
  659 <p>Note that the name grouping applied to the main configuration file is
  660 applied to the extension config files, so if you instead have:</p>
  661 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">qa</span><span class="p">]</span>
  662 <span class="n">recipients</span> <span class="o">=</span> <span class="n">email</span><span class="nd">@example</span><span class="o">.</span><span class="n">com</span>
  663 </pre></div>
  664 </div>
  665 <p>then the above <code class="docutils literal"><span class="pre">db.config.detectors['QA_RECIPIENTS']</span></code> will still work.</p>
  666 </div>
  667 </div>
  668 <div class="section" id="tracker-schema">
  669 <span id="index-17"></span><h2><a class="toc-backref" href="#id11">Tracker Schema</a><a class="headerlink" href="#tracker-schema" title="Permalink to this headline"></a></h2>
  670 <div class="admonition note">
  671 <p class="first admonition-title">Note</p>
  672 <p class="last">if you modify the schema, you’ll most likely need to edit the
  673 <a class="reference internal" href="#web-interface">web interface</a> HTML template files and <a class="reference internal" href="#detectors">detectors</a> to reflect
  674 your changes.</p>
  675 </div>
  676 <p>A tracker schema defines what data is stored in the tracker’s database.
  677 Schemas are defined using Python code in the <code class="docutils literal"><span class="pre">schema.py</span></code> module of your
  678 tracker.</p>
  679 <div class="section" id="the-schema-py-and-initial-data-py-modules">
  680 <h3><a class="toc-backref" href="#id12">The <code class="docutils literal"><span class="pre">schema.py</span></code> and <code class="docutils literal"><span class="pre">initial_data.py</span></code> modules</a><a class="headerlink" href="#the-schema-py-and-initial-data-py-modules" title="Permalink to this headline"></a></h3>
  681 <p>The schema.py module is used to define what your tracker looks like
  682 on the inside, the schema of the tracker. It defines the Classes
  683 and properties on each class. It also defines the security for
  684 those Classes. The next few sections describe how schemas work
  685 and what you can do with them.</p>
  686 <p>The initial_data.py module sets up the initial state of your
  687 tracker. It’s called exactly once - by the <code class="docutils literal"><span class="pre">roundup-admin</span> <span class="pre">initialise</span></code>
  688 command. See the start of the section on database content for more
  689 info about how this works.</p>
  690 </div>
  691 <div class="section" id="the-classic-schema">
  692 <span id="index-18"></span><h3><a class="toc-backref" href="#id13">The “classic” schema</a><a class="headerlink" href="#the-classic-schema" title="Permalink to this headline"></a></h3>
  693 <p>The “classic” schema looks like this (see section <a class="reference internal" href="#setkey-property">setkey(property)</a>
  694 below for the meaning of <code class="docutils literal"><span class="pre">'setkey'</span></code> – you may also want to look into
  695 the sections <a class="reference internal" href="#setlabelprop-property">setlabelprop(property)</a> and <a class="reference internal" href="#setorderprop-property">setorderprop(property)</a> for
  696 specifying (default) labelling and ordering of classes.):</p>
  697 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">pri</span> <span class="o">=</span> <span class="n">Class</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;priority&quot;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">order</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  698 <span class="n">pri</span><span class="o">.</span><span class="n">setkey</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span>
  699 
  700 <span class="n">stat</span> <span class="o">=</span> <span class="n">Class</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;status&quot;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">order</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  701 <span class="n">stat</span><span class="o">.</span><span class="n">setkey</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span>
  702 
  703 <span class="n">keyword</span> <span class="o">=</span> <span class="n">Class</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;keyword&quot;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  704 <span class="n">keyword</span><span class="o">.</span><span class="n">setkey</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span>
  705 
  706 <span class="n">user</span> <span class="o">=</span> <span class="n">Class</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;user&quot;</span><span class="p">,</span> <span class="n">username</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">organisation</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  707     <span class="n">password</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">address</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">realname</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  708     <span class="n">phone</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">alternate_addresses</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  709     <span class="n">queries</span><span class="o">=</span><span class="n">Multilink</span><span class="p">(</span><span class="s1">&#39;query&#39;</span><span class="p">),</span> <span class="n">roles</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">timezone</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  710 <span class="n">user</span><span class="o">.</span><span class="n">setkey</span><span class="p">(</span><span class="s2">&quot;username&quot;</span><span class="p">)</span>
  711 
  712 <span class="n">msg</span> <span class="o">=</span> <span class="n">FileClass</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;msg&quot;</span><span class="p">,</span> <span class="n">author</span><span class="o">=</span><span class="n">Link</span><span class="p">(</span><span class="s2">&quot;user&quot;</span><span class="p">),</span> <span class="n">summary</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  713     <span class="n">date</span><span class="o">=</span><span class="n">Date</span><span class="p">(),</span> <span class="n">recipients</span><span class="o">=</span><span class="n">Multilink</span><span class="p">(</span><span class="s2">&quot;user&quot;</span><span class="p">),</span>
  714     <span class="n">files</span><span class="o">=</span><span class="n">Multilink</span><span class="p">(</span><span class="s2">&quot;file&quot;</span><span class="p">),</span> <span class="n">messageid</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span> <span class="n">inreplyto</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  715 
  716 <span class="n">file</span> <span class="o">=</span> <span class="n">FileClass</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;file&quot;</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  717 
  718 <span class="n">issue</span> <span class="o">=</span> <span class="n">IssueClass</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;issue&quot;</span><span class="p">,</span> <span class="n">keyword</span><span class="o">=</span><span class="n">Multilink</span><span class="p">(</span><span class="s2">&quot;keyword&quot;</span><span class="p">),</span>
  719     <span class="n">status</span><span class="o">=</span><span class="n">Link</span><span class="p">(</span><span class="s2">&quot;status&quot;</span><span class="p">),</span> <span class="n">assignedto</span><span class="o">=</span><span class="n">Link</span><span class="p">(</span><span class="s2">&quot;user&quot;</span><span class="p">),</span>
  720     <span class="n">priority</span><span class="o">=</span><span class="n">Link</span><span class="p">(</span><span class="s2">&quot;priority&quot;</span><span class="p">))</span>
  721 <span class="n">issue</span><span class="o">.</span><span class="n">setkey</span><span class="p">(</span><span class="s1">&#39;title&#39;</span><span class="p">)</span>
  722 </pre></div>
  723 </div>
  724 </div>
  725 <div class="section" id="what-you-can-t-do-to-the-schema">
  726 <span id="index-19"></span><h3><a class="toc-backref" href="#id14">What you can’t do to the schema</a><a class="headerlink" href="#what-you-can-t-do-to-the-schema" title="Permalink to this headline"></a></h3>
  727 <p>You must never:</p>
  728 <dl class="docutils">
  729 <dt><strong>Remove the users class</strong></dt>
  730 <dd>This class is the only <em>required</em> class in Roundup.</dd>
  731 <dt><strong>Remove the “username”, “address”, “password” or “realname” user properties</strong></dt>
  732 <dd>Various parts of Roundup require these properties. Don’t remove them.</dd>
  733 <dt><strong>Change the type of a property</strong></dt>
  734 <dd>Property types must <em>never</em> be changed - the database simply doesn’t take
  735 this kind of action into account. Note that you can’t just remove a
  736 property and re-add it as a new type either. If you wanted to make the
  737 assignedto property a Multilink, you’d need to create a new property
  738 assignedto_list and remove the old assignedto property.</dd>
  739 </dl>
  740 </div>
  741 <div class="section" id="what-you-can-do-to-the-schema">
  742 <h3><a class="toc-backref" href="#id15">What you can do to the schema</a><a class="headerlink" href="#what-you-can-do-to-the-schema" title="Permalink to this headline"></a></h3>
  743 <p>Your schema may be changed at any time before or after the tracker has been
  744 initialised (or used). You may:</p>
  745 <dl class="docutils">
  746 <dt><strong>Add new properties to classes, or add whole new classes</strong></dt>
  747 <dd>This is painless and easy to do - there are generally no repercussions
  748 from adding new information to a tracker’s schema.</dd>
  749 <dt><strong>Remove properties</strong></dt>
  750 <dd>Removing properties is a little more tricky - you need to make sure that
  751 the property is no longer used in the <a class="reference internal" href="#web-interface">web interface</a> <em>or</em> by the
  752 <a class="reference internal" href="#detectors">detectors</a>.</dd>
  753 </dl>
  754 </div>
  755 <div class="section" id="classes-and-properties-creating-a-new-information-store">
  756 <h3><a class="toc-backref" href="#id16">Classes and Properties - creating a new information store</a><a class="headerlink" href="#classes-and-properties-creating-a-new-information-store" title="Permalink to this headline"></a></h3>
  757 <p>In the tracker above, we’ve defined 7 classes of information:</p>
  758 <blockquote>
  759 <div><dl class="docutils">
  760 <dt>priority</dt>
  761 <dd>Defines the possible levels of urgency for issues.</dd>
  762 <dt>status</dt>
  763 <dd>Defines the possible states of processing the issue may be in.</dd>
  764 <dt>keyword</dt>
  765 <dd>Initially empty, will hold keywords useful for searching issues.</dd>
  766 <dt>user</dt>
  767 <dd>Initially holding the “admin” user, will eventually have an entry
  768 for all users using roundup.</dd>
  769 <dt>msg</dt>
  770 <dd>Initially empty, will hold all e-mail messages sent to or
  771 generated by roundup.</dd>
  772 <dt>file</dt>
  773 <dd>Initially empty, will hold all files attached to issues.</dd>
  774 <dt>issue</dt>
  775 <dd>Initially empty, this is where the issue information is stored.</dd>
  776 </dl>
  777 </div></blockquote>
  778 <p>We define the “priority” and “status” classes to allow two things:</p>
  779 <blockquote>
  780 <div><ol class="arabic simple">
  781 <li>reduction in the amount of information stored on the issue</li>
  782 <li>more powerful, accurate searching of issues by priority and status</li>
  783 </ol>
  784 </div></blockquote>
  785 <p>By only requiring a link on the issue (which is stored as a single
  786 number) we reduce the chance that someone mis-types a priority or
  787 status - or simply makes a new one up.</p>
  788 <div class="section" id="class-and-items">
  789 <h4>Class and Items<a class="headerlink" href="#class-and-items" title="Permalink to this headline"></a></h4>
  790 <p>A Class defines a particular class (or type) of data that will be stored
  791 in the database. A class comprises one or more properties, which gives
  792 the information about the class items.</p>
  793 <p>The actual data entered into the database, using <code class="docutils literal"><span class="pre">class.create()</span></code>, are
  794 called items. They have a special immutable property called <code class="docutils literal"><span class="pre">'id'</span></code>. We
  795 sometimes refer to this as the <em>itemid</em>.</p>
  796 </div>
  797 <div class="section" id="properties">
  798 <span id="index-20"></span><h4>Properties<a class="headerlink" href="#properties" title="Permalink to this headline"></a></h4>
  799 <p>A Class is comprised of one or more properties of the following types:</p>
  800 <blockquote>
  801 <div><dl class="docutils">
  802 <dt>String</dt>
  803 <dd>properties are for storing arbitrary-length strings.</dd>
  804 <dt>Password</dt>
  805 <dd>properties are for storing encoded arbitrary-length strings.
  806 The default encoding is defined on the <code class="docutils literal"><span class="pre">roundup.password.Password</span></code>
  807 class.</dd>
  808 <dt>Date</dt>
  809 <dd>properties store date-and-time stamps. Their values are Timestamp
  810 objects.</dd>
  811 <dt>Interval</dt>
  812 <dd>properties store time periods rather than absolute dates. For
  813 example 2 hours.</dd>
  814 <dt>Integer</dt>
  815 <dd>properties store integer values. (Number can store real/float values.)</dd>
  816 <dt>Number</dt>
  817 <dd>properties store numeric values. There is an option to use
  818 double-precision floating point numbers.</dd>
  819 <dt>Boolean</dt>
  820 <dd>properties store on/off, yes/no, true/false values.</dd>
  821 <dt>Link</dt>
  822 <dd>properties refers to a single other item selected from a
  823 specified class. The class is part of the property; the value is an
  824 integer, the id of the chosen item.</dd>
  825 <dt>Multilink</dt>
  826 <dd>properties refer to possibly many items in a specified
  827 class. The value is a list of integers.</dd>
  828 </dl>
  829 </div></blockquote>
  830 <p>Properties can have additional attributes to change the default
  831 behaviour:</p>
  832 <ul id="index-21">
  833 <li><p class="first">All properties support the following attributes:</p>
  834 <blockquote>
  835 <div><ul>
  836 <li><p class="first"><code class="docutils literal"><span class="pre">required</span></code>: see <a class="reference external" href="design.html">design documentation</a>. Adds the property to
  837 the list returned by calling get_required_props for the class.</p>
  838 </li>
  839 <li><p class="first"><code class="docutils literal"><span class="pre">default_value</span></code>: see <a class="reference external" href="design.html">design documentation</a> Sets the default
  840 value if the property is not set.</p>
  841 </li>
  842 <li><p class="first"><code class="docutils literal"><span class="pre">quiet</span></code>: see <a class="reference external" href="design.html">design documentation</a>. Suppresses user visible
  843 to changes to this property. The property change is not reported:</p>
  844 <blockquote>
  845 <div><ul class="simple">
  846 <li>in the change feedback/confirmation message in the web
  847 interface</li>
  848 <li>the property change section of the nosy email</li>
  849 <li>the web history at the bottom of an item’s page</li>
  850 </ul>
  851 </div></blockquote>
  852 </li>
  853 </ul>
  854 <blockquote>
  855 <div><p>This can be used to store state of the user interface (e.g. the
  856 names of elements that are collapsed or hidden from the
  857 user). Making properties that are updated as an indirect result of
  858 a user’s change (e.g. updating a blockers property, counting
  859 number of times an issue was reopened or reassigned etc.) should
  860 not be displayed to the user as they can be confusing.</p>
  861 </div></blockquote>
  862 </div></blockquote>
  863 </li>
  864 </ul>
  865 <ul class="simple" id="index-22">
  866 <li>String properties can have an <code class="docutils literal"><span class="pre">indexme</span></code> attribute that defines if the
  867 property should be part of the full text index. The default is ‘no’ but this
  868 can be set to ‘yes’ to allow a property’s contents to be in the full
  869 text index.</li>
  870 </ul>
  871 <ul id="index-23">
  872 <li><p class="first">Number properties can have a <code class="docutils literal"><span class="pre">use_double</span></code> attribute that, when set
  873 to <code class="docutils literal"><span class="pre">True</span></code>, will use double precision floating point in the database.</p>
  874 </li>
  875 <li><p class="first">Link and Multilink properties can have several attributes:</p>
  876 <ul class="simple" id="index-24">
  877 <li><code class="docutils literal"><span class="pre">do_journal</span></code>: By default, every change of a link property is
  878 recorded in the item being linked to (or being unlinked). A typical
  879 use-case for setting <code class="docutils literal"><span class="pre">do_journal='no'</span></code> would be to turn off
  880 journalling of nosy list, message author and message recipient link
  881 and unlink events to prevent the journal from clogged with these
  882 events.</li>
  883 </ul>
  884 <ul class="simple" id="index-25">
  885 <li><code class="docutils literal"><span class="pre">try_id_parsing</span></code> is turned on by default. If entering a number
  886 into a Link or Multilink field, roundup interprets this number as an
  887 ID of the item to link to. Sometimes items can have numeric names
  888 (like, e.g., product codes). For these roundup needs to match the
  889 numeric name and should never match an ID. In this case you can set
  890 <code class="docutils literal"><span class="pre">try_id_parsing='no'</span></code>.</li>
  891 </ul>
  892 <ul id="index-26">
  893 <li><p class="first">The <code class="docutils literal"><span class="pre">rev_multilink</span></code> option takes a property name to be inserted
  894 into the linked-to class. This property is a Multilink property that
  895 links back to the current class. The new Multilink is read-only (it
  896 is automatically modified if the Link or Multilink property defining
  897 it is modified). The new property can be used in normal searches
  898 using the “filter” method of the Class. This means it can be used
  899 like other Multilink properties when searching (in an index
  900 template) or via the REST and XMLRPC APIs.</p>
  901 <p>As a example, suppose you want to group multiple issues into a
  902 super issue. Each issue can be part of only one super issue. It is
  903 inefficient to find all of the issues that are part of the
  904 super issue by searching through all issues in the system looking
  905 at the part_of link property. To make this more efficient, you
  906 can declare an issue’s part_of property as:</p>
  907 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">issue</span> <span class="o">=</span> <span class="n">IssueClass</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;issue&quot;</span><span class="p">,</span>
  908           <span class="o">...</span>
  909           <span class="n">part_of</span> <span class="o">=</span> <span class="n">Link</span><span class="p">(</span><span class="s2">&quot;issue&quot;</span><span class="p">,</span> <span class="n">rev_multilink</span><span class="o">=</span><span class="s2">&quot;components&quot;</span><span class="p">),</span>
  910           <span class="o">...</span> <span class="p">)</span>
  911 </pre></div>
  912 </div>
  913 <p>This automatically creates the <code class="docutils literal"><span class="pre">components</span></code> multilink on the issue
  914 class. The <code class="docutils literal"><span class="pre">components</span></code> multilink is never explicitly declared in
  915 the issue class, but it has the same effect as though you had
  916 declared the class as:</p>
  917 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">issue</span> <span class="o">=</span> <span class="n">IssueClass</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;issue&quot;</span><span class="p">,</span>
  918           <span class="o">...</span>
  919           <span class="n">part_of</span> <span class="o">=</span> <span class="n">Link</span><span class="p">(</span><span class="s2">&quot;issue&quot;</span><span class="p">),</span>
  920           <span class="n">components</span> <span class="o">=</span> <span class="n">Multilink</span><span class="p">(</span><span class="s2">&quot;issue&quot;</span><span class="p">),</span>
  921           <span class="o">...</span> <span class="p">)</span>
  922 </pre></div>
  923 </div>
  924 <p>Then wrote a detector to update the components property on the
  925 corresponding issue. Writing this detector can be tricky. There is
  926 one other difference, you can not explicitly set/modify the
  927 <code class="docutils literal"><span class="pre">components</span></code> multilink.</p>
  928 <p>The effect of setting <code class="docutils literal"><span class="pre">part_of</span> <span class="pre">=</span> <span class="pre">3456</span></code> on issue1234
  929 automatically adds “1234” to the <code class="docutils literal"><span class="pre">components</span></code> property on
  930 issue3456. You can search the <code class="docutils literal"><span class="pre">components</span></code> multilink just like a
  931 regular multilink, but you can’t explicitly assign to it.
  932 Another difference of reverse multilinks to normal multilinks
  933 is that when a linked node is retired, the node vanishes from the
  934 multilink, e.g. in the example above, if an issue with <code class="docutils literal"><span class="pre">part_of</span></code>
  935 set to another issue is retired this issue vanishes from the
  936 <code class="docutils literal"><span class="pre">components</span></code> multilink of the other issue.</p>
  937 <p>You can also link between different classes. So you can modify
  938 the issue definition to include:</p>
  939 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">issue</span> <span class="o">=</span> <span class="n">IssueClass</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;issue&quot;</span><span class="p">,</span>
  940           <span class="o">...</span>
  941           <span class="n">assigned_to</span> <span class="o">=</span> <span class="n">Link</span><span class="p">(</span><span class="s2">&quot;user&quot;</span><span class="p">,</span> <span class="n">rev_multilink</span><span class="o">=</span><span class="s2">&quot;responsibleFor&quot;</span><span class="p">),</span>
  942           <span class="o">...</span> <span class="p">)</span>
  943 </pre></div>
  944 </div>
  945 <p>This makes it easy to list all issues that the user is responsible
  946 for (aka assigned_to).</p>
  947 </li>
  948 </ul>
  949 <ul id="index-27">
  950 <li><p class="first">The <code class="docutils literal"><span class="pre">msg_header_property</span></code> is used by the mail gateway when sending
  951 out messages. When a link or multilink property of an issue changes,
  952 roundup creates email headers of the form:</p>
  953 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">X</span><span class="o">-</span><span class="n">Roundup</span><span class="o">-</span><span class="n">issue</span><span class="o">-</span><span class="n">prop</span><span class="p">:</span> <span class="n">value</span>
  954 </pre></div>
  955 </div>
  956 <p>where <code class="docutils literal"><span class="pre">value</span></code> is the <code class="docutils literal"><span class="pre">name</span></code> property for the linked item(s).
  957 For example, if you have a multilink for attached_files in your
  958 issue, you will see a header:</p>
  959 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">X</span><span class="o">-</span><span class="n">Roundup</span><span class="o">-</span><span class="n">issue</span><span class="o">-</span><span class="n">attached_files</span><span class="p">:</span> <span class="n">MySpecialFile</span><span class="o">.</span><span class="n">doc</span><span class="p">,</span> <span class="n">HisResume</span><span class="o">.</span><span class="n">txt</span>
  960 </pre></div>
  961 </div>
  962 <p>when the class for attached files is defined as:</p>
  963 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">file</span> <span class="o">=</span> <span class="n">FileClass</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;file&quot;</span><span class="p">,</span>
  964          <span class="n">name</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  965 </pre></div>
  966 </div>
  967 <p><code class="docutils literal"><span class="pre">MySpecialFile.doc</span></code> is the name for the file object.</p>
  968 <p>If you have an <code class="docutils literal"><span class="pre">assigned_to</span></code> property in your issue class that
  969 links to the user class and you want to add a header:</p>
  970 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">X</span><span class="o">-</span><span class="n">Roundup</span><span class="o">-</span><span class="n">issue</span><span class="o">-</span><span class="n">assigned_to</span><span class="p">:</span> <span class="o">...</span>
  971 </pre></div>
  972 </div>
  973 <p>so that the mail recipients can filter emails where
  974 <code class="docutils literal"><span class="pre">X-Roundup-issue-assigned_to:</span> <span class="pre">name</span></code> that contains their
  975 username. The user class is defined as:</p>
  976 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">user</span> <span class="o">=</span> <span class="n">Class</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="s2">&quot;user&quot;</span><span class="p">,</span>
  977          <span class="n">username</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  978          <span class="n">password</span><span class="o">=</span><span class="n">Password</span><span class="p">(),</span>
  979          <span class="n">address</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  980          <span class="n">realname</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  981          <span class="n">phone</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  982          <span class="n">organisation</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  983          <span class="n">alternate_addresses</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>
  984          <span class="n">queries</span><span class="o">=</span><span class="n">Multilink</span><span class="p">(</span><span class="s1">&#39;query&#39;</span><span class="p">),</span>
  985          <span class="n">roles</span><span class="o">=</span><span class="n">String</span><span class="p">(),</span>     <span class="c1"># comma-separated string of Role names</span>
  986          <span class="n">timezone</span><span class="o">=</span><span class="n">String</span><span class="p">())</span>
  987 </pre></div>
  988 </div>
  989 <p>Because there is no <code class="docutils literal"><span class="pre">name</span></code> parameter for the user class, there
  990 will be no header. However setting:</p>
  991 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">assigned_to</span><span class="o">=</span><span class="n">Link</span><span class="p">(</span><span class="s2">&quot;user&quot;</span><span class="p">,</span> <span class="n">msg_header_property</span><span class="o">=</span><span class="s2">&quot;username&quot;</span><span class="p">)</span>
  992 </pre></div>
  993 </div>
  994 <p>will make the mail gateway generate an <code class="docutils literal"><span class="pre">X-Roundup-issue-assigned_to</span></code>
  995 using the username property of the linked user.</p>
  996 <p>Assume assigned_to for an issue is linked to the user with
  997 username=joe_user, setting:</p>
  998 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">msg_header_property</span><span class="o">=</span><span class="s2">&quot;username&quot;</span>
  999 </pre></div>
 1000 </div>
 1001 <p>for the assigned_to property will generated message headers of the
 1002 form:</p>
 1003 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">X</span><span class="o">-</span><span class="n">Roundup</span><span class="o">-</span><span class="n">issue</span><span class="o">-</span><span class="n">assigned_to</span><span class="p">:</span> <span class="n">joe_user</span>
 1004 </pre></div>
 1005 </div>
 1006 <p>for emails sent on issues where joe_user has been assigned to the issue.</p>
 1007 <p>If this property is set to the empty string “”, it will prevent
 1008 the header from being generated on outgoing mail.</p>
 1009 </li>
 1010 </ul>
 1011 </li>
 1012 </ul>
 1013 <p id="index-28">All Classes automatically have a number of properties by default:</p>
 1014 <dl class="docutils">
 1015 <dt><em>creator</em></dt>
 1016 <dd>Link to the user that created the item.</dd>
 1017 <dt><em>creation</em></dt>
 1018 <dd>Date the item was created.</dd>
 1019 <dt><em>actor</em></dt>
 1020 <dd>Link to the user that last modified the item.</dd>
 1021 <dt><em>activity</em></dt>
 1022 <dd>Date the item was last modified.</dd>
 1023 </dl>
 1024 </div>
 1025 <div class="section" id="fileclass">
 1026 <span id="index-29"></span><h4>FileClass<a class="headerlink" href="#fileclass" title="Permalink to this headline"></a></h4>
 1027 <p>FileClasses save their “content” attribute off in a separate file from
 1028 the rest of the database. This reduces the number of large entries in
 1029 the database, which generally makes databases more efficient, and also
 1030 allows us to use command-line tools to operate on the files. They are
 1031 stored in the files sub-directory of the <code class="docutils literal"><span class="pre">'db'</span></code> directory in your
 1032 tracker. FileClasses also have a “type” attribute to store the MIME
 1033 type of the file.</p>
 1034 </div>
 1035 <div class="section" id="issueclass">
 1036 <span id="index-30"></span><h4>IssueClass<a class="headerlink" href="#issueclass" title="Permalink to this headline"></a></h4>
 1037 <p>IssueClasses automatically include the “messages”, “files”, “nosy”, and
 1038 “superseder” properties.</p>
 1039 <p>The messages and files properties list the links to the messages and
 1040 files related to the issue. The nosy property is a list of links to
 1041 users who wish to be informed of changes to the issue - they get “CC’ed”
 1042 e-mails when messages are sent to or generated by the issue. The nosy
 1043 reactor (in the <code class="docutils literal"><span class="pre">'detectors'</span></code> directory) handles this action. The
 1044 superseder link indicates an issue which has superseded this one.</p>
 1045 <p>They also have the dynamically generated “creation”, “activity” and
 1046 “creator” properties.</p>
 1047 <p>The value of the “creation” property is the date when an item was
 1048 created, and the value of the “activity” property is the date when any
 1049 property on the item was last edited (equivalently, these are the dates
 1050 on the first and last records in the item’s journal). The “creator”
 1051 property holds a link to the user that created the issue.</p>
 1052 </div>
 1053 <div class="section" id="setkey-property">
 1054 <h4>setkey(property)<a class="headerlink" href="#setkey-property" title="Permalink to this headline"></a></h4>
 1055 <p id="index-31">Select a String property of the class to be the key property. The key
 1056 property must be unique, and allows references to the items in the class
 1057 by the content of the key property. That is, we can refer to users by
 1058 their username: for example, let’s say that there’s an issue in roundup,
 1059 issue 23. There’s also a user, richard, who happens to be user 2. To
 1060 assign an issue to him, we could do either of:</p>
 1061 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">roundup</span><span class="o">-</span><span class="n">admin</span> <span class="nb">set</span> <span class="n">issue23</span> <span class="n">assignedto</span><span class="o">=</span><span class="mi">2</span>
 1062 </pre></div>
 1063 </div>
 1064 <p>or:</p>
 1065 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">roundup</span><span class="o">-</span><span class="n">admin</span> <span class="nb">set</span> <span class="n">issue23</span> <span class="n">assignedto</span><span class="o">=</span><span class="n">richard</span>
 1066 </pre></div>
 1067 </div>
 1068 <p>Note, the same thing can be done in the web and e-mail interfaces.</p>
 1069 </div>
 1070 <div class="section" id="setlabelprop-property">
 1071 <h4>setlabelprop(property)<a class="headerlink" href="#setlabelprop-property" title="Permalink to this headline"></a></h4>
 1072 <p>Select a property of the class to be the label property. The label
 1073 property is used whereever an item should be uniquely identified, e.g.,
 1074 when displaying a link to an item. If setlabelprop is not specified for
 1075 a class, the following values are tried for the label:</p>
 1076 <blockquote>
 1077 <div><ul class="simple">
 1078 <li>the key of the class (see the <a class="reference internal" href="#setkey-property">setkey(property)</a> section above)</li>
 1079 <li>the “name” property</li>
 1080 <li>the “title” property</li>
 1081 <li>the first property from the sorted property name list</li>
 1082 </ul>
 1083 </div></blockquote>
 1084 <p>So in most cases you can get away without specifying setlabelprop
 1085 explicitly.</p>
 1086 <p>You should make sure that users have View access to this property or
 1087 the id property for a class. If the property can not be viewed by a
 1088 user, looping over items in the class (e.g. messages attached to an
 1089 issue) will not work.</p>
 1090 </div>
 1091 <div class="section" id="setorderprop-property">
 1092 <h4>setorderprop(property)<a class="headerlink" href="#setorderprop-property" title="Permalink to this headline"></a></h4>
 1093 <p>Select a property of the class to be the order property. The order
 1094 property is used whenever using a default sort order for the class,
 1095 e.g., when grouping or sorting class A by a link to class B in the user
 1096 interface, the order property of class B is used for sorting.  If
 1097 setorderprop is not specified for a class, the following values are tried
 1098 for the order property:</p>
 1099 <blockquote>
 1100 <div><ul class="simple">
 1101 <li>the property named “order”</li>
 1102 <li>the label property (see <a class="reference internal" href="#setlabelprop-property">setlabelprop(property)</a> above)</li>
 1103 </ul>
 1104 </div></blockquote>
 1105 <p>So in most cases you can get away without specifying setorderprop
 1106 explicitly.</p>
 1107 </div>
 1108 <div class="section" id="create-information">
 1109 <h4>create(information)<a class="headerlink" href="#create-information" title="Permalink to this headline"></a></h4>
 1110 <p>Create an item in the database. This is generally used to create items
 1111 in the “definitional” classes like “priority” and “status”.</p>
 1112 </div>
 1113 <div class="section" id="a-note-about-ordering">
 1114 <h4>A note about ordering<a class="headerlink" href="#a-note-about-ordering" title="Permalink to this headline"></a></h4>
 1115 <p>When we sort items in the hyperdb, we use one of a number of methods,
 1116 depending on the properties being sorted on:</p>
 1117 <ol class="arabic simple">
 1118 <li>If it’s a String, Integer, Number, Date or Interval property, we
 1119 just sort the scalar value of the property. Strings are sorted
 1120 case-sensitively.</li>
 1121 <li>If it’s a Link property, we sort by either the linked item’s “order”
 1122 property (if it has one) or the linked item’s “id”.</li>
 1123 <li>Mulitlinks sort similar to #2, but we start with the first Multilink
 1124 list item, and if they’re the same, we sort by the second item, and
 1125 so on.</li>
 1126 </ol>
 1127 <p>Note that if an “order” property is defined on a Class that is used for
 1128 sorting, all items of that Class <em>must</em> have a value against the “order”
 1129 property, or sorting will result in random ordering.</p>
 1130 </div>
 1131 </div>
 1132 <div class="section" id="examples-of-adding-to-your-schema">
 1133 <h3><a class="toc-backref" href="#id17">Examples of adding to your schema</a><a class="headerlink" href="#examples-of-adding-to-your-schema" title="Permalink to this headline"></a></h3>
 1134 <p>Some examples are in the <a class="reference internal" href="#customexamples"><span class="std std-ref">Examples</span></a> section below.</p>
 1135 <p>Also the <a class="reference external" href="https://wiki.roundup-tracker.org/">Roundup wiki</a> has additional examples of how schemas can be
 1136 customised to add new functionality.</p>
 1137 </div>
 1138 </div>
 1139 <div class="section" id="detectors-adding-behaviour-to-your-tracker">
 1140 <span id="index-32"></span><h2><a class="toc-backref" href="#id18">Detectors - adding behaviour to your tracker</a><a class="headerlink" href="#detectors-adding-behaviour-to-your-tracker" title="Permalink to this headline"></a></h2>
 1141 <p id="detectors">Detectors are initialised every time you open your tracker database, so
 1142 you’re free to add and remove them any time, even after the database is
 1143 initialised via the <code class="docutils literal"><span class="pre">roundup-admin</span> <span class="pre">initialise</span></code> command.</p>
 1144 <p>The detectors in your tracker fire <em>before</em> (<strong>auditors</strong>) and <em>after</em>
 1145 (<strong>reactors</strong>) changes to the contents of your database. They are Python
 1146 modules that sit in your tracker’s <code class="docutils literal"><span class="pre">detectors</span></code> directory. You will
 1147 have some installed by default - have a look. You can write new
 1148 detectors or modify the existing ones. The existing detectors installed
 1149 for you are:</p>
 1150 <dl class="docutils" id="index-33">
 1151 <dt><strong>nosyreaction.py</strong></dt>
 1152 <dd>This provides the automatic nosy list maintenance and email sending.
 1153 The nosy reactor (<code class="docutils literal"><span class="pre">nosyreaction</span></code>) fires when new messages are added
 1154 to issues. The nosy auditor (<code class="docutils literal"><span class="pre">updatenosy</span></code>) fires when issues are
 1155 changed, and figures out what changes need to be made to the nosy list
 1156 (such as adding new authors, etc.)</dd>
 1157 <dt><strong>statusauditor.py</strong></dt>
 1158 <dd>This provides the <code class="docutils literal"><span class="pre">chatty</span></code> auditor which changes the issue status
 1159 from <code class="docutils literal"><span class="pre">unread</span></code> or <code class="docutils literal"><span class="pre">closed</span></code> to <code class="docutils literal"><span class="pre">chatting</span></code> if new messages appear.
 1160 It also provides the <code class="docutils literal"><span class="pre">presetunread</span></code> auditor which pre-sets the
 1161 status to <code class="docutils literal"><span class="pre">unread</span></code> on new items if the status isn’t explicitly
 1162 defined.</dd>
 1163 <dt><strong>messagesummary.py</strong></dt>
 1164 <dd>Generates the <code class="docutils literal"><span class="pre">summary</span></code> property for new messages based on the message
 1165 content.</dd>
 1166 <dt><strong>userauditor.py</strong></dt>
 1167 <dd>Verifies the content of some of the user fields (email addresses and
 1168 roles lists).</dd>
 1169 </dl>
 1170 <p>If you don’t want this default behaviour, you’re completely free to change
 1171 or remove these detectors.</p>
 1172 <p>See the detectors section in the <a class="reference external" href="design.html">design document</a> for details of the
 1173 interface for detectors.</p>
 1174 <div class="section" id="detector-api">
 1175 <span id="index-34"></span><h3><a class="toc-backref" href="#id19">Detector API</a><a class="headerlink" href="#detector-api" title="Permalink to this headline"></a></h3>
 1176 <p id="index-35">Auditors are called with the arguments:</p>
 1177 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">audit</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">cl</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="n">newdata</span><span class="p">)</span>
 1178 </pre></div>
 1179 </div>
 1180 <p>where <code class="docutils literal"><span class="pre">db</span></code> is the database, <code class="docutils literal"><span class="pre">cl</span></code> is an instance of Class or
 1181 IssueClass within the database, and <code class="docutils literal"><span class="pre">newdata</span></code> is a dictionary mapping
 1182 property names to values.</p>
 1183 <p>For a <code class="docutils literal"><span class="pre">create()</span></code> operation, the <code class="docutils literal"><span class="pre">itemid</span></code> argument is None and
 1184 newdata contains all of the initial property values with which the item
 1185 is about to be created.</p>
 1186 <p>For a <code class="docutils literal"><span class="pre">set()</span></code> operation, newdata contains only the names and values of
 1187 properties that are about to be changed.</p>
 1188 <p>For a <code class="docutils literal"><span class="pre">retire()</span></code> or <code class="docutils literal"><span class="pre">restore()</span></code> operation, newdata is None.</p>
 1189 <p id="index-36">Reactors are called with the arguments:</p>
 1190 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">react</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">cl</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="n">olddata</span><span class="p">)</span>
 1191 </pre></div>
 1192 </div>
 1193 <p>where <code class="docutils literal"><span class="pre">db</span></code> is the database, <code class="docutils literal"><span class="pre">cl</span></code> is an instance of Class or
 1194 IssueClass within the database, and <code class="docutils literal"><span class="pre">olddata</span></code> is a dictionary mapping
 1195 property names to values.</p>
 1196 <p>For a <code class="docutils literal"><span class="pre">create()</span></code> operation, the <code class="docutils literal"><span class="pre">itemid</span></code> argument is the id of the
 1197 newly-created item and <code class="docutils literal"><span class="pre">olddata</span></code> is None.</p>
 1198 <p>For a <code class="docutils literal"><span class="pre">set()</span></code> operation, <code class="docutils literal"><span class="pre">olddata</span></code> contains the names and previous
 1199 values of properties that were changed.</p>
 1200 <p>For a <code class="docutils literal"><span class="pre">retire()</span></code> or <code class="docutils literal"><span class="pre">restore()</span></code> operation, <code class="docutils literal"><span class="pre">itemid</span></code> is the id of
 1201 the retired or restored item and <code class="docutils literal"><span class="pre">olddata</span></code> is None.</p>
 1202 </div>
 1203 <div class="section" id="additional-detectors-ready-for-use">
 1204 <span id="index-37"></span><h3><a class="toc-backref" href="#id20">Additional Detectors Ready For Use</a><a class="headerlink" href="#additional-detectors-ready-for-use" title="Permalink to this headline"></a></h3>
 1205 <p>Sample additional detectors that have been found useful will appear in
 1206 the <code class="docutils literal"><span class="pre">'detectors'</span></code> directory of the Roundup distribution. If you want
 1207 to use one, copy it to the <code class="docutils literal"><span class="pre">'detectors'</span></code> of your tracker instance:</p>
 1208 <dl class="docutils">
 1209 <dt><strong>irker.py</strong></dt>
 1210 <dd>This detector sends notification on IRC through an irker daemon
 1211 (<a class="reference external" href="http://www.catb.org/esr/irker/">http://www.catb.org/esr/irker/</a>) when issues are created or messages
 1212 are added.  In order to use it you need to install irker, start the
 1213 irkerd daemon, and add an <code class="docutils literal"><span class="pre">[irker]</span></code> section in <code class="docutils literal"><span class="pre">detectors/config.ini</span></code>
 1214 that contains a comma-separated list of channels where the messages should
 1215 be sent, e.g. <code class="docutils literal"><span class="pre">channels</span> <span class="pre">=</span> <span class="pre">irc://chat.freenode.net/channelname</span></code>.</dd>
 1216 <dt><strong>newissuecopy.py</strong></dt>
 1217 <dd>This detector sends an email to a team address whenever a new issue is
 1218 created. The address is hard-coded into the detector, so edit it
 1219 before you use it (look for the text <a class="reference external" href="mailto:'team&#37;&#52;&#48;team&#46;host">‘team<span>&#64;</span>team<span>&#46;</span>host</a>’) or you’ll get
 1220 email errors!</dd>
 1221 <dt><strong>creator_resolution.py</strong></dt>
 1222 <dd>Catch attempts to set the status to “resolved” - if the assignedto
 1223 user isn’t the creator, then set the status to “confirm-done”. Note that
 1224 “classic” Roundup doesn’t have that status, so you’ll have to add it. If
 1225 you don’t want to though, it’ll just use “in-progress” instead.</dd>
 1226 <dt><strong>email_auditor.py</strong></dt>
 1227 <dd>If a file added to an issue is of type message/rfc822, we tack on the
 1228 extension .eml.
 1229 The reason for this is that Microsoft Internet Explorer will not open
 1230 things with a .eml attachment, as they deem it ‘unsafe’. Worse yet,
 1231 they’ll just give you an incomprehensible error message. For more
 1232 information, see the detector code - it has a length explanation.</dd>
 1233 </dl>
 1234 </div>
 1235 <div class="section" id="auditor-or-reactor">
 1236 <span id="index-38"></span><h3><a class="toc-backref" href="#id21">Auditor or Reactor?</a><a class="headerlink" href="#auditor-or-reactor" title="Permalink to this headline"></a></h3>
 1237 <p>Generally speaking, the following rules should be observed:</p>
 1238 <dl class="docutils">
 1239 <dt><strong>Auditors</strong></dt>
 1240 <dd>Are used for <a class="reference internal" href="#vetoing-creation-of-or-changes-to-items">vetoing creation of or changes to items</a>. They might
 1241 also make automatic changes to item properties.</dd>
 1242 <dt><strong>Reactors</strong></dt>
 1243 <dd>Detect changes in the database and react accordingly. They should avoid
 1244 making changes to the database where possible, as this could create
 1245 detector loops.</dd>
 1246 </dl>
 1247 </div>
 1248 <div class="section" id="vetoing-creation-of-or-changes-to-items">
 1249 <h3><a class="toc-backref" href="#id22">Vetoing creation of or changes to items</a><a class="headerlink" href="#vetoing-creation-of-or-changes-to-items" title="Permalink to this headline"></a></h3>
 1250 <p>Auditors may raise the <code class="docutils literal"><span class="pre">Reject</span></code> exception to prevent the creation of
 1251 or changes to items in the database.  The mail gateway, for example, will
 1252 not attach files or messages to issues when the creation of those files or
 1253 messages are prevented through the <code class="docutils literal"><span class="pre">Reject</span></code> exception. It’ll also not create
 1254 users if that creation is <code class="docutils literal"><span class="pre">Reject</span></code>’ed too.</p>
 1255 <p>To use, simply add at the top of your auditor:</p>
 1256 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">roundup.exceptions</span> <span class="k">import</span> <span class="n">Reject</span>
 1257 </pre></div>
 1258 </div>
 1259 <p>And then when your rejection criteria have been detected, simply:</p>
 1260 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">raise</span> <span class="n">Reject</span><span class="p">(</span><span class="s1">&#39;Description of error&#39;</span><span class="p">)</span>
 1261 </pre></div>
 1262 </div>
 1263 <p>Error messages raised with <code class="docutils literal"><span class="pre">Reject</span></code> automatically have any HTML content
 1264 escaped before being displayed to the user. To display an error message to the
 1265 user without performing any HTML escaping the <code class="docutils literal"><span class="pre">RejectRaw</span></code> should be used. All
 1266 security implications should be carefully considering before using
 1267 <code class="docutils literal"><span class="pre">RejectRaw</span></code>.</p>
 1268 </div>
 1269 <div class="section" id="generating-email-from-roundup">
 1270 <h3><a class="toc-backref" href="#id23">Generating email from Roundup</a><a class="headerlink" href="#generating-email-from-roundup" title="Permalink to this headline"></a></h3>
 1271 <p>The module <code class="docutils literal"><span class="pre">roundup.mailer</span></code> contains most of the nuts-n-bolts required
 1272 to generate email messages from Roundup.</p>
 1273 <p>In addition, the <code class="docutils literal"><span class="pre">IssueClass</span></code> methods <code class="docutils literal"><span class="pre">nosymessage()</span></code> and
 1274 <code class="docutils literal"><span class="pre">send_message()</span></code> are used to generate nosy messages, and may generate
 1275 messages which only consist of a change note (ie. the message id parameter
 1276 is not required - this is referred to as a “System Message” because it
 1277 comes from “the system” and not a user).</p>
 1278 <span class="target" id="index-39"></span></div>
 1279 </div>
 1280 <div class="section" id="extensions-adding-capabilities-to-your-tracker">
 1281 <span id="index-40"></span><h2><a class="toc-backref" href="#id24">Extensions - adding capabilities to your tracker</a><a class="headerlink" href="#extensions-adding-capabilities-to-your-tracker" title="Permalink to this headline"></a></h2>
 1282 <p id="extensions">While <a class="reference internal" href="#detectors">detectors</a> add new behavior by reacting to changes in tracked
 1283 objects, <cite>extensions</cite> add new actions and utilities to Roundup, which
 1284 are mostly used to enhance web interface.</p>
 1285 <p>You can create an extension by creating Python file in your tracker
 1286 <code class="docutils literal"><span class="pre">extensions</span></code> directory.  All files from this dir are loaded when
 1287 tracker instance is created, at which point it calls <code class="docutils literal"><span class="pre">init(instance)</span></code>
 1288 from each file supplying itself as a first argument.</p>
 1289 <p>Note that at this point web interface is not loaded, but extensions still
 1290 can register actions for in tracker instance. This may be fixed in
 1291 Roundup 1.6 by introducing <code class="docutils literal"><span class="pre">init_web(client)</span></code> callback or a more
 1292 flexible extension point mechanism.</p>
 1293 <blockquote>
 1294 <div><ul class="simple">
 1295 <li><code class="docutils literal"><span class="pre">instance.registerUtil</span></code> is used for adding <a class="reference internal" href="#templating-utilities">templating utilities</a>
 1296 (see <a class="reference internal" href="#adding-a-time-log-to-your-issues">adding a time log to your issues</a> for an example)</li>
 1297 <li><code class="docutils literal"><span class="pre">instance.registerAction</span></code> is used to add more actions to instance
 1298 and to web interface. See <a class="reference internal" href="#defining-new-web-actions">Defining new web actions</a> for details.
 1299 Generic action can be added by inheriting from <code class="docutils literal"><span class="pre">action.Action</span></code>
 1300 instead of <code class="docutils literal"><span class="pre">cgi.action.Action</span></code>.</li>
 1301 </ul>
 1302 </div></blockquote>
 1303 </div>
 1304 <div class="section" id="interfaces-py-hooking-into-the-core-of-roundup">
 1305 <h2><a class="toc-backref" href="#id25">interfaces.py - hooking into the core of roundup</a><a class="headerlink" href="#interfaces-py-hooking-into-the-core-of-roundup" title="Permalink to this headline"></a></h2>
 1306 <p id="interfaces-py">There is a magic trick for hooking into the core of roundup. Using
 1307 this you can:</p>
 1308 <blockquote>
 1309 <div><ul class="simple">
 1310 <li>modify class data structures</li>
 1311 <li>monkey patch core code to add new functionality</li>
 1312 <li>modify the email gateway</li>
 1313 <li>add new rest endpoints</li>
 1314 </ul>
 1315 </div></blockquote>
 1316 <p>but with great power comes great responsibility.</p>
 1317 <p>Interfaces.py has been around since the earliest releases of roundup
 1318 and used to be the main way to get a lot of customization done. In
 1319 modern roundup, the <a class="reference internal" href="#extensions">extensions</a> mechanism is used, but there are places
 1320 where interfaces.py is still useful.</p>
 1321 <div class="section" id="example-changing-cache-control-headers">
 1322 <h3><a class="toc-backref" href="#id26">Example: Changing Cache-Control headers</a><a class="headerlink" href="#example-changing-cache-control-headers" title="Permalink to this headline"></a></h3>
 1323 <p>The Client class in cgi/client.py has a lookup table that is used to
 1324 set the Cache-Control headers for static files. The entries in this
 1325 table are set from interfaces.py using:</p>
 1326 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">roundup.cgi.client</span> <span class="k">import</span> <span class="n">Client</span>
 1327 
 1328 <span class="n">Client</span><span class="o">.</span><span class="n">Cache_Control</span><span class="p">[</span><span class="s1">&#39;text/css&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;public, max-age=3600&quot;</span>
 1329 <span class="n">Client</span><span class="o">.</span><span class="n">Cache_Control</span><span class="p">[</span><span class="s1">&#39;application/javascript&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;public, max-age=30&quot;</span>
 1330 <span class="n">Client</span><span class="o">.</span><span class="n">Cache_Control</span><span class="p">[</span><span class="s1">&#39;rss.xml&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;public, max-age=900&quot;</span>
 1331 <span class="n">Client</span><span class="o">.</span><span class="n">Cache_Control</span><span class="p">[</span><span class="s1">&#39;local.js&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;public, max-age=7200&quot;</span>
 1332 </pre></div>
 1333 </div>
 1334 <p>In this case static files delivered using &#64;&#64;file will have cache
 1335 headers set. These files are searched for along the <cite>static_files</cite>
 1336 path in the tracker’s <cite>config.ini</cite>. In the example above:</p>
 1337 <blockquote>
 1338 <div><ul class="simple">
 1339 <li>a css file (e.g. &#64;&#64;file/style.css) will be cached for an hour</li>
 1340 <li>javascript files (e.g. &#64;&#64;file/libraries/jquery.js) will be cached
 1341 for 30 seconds</li>
 1342 <li>a file named rss.xml will be cached for 15 minutes</li>
 1343 <li>a file named local.js will be cached for 2 hours</li>
 1344 </ul>
 1345 </div></blockquote>
 1346 <p>Note that a file name match overrides the mime type settings.</p>
 1347 </div>
 1348 <div class="section" id="example-implement-password-complexity-checking">
 1349 <h3><a class="toc-backref" href="#id27">Example: Implement password complexity checking</a><a class="headerlink" href="#example-implement-password-complexity-checking" title="Permalink to this headline"></a></h3>
 1350 <p id="index-41">This example uses the <a class="reference external" href="https://github.com/dwolfhub/zxcvbn-python">zxcvbn</a> module that you can place in the zxcvbn
 1351 subdirectory of your tracker’s lib directory.</p>
 1352 <p>If you add this to the interfaces.py file in the root directory of
 1353 your tracker (same place as schema.py):</p>
 1354 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">roundup.password</span> <span class="k">as</span> <span class="nn">password</span>
 1355 <span class="kn">from</span> <span class="nn">roundup.exceptions</span> <span class="k">import</span> <span class="n">Reject</span>
 1356 <span class="kn">from</span> <span class="nn">zxcvbn</span> <span class="k">import</span> <span class="n">zxcvbn</span>
 1357 
 1358 <span class="c1"># monkey patch the setPassword method with this method</span>
 1359 <span class="c1"># that checks password strength.</span>
 1360 <span class="n">origPasswordFunc</span> <span class="o">=</span> <span class="n">password</span><span class="o">.</span><span class="n">Password</span><span class="o">.</span><span class="n">setPassword</span>
 1361 <span class="k">def</span> <span class="nf">mpPasswordFunc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">plaintext</span><span class="p">,</span> <span class="n">scheme</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 1362     <span class="sd">&quot;&quot;&quot; Replace the password set function with one that</span>
 1363 <span class="sd">        verifies that the password is complex enough. It</span>
 1364 <span class="sd">        has to be done at this point and not in an auditor</span>
 1365 <span class="sd">        as the auditor only sees the encrypted password.</span>
 1366 <span class="sd">    &quot;&quot;&quot;</span>
 1367     <span class="n">results</span> <span class="o">=</span> <span class="n">zxcvbn</span><span class="p">(</span><span class="n">plaintext</span><span class="p">)</span>
 1368     <span class="k">if</span> <span class="n">results</span><span class="p">[</span><span class="s1">&#39;score&#39;</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">:</span>
 1369         <span class="n">l</span> <span class="o">=</span> <span class="p">[]</span>
 1370         <span class="nb">map</span><span class="p">(</span><span class="n">l</span><span class="o">.</span><span class="n">extend</span><span class="p">,</span> <span class="p">[[</span><span class="n">results</span><span class="p">[</span><span class="s1">&#39;feedback&#39;</span><span class="p">][</span><span class="s1">&#39;warning&#39;</span><span class="p">]],</span> <span class="n">results</span><span class="p">[</span><span class="s1">&#39;feedback&#39;</span><span class="p">][</span><span class="s1">&#39;suggestions&#39;</span><span class="p">]])</span>
 1371         <span class="n">errormsg</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
 1372         <span class="k">raise</span> <span class="n">Reject</span> <span class="p">(</span><span class="s2">&quot;Password is too easy to guess. &quot;</span> <span class="o">+</span> <span class="n">errormsg</span><span class="p">)</span>
 1373     <span class="k">return</span> <span class="n">origPasswordFunc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">plaintext</span><span class="p">,</span> <span class="n">scheme</span><span class="p">,</span> <span class="n">config</span><span class="o">=</span><span class="n">config</span><span class="p">)</span>
 1374 
 1375 <span class="n">password</span><span class="o">.</span><span class="n">Password</span><span class="o">.</span><span class="n">setPassword</span> <span class="o">=</span> <span class="n">mpPasswordFunc</span>
 1376 </pre></div>
 1377 </div>
 1378 <p>it replaces the setPassword method in the Password class. The new
 1379 version validates that the password is sufficiently complex. Then it
 1380 passes off the setting of password to the original method.</p>
 1381 </div>
 1382 <div class="section" id="example-enhance-time-intervals">
 1383 <h3><a class="toc-backref" href="#id28">Example: Enhance time intervals</a><a class="headerlink" href="#example-enhance-time-intervals" title="Permalink to this headline"></a></h3>
 1384 <p>To make the user interface easier to use, you may want to support
 1385 other forms for intervals. For example you can support an interval
 1386 like 1.5 by interpreting it the same as 1:30 (1 hour 30 minutes).
 1387 Also you can allow a bare integer (e.g. 45) as a number of minutes.</p>
 1388 <p>To do this we intercept the from_raw method of the Interval class in
 1389 hyperdb.py with:</p>
 1390 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">roundup.hyperdb</span> <span class="k">as</span> <span class="nn">hyperdb</span>
 1391 <span class="n">origFrom_Raw</span> <span class="o">=</span> <span class="n">hyperdb</span><span class="o">.</span><span class="n">Interval</span><span class="o">.</span><span class="n">from_raw</span>
 1392 
 1393 <span class="k">def</span> <span class="nf">normalizeperiod</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>
 1394     <span class="sd">&#39;&#39;&#39; Convert alternate time forms into standard interval format</span>
 1395 
 1396 <span class="sd">        [+-] [#y] [#m] [#w] [#d] [[[H]H:MM]:SS]</span>
 1397 
 1398 <span class="sd">        if value is float, it&#39;s hour and fractional hours</span>
 1399 <span class="sd">        if value is integer, it&#39;s number of minutes</span>
 1400 <span class="sd">    &#39;&#39;&#39;</span>
 1401     <span class="k">if</span> <span class="s2">&quot;:&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
 1402         <span class="c1"># Not a specified interval</span>
 1403         <span class="c1"># if int consider number of minutes</span>
 1404         <span class="k">try</span><span class="p">:</span>
 1405             <span class="n">isMinutes</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
 1406             <span class="n">minutes</span> <span class="o">=</span> <span class="n">isMinutes</span><span class="o">%</span><span class="mi">60</span>
 1407             <span class="n">hours</span> <span class="o">=</span> <span class="p">(</span><span class="n">isMinutes</span> <span class="o">-</span> <span class="n">minutes</span><span class="p">)</span> <span class="o">/</span> <span class="mi">60</span>
 1408             <span class="n">value</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%d</span><span class="s2">:</span><span class="si">%d</span><span class="s2">&quot;</span><span class="o">%</span><span class="p">(</span><span class="n">hours</span><span class="p">,</span><span class="n">minutes</span><span class="p">)</span>
 1409         <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
 1410             <span class="k">pass</span>
 1411         <span class="c1"># if float, consider it number of hours and fractional hours.</span>
 1412         <span class="kn">import</span> <span class="nn">math</span>
 1413         <span class="k">try</span><span class="p">:</span>
 1414             <span class="n">afterdecimal</span><span class="p">,</span> <span class="n">beforedecimal</span> <span class="o">=</span> <span class="n">math</span><span class="o">.</span><span class="n">modf</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
 1415             <span class="n">value</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%d</span><span class="s2">:</span><span class="si">%d</span><span class="s2">&quot;</span><span class="o">%</span><span class="p">(</span><span class="n">beforedecimal</span><span class="p">,</span><span class="mi">60</span><span class="o">*</span><span class="n">afterdecimal</span><span class="p">)</span>
 1416         <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
 1417             <span class="k">pass</span>
 1418 
 1419     <span class="k">return</span> <span class="n">origFrom_Raw</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">)</span>
 1420 
 1421 <span class="n">hyperdb</span><span class="o">.</span><span class="n">Interval</span><span class="o">.</span><span class="n">from_raw</span> <span class="o">=</span> <span class="n">normalizeperiod</span>
 1422 </pre></div>
 1423 </div>
 1424 <p>any call to convert an interval from raw form now has two simpler
 1425 (and more friendly) ways to specify common time intervals.</p>
 1426 </div>
 1427 <div class="section" id="example-modifying-the-mail-gateway">
 1428 <h3><a class="toc-backref" href="#id29">Example: Modifying the mail gateway</a><a class="headerlink" href="#example-modifying-the-mail-gateway" title="Permalink to this headline"></a></h3>
 1429 <p>One site receives email on a main gateway. The virtual alias delivery
 1430 table on the postfix server is configured with:</p>
 1431 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">test</span><span class="o">-</span><span class="n">issues</span><span class="nd">@example</span><span class="o">.</span><span class="n">com</span>  <span class="n">roundup</span><span class="o">-</span><span class="n">test</span><span class="nd">@roundup</span><span class="o">-</span><span class="n">vm</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span>
 1432 <span class="n">test</span><span class="o">-</span><span class="n">support</span><span class="nd">@example</span><span class="o">.</span><span class="n">com</span> <span class="n">roundup</span><span class="o">-</span><span class="n">test</span><span class="o">+</span><span class="n">support</span><span class="o">-</span><span class="n">a</span><span class="nd">@roundup</span><span class="o">-</span><span class="n">vm</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span>
 1433 <span class="n">test</span><span class="nd">@support</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span> <span class="n">roundup</span><span class="o">-</span><span class="n">test</span><span class="o">+</span><span class="n">support</span><span class="o">-</span><span class="n">b</span><span class="nd">@roundup</span><span class="o">-</span><span class="n">vm</span><span class="o">.</span><span class="n">example</span><span class="o">.</span><span class="n">com</span>
 1434 </pre></div>
 1435 </div>
 1436 <p>These modifications to the mail gateway for roundup allows anonymous
 1437 submissions. It hides all of the requesters under the “support”
 1438 user. It also makes some other modifications to the mail parser
 1439 allowing keywords to be set and prefixes to be defined based on the
 1440 delivery alias.</p>
 1441 <p>This is the entry in interfaces.py:</p>
 1442 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">roundup.mailgw</span>
 1443 <span class="kn">import</span> <span class="nn">email.utils</span>
 1444 
 1445 <span class="k">class</span> <span class="nc">SupportTracker</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 1446     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">keyword</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 1447         <span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">=</span> <span class="n">prefix</span>
 1448         <span class="bp">self</span><span class="o">.</span><span class="n">keyword</span> <span class="o">=</span> <span class="n">keyword</span>
 1449 
 1450 <span class="c1"># Define new prefixes and keywords based on local address.</span>
 1451 <span class="n">support_trackers</span> <span class="o">=</span> <span class="p">{</span>
 1452     <span class="c1">### production instances ###</span>
 1453 
 1454     <span class="c1">### test instances ###</span>
 1455     <span class="s1">&#39;roundup-test+support-a&#39;</span><span class="p">:</span>
 1456         <span class="n">SupportTracker</span><span class="p">(</span><span class="n">prefix</span><span class="o">=</span><span class="s1">&#39;Support 1&#39;</span><span class="p">,</span> <span class="n">keyword</span><span class="o">=</span><span class="s1">&#39;support1&#39;</span><span class="p">),</span>
 1457     <span class="s1">&#39;roundup-test+support-b&#39;</span><span class="p">:</span>
 1458         <span class="n">SupportTracker</span><span class="p">(</span><span class="n">prefix</span><span class="o">=</span><span class="s1">&#39;Support 2&#39;</span><span class="p">,</span> <span class="n">keyword</span><span class="o">=</span><span class="s1">&#39;support2&#39;</span><span class="p">),</span>
 1459     <span class="s1">&#39;roundup-test2+support-a&#39;</span><span class="p">:</span>
 1460         <span class="n">SupportTracker</span><span class="p">(</span><span class="n">prefix</span><span class="o">=</span><span class="s1">&#39;Support 1&#39;</span><span class="p">,</span> <span class="n">keyword</span><span class="o">=</span><span class="s1">&#39;support1&#39;</span><span class="p">),</span>
 1461     <span class="s1">&#39;roundup-test2+support-b&#39;</span><span class="p">:</span>
 1462         <span class="n">SupportTracker</span><span class="p">(</span><span class="n">prefix</span><span class="o">=</span><span class="s1">&#39;Support 2&#39;</span><span class="p">,</span> <span class="n">keyword</span><span class="o">=</span><span class="s1">&#39;support2&#39;</span><span class="p">),</span>
 1463 <span class="p">}</span>
 1464 
 1465 <span class="k">class</span> <span class="nc">parsedMessage</span><span class="p">(</span><span class="n">roundup</span><span class="o">.</span><span class="n">mailgw</span><span class="o">.</span><span class="n">parsedMessage</span><span class="p">):</span>
 1466     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mailgw</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">support_tracker</span><span class="p">):</span>
 1467         <span class="n">roundup</span><span class="o">.</span><span class="n">mailgw</span><span class="o">.</span><span class="n">parsedMessage</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mailgw</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
 1468         <span class="k">if</span> <span class="n">support_tracker</span><span class="o">.</span><span class="n">prefix</span><span class="p">:</span>
 1469             <span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">%s</span><span class="s1">: &#39;</span> <span class="o">%</span> <span class="n">support_tracker</span><span class="o">.</span><span class="n">prefix</span>
 1470         <span class="k">else</span><span class="p">:</span>
 1471             <span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
 1472         <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span> <span class="o">=</span> <span class="p">[]</span>
 1473         <span class="k">if</span> <span class="n">support_tracker</span><span class="o">.</span><span class="n">keyword</span><span class="p">:</span>
 1474             <span class="k">try</span><span class="p">:</span>
 1475                 <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span> <span class="o">=</span> <span class="p">[</span>
 1476                     <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">keyword</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="n">support_tracker</span><span class="o">.</span><span class="n">keyword</span><span class="p">)]</span>
 1477             <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
 1478                 <span class="k">pass</span>
 1479         <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">ADD_AUTHOR_TO_NOSY</span> <span class="o">=</span> <span class="s1">&#39;no&#39;</span>
 1480         <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">ADD_RECIPIENTS_TO_NOSY</span> <span class="o">=</span> <span class="s1">&#39;no&#39;</span>
 1481         <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">MAILGW_KEEP_QUOTED_TEXT</span> <span class="o">=</span> <span class="s1">&#39;yes&#39;</span>
 1482         <span class="bp">self</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">MAILGW_LEAVE_BODY_UNCHANGED</span> <span class="o">=</span> <span class="s1">&#39;yes&#39;</span>
 1483         <span class="bp">self</span><span class="o">.</span><span class="n">classname</span> <span class="o">=</span> <span class="s1">&#39;issue&#39;</span>
 1484         <span class="bp">self</span><span class="o">.</span><span class="n">pfxmode</span> <span class="o">=</span> <span class="s1">&#39;loose&#39;</span>
 1485         <span class="bp">self</span><span class="o">.</span><span class="n">sfxmode</span> <span class="o">=</span> <span class="s1">&#39;none&#39;</span>
 1486         <span class="c1"># set the support user id</span>
 1487         <span class="bp">self</span><span class="o">.</span><span class="n">fixed_author</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">user</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s1">&#39;support&#39;</span><span class="p">)</span>
 1488         <span class="bp">self</span><span class="o">.</span><span class="n">fixed_props</span> <span class="o">=</span> <span class="p">{</span>
 1489             <span class="s1">&#39;nosy&#39;</span><span class="p">:</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">fixed_author</span><span class="p">],</span>
 1490             <span class="s1">&#39;keyword&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">keywords</span><span class="p">,</span>
 1491         <span class="p">}</span>
 1492 
 1493     <span class="k">def</span> <span class="nf">handle_help</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1494         <span class="k">pass</span>
 1495 
 1496     <span class="k">def</span> <span class="nf">check_subject</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1497         <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span><span class="p">:</span>
 1498             <span class="bp">self</span><span class="o">.</span><span class="n">subject</span> <span class="o">=</span> <span class="s1">&#39;no subject&#39;</span>
 1499 
 1500     <span class="k">def</span> <span class="nf">rego_confirm</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1501         <span class="k">pass</span>
 1502 
 1503     <span class="k">def</span> <span class="nf">get_author_id</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1504         <span class="c1"># force the support user to be the author</span>
 1505         <span class="bp">self</span><span class="o">.</span><span class="n">author</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fixed_author</span>
 1506 
 1507     <span class="k">def</span> <span class="nf">get_props</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1508         <span class="bp">self</span><span class="o">.</span><span class="n">props</span> <span class="o">=</span> <span class="p">{}</span>
 1509         <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">nodeid</span><span class="p">:</span>
 1510             <span class="bp">self</span><span class="o">.</span><span class="n">props</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">fixed_props</span><span class="p">)</span>
 1511             <span class="bp">self</span><span class="o">.</span><span class="n">props</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;</span><span class="si">%s%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span>
 1512                 <span class="bp">self</span><span class="o">.</span><span class="n">prefix</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;[&#39;</span><span class="p">,</span> <span class="s1">&#39;(&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;]&#39;</span><span class="p">,</span> <span class="s1">&#39;)&#39;</span><span class="p">)))</span>
 1513 
 1514     <span class="k">def</span> <span class="nf">get_content_and_attachments</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1515         <span class="n">roundup</span><span class="o">.</span><span class="n">mailgw</span><span class="o">.</span><span class="n">parsedMessage</span><span class="o">.</span><span class="n">get_content_and_attachments</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
 1516         <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">content</span><span class="p">:</span>
 1517             <span class="bp">self</span><span class="o">.</span><span class="n">content</span> <span class="o">=</span> <span class="s1">&#39;no text&#39;</span>
 1518         <span class="n">intro</span> <span class="o">=</span> <span class="p">[]</span>
 1519         <span class="k">for</span> <span class="n">header</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;From&#39;</span><span class="p">,</span> <span class="s1">&#39;To&#39;</span><span class="p">,</span> <span class="s1">&#39;Cc&#39;</span><span class="p">]:</span>
 1520             <span class="k">for</span> <span class="n">addr</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">getaddrlist</span><span class="p">(</span><span class="n">header</span><span class="p">):</span>
 1521                 <span class="n">intro</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1">: </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">header</span><span class="p">,</span> <span class="n">email</span><span class="o">.</span><span class="n">utils</span><span class="o">.</span><span class="n">formataddr</span><span class="p">(</span><span class="n">addr</span><span class="p">)))</span>
 1522         <span class="n">intro</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;Subject: </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span><span class="p">)</span>
 1523         <span class="n">intro</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">)</span>
 1524         <span class="bp">self</span><span class="o">.</span><span class="n">content</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">intro</span><span class="p">)</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">content</span>
 1525 
 1526 <span class="k">class</span> <span class="nc">MailGW</span><span class="p">(</span><span class="n">roundup</span><span class="o">.</span><span class="n">mailgw</span><span class="o">.</span><span class="n">MailGW</span><span class="p">):</span>
 1527     <span class="k">def</span> <span class="nf">parsed_message_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mailgw</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
 1528         <span class="n">support_tracker</span> <span class="o">=</span> <span class="kc">None</span>
 1529         <span class="c1"># The delivered-to header is unique to postfix</span>
 1530         <span class="c1"># it is the target address:</span>
 1531         <span class="c1">#   roundup-test+support-a@roundup-vm.example.com</span>
 1532         <span class="c1"># rather than</span>
 1533         <span class="c1">#   test-support@example.com</span>
 1534         <span class="n">recipients</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">getaddrlist</span><span class="p">(</span><span class="s1">&#39;delivered-to&#39;</span><span class="p">)</span>
 1535         <span class="k">if</span> <span class="n">recipients</span><span class="p">:</span>
 1536             <span class="n">localpart</span> <span class="o">=</span> <span class="n">recipients</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">rpartition</span><span class="p">(</span><span class="s1">&#39;@&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
 1537             <span class="n">support_tracker</span> <span class="o">=</span> <span class="n">support_trackers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">localpart</span><span class="p">)</span>
 1538         <span class="k">if</span> <span class="n">support_tracker</span><span class="p">:</span>
 1539             <span class="c1"># parse the mesage using the parsedMessage class</span>
 1540             <span class="c1"># defined above.</span>
 1541             <span class="k">return</span> <span class="n">parsedMessage</span><span class="p">(</span><span class="n">mailgw</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">support_tracker</span><span class="p">)</span>
 1542         <span class="k">else</span><span class="p">:</span>
 1543             <span class="c1"># parse the message normally</span>
 1544             <span class="k">return</span> <span class="n">roundup</span><span class="o">.</span><span class="n">mailgw</span><span class="o">.</span><span class="n">parsedMessage</span><span class="p">(</span><span class="n">mailgw</span><span class="p">,</span> <span class="n">message</span><span class="p">)</span>
 1545 </pre></div>
 1546 </div>
 1547 <p>This is the most complex example section. The mail gateway is also one
 1548 of the more complex subsystems in roundup, and modifying it is not
 1549 trivial.</p>
 1550 </div>
 1551 <div class="section" id="other-examples">
 1552 <h3><a class="toc-backref" href="#id30">Other Examples</a><a class="headerlink" href="#other-examples" title="Permalink to this headline"></a></h3>
 1553 <p>See the <a class="reference external" href="rest.html#programming-the-rest-api">rest interface documentation</a> for instructions on how to add
 1554 new rest endpoints using interfaces.py.</p>
 1555 </div>
 1556 </div>
 1557 <div class="section" id="database-content">
 1558 <h2><a class="toc-backref" href="#id31">Database Content</a><a class="headerlink" href="#database-content" title="Permalink to this headline"></a></h2>
 1559 <div class="admonition note">
 1560 <p class="first admonition-title">Note</p>
 1561 <p class="last">If you modify the content of definitional classes, you’ll most
 1562 likely need to edit the tracker <a class="reference internal" href="#detectors">detectors</a> to reflect your changes.</p>
 1563 </div>
 1564 <p>Customisation of the special “definitional” classes (eg. status,
 1565 priority, resolution, …) may be done either before or after the
 1566 tracker is initialised. The actual method of doing so is completely
 1567 different in each case though, so be careful to use the right one.</p>
 1568 <dl class="docutils">
 1569 <dt><strong>Changing content before tracker initialisation</strong></dt>
 1570 <dd>Edit the initial_data.py module in your tracker to alter the items
 1571 created using the <code class="docutils literal"><span class="pre">create(</span> <span class="pre">...</span> <span class="pre">)</span></code> methods.</dd>
 1572 <dt><strong>Changing content after tracker initialisation</strong></dt>
 1573 <dd><p class="first">As the “admin” user, click on the “class list” link in the web
 1574 interface to bring up a list of all database classes. Click on the
 1575 name of the class you wish to change the content of.</p>
 1576 <p class="last">You may also use the <code class="docutils literal"><span class="pre">roundup-admin</span></code> interface’s create, set and
 1577 retire methods to add, alter or remove items from the classes in
 1578 question.</p>
 1579 </dd>
 1580 </dl>
 1581 <p>See “<a class="reference internal" href="#adding-a-new-field-to-the-classic-schema">adding a new field to the classic schema</a>” for an example that
 1582 requires database content changes.</p>
 1583 </div>
 1584 <div class="section" id="security-access-controls">
 1585 <h2><a class="toc-backref" href="#id32">Security / Access Controls</a><a class="headerlink" href="#security-access-controls" title="Permalink to this headline"></a></h2>
 1586 <p>A set of Permissions is built into the security module by default:</p>
 1587 <ul class="simple">
 1588 <li>Create (everything)</li>
 1589 <li>Edit (everything)</li>
 1590 <li>View (everything)</li>
 1591 <li>Register (User class only)</li>
 1592 </ul>
 1593 <p>These are assigned to the “Admin” Role by default, and allow a user to do
 1594 anything. Every Class you define in your <a class="reference internal" href="#tracker-schema">tracker schema</a> also gets an
 1595 Create, Edit and View Permission of its own. The web and email interfaces
 1596 also define:</p>
 1597 <dl class="docutils">
 1598 <dt><em>Email Access</em></dt>
 1599 <dd>If defined, the user may use the email interface. Used by default to deny
 1600 Anonymous users access to the email interface. When granted to the
 1601 Anonymous user, they will be automatically registered by the email
 1602 interface (see also the <code class="docutils literal"><span class="pre">new_email_user_roles</span></code> configuration option).</dd>
 1603 <dt><em>Web Access</em></dt>
 1604 <dd>If defined, the user may use the web interface. All users are able to see
 1605 the login form, regardless of this setting (thus enabling logging in).</dd>
 1606 <dt><em>Web Roles</em></dt>
 1607 <dd>Controls user access to editing the “roles” property of the “user” class.
 1608 TODO: deprecate in favour of a property-based control.</dd>
 1609 <dt><em>Rest Access</em> and <em>Xmlrpc Access</em></dt>
 1610 <dd>These control access to the Rest and Xmlrpc endpoints. The Admin and User
 1611 roles have these by default in the classic tracker. See the
 1612 <a class="reference external" href="rest.html#enabling-the-rest-api">directions in the rest interface documentation</a> and the
 1613 <a class="reference external" href="xmlrpc.html#through-roundup">xmlrpc interface documentation</a>.</dd>
 1614 </dl>
 1615 <p>These are hooked into the default Roles:</p>
 1616 <ul class="simple">
 1617 <li>Admin (Create, Edit, View and everything; Web Roles)</li>
 1618 <li>User (Web Access; Email Access)</li>
 1619 <li>Anonymous (Web Access)</li>
 1620 </ul>
 1621 <p>And finally, the “admin” user gets the “Admin” Role, and the “anonymous”
 1622 user gets “Anonymous” assigned when the tracker is installed.</p>
 1623 <p>For the “User” Role, the “classic” tracker defines:</p>
 1624 <ul class="simple">
 1625 <li>Create, Edit and View issue, file, msg, query, keyword</li>
 1626 <li>View priority, status</li>
 1627 <li>View user</li>
 1628 <li>Edit their own user record</li>
 1629 </ul>
 1630 <p>And the “Anonymous” Role is defined as:</p>
 1631 <ul class="simple">
 1632 <li>Web interface access</li>
 1633 <li>Register user (for registration)</li>
 1634 <li>View issue, file, msg, query, keyword, priority, status</li>
 1635 </ul>
 1636 <p>Put together, these settings appear in the tracker’s <code class="docutils literal"><span class="pre">schema.py</span></code> file:</p>
 1637 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1">#</span>
 1638 <span class="c1"># TRACKER SECURITY SETTINGS</span>
 1639 <span class="c1">#</span>
 1640 <span class="c1"># See the configuration and customisation document for information</span>
 1641 <span class="c1"># about security setup.</span>
 1642 
 1643 <span class="c1">#</span>
 1644 <span class="c1"># REGULAR USERS</span>
 1645 <span class="c1">#</span>
 1646 <span class="c1"># Give the regular users access to the web and email interface</span>
 1647 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;Web Access&#39;</span><span class="p">)</span>
 1648 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;Email Access&#39;</span><span class="p">)</span>
 1649 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;Rest Access&#39;</span><span class="p">)</span>
 1650 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;Xmlrpc Access&#39;</span><span class="p">)</span>
 1651 
 1652 <span class="c1"># Assign the access and edit Permissions for issue, file and message</span>
 1653 <span class="c1"># to regular users now</span>
 1654 <span class="k">for</span> <span class="n">cl</span> <span class="ow">in</span> <span class="s1">&#39;issue&#39;</span><span class="p">,</span> <span class="s1">&#39;file&#39;</span><span class="p">,</span> <span class="s1">&#39;msg&#39;</span><span class="p">,</span> <span class="s1">&#39;query&#39;</span><span class="p">,</span> <span class="s1">&#39;keyword&#39;</span><span class="p">:</span>
 1655     <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;View&#39;</span><span class="p">,</span> <span class="n">cl</span><span class="p">)</span>
 1656     <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;Edit&#39;</span><span class="p">,</span> <span class="n">cl</span><span class="p">)</span>
 1657     <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;Create&#39;</span><span class="p">,</span> <span class="n">cl</span><span class="p">)</span>
 1658 <span class="k">for</span> <span class="n">cl</span> <span class="ow">in</span> <span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="s1">&#39;status&#39;</span><span class="p">:</span>
 1659     <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;View&#39;</span><span class="p">,</span> <span class="n">cl</span><span class="p">)</span>
 1660 
 1661 <span class="c1"># May users view other user information? Comment these lines out</span>
 1662 <span class="c1"># if you don&#39;t want them to</span>
 1663 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="s1">&#39;View&#39;</span><span class="p">,</span> <span class="s1">&#39;user&#39;</span><span class="p">)</span>
 1664 
 1665 <span class="c1"># Users should be able to edit their own details -- this permission</span>
 1666 <span class="c1"># is limited to only the situation where the Viewed or Edited item</span>
 1667 <span class="c1"># is their own.</span>
 1668 <span class="k">def</span> <span class="nf">own_record</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">userid</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="o">**</span><span class="n">ctx</span><span class="p">):</span>
 1669     <span class="sd">&#39;&#39;&#39;Determine whether the userid matches the item being accessed.&#39;&#39;&#39;</span>
 1670     <span class="k">return</span> <span class="n">userid</span> <span class="o">==</span> <span class="n">itemid</span>
 1671 <span class="n">p</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermission</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;View&#39;</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="s1">&#39;user&#39;</span><span class="p">,</span> <span class="n">check</span><span class="o">=</span><span class="n">own_record</span><span class="p">,</span>
 1672     <span class="n">description</span><span class="o">=</span><span class="s2">&quot;User is allowed to view their own user details&quot;</span><span class="p">)</span>
 1673 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
 1674 <span class="n">p</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermission</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Edit&#39;</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="s1">&#39;user&#39;</span><span class="p">,</span> <span class="n">check</span><span class="o">=</span><span class="n">own_record</span><span class="p">,</span>
 1675     <span class="n">description</span><span class="o">=</span><span class="s2">&quot;User is allowed to edit their own user details&quot;</span><span class="p">)</span>
 1676 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
 1677 
 1678 <span class="c1">#</span>
 1679 <span class="c1"># ANONYMOUS USER PERMISSIONS</span>
 1680 <span class="c1">#</span>
 1681 <span class="c1"># Let anonymous users access the web interface. Note that almost all</span>
 1682 <span class="c1"># trackers will need this Permission. The only situation where it&#39;s not</span>
 1683 <span class="c1"># required is in a tracker that uses an HTTP Basic Authenticated front-end.</span>
 1684 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;Anonymous&#39;</span><span class="p">,</span> <span class="s1">&#39;Web Access&#39;</span><span class="p">)</span>
 1685 
 1686 <span class="c1"># Let anonymous users access the email interface (note that this implies</span>
 1687 <span class="c1"># that they will be registered automatically, hence they will need the</span>
 1688 <span class="c1"># &quot;Create&quot; user Permission below)</span>
 1689 <span class="c1"># This is disabled by default to stop spam from auto-registering users on</span>
 1690 <span class="c1"># public trackers.</span>
 1691 <span class="c1">#db.security.addPermissionToRole(&#39;Anonymous&#39;, &#39;Email Access&#39;)</span>
 1692 
 1693 <span class="c1"># Assign the appropriate permissions to the anonymous user&#39;s Anonymous</span>
 1694 <span class="c1"># Role. Choices here are:</span>
 1695 <span class="c1"># - Allow anonymous users to register</span>
 1696 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;Anonymous&#39;</span><span class="p">,</span> <span class="s1">&#39;Create&#39;</span><span class="p">,</span> <span class="s1">&#39;user&#39;</span><span class="p">)</span>
 1697 
 1698 <span class="c1"># Allow anonymous users access to view issues (and the related, linked</span>
 1699 <span class="c1"># information)</span>
 1700 <span class="k">for</span> <span class="n">cl</span> <span class="ow">in</span> <span class="s1">&#39;issue&#39;</span><span class="p">,</span> <span class="s1">&#39;file&#39;</span><span class="p">,</span> <span class="s1">&#39;msg&#39;</span><span class="p">,</span> <span class="s1">&#39;keyword&#39;</span><span class="p">,</span> <span class="s1">&#39;priority&#39;</span><span class="p">,</span> <span class="s1">&#39;status&#39;</span><span class="p">:</span>
 1701     <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;Anonymous&#39;</span><span class="p">,</span> <span class="s1">&#39;View&#39;</span><span class="p">,</span> <span class="n">cl</span><span class="p">)</span>
 1702 
 1703 <span class="c1"># [OPTIONAL]</span>
 1704 <span class="c1"># Allow anonymous users access to create or edit &quot;issue&quot; items (and the</span>
 1705 <span class="c1"># related file and message items)</span>
 1706 <span class="c1">#for cl in &#39;issue&#39;, &#39;file&#39;, &#39;msg&#39;:</span>
 1707 <span class="c1">#   db.security.addPermissionToRole(&#39;Anonymous&#39;, &#39;Create&#39;, cl)</span>
 1708 <span class="c1">#   db.security.addPermissionToRole(&#39;Anonymous&#39;, &#39;Edit&#39;, cl)</span>
 1709 </pre></div>
 1710 </div>
 1711 <p id="index-42">You can use <code class="docutils literal"><span class="pre">roundup-admin</span> <span class="pre">security</span></code> to verify the permissions
 1712 defined in the schema. It also verifies that properties specified in
 1713 permissions are valid for the class. This helps detect typos that can
 1714 cause baffling permission issues.</p>
 1715 <div class="section" id="automatic-permission-checks">
 1716 <h3><a class="toc-backref" href="#id33">Automatic Permission Checks</a><a class="headerlink" href="#automatic-permission-checks" title="Permalink to this headline"></a></h3>
 1717 <p>Permissions are automatically checked when information is rendered
 1718 through the web. This includes:</p>
 1719 <ol class="arabic simple">
 1720 <li>View checks for properties when being rendered via the <code class="docutils literal"><span class="pre">plain()</span></code> or
 1721 similar methods. If the check fails, the text “[hidden]” will be
 1722 displayed.</li>
 1723 <li>Edit checks for properties when the edit field is being rendered via
 1724 the <code class="docutils literal"><span class="pre">field()</span></code> or similar methods. If the check fails, the property
 1725 will be rendered via the <code class="docutils literal"><span class="pre">plain()</span></code> method (see point 1. for subsequent
 1726 checking performed)</li>
 1727 <li>View checks are performed in index pages for each item being displayed
 1728 such that if the user does not have permission, the row is not rendered.</li>
 1729 <li>View checks are performed at the top of item pages for the Item being
 1730 displayed. If the user does not have permission, the text “You are not
 1731 allowed to view this page.” will be displayed.</li>
 1732 <li>View checks are performed at the top of index pages for the Class being
 1733 displayed. If the user does not have permission, the text “You are not
 1734 allowed to view this page.” will be displayed.</li>
 1735 </ol>
 1736 </div>
 1737 <div class="section" id="new-user-roles">
 1738 <h3><a class="toc-backref" href="#id34">New User Roles</a><a class="headerlink" href="#new-user-roles" title="Permalink to this headline"></a></h3>
 1739 <p>New users are assigned the Roles defined in the config file as:</p>
 1740 <ul class="simple">
 1741 <li>NEW_WEB_USER_ROLES</li>
 1742 <li>NEW_EMAIL_USER_ROLES</li>
 1743 </ul>
 1744 <p>The <a class="reference internal" href="#users-may-only-edit-their-issues">users may only edit their issues</a> example shows customisation of
 1745 these parameters.</p>
 1746 </div>
 1747 <div class="section" id="changing-access-controls">
 1748 <h3><a class="toc-backref" href="#id35">Changing Access Controls</a><a class="headerlink" href="#changing-access-controls" title="Permalink to this headline"></a></h3>
 1749 <p>You may alter the configuration variables to change the Role that new
 1750 web or email users get, for example to not give them access to the web
 1751 interface if they register through email.</p>
 1752 <p>You may use the <code class="docutils literal"><span class="pre">roundup-admin</span></code><code class="docutils literal"><span class="pre">security</span></code>” command to display the
 1753 current Role and Permission configuration in your tracker.</p>
 1754 <div class="section" id="adding-a-new-permission">
 1755 <h4>Adding a new Permission<a class="headerlink" href="#adding-a-new-permission" title="Permalink to this headline"></a></h4>
 1756 <p>When adding a new Permission, you will need to:</p>
 1757 <ol class="arabic">
 1758 <li><p class="first">add it to your tracker’s <code class="docutils literal"><span class="pre">schema.py</span></code> so it is created, using
 1759 <code class="docutils literal"><span class="pre">security.addPermission</span></code>, for example:</p>
 1760 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermission</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;View&quot;</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="s1">&#39;frozzle&#39;</span><span class="p">,</span>
 1761     <span class="n">description</span><span class="o">=</span><span class="s2">&quot;User is allowed to access frozzles&quot;</span><span class="p">)</span>
 1762 </pre></div>
 1763 </div>
 1764 <p>will set up a new “View” permission on the Class “frozzle”.</p>
 1765 </li>
 1766 <li><p class="first">enable it for the Roles that should have it (verify with
 1767 <code class="docutils literal"><span class="pre">roundup-admin</span> <span class="pre">security</span></code>”)</p>
 1768 </li>
 1769 <li><p class="first">add it to the relevant HTML interface templates</p>
 1770 </li>
 1771 <li><p class="first">add it to the appropriate xxxPermission methods on in your tracker
 1772 interfaces module</p>
 1773 </li>
 1774 </ol>
 1775 <p>The <code class="docutils literal"><span class="pre">addPermission</span></code> method takes a few optional parameters:</p>
 1776 <dl class="docutils">
 1777 <dt><strong>properties</strong></dt>
 1778 <dd>A sequence of property names that are the only properties to apply the
 1779 new Permission to (eg. <code class="docutils literal"><span class="pre">...</span> <span class="pre">klass='user',</span> <span class="pre">properties=('name',</span>
 1780 <span class="pre">'email')</span> <span class="pre">...</span></code>)</dd>
 1781 <dt><strong>props_only</strong></dt>
 1782 <dd><p class="first">A boolean value (set to false by default) that is a new feature
 1783 in roundup 1.6.
 1784 A permission defined using:</p>
 1785 <blockquote>
 1786 <div><code class="docutils literal"><span class="pre">properties=('list',</span> <span class="pre">'of',</span> <span class="pre">'property',</span> <span class="pre">'names')</span></code></div></blockquote>
 1787 <p>is used to determine access for things other than just those
 1788 properties. For example a check for View permission on the issue
 1789 class or an issue item can use any View permission for the issue
 1790 class even if that permission has a property list.  This can be
 1791 confusing and surprising as you would think that a permission
 1792 including properties would be used only for determining the
 1793 access permission for those properties.</p>
 1794 <p><code class="docutils literal"><span class="pre">roundup-admin</span> <span class="pre">security</span></code> will report invalid properties for the
 1795 class. For example a permission with an invalid summary property is
 1796 presented as:</p>
 1797 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">Allowed</span> <span class="n">to</span> <span class="n">see</span> <span class="n">content</span> <span class="n">of</span> <span class="nb">object</span> <span class="n">regardless</span> <span class="n">of</span> <span class="n">spam</span> <span class="n">status</span>
 1798    <span class="p">(</span><span class="n">View</span> <span class="k">for</span> <span class="s2">&quot;file&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;content&#39;</span><span class="p">,</span> <span class="s1">&#39;summary&#39;</span><span class="p">)</span> <span class="n">only</span><span class="p">)</span>
 1799 
 1800 <span class="o">**</span><span class="n">Invalid</span> <span class="n">properties</span> <span class="k">for</span> <span class="n">file</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;summary&#39;</span><span class="p">]</span>
 1801 </pre></div>
 1802 </div>
 1803 <p>Setting <code class="docutils literal"><span class="pre">props_only=True</span></code> will make the permission valid only for
 1804 those properties.</p>
 1805 <p>If you use a lot of permissions with property checks, it can be
 1806 difficult to change all of them. Calling the function:</p>
 1807 <blockquote>
 1808 <div>db.security.set_props_only_default(True)</div></blockquote>
 1809 <p class="last">at the top of <code class="docutils literal"><span class="pre">schema.py</span></code> will make every permission creation
 1810 behave as though props_only was set to True. It is expected that the
 1811 default of True will become the default in a future Roundup release.</p>
 1812 </dd>
 1813 <dt><strong>check</strong></dt>
 1814 <dd><p class="first">A function to be executed which returns boolean determining whether
 1815 the Permission is allowed. If it returns True, the permission is
 1816 allowed, if it returns False the permission is denied.  The function
 1817 can have one of two signatures:</p>
 1818 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">check</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">userid</span><span class="p">,</span> <span class="n">itemid</span><span class="p">)</span>
 1819 </pre></div>
 1820 </div>
 1821 <p>or:</p>
 1822 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">check</span><span class="p">(</span><span class="n">db</span><span class="p">,</span> <span class="n">userid</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="o">**</span><span class="n">ctx</span><span class="p">)</span>
 1823 </pre></div>
 1824 </div>
 1825 <p>where <code class="docutils literal"><span class="pre">db</span></code> is a handle on the open database, <code class="docutils literal"><span class="pre">userid</span></code> is
 1826 the user attempting access and <code class="docutils literal"><span class="pre">itemid</span></code> is the specific item being
 1827 accessed. If the second form is used the <code class="docutils literal"><span class="pre">ctx</span></code> dictionary is
 1828 defined with the following values:</p>
 1829 <div class="last highlight-default"><div class="highlight"><pre><span></span><span class="n">ctx</span><span class="p">[</span><span class="s1">&#39;property&#39;</span><span class="p">]</span> <span class="n">the</span> <span class="n">name</span> <span class="n">of</span> <span class="n">the</span> <span class="nb">property</span> <span class="n">being</span> <span class="n">checked</span> <span class="ow">or</span> <span class="kc">None</span> <span class="k">if</span>
 1830        <span class="n">it</span><span class="s1">&#39;s a class check.</span>
 1831 
 1832 <span class="n">ctx</span><span class="p">[</span><span class="s1">&#39;classname&#39;</span><span class="p">]</span> <span class="n">the</span> <span class="n">name</span> <span class="n">of</span> <span class="n">the</span> <span class="k">class</span> <span class="nc">that</span> <span class="ow">is</span> <span class="n">being</span> <span class="n">checked</span>
 1833        <span class="p">(</span><span class="n">issue</span><span class="p">,</span> <span class="n">query</span> <span class="o">....</span><span class="p">)</span><span class="o">.</span>
 1834 
 1835 <span class="n">ctx</span><span class="p">[</span><span class="s1">&#39;permission&#39;</span><span class="p">]</span> <span class="n">the</span> <span class="n">name</span> <span class="n">of</span> <span class="n">the</span> <span class="n">permission</span> <span class="p">(</span><span class="n">e</span><span class="o">.</span><span class="n">g</span><span class="o">.</span> <span class="n">View</span><span class="p">,</span> <span class="n">Edit</span><span class="o">...</span><span class="p">)</span><span class="o">.</span>
 1836 </pre></div>
 1837 </div>
 1838 </dd>
 1839 </dl>
 1840 <p>The second form is preferred as it makes it easier to implement more
 1841 complex permission schemes. An example of the use of <code class="docutils literal"><span class="pre">ctx</span></code> can be
 1842 found in the <code class="docutils literal"><span class="pre">upgrading.txt</span></code> or <a class="reference external" href="upgrading.html">upgrading.html</a> document.</p>
 1843 </div>
 1844 <div class="section" id="example-scenarios">
 1845 <h4>Example Scenarios<a class="headerlink" href="#example-scenarios" title="Permalink to this headline"></a></h4>
 1846 <p>See the <a class="reference internal" href="#examples">examples</a> section for longer examples of customisation.</p>
 1847 <dl class="docutils">
 1848 <dt><strong>anonymous access through the e-mail gateway</strong></dt>
 1849 <dd>Give the “anonymous” user the “Email Access”, (“Edit”, “issue”) and
 1850 (“Create”, “msg”) Permissions but do not not give them the (“Create”,
 1851 “user”) Permission. This means that when an unknown user sends email
 1852 into the tracker, they’re automatically logged in as “anonymous”.
 1853 Since they don’t have the (“Create”, “user”) Permission, they won’t
 1854 be automatically registered, but since “anonymous” has permission to
 1855 use the gateway, they’ll still be able to submit issues. Note that
 1856 the Sender information - their email address - will not be available
 1857 - they’re <em>anonymous</em>.</dd>
 1858 <dt><strong>automatic registration of users in the e-mail gateway</strong></dt>
 1859 <dd>By giving the “anonymous” user the (“Register”, “user”) Permission, any
 1860 unidentified user will automatically be registered with the tracker
 1861 (with no password, so they won’t be able to log in through
 1862 the web until an admin sets their password). By default new Roundup
 1863 trackers don’t allow this as it opens them up to spam. It may be enabled
 1864 by uncommenting the appropriate addPermissionToRole in your tracker’s
 1865 <code class="docutils literal"><span class="pre">schema.py</span></code> file. The new user is given the Roles list defined in the
 1866 “new_email_user_roles” config variable.</dd>
 1867 <dt><strong>only developers may be assigned issues</strong></dt>
 1868 <dd>Create a new Permission called “Fixer” for the “issue” class. Create a
 1869 new Role “Developer” which has that Permission, and assign that to the
 1870 appropriate users. Filter the list of users available in the assignedto
 1871 list to include only those users. Enforce the Permission with an
 1872 auditor. See the example
 1873 <a class="reference internal" href="#restricting-the-list-of-users-that-are-assignable-to-a-task">restricting the list of users that are assignable to a task</a>.</dd>
 1874 <dt><strong>only managers may sign off issues as complete</strong></dt>
 1875 <dd><p class="first">Create a new Permission called “Closer” for the “issue” class. Create a
 1876 new Role “Manager” which has that Permission, and assign that to the
 1877 appropriate users. In your web interface, only display the “resolved”
 1878 issue state option when the user has the “Closer” Permissions. Enforce
 1879 the Permission with an auditor. This is very similar to the previous
 1880 example, except that the web interface check would look like:</p>
 1881 <div class="last highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">option</span> <span class="n">tal</span><span class="p">:</span><span class="n">condition</span><span class="o">=</span><span class="s2">&quot;python:request.user.hasPermission(&#39;Closer&#39;)&quot;</span>
 1882         <span class="n">value</span><span class="o">=</span><span class="s2">&quot;resolved&quot;</span><span class="o">&gt;</span><span class="n">Resolved</span><span class="o">&lt;/</span><span class="n">option</span><span class="o">&gt;</span>
 1883 </pre></div>
 1884 </div>
 1885 </dd>
 1886 <dt><strong>don’t give web access to users who register through email</strong></dt>
 1887 <dd>Create a new Role called “Email User” which has all the Permissions of
 1888 the normal “User” Role minus the “Web Access” Permission. This will
 1889 allow users to send in emails to the tracker, but not access the web
 1890 interface.</dd>
 1891 <dt><strong>let some users edit the details of all users</strong></dt>
 1892 <dd><p class="first">Create a new Role called “User Admin” which has the Permission for
 1893 editing users:</p>
 1894 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addRole</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;User Admin&#39;</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s1">&#39;Managing users&#39;</span><span class="p">)</span>
 1895 <span class="n">p</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">getPermission</span><span class="p">(</span><span class="s1">&#39;Edit&#39;</span><span class="p">,</span> <span class="s1">&#39;user&#39;</span><span class="p">)</span>
 1896 <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">addPermissionToRole</span><span class="p">(</span><span class="s1">&#39;User Admin&#39;</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
 1897 </pre></div>
 1898 </div>
 1899 <p class="last">and assign the Role to the users who need the permission.</p>
 1900 </dd>
 1901 </dl>
 1902 </div>
 1903 </div>
 1904 </div>
 1905 <div class="section" id="web-interface">
 1906 <h2><a class="toc-backref" href="#id36">Web Interface</a><a class="headerlink" href="#web-interface" title="Permalink to this headline"></a></h2>
 1907 <div class="contents local topic" id="id3">
 1908 <ul class="simple">
 1909 <li><a class="reference internal" href="#repercussions-of-changing-the-tracker-schema" id="id63">Repercussions of changing the tracker schema</a></li>
 1910 <li><a class="reference internal" href="#how-requests-are-processed" id="id64">How requests are processed</a></li>
 1911 <li><a class="reference internal" href="#roundup-url-design" id="id65">Roundup URL design</a></li>
 1912 <li><a class="reference internal" href="#determining-web-context" id="id66">Determining web context</a></li>
 1913 <li><a class="reference internal" href="#the-home-context" id="id67">The “home” Context</a></li>
 1914 <li><a class="reference internal" href="#serving-static-content" id="id68">Serving static content</a></li>
 1915 <li><a class="reference internal" href="#performing-actions-in-web-requests" id="id69">Performing actions in web requests</a></li>
 1916 <li><a class="reference internal" href="#protecting-users-from-web-application-attacks" id="id70">Protecting users from web application attacks</a></li>
 1917 <li><a class="reference internal" href="#special-form-variables" id="id71">Special form variables</a></li>
 1918 <li><a class="reference internal" href="#default-templates" id="id72">Default templates</a></li>
 1919 <li><a class="reference internal" href="#implementing-modal-editing-using-template" id="id73">Implementing Modal Editing Using &#64;template</a></li>
 1920 <li><a class="reference internal" href="#how-the-templates-work" id="id74">How the templates work</a><ul>
 1921 <li><a class="reference internal" href="#templating-engines" id="id75">Templating engines</a></li>
 1922 <li><a class="reference internal" href="#basic-templating-actions" id="id76">Basic Templating Actions</a></li>
 1923 <li><a class="reference internal" href="#templating-expressions" id="id77">Templating Expressions</a></li>
 1924 <li><a class="reference internal" href="#template-macros" id="id78">Template Macros</a></li>
 1925 </ul>
 1926 </li>
 1927 <li><a class="reference internal" href="#information-available-to-templates" id="id79">Information available to templates</a><ul>
 1928 <li><a class="reference internal" href="#the-context-variable" id="id80">The context variable</a><ul>
 1929 <li><a class="reference internal" href="#hyperdb-class-wrapper" id="id81">Hyperdb class wrapper</a></li>
 1930 <li><a class="reference internal" href="#hyperdb-item-wrapper" id="id82">Hyperdb item wrapper</a></li>
 1931 <li><a class="reference internal" href="#hyperdb-property-wrapper" id="id83">Hyperdb property wrapper</a></li>
 1932 </ul>
 1933 </li>
 1934 <li><a class="reference internal" href="#the-request-variable" id="id84">The request variable</a><ul>
 1935 <li><a class="reference internal" href="#the-form-variable" id="id85">The form variable</a></li>
 1936 </ul>
 1937 </li>
 1938 <li><a class="reference internal" href="#the-db-variable" id="id86">The db variable</a></li>
 1939 <li><a class="reference internal" href="#the-templates-variable" id="id87">The templates variable</a></li>
 1940 <li><a class="reference internal" href="#the-repeat-variable" id="id88">The repeat variable</a></li>
 1941 <li><a class="reference internal" href="#the-utils-variable" id="id89">The utils variable</a><ul>
 1942 <li><a class="reference internal" href="#batching" id="id90">Batching</a></li>
 1943 </ul>
 1944 </li>
 1945 <li><a class="reference internal" href="#translations" id="id91">Translations</a></li>
 1946 </ul>
 1947 </li>
 1948 <li><a class="reference internal" href="#displaying-properties" id="id92">Displaying Properties</a></li>
 1949 <li><a class="reference internal" href="#index-views" id="id93">Index Views</a><ul>
 1950 <li><a class="reference internal" href="#index-view-specifiers" id="id94">Index View Specifiers</a></li>
 1951 </ul>
 1952 </li>
 1953 <li><a class="reference internal" href="#searching-views" id="id95">Searching Views</a></li>
 1954 <li><a class="reference internal" href="#item-views" id="id96">Item Views</a><ul>
 1955 <li><a class="reference internal" href="#editor-section" id="id97">Editor Section</a><ul>
 1956 <li><a class="reference internal" href="#form-values" id="id98">Form values</a></li>
 1957 </ul>
 1958 </li>
 1959 <li><a class="reference internal" href="#spool-section" id="id99">Spool Section</a></li>
 1960 <li><a class="reference internal" href="#history-section" id="id100">History Section</a></li>
 1961 </ul>
 1962 </li>
 1963 <li><a class="reference internal" href="#defining-new-web-actions" id="id101">Defining new web actions</a><ul>
 1964 <li><a class="reference internal" href="#define-the-new-action-class" id="id102">Define the new action class</a></li>
 1965 <li><a class="reference internal" href="#register-the-action-class" id="id103">Register the action class</a></li>
 1966 <li><a class="reference internal" href="#use-the-new-action" id="id104">Use the new action</a></li>
 1967 <li><a class="reference internal" href="#actions-may-return-content-to-the-user" id="id105">Actions may return content to the user</a></li>
 1968 </ul>
 1969 </li>
 1970 <li><a class="reference internal" href="#bit-character-set-support-in-web-interface" id="id106">8-bit character set support in Web interface</a></li>
 1971 </ul>
 1972 </div>
 1973 <p>The web interface is provided by the <code class="docutils literal"><span class="pre">roundup.cgi.client</span></code> module and
 1974 is used by <code class="docutils literal"><span class="pre">roundup.cgi</span></code>, <code class="docutils literal"><span class="pre">roundup-server</span></code> and <code class="docutils literal"><span class="pre">ZRoundup</span></code>
 1975 (<code class="docutils literal"><span class="pre">ZRoundup</span></code>  is broken, until further notice). In all cases, we
 1976 determine which tracker is being accessed (the first part of the URL
 1977 path inside the scope of the CGI handler) and pass control on to the
 1978 <code class="docutils literal"><span class="pre">roundup.cgi.client.Client</span></code> class - which handles the rest of the
 1979 access through its <code class="docutils literal"><span class="pre">main()</span></code> method. This means that you can do pretty
 1980 much anything you want as a web interface to your tracker.</p>
 1981 <div class="section" id="repercussions-of-changing-the-tracker-schema">
 1982 <h3><a class="toc-backref" href="#id63">Repercussions of changing the tracker schema</a><a class="headerlink" href="#repercussions-of-changing-the-tracker-schema" title="Permalink to this headline"></a></h3>
 1983 <p>If you choose to change the <a class="reference internal" href="#tracker-schema">tracker schema</a> you will need to ensure
 1984 the web interface knows about it:</p>
 1985 <ol class="arabic simple">
 1986 <li>Index, item and search pages for the relevant classes may need to
 1987 have properties added or removed,</li>
 1988 <li>The “page” template may require links to be changed, as might the
 1989 “home” page’s content arguments.</li>
 1990 </ol>
 1991 </div>
 1992 <div class="section" id="how-requests-are-processed">
 1993 <h3><a class="toc-backref" href="#id64">How requests are processed</a><a class="headerlink" href="#how-requests-are-processed" title="Permalink to this headline"></a></h3>
 1994 <p>The basic processing of a web request proceeds as follows:</p>
 1995 <ol class="arabic simple">
 1996 <li>figure out who we are, defaulting to the “anonymous” user</li>
 1997 <li>figure out what the request is for - we call this the “context”</li>
 1998 <li>handle any requested action (item edit, search, …)</li>
 1999 <li>render the template requested by the context, resulting in HTML
 2000 output</li>
 2001 </ol>
 2002 <p>In some situations, exceptions occur:</p>
 2003 <ul class="simple">
 2004 <li>HTTP Redirect  (generally raised by an action)</li>
 2005 <li><dl class="first docutils">
 2006 <dt>SendFile       (generally raised by <code class="docutils literal"><span class="pre">determine_context</span></code>)</dt>
 2007 <dd>here we serve up a FileClass “content” property</dd>
 2008 </dl>
 2009 </li>
 2010 <li><dl class="first docutils">
 2011 <dt>SendStaticFile (generally raised by <code class="docutils literal"><span class="pre">determine_context</span></code>)</dt>
 2012 <dd>here we serve up a file from the tracker “html” directory</dd>
 2013 </dl>
 2014 </li>
 2015 <li><dl class="first docutils">
 2016 <dt>Unauthorised   (generally raised by an action)</dt>
 2017 <dd>here the action is cancelled, the request is rendered and an error
 2018 message is displayed indicating that permission was not granted for
 2019 the action to take place</dd>
 2020 </dl>
 2021 </li>
 2022 <li><dl class="first docutils">
 2023 <dt>NotFound       (raised wherever it needs to be)</dt>
 2024 <dd>this exception percolates up to the CGI interface that called the
 2025 client</dd>
 2026 </dl>
 2027 </li>
 2028 </ul>
 2029 </div>
 2030 <div class="section" id="roundup-url-design">
 2031 <h3><a class="toc-backref" href="#id65">Roundup URL design</a><a class="headerlink" href="#roundup-url-design" title="Permalink to this headline"></a></h3>
 2032 <p>Each tracker has several hardcoded URLs. These three are equivalent and
 2033 lead to the main tracker page:</p>
 2034 <ol class="arabic simple">
 2035 <li><code class="docutils literal"><span class="pre">/</span></code></li>
 2036 <li><code class="docutils literal"><span class="pre">/index</span></code></li>
 2037 <li><code class="docutils literal"><span class="pre">/home</span></code></li>
 2038 </ol>
 2039 <p>The following prefix is used to access static resources:</p>
 2040 <ol class="arabic simple" start="4">
 2041 <li><code class="docutils literal"><span class="pre">/&#64;&#64;file/</span></code></li>
 2042 </ol>
 2043 <p>All other URLs depend on the classes configured in Roundup database.
 2044 Each class receives two URLs - one for the class itself and another
 2045 for specific items of that class. Example for class URL:</p>
 2046 <ol class="arabic simple" start="5">
 2047 <li><code class="docutils literal"><span class="pre">/issue</span></code></li>
 2048 </ol>
 2049 <p>This is usually used to show listings of class items. The URL for
 2050 for specific object of issue class with id 1 will look like:</p>
 2051 <ol class="arabic simple" start="6">
 2052 <li><code class="docutils literal"><span class="pre">/issue1</span></code></li>
 2053 </ol>
 2054 </div>
 2055 <div class="section" id="determining-web-context">
 2056 <h3><a class="toc-backref" href="#id66">Determining web context</a><a class="headerlink" href="#determining-web-context" title="Permalink to this headline"></a></h3>
 2057 <p>To determine the “context” of a request (what request is for), we look at
 2058 the URL path after the tracker root and at <code class="docutils literal"><span class="pre">&#64;template</span></code> request
 2059 parameter. Typical URL paths look like:</p>
 2060 <ol class="arabic simple">
 2061 <li><code class="docutils literal"><span class="pre">/tracker/issue</span></code></li>
 2062 <li><code class="docutils literal"><span class="pre">/tracker/issue1</span></code></li>
 2063 <li><code class="docutils literal"><span class="pre">/tracker/&#64;&#64;file/style.css</span></code></li>
 2064 <li><code class="docutils literal"><span class="pre">/cgi-bin/roundup.cgi/tracker/file1</span></code></li>
 2065 <li><code class="docutils literal"><span class="pre">/cgi-bin/roundup.cgi/tracker/file1/kitten.png</span></code></li>
 2066 </ol>
 2067 <p>where tracker root is <code class="docutils literal"><span class="pre">/tracker/</span></code> or <code class="docutils literal"><span class="pre">/cgi-bin/roundup.cgi/tracker/</span></code>
 2068 We’re looking at “issue”, “issue1”, “&#64;&#64;file/style.css”, “file1” and
 2069 “file1/kitten.png” in the cases above.</p>
 2070 <ol class="loweralpha simple">
 2071 <li>with is no path we are in the “home” context. See <a class="reference internal" href="#the-home-context">the “home”
 2072 context</a> below for details. “index” or “home” paths may also be used
 2073 to switch into “home” context.</li>
 2074 <li>for paths starting with “&#64;&#64;file” the additional path entry (“style.css”
 2075 in the example above) specifies the static file to be served
 2076 from the tracker TEMPLATES directory (or STATIC_FILES, if configured).
 2077 This is usually the tracker’s “html” directory. Internally this works
 2078 by raising SendStaticFile exception.</li>
 2079 <li>if there is something in the path (as in example 1, “issue”), it
 2080 identifies the tracker class to display.</li>
 2081 <li>if the path is an item designator (as in examples 2 and 4, “issue1”
 2082 and “file1”), then we’re to display a specific item.</li>
 2083 <li>if the path starts with an item designator and is longer than one
 2084 entry (as in example 5, “file1/kitten.png”), then we’re assumed to be
 2085 handling an item of a <code class="docutils literal"><span class="pre">FileClass</span></code>, and the extra path information
 2086 gives the filename that the client is going to label the download
 2087 with (i.e. “file1/kitten.png” is nicer to download than “file1”).
 2088 This raises a <code class="docutils literal"><span class="pre">SendFile</span></code> exception.</li>
 2089 </ol>
 2090 <p>Neither b. or e. use templates and stop before the template is
 2091 determined. For other contexts the template used is specified by the
 2092 <code class="docutils literal"><span class="pre">&#64;template</span></code> variable, which defaults to:</p>
 2093 <ul class="simple">
 2094 <li>only classname supplied:       “index”</li>
 2095 <li>full item designator supplied: “item”</li>
 2096 </ul>
 2097 </div>
 2098 <div class="section" id="the-home-context">
 2099 <h3><a class="toc-backref" href="#id67">The “home” Context</a><a class="headerlink" href="#the-home-context" title="Permalink to this headline"></a></h3>
 2100 <p>The “home” context is special because it allows you to add templated
 2101 pages to your tracker that don’t rely on a class or item (ie. an issues
 2102 list or specific issue).</p>
 2103 <p>Let’s say you wish to add frames to control the layout of your tracker’s
 2104 interface. You’d probably have:</p>
 2105 <ul>
 2106 <li><p class="first">A top-level frameset page. This page probably wouldn’t be templated, so
 2107 it could be served as a static file (see <a class="reference internal" href="#serving-static-content">serving static content</a>)</p>
 2108 </li>
 2109 <li><p class="first">A sidebar frame that is templated. Let’s call this page
 2110 “home.navigation.html” in your tracker’s “html” directory. To load that
 2111 page up, you use the URL:</p>
 2112 <blockquote>
 2113 <div><p>&lt;tracker url&gt;/<a class="reference external" href="mailto:home?&#37;&#52;&#48;template=navigation">home?<span>&#64;</span>template=navigation</a></p>
 2114 </div></blockquote>
 2115 </li>
 2116 </ul>
 2117 </div>
 2118 <div class="section" id="serving-static-content">
 2119 <h3><a class="toc-backref" href="#id68">Serving static content</a><a class="headerlink" href="#serving-static-content" title="Permalink to this headline"></a></h3>
 2120 <p>See the previous section <a class="reference internal" href="#determining-web-context">determining web context</a> where it describes
 2121 <code class="docutils literal"><span class="pre">&#64;&#64;file</span></code> paths.</p>
 2122 </div>
 2123 <div class="section" id="performing-actions-in-web-requests">
 2124 <h3><a class="toc-backref" href="#id69">Performing actions in web requests</a><a class="headerlink" href="#performing-actions-in-web-requests" title="Permalink to this headline"></a></h3>
 2125 <p>When a user requests a web page, they may optionally also request for an
 2126 action to take place. As described in <a class="reference internal" href="#how-requests-are-processed">how requests are processed</a>, the
 2127 action is performed before the requested page is generated. Actions are
 2128 triggered by using a <code class="docutils literal"><span class="pre">&#64;action</span></code> CGI variable, where the value is one
 2129 of:</p>
 2130 <dl class="docutils">
 2131 <dt><strong>login</strong></dt>
 2132 <dd>Attempt to log a user in.</dd>
 2133 <dt><strong>logout</strong></dt>
 2134 <dd>Log the user out - make them “anonymous”.</dd>
 2135 <dt><strong>register</strong></dt>
 2136 <dd>Attempt to create a new user based on the contents of the form and then
 2137 log them in.</dd>
 2138 <dt><strong>edit</strong></dt>
 2139 <dd>Perform an edit of an item in the database. There are some <a class="reference internal" href="#special-form-variables">special form
 2140 variables</a> you may use.</dd>
 2141 <dt><strong>new</strong></dt>
 2142 <dd>Add a new item to the database. You may use the same <a class="reference internal" href="#special-form-variables">special form
 2143 variables</a> as in the “edit” action. Also you can set the
 2144 <code class="docutils literal"><span class="pre">__redirect_to</span></code> form variable to the URL that should be displayed after
 2145 the new item is created. This is useful if you want to create another
 2146 item rather than edit the newly created item.</dd>
 2147 <dt><strong>retire</strong></dt>
 2148 <dd>Retire the item in the database.</dd>
 2149 <dt><strong>editCSV</strong></dt>
 2150 <dd>Performs an edit of all of a class’ items in one go. See also the
 2151 <em>class</em>.csv templating method which generates the CSV data to be
 2152 edited, and the <code class="docutils literal"><span class="pre">'_generic.index'</span></code> template which uses both of these
 2153 features.</dd>
 2154 <dt><strong>search</strong></dt>
 2155 <dd><p class="first">Mangle some of the form variables:</p>
 2156 <ul class="last simple">
 2157 <li>Set the form “:filter” variable based on the values of the filter
 2158 variables - if they’re set to anything other than “dontcare” then add
 2159 them to :filter.</li>
 2160 <li>Also handle the “:queryname” variable and save off the query to the
 2161 user’s query list.</li>
 2162 </ul>
 2163 </dd>
 2164 </dl>
 2165 <p>Each of the actions is implemented by a corresponding <code class="docutils literal"><span class="pre">*XxxAction*</span></code> (where
 2166 “Xxx” is the name of the action) class in the <code class="docutils literal"><span class="pre">roundup.cgi.actions</span></code> module.
 2167 These classes are registered with <code class="docutils literal"><span class="pre">roundup.cgi.client.Client</span></code>. If you need
 2168 to define new actions, you may add them there (see <a class="reference internal" href="#defining-new-web-actions">defining new
 2169 web actions</a>).</p>
 2170 <p>Each action class also has a <code class="docutils literal"><span class="pre">*permission*</span></code> method which determines whether
 2171 the action is permissible given the current user. The base permission checks
 2172 for each action are:</p>
 2173 <dl class="docutils">
 2174 <dt><strong>login</strong></dt>
 2175 <dd>Determine whether the user has the “Web Access” Permission.</dd>
 2176 <dt><strong>logout</strong></dt>
 2177 <dd>No permission checks are made.</dd>
 2178 <dt><strong>register</strong></dt>
 2179 <dd>Determine whether the user has the (“Create”, “user”) Permission.</dd>
 2180 <dt><strong>edit</strong></dt>
 2181 <dd>Determine whether the user has permission to edit this item. If we’re
 2182 editing the “user” class, users are allowed to edit their own details -
 2183 unless they try to edit the “roles” property, which requires the
 2184 special Permission “Web Roles”.</dd>
 2185 <dt><strong>new</strong></dt>
 2186 <dd>Determine whether the user has permission to create this item. No
 2187 additional property checks are made. Additionally, new user items may
 2188 be created if the user has the (“Create”, “user”) Permission.</dd>
 2189 <dt><strong>editCSV</strong></dt>
 2190 <dd>Determine whether the user has permission to edit this class.</dd>
 2191 <dt><strong>search</strong></dt>
 2192 <dd>Determine whether the user has permission to view this class.</dd>
 2193 </dl>
 2194 </div>
 2195 <div class="section" id="protecting-users-from-web-application-attacks">
 2196 <h3><a class="toc-backref" href="#id70">Protecting users from web application attacks</a><a class="headerlink" href="#protecting-users-from-web-application-attacks" title="Permalink to this headline"></a></h3>
 2197 <p>There is a class of attacks known as Cross Site Request Forgeries
 2198 (CSRF). Malicious code running in the browser can making a
 2199 request to roundup while you are logged into roundup.  The
 2200 malicious code piggy backs on your existing roundup session to
 2201 make changes without your knowledge. Roundup 1.6 has support for
 2202 defending against this by analyzing the</p>
 2203 <ul class="simple">
 2204 <li>Referer,</li>
 2205 <li>Origin, and</li>
 2206 <li>Host or</li>
 2207 <li>X-Forwarded-Host</li>
 2208 </ul>
 2209 <p>HTTP headers. It compares the headers to the value of the web setting
 2210 in the [tracker] section of the tracker’s <code class="docutils literal"><span class="pre">config.ini</span></code>.</p>
 2211 <p>Also a per form token (also called a nonce) can be enabled for
 2212 the tracker using the <code class="docutils literal"><span class="pre">csrf_enforce_token</span></code> option in
 2213 config.ini.  When enabled, roundup will validate a hidden form
 2214 field called <code class="docutils literal"><span class="pre">&#64;csrf</span></code>. If the validation fails (or the token
 2215 is used more than once) the request is rejected.  The <code class="docutils literal"><span class="pre">&#64;csrf</span></code>
 2216 input field is added automatically by calling the <code class="docutils literal"><span class="pre">submit</span></code>
 2217 function/path. It can also be added manually by calling
 2218 anti_csrf_nonce() directly. For example:</p>
 2219 <blockquote>
 2220 <div><dl class="docutils">
 2221 <dt>&lt;input name=”&#64;csrf” type=”hidden”</dt>
 2222 <dd>tal:attributes=”value python:utils.anti_csrf_nonce(lifetime=10)”&gt;</dd>
 2223 </dl>
 2224 </div></blockquote>
 2225 <p>By default a nonce lifetime is 2 weeks. However the lifetime (in
 2226 minutes) can be set by passing a lifetime argument as shown
 2227 above. The example above makes the nonce lifetime 10 minutes.</p>
 2228 <p>Search for &#64;csrf in this document for more examples. There are
 2229 more examples and information in <code class="docutils literal"><span class="pre">upgrading.txt</span></code>.</p>
 2230 <p>The token protects you because malicious code supplied by another
 2231 site is unable to obtain the token. Thus many attempts they make
 2232 to submit a request are rejected.</p>
 2233 <p>The protection on the xmlrpc interface is untested, but is based
 2234 on a valid header check against the roundup url and the presence
 2235 of the <code class="docutils literal"><span class="pre">X-REQUESTED-WITH</span></code> header. Work to improve this is a
 2236 future project after the 1.6 release.</p>
 2237 <p>The enforcement levels can be modified in <code class="docutils literal"><span class="pre">config.ini</span></code>. Refer to
 2238 that file for details.</p>
 2239 </div>
 2240 <div class="section" id="special-form-variables">
 2241 <h3><a class="toc-backref" href="#id71">Special form variables</a><a class="headerlink" href="#special-form-variables" title="Permalink to this headline"></a></h3>
 2242 <p>Item properties and their values are edited with html FORM
 2243 variables and their values. You can:</p>
 2244 <ul class="simple">
 2245 <li>Change the value of some property of the current item.</li>
 2246 <li>Create a new item of any class, and edit the new item’s
 2247 properties,</li>
 2248 <li>Attach newly created items to a multilink property of the
 2249 current item.</li>
 2250 <li>Remove items from a multilink property of the current item.</li>
 2251 <li>Specify that some properties are required for the edit
 2252 operation to be successful.</li>
 2253 <li>Redirect to a different page after creating a new item (new action
 2254 only, not edit action). Usually you end up on the page for the
 2255 created item.</li>
 2256 <li>Set up user interface locale.</li>
 2257 </ul>
 2258 <p>These operations will only take place if the form action (the
 2259 <code class="docutils literal"><span class="pre">&#64;action</span></code> variable) is “edit” or “new”.</p>
 2260 <p>In the following, &lt;bracketed&gt; values are variable, “&#64;” may be
 2261 either “:” or “&#64;”, and other text “required” is fixed.</p>
 2262 <p>Two special form variables are used to specify user language preferences:</p>
 2263 <dl class="docutils">
 2264 <dt><code class="docutils literal"><span class="pre">&#64;language</span></code></dt>
 2265 <dd>value may be locale name or <code class="docutils literal"><span class="pre">none</span></code>. If this variable is set to
 2266 locale name, web interface language is changed to given value
 2267 (provided that appropriate translation is available), the value
 2268 is stored in the browser cookie and will be used for all following
 2269 requests.  If value is <code class="docutils literal"><span class="pre">none</span></code> the cookie is removed and the
 2270 language is changed to the tracker default, set up in the tracker
 2271 configuration or OS environment.</dd>
 2272 <dt><code class="docutils literal"><span class="pre">&#64;charset</span></code></dt>
 2273 <dd>value may be character set name or <code class="docutils literal"><span class="pre">none</span></code>.  Character set name
 2274 is stored in the browser cookie and sets output encoding for all
 2275 HTML pages generated by Roundup.  If value is <code class="docutils literal"><span class="pre">none</span></code> the cookie
 2276 is removed and HTML output is reset to Roundup internal encoding
 2277 (UTF-8).</dd>
 2278 </dl>
 2279 <p>Most properties are specified as form variables:</p>
 2280 <dl class="docutils">
 2281 <dt><code class="docutils literal"><span class="pre">&lt;propname&gt;</span></code></dt>
 2282 <dd>property on the current context item</dd>
 2283 <dt><code class="docutils literal"><span class="pre">&lt;designator&gt;&quot;&#64;&quot;&lt;propname&gt;</span></code></dt>
 2284 <dd>property on the indicated item (for editing related information)</dd>
 2285 </dl>
 2286 <p>Designators name a specific item of a class.</p>
 2287 <dl class="docutils">
 2288 <dt><code class="docutils literal"><span class="pre">&lt;classname&gt;&lt;N&gt;</span></code></dt>
 2289 <dd>Name an existing item of class &lt;classname&gt;.</dd>
 2290 <dt><code class="docutils literal"><span class="pre">&lt;classname&gt;&quot;-&quot;&lt;N&gt;</span></code></dt>
 2291 <dd>Name the &lt;N&gt;th new item of class &lt;classname&gt;. If the form
 2292 submission is successful, a new item of &lt;classname&gt; is
 2293 created. Within the submitted form, a particular
 2294 designator of this form always refers to the same new
 2295 item.</dd>
 2296 </dl>
 2297 <p>Once we have determined the “propname”, we look at it to see
 2298 if it’s special:</p>
 2299 <dl class="docutils">
 2300 <dt><code class="docutils literal"><span class="pre">&#64;required</span></code></dt>
 2301 <dd><p class="first">The associated form value is a comma-separated list of
 2302 property names that must be specified when the form is
 2303 submitted for the edit operation to succeed.</p>
 2304 <p>When the &lt;designator&gt; is missing, the properties are
 2305 for the current context item.  When &lt;designator&gt; is
 2306 present, they are for the item specified by
 2307 &lt;designator&gt;.</p>
 2308 <p class="last">The “&#64;required” specifier must come before any of the
 2309 properties it refers to are assigned in the form.</p>
 2310 </dd>
 2311 <dt><code class="docutils literal"><span class="pre">&#64;remove&#64;&lt;propname&gt;=id(s)</span></code> or <code class="docutils literal"><span class="pre">&#64;add&#64;&lt;propname&gt;=id(s)</span></code></dt>
 2312 <dd>The “&#64;add&#64;” and “&#64;remove&#64;” edit actions apply only to
 2313 Multilink properties.  The form value must be a
 2314 comma-separate list of keys for the class specified by
 2315 the simple form variable.  The listed items are added
 2316 to (respectively, removed from) the specified
 2317 property.</dd>
 2318 <dt><code class="docutils literal"><span class="pre">&#64;link&#64;&lt;propname&gt;=&lt;designator&gt;</span></code></dt>
 2319 <dd>If the edit action is “&#64;link&#64;”, the simple form
 2320 variable must specify a Link or Multilink property.
 2321 The form value is a comma-separated list of
 2322 designators.  The item corresponding to each
 2323 designator is linked to the property given by simple
 2324 form variable.</dd>
 2325 <dt>None of the above (ie. just a simple form value)</dt>
 2326 <dd><p class="first">The value of the form variable is converted
 2327 appropriately, depending on the type of the property.</p>
 2328 <p>For a Link(‘klass’) property, the form value is a
 2329 single key for ‘klass’, where the key field is
 2330 specified in schema.py.</p>
 2331 <p>For a Multilink(‘klass’) property, the form value is a
 2332 comma-separated list of keys for ‘klass’, where the
 2333 key field is specified in schema.py.</p>
 2334 <p>Note that for simple-form-variables specifiying Link
 2335 and Multilink properties, the linked-to class must
 2336 have a key field.</p>
 2337 <p>For a String() property specifying a filename, the
 2338 file named by the form value is uploaded. This means we
 2339 try to set additional properties “filename” and “type” (if
 2340 they are valid for the class).  Otherwise, the property
 2341 is set to the form value.</p>
 2342 <p class="last">For Date(), Interval(), Boolean(), Integer() and Number()
 2343 properties, the form value is converted to the
 2344 appropriate</p>
 2345 </dd>
 2346 </dl>
 2347 <p>Any of the form variables may be prefixed with a classname or
 2348 designator.</p>
 2349 <p>Setting the form variable: <code class="docutils literal"><span class="pre">__redirect_to=</span></code> to a url when
 2350 &#64;action=new redirects the user to the specified url after successfully
 2351 creating the new item. This is useful if you want the user to create
 2352 another item rather than edit the newly created item.  Note that the
 2353 url assigned to <code class="docutils literal"><span class="pre">__redirect_to</span></code> must be url encoded/quoted and be
 2354 under the tracker’s base url. If the base_url uses http, you can set
 2355 the url to https.</p>
 2356 <p>Two special form values are supported for backwards compatibility:</p>
 2357 <dl class="docutils">
 2358 <dt>&#64;note</dt>
 2359 <dd><p class="first">This is equivalent to:</p>
 2360 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="nd">@link@messages</span><span class="o">=</span><span class="n">msg</span><span class="o">-</span><span class="mi">1</span>
 2361 <span class="n">msg</span><span class="o">-</span><span class="mi">1</span><span class="nd">@content</span><span class="o">=</span><span class="n">value</span>
 2362 </pre></div>
 2363 </div>
 2364 <p class="last">except that in addition, the “author” and “date” properties of
 2365 “msg-1” are set to the userid of the submitter, and the current
 2366 time, respectively.</p>
 2367 </dd>
 2368 <dt>&#64;file</dt>
 2369 <dd><p class="first">This is equivalent to:</p>
 2370 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="nd">@link@files</span><span class="o">=</span><span class="n">file</span><span class="o">-</span><span class="mi">1</span>
 2371 <span class="n">file</span><span class="o">-</span><span class="mi">1</span><span class="nd">@content</span><span class="o">=</span><span class="n">value</span>
 2372 </pre></div>
 2373 </div>
 2374 <p class="last">The String content value is handled as described above for file
 2375 uploads.</p>
 2376 </dd>
 2377 </dl>
 2378 <p>If both the “&#64;note” and “&#64;file” form variables are
 2379 specified, the action:</p>
 2380 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="nd">@link@msg</span><span class="o">-</span><span class="mi">1</span><span class="nd">@files</span><span class="o">=</span><span class="n">file</span><span class="o">-</span><span class="mi">1</span>
 2381 </pre></div>
 2382 </div>
 2383 <p>is also performed.</p>
 2384 <p>We also check that FileClass items have a “content” property with
 2385 actual content, otherwise we remove them from all_props before
 2386 returning.</p>
 2387 </div>
 2388 <div class="section" id="default-templates">
 2389 <h3><a class="toc-backref" href="#id72">Default templates</a><a class="headerlink" href="#default-templates" title="Permalink to this headline"></a></h3>
 2390 <p>The default templates are html4 compliant. If you wish to change them to be
 2391 xhtml compliant, you’ll need to change the <code class="docutils literal"><span class="pre">html_version</span></code> configuration
 2392 variable in <code class="docutils literal"><span class="pre">config.ini</span></code> to <code class="docutils literal"><span class="pre">'xhtml'</span></code> instead of <code class="docutils literal"><span class="pre">'html4'</span></code>.</p>
 2393 <p>Most customisation of the web view can be done by modifying the
 2394 templates in the tracker <code class="docutils literal"><span class="pre">'html'</span></code> directory. There are several types
 2395 of files in there. The <em>minimal</em> template includes:</p>
 2396 <dl class="docutils">
 2397 <dt><strong>page.html</strong></dt>
 2398 <dd>This template usually defines the overall look of your tracker. When
 2399 you view an issue, it appears inside this template. When you view an
 2400 index, it also appears inside this template. This template defines a
 2401 macro called “icing” which is used by almost all other templates as a
 2402 coating for their content, using its “content” slot. It also defines
 2403 the “head_title” and “body_title” slots to allow setting of the page
 2404 title.</dd>
 2405 <dt><strong>home.html</strong></dt>
 2406 <dd>the default page displayed when no other page is indicated by the user</dd>
 2407 <dt><strong>home.classlist.html</strong></dt>
 2408 <dd>a special version of the default page that lists the classes in the
 2409 tracker</dd>
 2410 <dt><strong>classname.item.html</strong></dt>
 2411 <dd>displays an item of the <em>classname</em> class</dd>
 2412 <dt><strong>classname.index.html</strong></dt>
 2413 <dd>displays a list of <em>classname</em> items</dd>
 2414 <dt><strong>classname.search.html</strong></dt>
 2415 <dd>displays a search page for <em>classname</em> items</dd>
 2416 <dt><strong>_generic.index.html</strong></dt>
 2417 <dd>used to display a list of items where there is no
 2418 <code class="docutils literal"><span class="pre">*classname*.index</span></code> available</dd>
 2419 <dt><strong>_generic.help.html</strong></dt>
 2420 <dd>used to display a “class help” page where there is no
 2421 <code class="docutils literal"><span class="pre">*classname*.help</span></code></dd>
 2422 <dt><strong>user.register.html</strong></dt>
 2423 <dd>a special page just for the user class, that renders the registration
 2424 page</dd>
 2425 <dt><strong>style.css</strong></dt>
 2426 <dd>a static file that is served up as-is</dd>
 2427 </dl>
 2428 <p>The <em>classic</em> template has a number of additional templates.</p>
 2429 <p>Remember that you can create any template extension you want to,
 2430 so if you just want to play around with the templating for new issues,
 2431 you can copy the current “issue.item” template to “issue.test”, and then
 2432 access the test template using the “&#64;template” URL argument:</p>
 2433 <div class="highlight-default"><div class="highlight"><pre><span></span>http://your.tracker.example/tracker/issue?@template=test
 2434 </pre></div>
 2435 </div>
 2436 <p>and it won’t affect your users using the “issue.item” template.</p>
 2437 <p>You can also put templates into a subdirectory of the template
 2438 directory. So if you specify:</p>
 2439 <div class="highlight-default"><div class="highlight"><pre><span></span>http://your.tracker.example/tracker/issue?@template=test/item
 2440 </pre></div>
 2441 </div>
 2442 <p>you will use the template at: <code class="docutils literal"><span class="pre">test/issue.item.html</span></code>. If that
 2443 template doesn’t exit it will try to use
 2444 <code class="docutils literal"><span class="pre">test/_generic.item.html</span></code>. If that template doesn’t exist
 2445 it will return an error.</p>
 2446 </div>
 2447 <div class="section" id="implementing-modal-editing-using-template">
 2448 <h3><a class="toc-backref" href="#id73">Implementing Modal Editing Using &#64;template</a><a class="headerlink" href="#implementing-modal-editing-using-template" title="Permalink to this headline"></a></h3>
 2449 <p>Many item templates allow you to edit the item. They contain
 2450 code that renders edit boxes if the user has edit permissions.
 2451 Otherwise the template will just display the item information.</p>
 2452 <p>In some cases you want to do a modal edit. The user has to take some
 2453 action (click a button or follow a link) to shift from display mode to
 2454 edit mode. When the changes are submitted, ending the edit mode,
 2455 the user is returned to display mode.</p>
 2456 <p>Modal workflows usually slow things down and are not implemented by
 2457 default templates. However for some workflows a modal edit is useful.
 2458 For example a batch edit mode that allows the user to edit a number of
 2459 issues all from one form could be implemented as a modal workflow of:</p>
 2460 <ul class="simple">
 2461 <li>search for issues to modify</li>
 2462 <li>switch to edit mode and change values</li>
 2463 <li>exit back to the results of the search</li>
 2464 </ul>
 2465 <p>To implement the modal edit, assume you have an issue.edit.html
 2466 template that implements an edit form.  On the display page (a version
 2467 of issue.item.html modified to only display information) add a link
 2468 that calls the display url, but adds <code class="docutils literal"><span class="pre">&#64;template=edit</span></code> to the link.</p>
 2469 <p>This will now display the edit page. On the edit page you want to add
 2470 a hidden text field to your form named <code class="docutils literal"><span class="pre">&#64;template</span></code> with the value:
 2471 <code class="docutils literal"><span class="pre">item|edit</span></code>.  When the form is submitted it is validated. If the
 2472 form is correct the user will see the item rendered using the item
 2473 template. If there is an error (validation failed) the item will be
 2474 rendered using the edit template. The edit template that is rendered
 2475 will display all the changes that the user made to the form before it
 2476 was submitted. The user can correct the error and resubmit the changes
 2477 until the form validates.</p>
 2478 <p>If the form failed to validate but the <code class="docutils literal"><span class="pre">&#64;template</span></code> field had the
 2479 value <code class="docutils literal"><span class="pre">item</span></code> the user would still see the error, but all of the data
 2480 the user entered would be discarded. The user would have to redo all
 2481 the edits again.</p>
 2482 </div>
 2483 <div class="section" id="how-the-templates-work">
 2484 <h3><a class="toc-backref" href="#id74">How the templates work</a><a class="headerlink" href="#how-the-templates-work" title="Permalink to this headline"></a></h3>
 2485 <div class="section" id="templating-engines">
 2486 <h4><a class="toc-backref" href="#id75">Templating engines</a><a class="headerlink" href="#templating-engines" title="Permalink to this headline"></a></h4>
 2487 <p>Since version 1.4.20 Roundup supports two templating engines: the original
 2488 <a class="reference external" href="https://pagetemplates.readthedocs.io/en/latest/history/TALSpecification14.html">Template Attribute Language</a> (TAL) engine from Zope and the standalone
 2489 Chameleon templating engine. Chameleon is intended as a replacement for the
 2490 original TAL engine, and supports the same syntax,
 2491 but they are not 100% compatible. The major (and most likely the only)
 2492 incompatibility is the default expression type being
 2493 <code class="docutils literal"><span class="pre">python:</span></code> instead of <code class="docutils literal"><span class="pre">path:</span></code>. See also “Incompatibilities and
 2494 differences” section of <a class="reference external" href="https://chameleon.readthedocs.io/en/latest/reference.html?highlight=differences#incompatibilities-and-differences">Chameleon documentation</a>.</p>
 2495 <p><strong>NOTE1</strong>: For historical reasons, examples given below assumes path
 2496 expression as default expression type. With Chameleon you have to manually
 2497 resolve the path expressions. A Chameleon-based, z3c.pt, that is fully
 2498 compatible with the old TAL implementation, is planned to be included in a
 2499 future release.</p>
 2500 <p><strong>NOTE2</strong>: As of 1.4.20 Chameleon support is highly experimental and <strong>not</strong>
 2501 recommended for production use.</p>
 2502 </div>
 2503 <div class="section" id="basic-templating-actions">
 2504 <h4><a class="toc-backref" href="#id76">Basic Templating Actions</a><a class="headerlink" href="#basic-templating-actions" title="Permalink to this headline"></a></h4>
 2505 <p>Roundup’s templates consist of special attributes on the HTML tags.
 2506 These attributes form the <strong>Template Attribute Language</strong>, or TAL.
 2507 The basic TAL commands are:</p>
 2508 <dl class="docutils">
 2509 <dt><strong>tal:define=”variable expression; variable expression; …”</strong></dt>
 2510 <dd><p class="first">Define a new variable that is local to this tag and its contents. For
 2511 example:</p>
 2512 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">html</span> <span class="n">tal</span><span class="p">:</span><span class="n">define</span><span class="o">=</span><span class="s2">&quot;title request/description&quot;</span><span class="o">&gt;</span>
 2513  <span class="o">&lt;</span><span class="n">head</span><span class="o">&gt;&lt;</span><span class="n">title</span> <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;title&quot;</span><span class="o">&gt;&lt;/</span><span class="n">title</span><span class="o">&gt;&lt;/</span><span class="n">head</span><span class="o">&gt;</span>
 2514 <span class="o">&lt;/</span><span class="n">html</span><span class="o">&gt;</span>
 2515 </pre></div>
 2516 </div>
 2517 <p class="last">In this example, the variable “title” is defined as the result of the
 2518 expression “request/description”. The “tal:content” command inside the
 2519 &lt;html&gt; tag may then use the “title” variable.</p>
 2520 </dd>
 2521 <dt><strong>tal:condition=”expression”</strong></dt>
 2522 <dd><p class="first">Only keep this tag and its contents if the expression is true. For
 2523 example:</p>
 2524 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">p</span> <span class="n">tal</span><span class="p">:</span><span class="n">condition</span><span class="o">=</span><span class="s2">&quot;python:request.user.hasPermission(&#39;View&#39;, &#39;issue&#39;)&quot;</span><span class="o">&gt;</span>
 2525  <span class="n">Display</span> <span class="n">some</span> <span class="n">issue</span> <span class="n">information</span><span class="o">.</span>
 2526 <span class="o">&lt;/</span><span class="n">p</span><span class="o">&gt;</span>
 2527 </pre></div>
 2528 </div>
 2529 <p class="last">In the example, the &lt;p&gt; tag and its contents are only displayed if
 2530 the user has the “View” permission for issues. We consider the number
 2531 zero, a blank string, an empty list, and the built-in variable
 2532 nothing to be false values. Nearly every other value is true,
 2533 including non-zero numbers, and strings with anything in them (even
 2534 spaces!).</p>
 2535 </dd>
 2536 <dt><strong>tal:repeat=”variable expression”</strong></dt>
 2537 <dd><p class="first">Repeat this tag and its contents for each element of the sequence
 2538 that the expression returns, defining a new local variable and a
 2539 special “repeat” variable for each element. For example:</p>
 2540 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">tr</span> <span class="n">tal</span><span class="p">:</span><span class="n">repeat</span><span class="o">=</span><span class="s2">&quot;u user/list&quot;</span><span class="o">&gt;</span>
 2541  <span class="o">&lt;</span><span class="n">td</span> <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;u/id&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 2542  <span class="o">&lt;</span><span class="n">td</span> <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;u/username&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 2543  <span class="o">&lt;</span><span class="n">td</span> <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;u/realname&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 2544 <span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
 2545 </pre></div>
 2546 </div>
 2547 <p class="last">The example would iterate over the sequence of users returned by
 2548 “user/list” and define the local variable “u” for each entry. Using
 2549 the repeat command creates a new variable called “repeat” which you
 2550 may access to gather information about the iteration. See the section
 2551 below on <a class="reference internal" href="#the-repeat-variable">the repeat variable</a>.</p>
 2552 </dd>
 2553 <dt><strong>tal:replace=”expression”</strong></dt>
 2554 <dd><p class="first">Replace this tag with the result of the expression. For example:</p>
 2555 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">span</span> <span class="n">tal</span><span class="p">:</span><span class="n">replace</span><span class="o">=</span><span class="s2">&quot;request/user/realname&quot;</span> <span class="o">/&gt;</span>
 2556 </pre></div>
 2557 </div>
 2558 <p class="last">The example would replace the &lt;span&gt; tag and its contents with the
 2559 user’s realname. If the user’s realname was “Bruce”, then the
 2560 resultant output would be “Bruce”.</p>
 2561 </dd>
 2562 <dt><strong>tal:content=”expression”</strong></dt>
 2563 <dd><p class="first">Replace the contents of this tag with the result of the expression.
 2564 For example:</p>
 2565 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">span</span> <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;request/user/realname&quot;</span><span class="o">&gt;</span><span class="n">user</span><span class="s1">&#39;s name appears here</span>
 2566 <span class="o">&lt;/</span><span class="n">span</span><span class="o">&gt;</span>
 2567 </pre></div>
 2568 </div>
 2569 <p class="last">The example would replace the contents of the &lt;span&gt; tag with the
 2570 user’s realname. If the user’s realname was “Bruce” then the
 2571 resultant output would be “&lt;span&gt;Bruce&lt;/span&gt;”.</p>
 2572 </dd>
 2573 <dt><strong>tal:attributes=”attribute expression; attribute expression; …”</strong></dt>
 2574 <dd><p class="first">Set attributes on this tag to the results of expressions. For
 2575 example:</p>
 2576 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">a</span> <span class="n">tal</span><span class="p">:</span><span class="n">attributes</span><span class="o">=</span><span class="s2">&quot;href string:user${request/user/id}&quot;</span><span class="o">&gt;</span><span class="n">My</span> <span class="n">Details</span><span class="o">&lt;/</span><span class="n">a</span><span class="o">&gt;</span>
 2577 </pre></div>
 2578 </div>
 2579 <p class="last">In the example, the “href” attribute of the &lt;a&gt; tag is set to the
 2580 value of the “string:user${request/user/id}” expression, which will
 2581 be something like “user123”.</p>
 2582 </dd>
 2583 <dt><strong>tal:omit-tag=”expression”</strong></dt>
 2584 <dd><p class="first">Remove this tag (but not its contents) if the expression is true. For
 2585 example:</p>
 2586 <div class="highlight-default"><div class="highlight"><pre><span></span>&lt;span tal:omit-tag=&quot;python:1&quot;&gt;Hello, world!&lt;/span&gt;
 2587 </pre></div>
 2588 </div>
 2589 <p>would result in output of:</p>
 2590 <div class="last highlight-default"><div class="highlight"><pre><span></span>Hello, world!
 2591 </pre></div>
 2592 </div>
 2593 </dd>
 2594 </dl>
 2595 <p>Note that the commands on a given tag are evaulated in the order above,
 2596 so <em>define</em> comes before <em>condition</em>, and so on.</p>
 2597 <p>Additionally, you may include tags such as &lt;tal:block&gt;, which are
 2598 removed from output. Its content is kept, but the tag itself is not (so
 2599 don’t go using any “tal:attributes” commands on it). This is useful for
 2600 making arbitrary blocks of HTML conditional or repeatable (very handy
 2601 for repeating multiple table rows, which would othewise require an
 2602 illegal tag placement to effect the repeat).</p>
 2603 </div>
 2604 <div class="section" id="templating-expressions">
 2605 <h4><a class="toc-backref" href="#id77">Templating Expressions</a><a class="headerlink" href="#templating-expressions" title="Permalink to this headline"></a></h4>
 2606 <p>Templating Expressions are covered by <a class="reference external" href="https://pagetemplates.readthedocs.io/en/latest/history/TALESSpecification13.html">Template Attribute Language
 2607 Expression Syntax</a>, or TALES. The expressions you may use in the
 2608 attribute values may be one of the following forms:</p>
 2609 <dl class="docutils">
 2610 <dt><strong>Path Expressions</strong> - eg. <code class="docutils literal"><span class="pre">item/status/checklist</span></code></dt>
 2611 <dd><p class="first">These are object attribute / item accesses. Roughly speaking, the
 2612 path <code class="docutils literal"><span class="pre">item/status/checklist</span></code> is broken into parts <code class="docutils literal"><span class="pre">item</span></code>,
 2613 <code class="docutils literal"><span class="pre">status</span></code> and <code class="docutils literal"><span class="pre">checklist</span></code>. The <code class="docutils literal"><span class="pre">item</span></code> part is the root of the
 2614 expression. We then look for a <code class="docutils literal"><span class="pre">status</span></code> attribute on <code class="docutils literal"><span class="pre">item</span></code>, or
 2615 failing that, a <code class="docutils literal"><span class="pre">status</span></code> item (as in <code class="docutils literal"><span class="pre">item['status']</span></code>). If that
 2616 fails, the path expression fails. When we get to the end, the object
 2617 we’re left with is evaluated to get a string - if it is a method, it
 2618 is called; if it is an object, it is stringified. Path expressions
 2619 may have an optional <code class="docutils literal"><span class="pre">path:</span></code> prefix, but they are the default
 2620 expression type, so it’s not necessary.</p>
 2621 <p>If an expression evaluates to <code class="docutils literal"><span class="pre">default</span></code>, then the expression is
 2622 “cancelled” - whatever HTML already exists in the template will
 2623 remain (tag content in the case of <code class="docutils literal"><span class="pre">tal:content</span></code>, attributes in the
 2624 case of <code class="docutils literal"><span class="pre">tal:attributes</span></code>).</p>
 2625 <p>If an expression evaluates to <code class="docutils literal"><span class="pre">nothing</span></code> then the target of the
 2626 expression is removed (tag content in the case of <code class="docutils literal"><span class="pre">tal:content</span></code>,
 2627 attributes in the case of <code class="docutils literal"><span class="pre">tal:attributes</span></code> and the tag itself in
 2628 the case of <code class="docutils literal"><span class="pre">tal:replace</span></code>).</p>
 2629 <p>If an element in the path may not exist, then you can use the <code class="docutils literal"><span class="pre">|</span></code>
 2630 operator in the expression to provide an alternative. So, the
 2631 expression <code class="docutils literal"><span class="pre">request/form/foo/value</span> <span class="pre">|</span> <span class="pre">default</span></code> would simply leave
 2632 the current HTML in place if the “foo” form variable doesn’t exist.</p>
 2633 <p class="last">You may use the python function <code class="docutils literal"><span class="pre">path</span></code>, as in
 2634 <code class="docutils literal"><span class="pre">path(&quot;item/status&quot;)</span></code>, to embed path expressions in Python
 2635 expressions.</p>
 2636 </dd>
 2637 <dt><strong>String Expressions</strong> - eg. <code class="docutils literal"><span class="pre">string:hello</span> <span class="pre">${user/name}</span></code></dt>
 2638 <dd>These expressions are simple string interpolations - though they can
 2639 be just plain strings with no interpolation if you want. The
 2640 expression in the <code class="docutils literal"><span class="pre">${</span> <span class="pre">...</span> <span class="pre">}</span></code> is just a path expression as above.</dd>
 2641 <dt><strong>Python Expressions</strong> - eg. <code class="docutils literal"><span class="pre">python:</span> <span class="pre">1+1</span></code></dt>
 2642 <dd>These expressions give the full power of Python. All the “root level”
 2643 variables are available, so <code class="docutils literal"><span class="pre">python:item.status.checklist()</span></code> would
 2644 be equivalent to <code class="docutils literal"><span class="pre">item/status/checklist</span></code>, assuming that
 2645 <code class="docutils literal"><span class="pre">checklist</span></code> is a method.</dd>
 2646 </dl>
 2647 <p>Modifiers:</p>
 2648 <dl class="docutils">
 2649 <dt><strong>structure</strong> - eg. <code class="docutils literal"><span class="pre">structure</span> <span class="pre">python:msg.content.plain(hyperlink=1)</span></code></dt>
 2650 <dd>The result of expressions are normally <em>escaped</em> to be safe for HTML
 2651 display (all “&lt;”, “&gt;” and “&amp;” are turned into special entities). The
 2652 <code class="docutils literal"><span class="pre">structure</span></code> expression modifier turns off this escaping - the
 2653 result of the expression is now assumed to be HTML, which is passed
 2654 to the web browser for rendering.</dd>
 2655 <dt><strong>not:</strong> - eg. <code class="docutils literal"><span class="pre">not:python:1=1</span></code></dt>
 2656 <dd>This simply inverts the logical true/false value of another
 2657 expression.</dd>
 2658 </dl>
 2659 </div>
 2660 <div class="section" id="template-macros">
 2661 <h4><a class="toc-backref" href="#id78">Template Macros</a><a class="headerlink" href="#template-macros" title="Permalink to this headline"></a></h4>
 2662 <p>Macros are used in Roundup to save us from repeating the same common
 2663 page stuctures over and over. The most common (and probably only) macro
 2664 you’ll use is the “icing” macro defined in the “page” template.</p>
 2665 <p>Macros are generated and used inside your templates using special
 2666 attributes similar to the <a class="reference internal" href="#basic-templating-actions">basic templating actions</a>. In this case,
 2667 though, the attributes belong to the <a class="reference external" href="https://pagetemplates.readthedocs.io/en/latest/history/TALESSpecification13.html">Macro Expansion Template
 2668 Attribute Language</a>, or METAL. The macro commands are:</p>
 2669 <dl class="docutils">
 2670 <dt><strong>metal:define-macro=”macro name”</strong></dt>
 2671 <dd><p class="first">Define that the tag and its contents are now a macro that may be
 2672 inserted into other templates using the <em>use-macro</em> command. For
 2673 example:</p>
 2674 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">html</span> <span class="n">metal</span><span class="p">:</span><span class="n">define</span><span class="o">-</span><span class="n">macro</span><span class="o">=</span><span class="s2">&quot;page&quot;</span><span class="o">&gt;</span>
 2675  <span class="o">...</span>
 2676 <span class="o">&lt;/</span><span class="n">html</span><span class="o">&gt;</span>
 2677 </pre></div>
 2678 </div>
 2679 <p class="last">defines a macro called “page” using the <code class="docutils literal"><span class="pre">&lt;html&gt;</span></code> tag and its
 2680 contents. Once defined, macros are stored on the template they’re
 2681 defined on in the <code class="docutils literal"><span class="pre">macros</span></code> attribute. You can access them later on
 2682 through the <code class="docutils literal"><span class="pre">templates</span></code> variable, eg. the most common
 2683 <code class="docutils literal"><span class="pre">templates/page/macros/icing</span></code> to access the “page” macro of the
 2684 “page” template.</p>
 2685 </dd>
 2686 <dt><strong>metal:use-macro=”path expression”</strong></dt>
 2687 <dd><p class="first">Use a macro, which is identified by the path expression (see above).
 2688 This will replace the current tag with the identified macro contents.
 2689 For example:</p>
 2690 <div class="last highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">tal</span><span class="p">:</span><span class="n">block</span> <span class="n">metal</span><span class="p">:</span><span class="n">use</span><span class="o">-</span><span class="n">macro</span><span class="o">=</span><span class="s2">&quot;templates/page/macros/icing&quot;</span><span class="o">&gt;</span>
 2691  <span class="o">...</span>
 2692 <span class="o">&lt;/</span><span class="n">tal</span><span class="p">:</span><span class="n">block</span><span class="o">&gt;</span>
 2693 
 2694 <span class="n">will</span> <span class="n">replace</span> <span class="n">the</span> <span class="n">tag</span> <span class="ow">and</span> <span class="n">its</span> <span class="n">contents</span> <span class="k">with</span> <span class="n">the</span> <span class="s2">&quot;page&quot;</span> <span class="n">macro</span> <span class="n">of</span> <span class="n">the</span>
 2695 <span class="s2">&quot;page&quot;</span> <span class="n">template</span><span class="o">.</span>
 2696 </pre></div>
 2697 </div>
 2698 </dd>
 2699 <dt><strong>metal:define-slot=”slot name”</strong> and <strong>metal:fill-slot=”slot name”</strong></dt>
 2700 <dd><p class="first">To define <em>dynamic</em> parts of the macro, you define “slots” which may
 2701 be filled when the macro is used with a <em>use-macro</em> command. For
 2702 example, the <code class="docutils literal"><span class="pre">templates/page/macros/icing</span></code> macro defines a slot like
 2703 so:</p>
 2704 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">title</span> <span class="n">metal</span><span class="p">:</span><span class="n">define</span><span class="o">-</span><span class="n">slot</span><span class="o">=</span><span class="s2">&quot;head_title&quot;</span><span class="o">&gt;</span><span class="n">title</span> <span class="n">goes</span> <span class="n">here</span><span class="o">&lt;/</span><span class="n">title</span><span class="o">&gt;</span>
 2705 </pre></div>
 2706 </div>
 2707 <p>In your <em>use-macro</em> command, you may now use a <em>fill-slot</em> command
 2708 like this:</p>
 2709 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">title</span> <span class="n">metal</span><span class="p">:</span><span class="n">fill</span><span class="o">-</span><span class="n">slot</span><span class="o">=</span><span class="s2">&quot;head_title&quot;</span><span class="o">&gt;</span><span class="n">My</span> <span class="n">Title</span><span class="o">&lt;/</span><span class="n">title</span><span class="o">&gt;</span>
 2710 </pre></div>
 2711 </div>
 2712 <p class="last">where the tag that fills the slot completely replaces the one defined
 2713 as the slot in the macro.</p>
 2714 </dd>
 2715 </dl>
 2716 <p>Note that you may not mix <a class="reference external" href="https://pagetemplates.readthedocs.io/en/latest/history/TALESSpecification13.html">METAL</a> and <a class="reference external" href="https://pagetemplates.readthedocs.io/en/latest/history/TALSpecification14.html">TAL</a> commands on the same tag, but
 2717 TAL commands may be used freely inside METAL-using tags (so your
 2718 <em>fill-slots</em> tags may have all manner of TAL inside them).</p>
 2719 </div>
 2720 </div>
 2721 <div class="section" id="information-available-to-templates">
 2722 <h3><a class="toc-backref" href="#id79">Information available to templates</a><a class="headerlink" href="#information-available-to-templates" title="Permalink to this headline"></a></h3>
 2723 <p>This is implemented by <code class="docutils literal"><span class="pre">roundup.cgi.templating.RoundupPageTemplate</span></code></p>
 2724 <p>The following variables are available to templates.</p>
 2725 <dl class="docutils">
 2726 <dt><strong>context</strong></dt>
 2727 <dd>The current context. This is either None, a <a class="reference internal" href="#hyperdb-class-wrapper">hyperdb class wrapper</a>
 2728 or a <a class="reference internal" href="#hyperdb-item-wrapper">hyperdb item wrapper</a></dd>
 2729 <dt><strong>request</strong></dt>
 2730 <dd><dl class="first last docutils">
 2731 <dt>Includes information about the current request, including:</dt>
 2732 <dd><ul class="first last simple">
 2733 <li>the current index information (<code class="docutils literal"><span class="pre">filterspec</span></code>, <code class="docutils literal"><span class="pre">filter</span></code> args,
 2734 <code class="docutils literal"><span class="pre">properties</span></code>, etc) parsed out of the form.</li>
 2735 <li>methods for easy filterspec link generation</li>
 2736 <li>“form”
 2737 The current CGI form information as a mapping of form argument name
 2738 to value (specifically a cgi.FieldStorage)</li>
 2739 <li>“env” the CGI environment variables</li>
 2740 <li>“base” the base URL for this instance</li>
 2741 <li>“user” a HTMLItem instance for the current user</li>
 2742 <li>“language” as determined by the browser or config</li>
 2743 <li>“classname” the current classname (possibly None)</li>
 2744 <li>“template” the current template (suffix, also possibly None)</li>
 2745 </ul>
 2746 </dd>
 2747 </dl>
 2748 </dd>
 2749 <dt><strong>config</strong></dt>
 2750 <dd>This variable holds all the values defined in the tracker config.ini
 2751 file (eg. TRACKER_NAME, etc.)</dd>
 2752 <dt><strong>db</strong></dt>
 2753 <dd>The current database, used to access arbitrary database items.</dd>
 2754 <dt><strong>templates</strong></dt>
 2755 <dd>Access to all the tracker templates by name. Used mainly in
 2756 <em>use-macro</em> commands.</dd>
 2757 <dt><strong>utils</strong></dt>
 2758 <dd>This variable makes available some utility functions like batching.</dd>
 2759 <dt><strong>nothing</strong></dt>
 2760 <dd><p class="first">This is a special variable - if an expression evaluates to this, then
 2761 the tag (in the case of a <code class="docutils literal"><span class="pre">tal:replace</span></code>), its contents (in the case
 2762 of <code class="docutils literal"><span class="pre">tal:content</span></code>) or some attributes (in the case of
 2763 <code class="docutils literal"><span class="pre">tal:attributes</span></code>) will not appear in the the output. So, for
 2764 example:</p>
 2765 <div class="highlight-default"><div class="highlight"><pre><span></span>&lt;span tal:attributes=&quot;class nothing&quot;&gt;Hello, World!&lt;/span&gt;
 2766 </pre></div>
 2767 </div>
 2768 <p>would result in:</p>
 2769 <div class="last highlight-default"><div class="highlight"><pre><span></span>&lt;span&gt;Hello, World!&lt;/span&gt;
 2770 </pre></div>
 2771 </div>
 2772 </dd>
 2773 <dt><strong>default</strong></dt>
 2774 <dd><p class="first">Also a special variable - if an expression evaluates to this, then the
 2775 existing HTML in the template will not be replaced or removed, it will
 2776 remain. So:</p>
 2777 <div class="highlight-default"><div class="highlight"><pre><span></span>&lt;span tal:replace=&quot;default&quot;&gt;Hello, World!&lt;/span&gt;
 2778 </pre></div>
 2779 </div>
 2780 <p>would result in:</p>
 2781 <div class="last highlight-default"><div class="highlight"><pre><span></span>&lt;span&gt;Hello, World!&lt;/span&gt;
 2782 </pre></div>
 2783 </div>
 2784 </dd>
 2785 <dt><strong>true</strong>, <strong>false</strong></dt>
 2786 <dd>Boolean constants that may be used in <a class="reference internal" href="#templating-expressions">templating expressions</a>
 2787 instead of <code class="docutils literal"><span class="pre">python:1</span></code> and <code class="docutils literal"><span class="pre">python:0</span></code>.</dd>
 2788 <dt><strong>i18n</strong></dt>
 2789 <dd><p class="first">Internationalization service, providing two string translation methods:</p>
 2790 <dl class="last docutils">
 2791 <dt><strong>gettext</strong> (<em>message</em>)</dt>
 2792 <dd>Return the localized translation of message</dd>
 2793 <dt><strong>ngettext</strong> (<em>singular</em>, <em>plural</em>, <em>number</em>)</dt>
 2794 <dd>Like <code class="docutils literal"><span class="pre">gettext()</span></code>, but consider plural forms. If a translation
 2795 is found, apply the plural formula to <em>number</em>, and return the
 2796 resulting message (some languages have more than two plural forms).
 2797 If no translation is found, return singular if <em>number</em> is 1;
 2798 return plural otherwise.</dd>
 2799 </dl>
 2800 </dd>