"Fossies" - the Fresh Open Source Software Archive

Member "roundup-2.0.0/share/doc/roundup/html/design.html" (13 Jul 2020, 160524 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>Roundup - An Issue-Tracking System for Knowledge Workers &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="Developing Roundup" href="developers.html" />
   28     <link rel="prev" title="Roundup: an Issue-Tracking System for Knowledge Workers" href="overview.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="#">Roundup - An Issue-Tracking System for Knowledge Workers</a><ul>
   48 <li><a class="reference internal" href="#introduction">Introduction</a></li>
   49 <li><a class="reference internal" href="#the-layer-cake">The Layer Cake</a></li>
   50 <li><a class="reference internal" href="#hyperdatabase">Hyperdatabase</a><ul>
   51 <li><a class="reference internal" href="#dates-and-date-arithmetic">Dates and Date Arithmetic</a></li>
   52 <li><a class="reference internal" href="#items-and-classes">Items and Classes</a></li>
   53 <li><a class="reference internal" href="#identifiers-and-designators">Identifiers and Designators</a></li>
   54 <li><a class="reference internal" href="#property-names-and-types">Property Names and Types</a></li>
   55 <li><a class="reference internal" href="#hyperdb-interface-specification">Hyperdb Interface Specification</a></li>
   56 <li><a class="reference internal" href="#hyperdatabase-implementations">Hyperdatabase Implementations</a></li>
   57 <li><a class="reference internal" href="#application-example">Application Example</a></li>
   58 </ul>
   59 </li>
   60 <li><a class="reference internal" href="#roundup-database">Roundup Database</a><ul>
   61 <li><a class="reference internal" href="#reserved-classes">Reserved Classes</a><ul>
   62 <li><a class="reference internal" href="#users">Users</a></li>
   63 <li><a class="reference internal" href="#messages">Messages</a></li>
   64 <li><a class="reference internal" href="#files">Files</a></li>
   65 </ul>
   66 </li>
   67 <li><a class="reference internal" href="#issue-classes">Issue Classes</a></li>
   68 <li><a class="reference internal" href="#roundupdb-interface-specification">Roundupdb Interface Specification</a></li>
   69 <li><a class="reference internal" href="#default-schema">Default Schema</a></li>
   70 </ul>
   71 </li>
   72 <li><a class="reference internal" href="#detector-interface">Detector Interface</a><ul>
   73 <li><a class="reference internal" href="#detector-interface-specification">Detector Interface Specification</a></li>
   74 <li><a class="reference internal" href="#detector-example">Detector Example</a></li>
   75 </ul>
   76 </li>
   77 <li><a class="reference internal" href="#command-interface">Command Interface</a><ul>
   78 <li><a class="reference internal" href="#command-interface-specification">Command Interface Specification</a></li>
   79 <li><a class="reference internal" href="#usage-example">Usage Example</a></li>
   80 </ul>
   81 </li>
   82 <li><a class="reference internal" href="#e-mail-user-interface">E-mail User Interface</a><ul>
   83 <li><a class="reference internal" href="#message-processing">Message Processing</a></li>
   84 <li><a class="reference internal" href="#nosy-lists">Nosy Lists</a></li>
   85 <li><a class="reference internal" href="#setting-properties">Setting Properties</a></li>
   86 </ul>
   87 </li>
   88 <li><a class="reference internal" href="#web-user-interface">Web User Interface</a><ul>
   89 <li><a class="reference internal" href="#views-and-view-specifiers">Views and View Specifiers</a></li>
   90 <li><a class="reference internal" href="#displaying-properties">Displaying Properties</a></li>
   91 <li><a class="reference internal" href="#index-views">Index Views</a><ul>
   92 <li><a class="reference internal" href="#index-view-specifiers">Index View Specifiers</a></li>
   93 <li><a class="reference internal" href="#index-section">Index Section</a></li>
   94 <li><a class="reference internal" href="#sorting">Sorting</a></li>
   95 </ul>
   96 </li>
   97 <li><a class="reference internal" href="#issue-views">Issue Views</a><ul>
   98 <li><a class="reference internal" href="#issue-view-specifiers">Issue View Specifiers</a></li>
   99 <li><a class="reference internal" href="#editor-section">Editor Section</a></li>
  100 <li><a class="reference internal" href="#spool-section">Spool Section</a></li>
  101 </ul>
  102 </li>
  103 </ul>
  104 </li>
  105 <li><a class="reference internal" href="#access-control">Access Control</a><ul>
  106 <li><a class="reference internal" href="#access-control-interface-specification">Access Control Interface Specification</a></li>
  107 <li><a class="reference internal" href="#authentication-of-users">Authentication of Users</a></li>
  108 <li><a class="reference internal" href="#anonymous-users">Anonymous Users</a></li>
  109 <li><a class="reference internal" href="#use-cases">Use Cases</a></li>
  110 </ul>
  111 </li>
  112 <li><a class="reference internal" href="#deployment-scenarios">Deployment Scenarios</a></li>
  113 <li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
  114 <li><a class="reference internal" href="#changes-to-this-document">Changes to this document</a></li>
  115 </ul>
  116 </li>
  117 </ul>
  118 
  119     <h4>Previous topic</h4>
  120     <p class="topless"><a href="overview.html"
  121                           title="previous chapter">Roundup: an Issue-Tracking System for Knowledge Workers</a></p>
  122     <h4>Next topic</h4>
  123     <p class="topless"><a href="developers.html"
  124                           title="next chapter">Developing Roundup</a></p>
  125     <h3>This Page</h3>
  126     <ul class="this-page-menu">
  127       <li><a href="_sources/design.txt"
  128              rel="nofollow">Show Source</a></li>
  129     </ul>
  130   <div id="searchbox" style="display: none">
  131     <h3>Quick search</h3>
  132       <form class="search" action="search.html" method="get">
  133         <input type="text" name="q" size="18" />
  134         <input type="submit" value="Go" />
  135         <input type="hidden" name="check_keywords" value="yes" />
  136         <input type="hidden" name="area" value="default" />
  137       </form>
  138       <p style="font-size: 90%">Enter search terms or a module, class or function name.</p>
  139   </div>
  140   <script type="text/javascript">$('#searchbox').show(0);</script>
  141       </div>
  142     </div>
  143     <div class="content">
  144        
  145     <div class="related related-top">
  146       <ul>
  147         <li class="right" style="margin-right: 10px">
  148           <a href="genindex.html" title="General Index"
  149              accesskey="I">index</a></li>
  150         <li class="right" >
  151           <a href="developers.html" title="Developing Roundup"
  152              accesskey="N">next</a></li>
  153         <li class="right" >
  154           <a href="overview.html" title="Roundup: an Issue-Tracking System for Knowledge Workers"
  155              accesskey="P">previous</a></li>
  156         <li><a href="index.html">Roundup 2.0.0 documentation</a></li> 
  157       </ul>
  158     </div>
  159        
  160   <div class="section" id="roundup-an-issue-tracking-system-for-knowledge-workers">
  161 <h1>Roundup - An Issue-Tracking System for Knowledge Workers<a class="headerlink" href="#roundup-an-issue-tracking-system-for-knowledge-workers" title="Permalink to this headline"></a></h1>
  162 <table class="docutils field-list" frame="void" rules="none">
  163 <col class="field-name" />
  164 <col class="field-body" />
  165 <tbody valign="top">
  166 <tr class="field-odd field"><th class="field-name">Authors:</th><td class="field-body">Ka-Ping Yee (original), Richard Jones (implementation)</td>
  167 </tr>
  168 </tbody>
  169 </table>
  170 <p>Contents</p>
  171 <div class="contents local topic" id="contents">
  172 <ul class="simple">
  173 <li><a class="reference internal" href="#introduction" id="id2">Introduction</a></li>
  174 <li><a class="reference internal" href="#the-layer-cake" id="id3">The Layer Cake</a></li>
  175 <li><a class="reference internal" href="#hyperdatabase" id="id4">Hyperdatabase</a><ul>
  176 <li><a class="reference internal" href="#dates-and-date-arithmetic" id="id5">Dates and Date Arithmetic</a></li>
  177 <li><a class="reference internal" href="#items-and-classes" id="id6">Items and Classes</a></li>
  178 <li><a class="reference internal" href="#identifiers-and-designators" id="id7">Identifiers and Designators</a></li>
  179 <li><a class="reference internal" href="#property-names-and-types" id="id8">Property Names and Types</a></li>
  180 <li><a class="reference internal" href="#hyperdb-interface-specification" id="id9">Hyperdb Interface Specification</a></li>
  181 <li><a class="reference internal" href="#hyperdatabase-implementations" id="id10">Hyperdatabase Implementations</a></li>
  182 <li><a class="reference internal" href="#application-example" id="id11">Application Example</a></li>
  183 </ul>
  184 </li>
  185 <li><a class="reference internal" href="#roundup-database" id="id12">Roundup Database</a><ul>
  186 <li><a class="reference internal" href="#reserved-classes" id="id13">Reserved Classes</a><ul>
  187 <li><a class="reference internal" href="#users" id="id14">Users</a></li>
  188 <li><a class="reference internal" href="#messages" id="id15">Messages</a></li>
  189 <li><a class="reference internal" href="#files" id="id16">Files</a></li>
  190 </ul>
  191 </li>
  192 <li><a class="reference internal" href="#issue-classes" id="id17">Issue Classes</a></li>
  193 <li><a class="reference internal" href="#roundupdb-interface-specification" id="id18">Roundupdb Interface Specification</a></li>
  194 <li><a class="reference internal" href="#default-schema" id="id19">Default Schema</a></li>
  195 </ul>
  196 </li>
  197 <li><a class="reference internal" href="#detector-interface" id="id20">Detector Interface</a><ul>
  198 <li><a class="reference internal" href="#detector-interface-specification" id="id21">Detector Interface Specification</a></li>
  199 <li><a class="reference internal" href="#detector-example" id="id22">Detector Example</a></li>
  200 </ul>
  201 </li>
  202 <li><a class="reference internal" href="#command-interface" id="id23">Command Interface</a><ul>
  203 <li><a class="reference internal" href="#command-interface-specification" id="id24">Command Interface Specification</a></li>
  204 <li><a class="reference internal" href="#usage-example" id="id25">Usage Example</a></li>
  205 </ul>
  206 </li>
  207 <li><a class="reference internal" href="#e-mail-user-interface" id="id26">E-mail User Interface</a><ul>
  208 <li><a class="reference internal" href="#message-processing" id="id27">Message Processing</a></li>
  209 <li><a class="reference internal" href="#nosy-lists" id="id28">Nosy Lists</a></li>
  210 <li><a class="reference internal" href="#setting-properties" id="id29">Setting Properties</a></li>
  211 </ul>
  212 </li>
  213 <li><a class="reference internal" href="#web-user-interface" id="id30">Web User Interface</a><ul>
  214 <li><a class="reference internal" href="#views-and-view-specifiers" id="id31">Views and View Specifiers</a></li>
  215 <li><a class="reference internal" href="#displaying-properties" id="id32">Displaying Properties</a></li>
  216 <li><a class="reference internal" href="#index-views" id="id33">Index Views</a><ul>
  217 <li><a class="reference internal" href="#index-view-specifiers" id="id34">Index View Specifiers</a></li>
  218 <li><a class="reference internal" href="#index-section" id="id35">Index Section</a></li>
  219 <li><a class="reference internal" href="#sorting" id="id36">Sorting</a></li>
  220 </ul>
  221 </li>
  222 <li><a class="reference internal" href="#issue-views" id="id37">Issue Views</a><ul>
  223 <li><a class="reference internal" href="#issue-view-specifiers" id="id38">Issue View Specifiers</a></li>
  224 <li><a class="reference internal" href="#editor-section" id="id39">Editor Section</a></li>
  225 <li><a class="reference internal" href="#spool-section" id="id40">Spool Section</a></li>
  226 </ul>
  227 </li>
  228 </ul>
  229 </li>
  230 <li><a class="reference internal" href="#access-control" id="id41">Access Control</a><ul>
  231 <li><a class="reference internal" href="#access-control-interface-specification" id="id42">Access Control Interface Specification</a></li>
  232 <li><a class="reference internal" href="#authentication-of-users" id="id43">Authentication of Users</a></li>
  233 <li><a class="reference internal" href="#anonymous-users" id="id44">Anonymous Users</a></li>
  234 <li><a class="reference internal" href="#use-cases" id="id45">Use Cases</a></li>
  235 </ul>
  236 </li>
  237 <li><a class="reference internal" href="#deployment-scenarios" id="id46">Deployment Scenarios</a></li>
  238 <li><a class="reference internal" href="#acknowledgements" id="id47">Acknowledgements</a></li>
  239 <li><a class="reference internal" href="#changes-to-this-document" id="id48">Changes to this document</a></li>
  240 </ul>
  241 </div>
  242 <div class="section" id="introduction">
  243 <h2><a class="toc-backref" href="#id2">Introduction</a><a class="headerlink" href="#introduction" title="Permalink to this headline"></a></h2>
  244 <p>This document presents a description of the components of the Roundup
  245 system and specifies their interfaces and behaviour in sufficient detail
  246 to guide an implementation. For the philosophy and rationale behind the
  247 Roundup design, see the first-round Software Carpentry <a class="reference external" href="spec.html">submission for
  248 Roundup</a>. This document fleshes out that design as well as specifying
  249 interfaces so that the components can be developed separately.</p>
  250 </div>
  251 <div class="section" id="the-layer-cake">
  252 <h2><a class="toc-backref" href="#id3">The Layer Cake</a><a class="headerlink" href="#the-layer-cake" title="Permalink to this headline"></a></h2>
  253 <p>Lots of software design documents come with a picture of a cake.
  254 Everybody seems to like them.  I also like cakes (I think they are
  255 tasty).  So I, too, shall include a picture of a cake here:</p>
  256 <div class="highlight-default"><div class="highlight"><pre><span></span> <span class="n">________________________________________________________________</span>
  257 <span class="o">|</span> <span class="n">E</span><span class="o">-</span><span class="n">mail</span> <span class="n">Client</span> <span class="o">|</span>  <span class="n">Web</span> <span class="n">Browser</span>  <span class="o">|</span>  <span class="n">Detector</span> <span class="n">Scripts</span>  <span class="o">|</span>   <span class="n">Shell</span>   <span class="o">|</span>
  258 <span class="o">|---------------+---------------+--------------------+-----------|</span>
  259 <span class="o">|</span>  <span class="n">E</span><span class="o">-</span><span class="n">mail</span> <span class="n">User</span>  <span class="o">|</span>   <span class="n">Web</span> <span class="n">User</span>    <span class="o">|</span>     <span class="n">Detector</span>       <span class="o">|</span>  <span class="n">Command</span>  <span class="o">|</span>
  260 <span class="o">|----------------------------------------------------------------|</span>
  261 <span class="o">|</span>                    <span class="n">Roundup</span> <span class="n">Database</span> <span class="n">Layer</span>                      <span class="o">|</span>
  262 <span class="o">|----------------------------------------------------------------|</span>
  263 <span class="o">|</span>                     <span class="n">Hyperdatabase</span> <span class="n">Layer</span>                        <span class="o">|</span>
  264 <span class="o">|----------------------------------------------------------------|</span>
  265 <span class="o">|</span>                        <span class="n">Storage</span> <span class="n">Layer</span>                           <span class="o">|</span>
  266  <span class="o">----------------------------------------------------------------</span>
  267 </pre></div>
  268 </div>
  269 <p>The colourful parts of the cake are part of our system; the faint grey
  270 parts of the cake are external components.</p>
  271 <p>I will now proceed to forgo all table manners and eat from the bottom of
  272 the cake to the top.  You may want to stand back a bit so you don’t get
  273 covered in crumbs.</p>
  274 </div>
  275 <div class="section" id="hyperdatabase">
  276 <h2><a class="toc-backref" href="#id4">Hyperdatabase</a><a class="headerlink" href="#hyperdatabase" title="Permalink to this headline"></a></h2>
  277 <p>The lowest-level component to be implemented is the hyperdatabase. The
  278 hyperdatabase is a flexible data store that can hold configurable data
  279 in records which we call items.</p>
  280 <p>The hyperdatabase is implemented on top of the storage layer, an
  281 external module for storing its data. The “batteries-includes” distribution
  282 implements the hyperdatabase on the standard anydbm module.  The storage
  283 layer could be a third-party RDBMS; for a low-maintenance solution,
  284 implementing the hyperdatabase on the SQLite RDBMS is suggested.</p>
  285 <div class="section" id="dates-and-date-arithmetic">
  286 <h3><a class="toc-backref" href="#id5">Dates and Date Arithmetic</a><a class="headerlink" href="#dates-and-date-arithmetic" title="Permalink to this headline"></a></h3>
  287 <p>Before we get into the hyperdatabase itself, we need a way of handling
  288 dates.  The hyperdatabase module provides Timestamp objects for
  289 representing date-and-time stamps and Interval objects for representing
  290 date-and-time intervals.</p>
  291 <p>As strings, date-and-time stamps are specified with the date in ISO8601
  292 international standard format (<code class="docutils literal"><span class="pre">yyyy-mm-dd</span></code>) joined to the time
  293 (<code class="docutils literal"><span class="pre">hh:mm:ss</span></code>) by a period “<code class="docutils literal"><span class="pre">.</span></code>”.  Dates in this form can be easily
  294 compared and are fairly readable when printed.  An example of a valid
  295 stamp is “<code class="docutils literal"><span class="pre">2000-06-24.13:03:59</span></code>”. We’ll call this the “full date
  296 format”.  When Timestamp objects are printed as strings, they appear in
  297 the full date format with the time always given in GMT.  The full date
  298 format is always exactly 19 characters long.</p>
  299 <p>For user input, some partial forms are also permitted: the whole time or
  300 just the seconds may be omitted; and the whole date may be omitted or
  301 just the year may be omitted.  If the time is given, the time is
  302 interpreted in the user’s local time zone. The Date constructor takes
  303 care of these conversions. In the following examples, suppose that
  304 <code class="docutils literal"><span class="pre">yyyy</span></code> is the current year, <code class="docutils literal"><span class="pre">mm</span></code> is the current month, and <code class="docutils literal"><span class="pre">dd</span></code> is
  305 the current day of the month; and suppose that the user is on Eastern
  306 Standard Time.</p>
  307 <ul class="simple">
  308 <li>2000-04-17” means &lt;Date 2000-04-17.00:00:00&gt;</li>
  309 <li>01-25” means &lt;Date yyyy-01-25.00:00:00&gt;</li>
  310 <li>2000-04-17.03:45” means &lt;Date 2000-04-17.08:45:00&gt;</li>
  311 <li>08-13.22:13” means &lt;Date yyyy-08-14.03:13:00&gt;</li>
  312 <li>11-07.09:32:43” means &lt;Date yyyy-11-07.14:32:43&gt;</li>
  313 <li>14:25” means &lt;Date yyyy-mm-dd.19:25:00&gt;</li>
  314 <li>8:47:11” means &lt;Date yyyy-mm-dd.13:47:11&gt;</li>
  315 <li>the special date “.” means “right now”</li>
  316 </ul>
  317 <p>Date intervals are specified using the suffixes “y”, “m”, and “d”.  The
  318 suffix “w” (for “week”) means 7 days. Time intervals are specified in
  319 hh:mm:ss format (the seconds may be omitted, but the hours and minutes
  320 may not).</p>
  321 <ul class="simple">
  322 <li>3y” means three years</li>
  323 <li>2y 1m” means two years and one month</li>
  324 <li>1m 25d” means one month and 25 days</li>
  325 <li>2w 3d” means two weeks and three days</li>
  326 <li>1d 2:50” means one day, two hours, and 50 minutes</li>
  327 <li>14:00” means 14 hours</li>
  328 <li>0:04:33” means four minutes and 33 seconds</li>
  329 </ul>
  330 <p>The Date class should understand simple date expressions of the form
  331 <em>stamp</em> <code class="docutils literal"><span class="pre">+</span></code> <em>interval</em> and <em>stamp</em> <code class="docutils literal"><span class="pre">-</span></code> <em>interval</em>. When adding or
  332 subtracting intervals involving months or years, the components are
  333 handled separately.  For example, when evaluating “<code class="docutils literal"><span class="pre">2000-06-25</span> <span class="pre">+</span> <span class="pre">1m</span>
  334 <span class="pre">10d</span></code>”, we first add one month to get 2000-07-25, then add 10 days to
  335 get 2000-08-04 (rather than trying to decide whether 1m 10d means 38 or
  336 40 or 41 days).</p>
  337 <p>Here is an outline of the Date and Interval classes:</p>
  338 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Date</span><span class="p">:</span>
  339     <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">spec</span><span class="p">,</span> <span class="n">offset</span><span class="p">):</span>
  340         <span class="sd">&quot;&quot;&quot;Construct a date given a specification and a time zone</span>
  341 <span class="sd">        offset.</span>
  342 
  343 <span class="sd">        &#39;spec&#39; is a full date or a partial form, with an optional</span>
  344 <span class="sd">        added or subtracted interval.  &#39;offset&#39; is the local time</span>
  345 <span class="sd">        zone offset from GMT in hours.</span>
  346 <span class="sd">        &quot;&quot;&quot;</span>
  347 
  348     <span class="k">def</span> <span class="nf">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">interval</span><span class="p">):</span>
  349         <span class="sd">&quot;&quot;&quot;Add an interval to this date to produce another date.&quot;&quot;&quot;</span>
  350 
  351     <span class="k">def</span> <span class="nf">__sub__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">interval</span><span class="p">):</span>
  352         <span class="sd">&quot;&quot;&quot;Subtract an interval from this date to produce another</span>
  353 <span class="sd">        date.</span>
  354 <span class="sd">        &quot;&quot;&quot;</span>
  355 
  356     <span class="k">def</span> <span class="nf">__cmp__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
  357         <span class="sd">&quot;&quot;&quot;Compare this date to another date.&quot;&quot;&quot;</span>
  358 
  359     <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  360         <span class="sd">&quot;&quot;&quot;Return this date as a string in the yyyy-mm-dd.hh:mm:ss</span>
  361 <span class="sd">        format.</span>
  362 <span class="sd">        &quot;&quot;&quot;</span>
  363 
  364     <span class="k">def</span> <span class="nf">local</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">offset</span><span class="p">):</span>
  365         <span class="sd">&quot;&quot;&quot;Return this date as yyyy-mm-dd.hh:mm:ss in a local time</span>
  366 <span class="sd">        zone.</span>
  367 <span class="sd">        &quot;&quot;&quot;</span>
  368 
  369 <span class="k">class</span> <span class="nc">Interval</span><span class="p">:</span>
  370     <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">spec</span><span class="p">):</span>
  371         <span class="sd">&quot;&quot;&quot;Construct an interval given a specification.&quot;&quot;&quot;</span>
  372 
  373     <span class="k">def</span> <span class="nf">__cmp__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
  374         <span class="sd">&quot;&quot;&quot;Compare this interval to another interval.&quot;&quot;&quot;</span>
  375 
  376     <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  377         <span class="sd">&quot;&quot;&quot;Return this interval as a string.&quot;&quot;&quot;</span>
  378 </pre></div>
  379 </div>
  380 <p>Here are some examples of how these classes would behave in practice.
  381 For the following examples, assume that we are on Eastern Standard Time
  382 and the current local time is 19:34:02 on 25 June 2000:</p>
  383 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">Date</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>
  384 <span class="go">&lt;Date 2000-06-26.00:34:02&gt;</span>
  385 <span class="gp">&gt;&gt;&gt; </span><span class="n">_</span><span class="o">.</span><span class="n">local</span><span class="p">(</span><span class="o">-</span><span class="mi">5</span><span class="p">)</span>
  386 <span class="go">&quot;2000-06-25.19:34:02&quot;</span>
  387 <span class="gp">&gt;&gt;&gt; </span><span class="n">Date</span><span class="p">(</span><span class="s2">&quot;. + 2d&quot;</span><span class="p">)</span>
  388 <span class="go">&lt;Date 2000-06-28.00:34:02&gt;</span>
  389 <span class="gp">&gt;&gt;&gt; </span><span class="n">Date</span><span class="p">(</span><span class="s2">&quot;1997-04-17&quot;</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">)</span>
  390 <span class="go">&lt;Date 1997-04-17.00:00:00&gt;</span>
  391 <span class="gp">&gt;&gt;&gt; </span><span class="n">Date</span><span class="p">(</span><span class="s2">&quot;01-25&quot;</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">)</span>
  392 <span class="go">&lt;Date 2000-01-25.00:00:00&gt;</span>
  393 <span class="gp">&gt;&gt;&gt; </span><span class="n">Date</span><span class="p">(</span><span class="s2">&quot;08-13.22:13&quot;</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">)</span>
  394 <span class="go">&lt;Date 2000-08-14.03:13:00&gt;</span>
  395 <span class="gp">&gt;&gt;&gt; </span><span class="n">Date</span><span class="p">(</span><span class="s2">&quot;14:25&quot;</span><span class="p">,</span> <span class="o">-</span><span class="mi">5</span><span class="p">)</span>
  396 <span class="go">&lt;Date 2000-06-25.19:25:00&gt;</span>
  397 <span class="gp">&gt;&gt;&gt; </span><span class="n">Interval</span><span class="p">(</span><span class="s2">&quot;  3w  1  d  2:00&quot;</span><span class="p">)</span>
  398 <span class="go">&lt;Interval 22d 2:00&gt;</span>
  399 <span class="gp">&gt;&gt;&gt; </span><span class="n">Date</span><span class="p">(</span><span class="s2">&quot;. + 2d&quot;</span><span class="p">)</span> <span class="o">-</span> <span class="n">Interval</span><span class="p">(</span><span class="s2">&quot;3w&quot;</span><span class="p">)</span>
  400 <span class="go">&lt;Date 2000-06-07.00:34:02&gt;</span>
  401 </pre></div>
  402 </div>
  403 </div>
  404 <div class="section" id="items-and-classes">
  405 <h3><a class="toc-backref" href="#id6">Items and Classes</a><a class="headerlink" href="#items-and-classes" title="Permalink to this headline"></a></h3>
  406 <p>Items contain data in properties.  To Python, these properties are
  407 presented as the key-value pairs of a dictionary. Each item belongs to a
  408 class which defines the names and types of its properties.  The database
  409 permits the creation and modification of classes as well as items.</p>
  410 </div>
  411 <div class="section" id="identifiers-and-designators">
  412 <h3><a class="toc-backref" href="#id7">Identifiers and Designators</a><a class="headerlink" href="#identifiers-and-designators" title="Permalink to this headline"></a></h3>
  413 <p>Each item has a numeric identifier which is unique among items in its
  414 class.  The items are numbered sequentially within each class in order
  415 of creation, starting from 1. The designator for an item is a way to
  416 identify an item in the database, and consists of the name of the item’s
  417 class concatenated with the item’s numeric identifier.</p>
  418 <p>For example, if “spam” and “eggs” are classes, the first item created in
  419 class “spam” has id 1 and designator “spam1”. The first item created in
  420 class “eggs” also has id 1 but has the distinct designator “eggs1”. Item
  421 designators are conventionally enclosed in square brackets when
  422 mentioned in plain text.  This permits a casual mention of, say,
  423 “[patch37]” in an e-mail message to be turned into an active hyperlink.</p>
  424 </div>
  425 <div class="section" id="property-names-and-types">
  426 <h3><a class="toc-backref" href="#id8">Property Names and Types</a><a class="headerlink" href="#property-names-and-types" title="Permalink to this headline"></a></h3>
  427 <p>Property names must begin with a letter.</p>
  428 <p>A property may be one of five basic types:</p>
  429 <ul class="simple">
  430 <li>String properties are for storing arbitrary-length strings.</li>
  431 <li>Boolean properties are for storing true/false, or yes/no values.</li>
  432 <li>Integer properties are for storing Integer (non real) numeric values.</li>
  433 <li>Number properties are for storing numeric values.</li>
  434 <li>Date properties store date-and-time stamps. Their values are Timestamp
  435 objects.</li>
  436 <li>A Link property refers to a single other item selected from a
  437 specified class.  The class is part of the property; the value is an
  438 integer, the id of the chosen item.</li>
  439 <li>A Multilink property refers to possibly many items in a specified
  440 class.  The value is a list of integers.</li>
  441 </ul>
  442 <p><em>None</em> is also a permitted value for any of these property types.  An
  443 attempt to store None into a Multilink property stores an empty list.</p>
  444 <p>A property that is not specified will return as None from a <em>get</em>
  445 operation.</p>
  446 </div>
  447 <div class="section" id="hyperdb-interface-specification">
  448 <h3><a class="toc-backref" href="#id9">Hyperdb Interface Specification</a><a class="headerlink" href="#hyperdb-interface-specification" title="Permalink to this headline"></a></h3>
  449 <p>TODO: replace the Interface Specifications with links to the pydoc</p>
  450 <p>The hyperdb module provides property objects to designate the different
  451 kinds of properties.</p>
  452 <p>All property objects support the following settings:</p>
  453 <dl class="docutils">
  454 <dt>quiet=False:</dt>
  455 <dd><p class="first">if set to True, changes to the property will not be shown to the
  456 user. This can be used for administrative properties that are
  457 automatically updated when a user makes some other change. This
  458 reduces confusion by the user and clutter in the display.
  459 The property change will not be shown in:</p>
  460 <blockquote class="last">
  461 <div><ul class="simple">
  462 <li>the change confirmation message when a change is entered in the web interface</li>
  463 <li>the property change section of the change note email (“nosy email”)</li>
  464 <li>the web history shown at the bottom of an item page</li>
  465 </ul>
  466 </div></blockquote>
  467 </dd>
  468 <dt>required=False:</dt>
  469 <dd>if set to True, the property name is returned when calling
  470 get_required_props(self, propnames = []). Any additional props
  471 specified in propnames is merged with the required props.</dd>
  472 <dt>default_value=None or [] depending on object type:</dt>
  473 <dd>this sets the default value if none is specified. The default
  474 value can be retrieved by calling the get_default_value()
  475 method on the property object.</dd>
  476 </dl>
  477 <p>E.G. assuming title is part of an Issue:</p>
  478 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">title</span><span class="o">=</span><span class="n">String</span><span class="p">(</span><span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">default_value</span><span class="o">=</span><span class="s2">&quot;not set&quot;</span><span class="p">,</span><span class="n">quiet</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
  479 </pre></div>
  480 </div>
  481 <p>will create a property called <code class="docutils literal"><span class="pre">title</span></code> that will be included in the
  482 get_required_props() output. Calling
  483 db.issue.properties[‘title’].get_default_value() will return “not set”.
  484 Changes to the property will not be displayed in:</p>
  485 <blockquote>
  486 <div><ul class="simple">
  487 <li>emailed change notes,</li>
  488 <li>the history at the end of the item pages in the web interface</li>
  489 <li>in the confirmation notice (displayed as a green banner)
  490 shown on changes.</li>
  491 </ul>
  492 </div></blockquote>
  493 <p>These objects are used when specifying what properties belong in classes:</p>
  494 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">String</span><span class="p">:</span>
  495     <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">indexme</span><span class="o">=</span><span class="s1">&#39;no&#39;</span><span class="p">):</span>
  496         <span class="sd">&quot;&quot;&quot;An object designating a String property.&quot;&quot;&quot;</span>
  497 
  498 <span class="k">class</span> <span class="nc">Boolean</span><span class="p">:</span>
  499     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  500         <span class="sd">&quot;&quot;&quot;An object designating a Boolean property.&quot;&quot;&quot;</span>
  501 
  502 <span class="k">class</span> <span class="nc">Integer</span><span class="p">:</span>
  503     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  504         <span class="sd">&quot;&quot;&quot;An object designating an Integer property.&quot;&quot;&quot;</span>
  505 
  506 <span class="k">class</span> <span class="nc">Number</span><span class="p">:</span>
  507     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  508         <span class="sd">&quot;&quot;&quot;An object designating a Number property.&quot;&quot;&quot;</span>
  509 
  510 <span class="k">class</span> <span class="nc">Date</span><span class="p">:</span>
  511     <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  512         <span class="sd">&quot;&quot;&quot;An object designating a Date property.&quot;&quot;&quot;</span>
  513 
  514 <span class="k">class</span> <span class="nc">Link</span><span class="p">:</span>
  515     <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">classname</span><span class="p">,</span> <span class="n">do_journal</span><span class="o">=</span><span class="s1">&#39;yes&#39;</span><span class="p">):</span>
  516         <span class="sd">&quot;&quot;&quot;An object designating a Link property that links to</span>
  517 <span class="sd">        items in a specified class.</span>
  518 
  519 <span class="sd">        If the do_journal argument is not &#39;yes&#39; then changes to</span>
  520 <span class="sd">        the property are not journalled in the linked item.</span>
  521 <span class="sd">        &quot;&quot;&quot;</span>
  522 
  523 <span class="k">class</span> <span class="nc">Multilink</span><span class="p">:</span>
  524     <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">classname</span><span class="p">,</span> <span class="n">do_journal</span><span class="o">=</span><span class="s1">&#39;yes&#39;</span><span class="p">):</span>
  525         <span class="sd">&quot;&quot;&quot;An object designating a Multilink property that links</span>
  526 <span class="sd">        to items in a specified class.</span>
  527 
  528 <span class="sd">        If the do_journal argument is not &#39;yes&#39; then changes to</span>
  529 <span class="sd">        the property are not journalled in the linked item(s).</span>
  530 <span class="sd">        &quot;&quot;&quot;</span>
  531 </pre></div>
  532 </div>
  533 <p>Here is the interface provided by the hyperdatabase:</p>
  534 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Database</span><span class="p">:</span>
  535     <span class="sd">&quot;&quot;&quot;A database for storing records containing flexible data</span>
  536 <span class="sd">    types.</span>
  537 <span class="sd">    &quot;&quot;&quot;</span>
  538 
  539     <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">config</span><span class="p">,</span> <span class="n">journaltag</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
  540         <span class="sd">&quot;&quot;&quot;Open a hyperdatabase given a specifier to some storage.</span>
  541 
  542 <span class="sd">        The &#39;storagelocator&#39; is obtained from config.DATABASE. The</span>
  543 <span class="sd">        meaning of &#39;storagelocator&#39; depends on the particular</span>
  544 <span class="sd">        implementation of the hyperdatabase.  It could be a file</span>
  545 <span class="sd">        name, a directory path, a socket descriptor for a connection</span>
  546 <span class="sd">        to a database over the network, etc.</span>
  547 
  548 <span class="sd">        The &#39;journaltag&#39; is a token that will be attached to the</span>
  549 <span class="sd">        journal entries for any edits done on the database.  If</span>
  550 <span class="sd">        &#39;journaltag&#39; is None, the database is opened in read-only</span>
  551 <span class="sd">        mode: the Class.create(), Class.set(), Class.retire(), and</span>
  552 <span class="sd">        Class.restore() methods are disabled.</span>
  553 <span class="sd">        &quot;&quot;&quot;</span>
  554 
  555     <span class="k">def</span> <span class="nf">__getattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">classname</span><span class="p">):</span>
  556         <span class="sd">&quot;&quot;&quot;A convenient way of calling self.getclass(classname).&quot;&quot;&quot;</span>
  557 
  558     <span class="k">def</span> <span class="nf">getclasses</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  559         <span class="sd">&quot;&quot;&quot;Return a list of the names of all existing classes.&quot;&quot;&quot;</span>
  560 
  561     <span class="k">def</span> <span class="nf">getclass</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">classname</span><span class="p">):</span>
  562         <span class="sd">&quot;&quot;&quot;Get the Class object representing a particular class.</span>
  563 
  564 <span class="sd">        If &#39;classname&#39; is not a valid class name, a KeyError is</span>
  565 <span class="sd">        raised.</span>
  566 <span class="sd">        &quot;&quot;&quot;</span>
  567 
  568 <span class="k">class</span> <span class="nc">Class</span><span class="p">:</span>
  569     <span class="sd">&quot;&quot;&quot;The handle to a particular class of items in a hyperdatabase.</span>
  570 <span class="sd">    &quot;&quot;&quot;</span>
  571 
  572     <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">db</span><span class="p">,</span> <span class="n">classname</span><span class="p">,</span> <span class="o">**</span><span class="n">properties</span><span class="p">):</span>
  573         <span class="sd">&quot;&quot;&quot;Create a new class with a given name and property</span>
  574 <span class="sd">        specification.</span>
  575 
  576 <span class="sd">        &#39;classname&#39; must not collide with the name of an existing</span>
  577 <span class="sd">        class, or a ValueError is raised.  The keyword arguments in</span>
  578 <span class="sd">        &#39;properties&#39; must map names to property objects, or a</span>
  579 <span class="sd">        TypeError is raised.</span>
  580 
  581 <span class="sd">        A proxied reference to the database is available as the</span>
  582 <span class="sd">        &#39;db&#39; attribute on instances. For example, in</span>
  583 <span class="sd">        &#39;IssueClass.send_message&#39;, the following is used to lookup</span>
  584 <span class="sd">        users, messages and files::</span>
  585 
  586 <span class="sd">            users = self.db.user</span>
  587 <span class="sd">            messages = self.db.msg</span>
  588 <span class="sd">            files = self.db.file</span>
  589 <span class="sd">        &quot;&quot;&quot;</span>
  590 
  591     <span class="c1"># Editing items:</span>
  592 
  593     <span class="k">def</span> <span class="nf">create</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">propvalues</span><span class="p">):</span>
  594         <span class="sd">&quot;&quot;&quot;Create a new item of this class and return its id.</span>
  595 
  596 <span class="sd">        The keyword arguments in &#39;propvalues&#39; map property names to</span>
  597 <span class="sd">        values. The values of arguments must be acceptable for the</span>
  598 <span class="sd">        types of their corresponding properties or a TypeError is</span>
  599 <span class="sd">        raised.  If this class has a key property, it must be</span>
  600 <span class="sd">        present and its value must not collide with other key</span>
  601 <span class="sd">        strings or a ValueError is raised.  Any other properties on</span>
  602 <span class="sd">        this class that are missing from the &#39;propvalues&#39; dictionary</span>
  603 <span class="sd">        are set to None.  If an id in a link or multilink property</span>
  604 <span class="sd">        does not refer to a valid item, an IndexError is raised.</span>
  605 <span class="sd">        &quot;&quot;&quot;</span>
  606 
  607     <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="n">propname</span><span class="p">):</span>
  608         <span class="sd">&quot;&quot;&quot;Get the value of a property on an existing item of this</span>
  609 <span class="sd">        class.</span>
  610 
  611 <span class="sd">        &#39;itemid&#39; must be the id of an existing item of this class or</span>
  612 <span class="sd">        an IndexError is raised.  &#39;propname&#39; must be the name of a</span>
  613 <span class="sd">        property of this class or a KeyError is raised.</span>
  614 <span class="sd">        &quot;&quot;&quot;</span>
  615 
  616     <span class="k">def</span> <span class="nf">set</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="o">**</span><span class="n">propvalues</span><span class="p">):</span>
  617         <span class="sd">&quot;&quot;&quot;Modify a property on an existing item of this class.</span>
  618 
  619 <span class="sd">        &#39;itemid&#39; must be the id of an existing item of this class or</span>
  620 <span class="sd">        an IndexError is raised.  Each key in &#39;propvalues&#39; must be</span>
  621 <span class="sd">        the name of a property of this class or a KeyError is</span>
  622 <span class="sd">        raised.  All values in &#39;propvalues&#39; must be acceptable types</span>
  623 <span class="sd">        for their corresponding properties or a TypeError is raised.</span>
  624 <span class="sd">        If the value of the key property is set, it must not collide</span>
  625 <span class="sd">        with other key strings or a ValueError is raised.  If the</span>
  626 <span class="sd">        value of a Link or Multilink property contains an invalid</span>
  627 <span class="sd">        item id, a ValueError is raised.</span>
  628 <span class="sd">        &quot;&quot;&quot;</span>
  629 
  630     <span class="k">def</span> <span class="nf">retire</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">):</span>
  631         <span class="sd">&quot;&quot;&quot;Retire an item.</span>
  632 
  633 <span class="sd">        The properties on the item remain available from the get()</span>
  634 <span class="sd">        method, and the item&#39;s id is never reused.  Retired items</span>
  635 <span class="sd">        are not returned by the find(), list(), or lookup() methods,</span>
  636 <span class="sd">        and other items may reuse the values of their key</span>
  637 <span class="sd">        properties.</span>
  638 <span class="sd">        &quot;&quot;&quot;</span>
  639 
  640     <span class="k">def</span> <span class="nf">restore</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">nodeid</span><span class="p">):</span>
  641     <span class="sd">&#39;&#39;&#39;Restore a retired node.</span>
  642 
  643 <span class="sd">    Make node available for all operations like it was before</span>
  644 <span class="sd">    retirement.</span>
  645 <span class="sd">    &#39;&#39;&#39;</span>
  646 
  647     <span class="k">def</span> <span class="nf">history</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">):</span>
  648         <span class="sd">&quot;&quot;&quot;Retrieve the journal of edits on a particular item.</span>
  649 
  650 <span class="sd">        &#39;itemid&#39; must be the id of an existing item of this class or</span>
  651 <span class="sd">        an IndexError is raised.</span>
  652 
  653 <span class="sd">        The returned list contains tuples of the form</span>
  654 
  655 <span class="sd">            (date, tag, action, params)</span>
  656 
  657 <span class="sd">        &#39;date&#39; is a Timestamp object specifying the time of the</span>
  658 <span class="sd">        change and &#39;tag&#39; is the journaltag specified when the</span>
  659 <span class="sd">        database was opened. &#39;action&#39; may be:</span>
  660 
  661 <span class="sd">            &#39;create&#39; or &#39;set&#39; -- &#39;params&#39; is a dictionary of</span>
  662 <span class="sd">                property values</span>
  663 <span class="sd">            &#39;link&#39; or &#39;unlink&#39; -- &#39;params&#39; is (classname, itemid,</span>
  664 <span class="sd">                propname)</span>
  665 <span class="sd">            &#39;retire&#39; -- &#39;params&#39; is None</span>
  666 <span class="sd">        &quot;&quot;&quot;</span>
  667 
  668     <span class="c1"># Locating items:</span>
  669 
  670     <span class="k">def</span> <span class="nf">setkey</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">propname</span><span class="p">):</span>
  671         <span class="sd">&quot;&quot;&quot;Select a String property of this class to be the key</span>
  672 <span class="sd">        property.</span>
  673 
  674 <span class="sd">        &#39;propname&#39; must be the name of a String property of this</span>
  675 <span class="sd">        class or None, or a TypeError is raised.  The values of the</span>
  676 <span class="sd">        key property on all existing items must be unique or a</span>
  677 <span class="sd">        ValueError is raised.</span>
  678 <span class="sd">        &quot;&quot;&quot;</span>
  679 
  680     <span class="k">def</span> <span class="nf">getkey</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  681         <span class="sd">&quot;&quot;&quot;Return the name of the key property for this class or</span>
  682 <span class="sd">        None.</span>
  683 <span class="sd">        &quot;&quot;&quot;</span>
  684 
  685     <span class="k">def</span> <span class="nf">lookup</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">keyvalue</span><span class="p">):</span>
  686         <span class="sd">&quot;&quot;&quot;Locate a particular item by its key property and return</span>
  687 <span class="sd">        its id.</span>
  688 
  689 <span class="sd">        If this class has no key property, a TypeError is raised.</span>
  690 <span class="sd">        If the &#39;keyvalue&#39; matches one of the values for the key</span>
  691 <span class="sd">        property among the items in this class, the matching item&#39;s</span>
  692 <span class="sd">        id is returned; otherwise a KeyError is raised.</span>
  693 <span class="sd">        &quot;&quot;&quot;</span>
  694 
  695     <span class="k">def</span> <span class="nf">find</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">propspec</span><span class="p">):</span>
  696         <span class="sd">&quot;&quot;&quot;Get the ids of items in this class which link to the</span>
  697 <span class="sd">        given items.</span>
  698 
  699 <span class="sd">        &#39;propspec&#39; consists of keyword args propname=itemid or</span>
  700 <span class="sd">                   propname={&lt;itemid 1&gt;:1, &lt;itemid 2&gt;:1, ...}</span>
  701 <span class="sd">        &#39;propname&#39; must be the name of a property in this class,</span>
  702 <span class="sd">                   or a KeyError is raised.  That property must</span>
  703 <span class="sd">                   be a Link or Multilink property, or a TypeError</span>
  704 <span class="sd">                   is raised.</span>
  705 
  706 <span class="sd">        Any item in this class whose &#39;propname&#39; property links to</span>
  707 <span class="sd">        any of the itemids will be returned. Examples::</span>
  708 
  709 <span class="sd">            db.issue.find(messages=&#39;1&#39;)</span>
  710 <span class="sd">            db.issue.find(messages={&#39;1&#39;:1,&#39;3&#39;:1}, files={&#39;7&#39;:1})</span>
  711 <span class="sd">        &quot;&quot;&quot;</span>
  712 
  713     <span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">search_matches</span><span class="p">,</span> <span class="n">filterspec</span><span class="p">,</span> <span class="n">sort</span><span class="p">,</span> <span class="n">group</span><span class="p">,</span>
  714                <span class="n">retired</span><span class="p">,</span> <span class="n">exact_match_spec</span><span class="p">,</span> <span class="n">limit</span><span class="p">,</span> <span class="n">offset</span><span class="p">):</span>
  715         <span class="sd">&quot;&quot;&quot;Return a list of the ids of the active nodes in this class that</span>
  716 <span class="sd">        match the &#39;filter&#39; spec, sorted by the group spec and then the</span>
  717 <span class="sd">        sort spec. The arguments sort, group, retired, and</span>
  718 <span class="sd">        exact_match_spec are optional.</span>
  719 
  720 <span class="sd">        &quot;search_matches&quot; is a container type which by default is</span>
  721 <span class="sd">        None and optionally contains IDs of items to match. If</span>
  722 <span class="sd">        non-empty only IDs of the initial set are returned.</span>
  723 
  724 <span class="sd">        &quot;filterspec&quot; is {propname: value(s)}</span>
  725 <span class="sd">        &quot;exact_match_spec&quot; is the same format as &quot;filterspec&quot; but</span>
  726 <span class="sd">        specifies exact match for the given propnames. This only</span>
  727 <span class="sd">        makes a difference for String properties, these specify case</span>
  728 <span class="sd">        insensitive substring search when in &quot;filterspec&quot; and exact</span>
  729 <span class="sd">        match when in exact_match_spec.</span>
  730 
  731 <span class="sd">        &quot;sort&quot; and &quot;group&quot; are [(dir, prop), ...] where dir is &#39;+&#39;, &#39;-&#39;</span>
  732 <span class="sd">        or None and prop is a prop name or None. Note that for</span>
  733 <span class="sd">        backward-compatibility reasons a single (dir, prop) tuple is</span>
  734 <span class="sd">        also allowed.</span>
  735 
  736 <span class="sd">        The parameter retired when set to False, returns only live</span>
  737 <span class="sd">        (un-retired) results. When setting it to True, only retired</span>
  738 <span class="sd">        items are returned. If None, both retired and unretired</span>
  739 <span class="sd">        items are returned. The default is False, i.e. only live</span>
  740 <span class="sd">        items are returned by default.</span>
  741 
  742 <span class="sd">        The &quot;limit&quot; and &quot;offset&quot; parameters define a limit on the</span>
  743 <span class="sd">        number of results returned and an offset before returning</span>
  744 <span class="sd">        any results, respectively. These can be used when displaying</span>
  745 <span class="sd">        a number of items in a pagination application or similar. A</span>
  746 <span class="sd">        common use-case is returning the first item of a sorted</span>
  747 <span class="sd">        search by specifying limit=1 (i.e. the maximum or minimum</span>
  748 <span class="sd">        depending on sort order).</span>
  749 
  750 <span class="sd">        The filter must match all properties specificed. If the property</span>
  751 <span class="sd">        value to match is a list:</span>
  752 
  753 <span class="sd">        1. String properties must match all elements in the list, and</span>
  754 <span class="sd">        2. Other properties must match any of the elements in the list.</span>
  755 
  756 <span class="sd">        This also means that for strings in exact_match_spec it</span>
  757 <span class="sd">        doesn&#39;t make sense to specify multiple values because those</span>
  758 <span class="sd">        cannot all be matched.</span>
  759 
  760 <span class="sd">        The propname in filterspec and prop in a sort/group spec may be</span>
  761 <span class="sd">        transitive, i.e., it may contain properties of the form</span>
  762 <span class="sd">        link.link.link.name, e.g. you can search for all issues where</span>
  763 <span class="sd">        a message was added by a certain user in the last week with a</span>
  764 <span class="sd">        filterspec of</span>
  765 <span class="sd">        {&#39;messages.author&#39; : &#39;42&#39;, &#39;messages.creation&#39; : &#39;.-1w;&#39;}</span>
  766 <span class="sd">        &quot;&quot;&quot;</span>
  767 
  768     <span class="k">def</span> <span class="nf">list</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  769         <span class="sd">&quot;&quot;&quot;Return a list of the ids of the active items in this</span>
  770 <span class="sd">        class.</span>
  771 <span class="sd">        &quot;&quot;&quot;</span>
  772 
  773     <span class="k">def</span> <span class="nf">count</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  774         <span class="sd">&quot;&quot;&quot;Get the number of items in this class.</span>
  775 
  776 <span class="sd">        If the returned integer is &#39;numitems&#39;, the ids of all the</span>
  777 <span class="sd">        items in this class run from 1 to numitems, and numitems+1</span>
  778 <span class="sd">        will be the id of the next item to be created in this class.</span>
  779 <span class="sd">        &quot;&quot;&quot;</span>
  780 
  781     <span class="c1"># Manipulating properties:</span>
  782 
  783     <span class="k">def</span> <span class="nf">getprops</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
  784         <span class="sd">&quot;&quot;&quot;Return a dictionary mapping property names to property</span>
  785 <span class="sd">        objects.</span>
  786 <span class="sd">        &quot;&quot;&quot;</span>
  787 
  788     <span class="k">def</span> <span class="nf">addprop</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">properties</span><span class="p">):</span>
  789         <span class="sd">&quot;&quot;&quot;Add properties to this class.</span>
  790 
  791 <span class="sd">        The keyword arguments in &#39;properties&#39; must map names to</span>
  792 <span class="sd">        property objects, or a TypeError is raised.  None of the</span>
  793 <span class="sd">        keys in &#39;properties&#39; may collide with the names of existing</span>
  794 <span class="sd">        properties, or a ValueError is raised before any properties</span>
  795 <span class="sd">        have been added.</span>
  796 <span class="sd">        &quot;&quot;&quot;</span>
  797 
  798     <span class="k">def</span> <span class="nf">getitem</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="n">cache</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
  799         <span class="sd">&quot;&quot;&quot; Return a Item convenience wrapper for the item.</span>
  800 
  801 <span class="sd">        &#39;itemid&#39; must be the id of an existing item of this class or</span>
  802 <span class="sd">        an IndexError is raised.</span>
  803 
  804 <span class="sd">        &#39;cache&#39; indicates whether the transaction cache should be</span>
  805 <span class="sd">        queried for the item. If the item has been modified and you</span>
  806 <span class="sd">        need to determine what its values prior to modification are,</span>
  807 <span class="sd">        you need to set cache=0.</span>
  808 <span class="sd">        &quot;&quot;&quot;</span>
  809 
  810 <span class="k">class</span> <span class="nc">Item</span><span class="p">:</span>
  811     <span class="sd">&quot;&quot;&quot; A convenience wrapper for the given item. It provides a</span>
  812 <span class="sd">    mapping interface to a single item&#39;s properties</span>
  813 <span class="sd">    &quot;&quot;&quot;</span>
  814 </pre></div>
  815 </div>
  816 </div>
  817 <div class="section" id="hyperdatabase-implementations">
  818 <h3><a class="toc-backref" href="#id10">Hyperdatabase Implementations</a><a class="headerlink" href="#hyperdatabase-implementations" title="Permalink to this headline"></a></h3>
  819 <p>Hyperdatabase implementations exist to create the interface described in
  820 the <a class="reference internal" href="#hyperdb-interface-specification">hyperdb interface specification</a> over an existing storage
  821 mechanism. Examples are relational databases, *dbm key-value databases,
  822 and so on.</p>
  823 <p>Several implementations are provided - they belong in the
  824 <code class="docutils literal"><span class="pre">roundup.backends</span></code> package.</p>
  825 </div>
  826 <div class="section" id="application-example">
  827 <h3><a class="toc-backref" href="#id11">Application Example</a><a class="headerlink" href="#application-example" title="Permalink to this headline"></a></h3>
  828 <p>Here is an example of how the hyperdatabase module would work in
  829 practice:</p>
  830 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">hyperdb</span>
  831 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span> <span class="o">=</span> <span class="n">hyperdb</span><span class="o">.</span><span class="n">Database</span><span class="p">(</span><span class="s2">&quot;foo.db&quot;</span><span class="p">,</span> <span class="s2">&quot;ping&quot;</span><span class="p">)</span>
  832 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span>
  833 <span class="go">&lt;hyperdb.Database &quot;foo.db&quot; opened by &quot;ping&quot;&gt;</span>
  834 <span class="gp">&gt;&gt;&gt; </span><span class="n">hyperdb</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">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
  835 <span class="go">&lt;hyperdb.Class &quot;status&quot;&gt;</span>
  836 <span class="gp">&gt;&gt;&gt; </span><span class="n">_</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>
  837 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;unread&quot;</span><span class="p">)</span>
  838 <span class="go">1</span>
  839 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;in-progress&quot;</span><span class="p">)</span>
  840 <span class="go">2</span>
  841 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;testing&quot;</span><span class="p">)</span>
  842 <span class="go">3</span>
  843 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;resolved&quot;</span><span class="p">)</span>
  844 <span class="go">4</span>
  845 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
  846 <span class="go">4</span>
  847 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">list</span><span class="p">()</span>
  848 <span class="go">[1, 2, 3, 4]</span>
  849 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s2">&quot;in-progress&quot;</span><span class="p">)</span>
  850 <span class="go">2</span>
  851 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">retire</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
  852 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">list</span><span class="p">()</span>
  853 <span class="go">[1, 2, 4]</span>
  854 <span class="gp">&gt;&gt;&gt; </span><span class="n">hyperdb</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;issue&quot;</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span> <span class="n">status</span><span class="o">=</span><span class="n">hyperdb</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>
  855 <span class="go">&lt;hyperdb.Class &quot;issue&quot;&gt;</span>
  856 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&quot;spam&quot;</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
  857 <span class="go">1</span>
  858 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&quot;eggs&quot;</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
  859 <span class="go">2</span>
  860 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&quot;ham&quot;</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
  861 <span class="go">3</span>
  862 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&quot;arguments&quot;</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
  863 <span class="go">4</span>
  864 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">&quot;abuse&quot;</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
  865 <span class="go">5</span>
  866 <span class="gp">&gt;&gt;&gt; </span><span class="n">hyperdb</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">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
  867 <span class="gp">... </span><span class="n">password</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
  868 <span class="go">&lt;hyperdb.Class &quot;user&quot;&gt;</span>
  869 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">addprop</span><span class="p">(</span><span class="n">fixer</span><span class="o">=</span><span class="n">hyperdb</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>
  870 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">getprops</span><span class="p">()</span>
  871 <span class="go">{&quot;title&quot;: &lt;hyperdb.String&gt;, &quot;status&quot;: &lt;hyperdb.Link to &quot;status&quot;&gt;,</span>
  872 <span class="go"> &quot;user&quot;: &lt;hyperdb.Link to &quot;user&quot;&gt;}</span>
  873 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
  874 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s2">&quot;status&quot;</span><span class="p">)</span>
  875 <span class="go">2</span>
  876 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="p">)</span>
  877 <span class="go">&quot;in-progress&quot;</span>
  878 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="s2">&quot;title&quot;</span><span class="p">)</span>
  879 <span class="go">&quot;abuse&quot;</span>
  880 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s2">&quot;status&quot;</span><span class="p">,</span> <span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s2">&quot;in-progress&quot;</span><span class="p">))</span>
  881 <span class="go">[2, 4, 5]</span>
  882 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">history</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
  883 <span class="go">[(&lt;Date 2000-06-28.19:09:43&gt;, &quot;ping&quot;, &quot;create&quot;, {&quot;title&quot;: &quot;abuse&quot;,</span>
  884 <span class="go">&quot;status&quot;: 1}),</span>
  885 <span class="go"> (&lt;Date 2000-06-28.19:11:04&gt;, &quot;ping&quot;, &quot;set&quot;, {&quot;status&quot;: 2})]</span>
  886 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">history</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
  887 <span class="go">[(&lt;Date 2000-06-28.19:09:43&gt;, &quot;ping&quot;, &quot;link&quot;, (&quot;issue&quot;, 5, &quot;status&quot;)),</span>
  888 <span class="go"> (&lt;Date 2000-06-28.19:11:04&gt;, &quot;ping&quot;, &quot;unlink&quot;, (&quot;issue&quot;, 5, &quot;status&quot;))]</span>
  889 <span class="gp">&gt;&gt;&gt; </span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">history</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
  890 <span class="go">[(&lt;Date 2000-06-28.19:11:04&gt;, &quot;ping&quot;, &quot;link&quot;, (&quot;issue&quot;, 5, &quot;status&quot;))]</span>
  891 </pre></div>
  892 </div>
  893 <p>For the purposes of journalling, when a Multilink property is set to a
  894 new list of items, the hyperdatabase compares the old list to the new
  895 list. The journal records “unlink” events for all the items that appear
  896 in the old list but not the new list, and “link” events for all the
  897 items that appear in the new list but not in the old list.</p>
  898 </div>
  899 </div>
  900 <div class="section" id="roundup-database">
  901 <h2><a class="toc-backref" href="#id12">Roundup Database</a><a class="headerlink" href="#roundup-database" title="Permalink to this headline"></a></h2>
  902 <p>The Roundup database layer is implemented on top of the hyperdatabase
  903 and mediates calls to the database. Some of the classes in the Roundup
  904 database are considered issue classes. The Roundup database layer adds
  905 detectors and user items, and on issues it provides mail spools, nosy
  906 lists, and superseders.</p>
  907 <div class="section" id="reserved-classes">
  908 <h3><a class="toc-backref" href="#id13">Reserved Classes</a><a class="headerlink" href="#reserved-classes" title="Permalink to this headline"></a></h3>
  909 <p>Internal to this layer we reserve three special classes of items that
  910 are not issues.</p>
  911 <div class="section" id="users">
  912 <h4><a class="toc-backref" href="#id14">Users</a><a class="headerlink" href="#users" title="Permalink to this headline"></a></h4>
  913 <p>Users are stored in the hyperdatabase as items of class “user”.  The
  914 “user” class has the definition:</p>
  915 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">hyperdb</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">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
  916                           <span class="n">password</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
  917                           <span class="n">address</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
  918 <span class="n">db</span><span class="o">.</span><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>
  919 </pre></div>
  920 </div>
  921 </div>
  922 <div class="section" id="messages">
  923 <h4><a class="toc-backref" href="#id15">Messages</a><a class="headerlink" href="#messages" title="Permalink to this headline"></a></h4>
  924 <p>E-mail messages are represented by hyperdatabase items of class “msg”.
  925 The actual text content of the messages is stored in separate files.
  926 (There’s no advantage to be gained by stuffing them into the
  927 hyperdatabase, and if messages are stored in ordinary text files, they
  928 can be grepped from the command line.)  The text of a message is saved
  929 in a file named after the message item designator (e.g. “msg23”) for the
  930 sake of the command interface (see below).  Attachments are stored
  931 separately and associated with “file” items. The “msg” class has the
  932 definition:</p>
  933 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">hyperdb</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;msg&quot;</span><span class="p">,</span> <span class="n">author</span><span class="o">=</span><span class="n">hyperdb</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>
  934                          <span class="n">recipients</span><span class="o">=</span><span class="n">hyperdb</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>
  935                          <span class="n">date</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">Date</span><span class="p">(),</span>
  936                          <span class="n">summary</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
  937                          <span class="n">files</span><span class="o">=</span><span class="n">hyperdb</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>
  938 </pre></div>
  939 </div>
  940 <p>The “author” property indicates the author of the message (a “user” item
  941 must exist in the hyperdatabase for any messages that are stored in the
  942 system). The “summary” property contains a summary of the message for
  943 display in a message index.</p>
  944 </div>
  945 <div class="section" id="files">
  946 <h4><a class="toc-backref" href="#id16">Files</a><a class="headerlink" href="#files" title="Permalink to this headline"></a></h4>
  947 <p>Submitted files are represented by hyperdatabase items of class “file”.
  948 Like e-mail messages, the file content is stored in files outside the
  949 database, named after the file item designator (e.g. “file17”). The
  950 “file” class has the definition:</p>
  951 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">hyperdb</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;file&quot;</span><span class="p">,</span> <span class="n">user</span><span class="o">=</span><span class="n">hyperdb</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>
  952                           <span class="n">name</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
  953                           <span class="nb">type</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
  954 </pre></div>
  955 </div>
  956 <p>The “user” property indicates the user who submitted the file, the
  957 “name” property holds the original name of the file, and the “type”
  958 property holds the MIME type of the file as received.</p>
  959 </div>
  960 </div>
  961 <div class="section" id="issue-classes">
  962 <h3><a class="toc-backref" href="#id17">Issue Classes</a><a class="headerlink" href="#issue-classes" title="Permalink to this headline"></a></h3>
  963 <p>All issues have the following standard properties:</p>
  964 <table border="1" class="docutils">
  965 <colgroup>
  966 <col width="30%" />
  967 <col width="70%" />
  968 </colgroup>
  969 <thead valign="bottom">
  970 <tr class="row-odd"><th class="head">Property</th>
  971 <th class="head">Definition</th>
  972 </tr>
  973 </thead>
  974 <tbody valign="top">
  975 <tr class="row-even"><td>title</td>
  976 <td>hyperdb.String()</td>
  977 </tr>
  978 <tr class="row-odd"><td>messages</td>
  979 <td>hyperdb.Multilink(“msg”)</td>
  980 </tr>
  981 <tr class="row-even"><td>files</td>
  982 <td>hyperdb.Multilink(“file”)</td>
  983 </tr>
  984 <tr class="row-odd"><td>nosy</td>
  985 <td>hyperdb.Multilink(“user”)</td>
  986 </tr>
  987 <tr class="row-even"><td>superseder</td>
  988 <td>hyperdb.Multilink(“issue”)</td>
  989 </tr>
  990 </tbody>
  991 </table>
  992 <p>Also, two Date properties named “creation” and “activity” are fabricated
  993 by the Roundup database layer. Two user Link properties, “creator” and
  994 “actor” are also fabricated. By “fabricated” we mean that no such
  995 properties are actually stored in the hyperdatabase, but when properties
  996 on issues are requested, the “creation”/”creator” and “activity”/”actor”
  997 properties are made available. The value of the “creation”/”creator”
  998 properties relate to issue creation, and the value of the “activity”/
  999 “actor” properties relate to the last editing of any property on the issue
 1000 (equivalently, these are the dates on the first and last records in the
 1001 issue’s journal).</p>
 1002 </div>
 1003 <div class="section" id="roundupdb-interface-specification">
 1004 <h3><a class="toc-backref" href="#id18">Roundupdb Interface Specification</a><a class="headerlink" href="#roundupdb-interface-specification" title="Permalink to this headline"></a></h3>
 1005 <p>The interface to a Roundup database delegates most method calls to the
 1006 hyperdatabase, except for the following changes and additional methods:</p>
 1007 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Database</span><span class="p">:</span>
 1008     <span class="k">def</span> <span class="nf">getuid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1009         <span class="sd">&quot;&quot;&quot;Return the id of the &quot;user&quot; item associated with the user</span>
 1010 <span class="sd">        that owns this connection to the hyperdatabase.&quot;&quot;&quot;</span>
 1011 
 1012 <span class="k">class</span> <span class="nc">Class</span><span class="p">:</span>
 1013     <span class="c1"># Overridden methods:</span>
 1014 
 1015     <span class="k">def</span> <span class="nf">create</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">propvalues</span><span class="p">):</span>
 1016     <span class="k">def</span> <span class="nf">set</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">propvalues</span><span class="p">):</span>
 1017     <span class="k">def</span> <span class="nf">retire</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">):</span>
 1018         <span class="sd">&quot;&quot;&quot;These operations trigger detectors and can be vetoed.</span>
 1019 <span class="sd">        Attempts to modify the &quot;creation&quot;, &quot;creator&quot;, &quot;activity&quot;</span>
 1020 <span class="sd">        properties or &quot;actor&quot; cause a KeyError.</span>
 1021 <span class="sd">        &quot;&quot;&quot;</span>
 1022 
 1023 <span class="k">class</span> <span class="nc">IssueClass</span><span class="p">(</span><span class="n">Class</span><span class="p">):</span>
 1024     <span class="c1"># Overridden methods:</span>
 1025 
 1026     <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">db</span><span class="p">,</span> <span class="n">classname</span><span class="p">,</span> <span class="o">**</span><span class="n">properties</span><span class="p">):</span>
 1027         <span class="sd">&quot;&quot;&quot;The newly-created class automatically includes the</span>
 1028 <span class="sd">        &quot;messages&quot;, &quot;files&quot;, &quot;nosy&quot;, and &quot;superseder&quot; properties.</span>
 1029 <span class="sd">        If the &#39;properties&#39; dictionary attempts to specify any of</span>
 1030 <span class="sd">        these properties or a &quot;creation&quot;, &quot;creator&quot;, &quot;activity&quot; or</span>
 1031 <span class="sd">        &quot;actor&quot; property, a ValueError is raised.&quot;&quot;&quot;</span>
 1032 
 1033     <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="n">propname</span><span class="p">):</span>
 1034     <span class="k">def</span> <span class="nf">getprops</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
 1035         <span class="sd">&quot;&quot;&quot;In addition to the actual properties on the item, these</span>
 1036 <span class="sd">        methods provide the &quot;creation&quot;, &quot;creator&quot;, &quot;activity&quot; and</span>
 1037 <span class="sd">        &quot;actor&quot; properties.&quot;&quot;&quot;</span>
 1038 
 1039     <span class="c1"># New methods:</span>
 1040 
 1041     <span class="k">def</span> <span class="nf">addmessage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="n">summary</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
 1042         <span class="sd">&quot;&quot;&quot;Add a message to an issue&#39;s mail spool.</span>
 1043 
 1044 <span class="sd">        A new &quot;msg&quot; item is constructed using the current date, the</span>
 1045 <span class="sd">        user that owns the database connection as the author, and</span>
 1046 <span class="sd">        the specified summary text.  The &quot;files&quot; and &quot;recipients&quot;</span>
 1047 <span class="sd">        fields are left empty.  The given text is saved as the body</span>
 1048 <span class="sd">        of the message and the item is appended to the &quot;messages&quot;</span>
 1049 <span class="sd">        field of the specified issue.</span>
 1050 <span class="sd">        &quot;&quot;&quot;</span>
 1051 
 1052     <span class="k">def</span> <span class="nf">nosymessage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span> <span class="n">msgid</span><span class="p">):</span>
 1053         <span class="sd">&quot;&quot;&quot;Send a message to the members of an issue&#39;s nosy list.</span>
 1054 
 1055 <span class="sd">        The message is sent only to users on the nosy list who are</span>
 1056 <span class="sd">        not already on the &quot;recipients&quot; list for the message.  These</span>
 1057 <span class="sd">        users are then added to the message&#39;s &quot;recipients&quot; list.</span>
 1058 <span class="sd">        &quot;&quot;&quot;</span>
 1059 </pre></div>
 1060 </div>
 1061 </div>
 1062 <div class="section" id="default-schema">
 1063 <h3><a class="toc-backref" href="#id19">Default Schema</a><a class="headerlink" href="#default-schema" title="Permalink to this headline"></a></h3>
 1064 <p>The default schema included with Roundup turns it into a typical
 1065 software bug tracker.  The database is set up like this:</p>
 1066 <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">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
 1067             <span class="n">order</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
 1068 <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>
 1069 <span class="n">pri</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;critical&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;1&quot;</span><span class="p">)</span>
 1070 <span class="n">pri</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;urgent&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;2&quot;</span><span class="p">)</span>
 1071 <span class="n">pri</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;bug&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;3&quot;</span><span class="p">)</span>
 1072 <span class="n">pri</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;feature&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;4&quot;</span><span class="p">)</span>
 1073 <span class="n">pri</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;wish&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;5&quot;</span><span class="p">)</span>
 1074 
 1075 <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">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
 1076              <span class="n">order</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
 1077 <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>
 1078 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;unread&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;1&quot;</span><span class="p">)</span>
 1079 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;deferred&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;2&quot;</span><span class="p">)</span>
 1080 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;chatting&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;3&quot;</span><span class="p">)</span>
 1081 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;need-eg&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;4&quot;</span><span class="p">)</span>
 1082 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;in-progress&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;5&quot;</span><span class="p">)</span>
 1083 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;testing&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;6&quot;</span><span class="p">)</span>
 1084 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;done-cbb&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;7&quot;</span><span class="p">)</span>
 1085 <span class="n">stat</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">&quot;resolved&quot;</span><span class="p">,</span> <span class="n">order</span><span class="o">=</span><span class="s2">&quot;8&quot;</span><span class="p">)</span>
 1086 
 1087 <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">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
 1088 
 1089 <span class="n">Class</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">fixer</span><span class="o">=</span><span class="n">hyperdb</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>
 1090                    <span class="n">keyword</span><span class="o">=</span><span class="n">hyperdb</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>
 1091                    <span class="n">priority</span><span class="o">=</span><span class="n">hyperdb</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>
 1092                    <span class="n">status</span><span class="o">=</span><span class="n">hyperdb</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>
 1093 </pre></div>
 1094 </div>
 1095 <p>(The “order” property hasn’t been explained yet.  It gets used by the
 1096 Web user interface for sorting.)</p>
 1097 <p>The above isn’t as pretty-looking as the schema specification in the
 1098 first-stage submission, but it could be made just as easy with the
 1099 addition of a convenience function like Choice for setting up the
 1100 “priority” and “status” classes:</p>
 1101 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">Choice</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="o">*</span><span class="n">options</span><span class="p">):</span>
 1102     <span class="n">cl</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="n">name</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">(),</span>
 1103                <span class="n">order</span><span class="o">=</span><span class="n">hyperdb</span><span class="o">.</span><span class="n">String</span><span class="p">())</span>
 1104     <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">options</span><span class="p">)):</span>
 1105         <span class="n">cl</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">option</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">order</span><span class="o">=</span><span class="n">i</span><span class="p">)</span>
 1106     <span class="k">return</span> <span class="n">hyperdb</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
 1107 </pre></div>
 1108 </div>
 1109 </div>
 1110 </div>
 1111 <div class="section" id="detector-interface">
 1112 <span id="index-0"></span><h2><a class="toc-backref" href="#id20">Detector Interface</a><a class="headerlink" href="#detector-interface" title="Permalink to this headline"></a></h2>
 1113 <p>Detectors are Python functions that are triggered on certain kinds of
 1114 events.  These functions are placed in a special directory which exists
 1115 just for this purpose.  Importing the Roundup
 1116 database module also imports all the modules in this directory, and the
 1117 <code class="docutils literal"><span class="pre">init()</span></code> function of each module is called when a database is opened
 1118 to provide it a chance to register its detectors.</p>
 1119 <p>There are two kinds of detectors:</p>
 1120 <ol class="arabic simple">
 1121 <li>an <cite>auditor</cite> is triggered just before modifying an item</li>
 1122 <li>a <cite>reactor</cite> is triggered just after an item has been modified</li>
 1123 </ol>
 1124 <p>When the Roundup database is about to perform a <code class="docutils literal"><span class="pre">create()</span></code>, <code class="docutils literal"><span class="pre">set()</span></code>,
 1125 <code class="docutils literal"><span class="pre">retire()</span></code>, or <code class="docutils literal"><span class="pre">restore</span></code> operation, it first calls any <em>auditors</em>
 1126 that have been registered for that operation on that class. Any auditor
 1127 may raise a <em>Reject</em> exception to abort the operation.</p>
 1128 <p>If none of the auditors raises an exception, the database proceeds to
 1129 carry out the operation.  After it’s done, it then calls all of the
 1130 <em>reactors</em> that have been registered for the operation.</p>
 1131 <div class="section" id="detector-interface-specification">
 1132 <span id="index-1"></span><h3><a class="toc-backref" href="#id21">Detector Interface Specification</a><a class="headerlink" href="#detector-interface-specification" title="Permalink to this headline"></a></h3>
 1133 <p>The <code class="docutils literal"><span class="pre">audit()</span></code> and <code class="docutils literal"><span class="pre">react()</span></code> methods register detectors on a given
 1134 class of items:</p>
 1135 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Class</span><span class="p">:</span>
 1136     <span class="k">def</span> <span class="nf">audit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">,</span> <span class="n">detector</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">100</span><span class="p">):</span>
 1137         <span class="sd">&quot;&quot;&quot;Register an auditor on this class.</span>
 1138 
 1139 <span class="sd">        &#39;event&#39; should be one of &quot;create&quot;, &quot;set&quot;, &quot;retire&quot;, or</span>
 1140 <span class="sd">        &quot;restore&quot;. &#39;detector&#39; should be a function accepting four</span>
 1141 <span class="sd">        arguments. Detectors are called in priority order, execution</span>
 1142 <span class="sd">        order is undefined for detectors with the same priority.</span>
 1143 <span class="sd">        &quot;&quot;&quot;</span>
 1144 
 1145     <span class="k">def</span> <span class="nf">react</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">,</span> <span class="n">detector</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">100</span><span class="p">):</span>
 1146         <span class="sd">&quot;&quot;&quot;Register a reactor on this class.</span>
 1147 
 1148 <span class="sd">        &#39;event&#39; should be one of &quot;create&quot;, &quot;set&quot;, &quot;retire&quot;, or</span>
 1149 <span class="sd">        &quot;restore&quot;. &#39;detector&#39; should be a function accepting four</span>
 1150 <span class="sd">        arguments. Detectors are called in priority order, execution</span>
 1151 <span class="sd">        order is undefined for detectors with the same priority.</span>
 1152 <span class="sd">        &quot;&quot;&quot;</span>
 1153 </pre></div>
 1154 </div>
 1155 <p>Auditors are called with the arguments:</p>
 1156 <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>
 1157 </pre></div>
 1158 </div>
 1159 <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
 1160 IssueClass within the database, and <code class="docutils literal"><span class="pre">newdata</span></code> is a dictionary mapping
 1161 property names to values.</p>
 1162 <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
 1163 newdata contains all of the initial property values with which the item
 1164 is about to be created.</p>
 1165 <p>For a <code class="docutils literal"><span class="pre">set()</span></code> operation, newdata contains only the names and values of
 1166 properties that are about to be changed.</p>
 1167 <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>
 1168 <p>Reactors are called with the arguments:</p>
 1169 <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>
 1170 </pre></div>
 1171 </div>
 1172 <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
 1173 IssueClass within the database, and <code class="docutils literal"><span class="pre">olddata</span></code> is a dictionary mapping
 1174 property names to values.</p>
 1175 <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
 1176 newly-created item and <code class="docutils literal"><span class="pre">olddata</span></code> is None.</p>
 1177 <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
 1178 values of properties that were changed.</p>
 1179 <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
 1180 the retired or restored item and <code class="docutils literal"><span class="pre">olddata</span></code> is None.</p>
 1181 </div>
 1182 <div class="section" id="detector-example">
 1183 <h3><a class="toc-backref" href="#id22">Detector Example</a><a class="headerlink" href="#detector-example" title="Permalink to this headline"></a></h3>
 1184 <p>Here is an example of detectors written for a hypothetical
 1185 project-management application, where users can signal approval of a
 1186 project by adding themselves to an “approvals” list, and a project
 1187 proceeds when it has three approvals:</p>
 1188 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># Permit users only to add themselves to the &quot;approvals&quot; list.</span>
 1189 
 1190 <span class="k">def</span> <span class="nf">check_approvals</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="nb">id</span><span class="p">,</span> <span class="n">newdata</span><span class="p">):</span>
 1191     <span class="k">if</span> <span class="s2">&quot;approvals&quot;</span> <span class="ow">in</span> <span class="n">newdata</span><span class="p">:</span>
 1192         <span class="k">if</span> <span class="n">cl</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="s2">&quot;status&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s2">&quot;approved&quot;</span><span class="p">):</span>
 1193             <span class="k">raise</span> <span class="n">Reject</span><span class="p">(</span><span class="s2">&quot;You can&#39;t modify the approvals list &quot;</span>
 1194                 <span class="s2">&quot;for a project that has already been approved.&quot;</span><span class="p">)</span>
 1195         <span class="n">old</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="s2">&quot;approvals&quot;</span><span class="p">)</span>
 1196         <span class="n">new</span> <span class="o">=</span> <span class="n">newdata</span><span class="p">[</span><span class="s2">&quot;approvals&quot;</span><span class="p">]</span>
 1197         <span class="k">for</span> <span class="n">uid</span> <span class="ow">in</span> <span class="n">old</span><span class="p">:</span>
 1198             <span class="k">if</span> <span class="n">uid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">new</span> <span class="ow">and</span> <span class="n">uid</span> <span class="o">!=</span> <span class="n">db</span><span class="o">.</span><span class="n">getuid</span><span class="p">():</span>
 1199                 <span class="k">raise</span> <span class="n">Reject</span><span class="p">(</span><span class="s2">&quot;You can&#39;t remove other users from &quot;</span>
 1200                     <span class="s2">&quot;the approvals list; you can only remove &quot;</span>
 1201                     <span class="s2">&quot;yourself.&quot;</span><span class="p">)</span>
 1202         <span class="k">for</span> <span class="n">uid</span> <span class="ow">in</span> <span class="n">new</span><span class="p">:</span>
 1203             <span class="k">if</span> <span class="n">uid</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">old</span> <span class="ow">and</span> <span class="n">uid</span> <span class="o">!=</span> <span class="n">db</span><span class="o">.</span><span class="n">getuid</span><span class="p">():</span>
 1204                 <span class="k">raise</span> <span class="n">Reject</span><span class="p">(</span><span class="s2">&quot;You can&#39;t add other users to the &quot;</span>
 1205                     <span class="s2">&quot;approvals list; you can only add yourself.&quot;</span><span class="p">)</span>
 1206 
 1207 <span class="c1"># When three people have approved a project, change its status from</span>
 1208 <span class="c1"># &quot;pending&quot; to &quot;approved&quot;.</span>
 1209 
 1210 <span class="k">def</span> <span class="nf">approve_project</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="nb">id</span><span class="p">,</span> <span class="n">olddata</span><span class="p">):</span>
 1211     <span class="k">if</span> <span class="p">(</span><span class="s2">&quot;approvals&quot;</span> <span class="ow">in</span> <span class="n">olddata</span> <span class="ow">and</span>
 1212         <span class="nb">len</span><span class="p">(</span><span class="n">cl</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="s2">&quot;approvals&quot;</span><span class="p">))</span> <span class="o">==</span> <span class="mi">3</span><span class="p">):</span>
 1213         <span class="k">if</span> <span class="n">cl</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="s2">&quot;status&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s2">&quot;pending&quot;</span><span class="p">):</span>
 1214             <span class="n">cl</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="n">status</span><span class="o">=</span><span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s2">&quot;approved&quot;</span><span class="p">))</span>
 1215 
 1216 <span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">db</span><span class="p">):</span>
 1217     <span class="n">db</span><span class="o">.</span><span class="n">project</span><span class="o">.</span><span class="n">audit</span><span class="p">(</span><span class="s2">&quot;set&quot;</span><span class="p">,</span> <span class="n">check_approval</span><span class="p">)</span>
 1218     <span class="n">db</span><span class="o">.</span><span class="n">project</span><span class="o">.</span><span class="n">react</span><span class="p">(</span><span class="s2">&quot;set&quot;</span><span class="p">,</span> <span class="n">approve_project</span><span class="p">)</span>
 1219 </pre></div>
 1220 </div>
 1221 <p>Here is another example of a detector that can allow or prevent the
 1222 creation of new items.  In this scenario, patches for a software project
 1223 are submitted by sending in e-mail with an attached file, and we want to
 1224 ensure that there are text/plain attachments on the message.  The
 1225 maintainer of the package can then apply the patch by setting its status
 1226 to “applied”:</p>
 1227 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># Only accept attempts to create new patches that come with patch</span>
 1228 <span class="c1"># files.</span>
 1229 
 1230 <span class="k">def</span> <span class="nf">check_new_patch</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="nb">id</span><span class="p">,</span> <span class="n">newdata</span><span class="p">):</span>
 1231     <span class="k">if</span> <span class="ow">not</span> <span class="n">newdata</span><span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]:</span>
 1232         <span class="k">raise</span> <span class="n">Reject</span><span class="p">(</span><span class="s2">&quot;You can&#39;t submit a new patch without &quot;</span>
 1233                      <span class="s2">&quot;attaching a patch file.&quot;</span><span class="p">)</span>
 1234     <span class="k">for</span> <span class="n">fileid</span> <span class="ow">in</span> <span class="n">newdata</span><span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]:</span>
 1235         <span class="k">if</span> <span class="n">db</span><span class="o">.</span><span class="n">file</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">fileid</span><span class="p">,</span> <span class="s2">&quot;type&quot;</span><span class="p">)</span> <span class="o">!=</span> <span class="s2">&quot;text/plain&quot;</span><span class="p">:</span>
 1236             <span class="k">raise</span> <span class="n">Reject</span><span class="p">(</span><span class="s2">&quot;Submitted patch files must be &quot;</span>
 1237                          <span class="s2">&quot;text/plain.&quot;</span><span class="p">)</span>
 1238 
 1239 <span class="c1"># When the status is changed from &quot;approved&quot; to &quot;applied&quot;, apply the</span>
 1240 <span class="c1"># patch.</span>
 1241 
 1242 <span class="k">def</span> <span class="nf">apply_patch</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="nb">id</span><span class="p">,</span> <span class="n">olddata</span><span class="p">):</span>
 1243     <span class="k">if</span> <span class="p">(</span><span class="n">cl</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="p">,</span> <span class="s2">&quot;status&quot;</span><span class="p">)</span> <span class="o">==</span> <span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s2">&quot;applied&quot;</span><span class="p">)</span> <span class="ow">and</span>
 1244         <span class="n">olddata</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="n">db</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">lookup</span><span class="p">(</span><span class="s2">&quot;approved&quot;</span><span class="p">)):</span>
 1245         <span class="c1"># ...apply the patch...</span>
 1246 
 1247 <span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">db</span><span class="p">):</span>
 1248     <span class="n">db</span><span class="o">.</span><span class="n">patch</span><span class="o">.</span><span class="n">audit</span><span class="p">(</span><span class="s2">&quot;create&quot;</span><span class="p">,</span> <span class="n">check_new_patch</span><span class="p">)</span>
 1249     <span class="n">db</span><span class="o">.</span><span class="n">patch</span><span class="o">.</span><span class="n">react</span><span class="p">(</span><span class="s2">&quot;set&quot;</span><span class="p">,</span> <span class="n">apply_patch</span><span class="p">)</span>
 1250 </pre></div>
 1251 </div>
 1252 </div>
 1253 </div>
 1254 <div class="section" id="command-interface">
 1255 <h2><a class="toc-backref" href="#id23">Command Interface</a><a class="headerlink" href="#command-interface" title="Permalink to this headline"></a></h2>
 1256 <p>The command interface is a very simple and minimal interface, intended
 1257 only for quick searches and checks from the shell prompt. (Anything more
 1258 interesting can simply be written in Python using the Roundup database
 1259 module.)</p>
 1260 <div class="section" id="command-interface-specification">
 1261 <span id="index-2"></span><h3><a class="toc-backref" href="#id24">Command Interface Specification</a><a class="headerlink" href="#command-interface-specification" title="Permalink to this headline"></a></h3>
 1262 <p>A single command, <code class="docutils literal"><span class="pre">roundup-admin</span></code>, provides basic access to the hyperdatabase
 1263 from the command line:</p>
 1264 <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="n">help</span>
 1265 <span class="n">roundup</span><span class="o">-</span><span class="n">admin</span> <span class="n">get</span> <span class="p">[</span><span class="o">-</span><span class="nb">list</span><span class="p">]</span> <span class="n">designator</span><span class="p">[,</span> <span class="n">designator</span><span class="p">,</span><span class="o">...</span><span class="p">]</span> <span class="n">propname</span>
 1266 <span class="n">roundup</span><span class="o">-</span><span class="n">admin</span> <span class="nb">set</span> <span class="n">designator</span><span class="p">[,</span> <span class="n">designator</span><span class="p">,</span><span class="o">...</span><span class="p">]</span> <span class="n">propname</span><span class="o">=</span><span class="n">value</span> <span class="o">...</span>
 1267 <span class="n">roundup</span><span class="o">-</span><span class="n">admin</span> <span class="n">find</span> <span class="p">[</span><span class="o">-</span><span class="nb">list</span><span class="p">]</span> <span class="n">classname</span> <span class="n">propname</span><span class="o">=</span><span class="n">value</span> <span class="o">...</span>
 1268 </pre></div>
 1269 </div>
 1270 <p>See <code class="docutils literal"><span class="pre">roundup-admin</span> <span class="pre">help</span> <span class="pre">commands</span></code> for a complete list of commands.</p>
 1271 <p>Property values are represented as strings in command arguments and in
 1272 the printed results:</p>
 1273 <ul class="simple">
 1274 <li>Strings are, well, strings.</li>
 1275 <li>Integers/Numbers are displayed the same as strings.</li>
 1276 <li>Booleans are displayed as ‘Yes’ or ‘No’.</li>
 1277 <li>Date values are printed in the full date format in the local time
 1278 zone, and accepted in the full format or any of the partial formats
 1279 explained above.</li>
 1280 <li>Link values are printed as item designators.  When given as an
 1281 argument, item designators and key strings are both accepted.</li>
 1282 <li>Multilink values are printed as lists of item designators joined by
 1283 commas.  When given as an argument, item designators and key strings
 1284 are both accepted; an empty string, a single item, or a list of items
 1285 joined by commas is accepted.</li>
 1286 </ul>
 1287 <p>When multiple items are specified to the roundup-admin get or roundup-admin set
 1288 commands, the specified properties are retrieved or set on all the
 1289 listed items.</p>
 1290 <p>When multiple results are returned by the roundup-admin get or
 1291 roundup-admin find
 1292 commands, they are printed one per line (default) or joined by commas
 1293 (with the -list) option.</p>
 1294 </div>
 1295 <div class="section" id="usage-example">
 1296 <span id="index-3"></span><h3><a class="toc-backref" href="#id25">Usage Example</a><a class="headerlink" href="#usage-example" title="Permalink to this headline"></a></h3>
 1297 <p>To find all messages regarding in-progress issues that contain the word
 1298 “spam”, for example, you could execute the following command from the
 1299 directory where the database dumps its files:</p>
 1300 <div class="highlight-default"><div class="highlight"><pre><span></span>shell% for issue in `roundup-admin find issue status=in-progress`; do
 1301 &gt; grep -l spam `roundup-admin get $issue messages`
 1302 &gt; done
 1303 msg23
 1304 msg49
 1305 msg50
 1306 msg61
 1307 shell%
 1308 </pre></div>
 1309 </div>
 1310 <p>Or, using the -list option, this can be written as a single command:</p>
 1311 <div class="highlight-default"><div class="highlight"><pre><span></span>shell% grep -l spam `roundup-admin get \
 1312     \`roundup-admin find -list issue status=in-progress\` messages`
 1313 msg23
 1314 msg49
 1315 msg50
 1316 msg61
 1317 shell%
 1318 </pre></div>
 1319 </div>
 1320 </div>
 1321 </div>
 1322 <div class="section" id="e-mail-user-interface">
 1323 <h2><a class="toc-backref" href="#id26">E-mail User Interface</a><a class="headerlink" href="#e-mail-user-interface" title="Permalink to this headline"></a></h2>
 1324 <p>The Roundup system must be assigned an e-mail address at which to
 1325 receive mail.  Messages should be piped to the Roundup mail-handling
 1326 script by the mail delivery system (e.g. using an alias beginning with
 1327 “|” for sendmail).</p>
 1328 <div class="section" id="message-processing">
 1329 <h3><a class="toc-backref" href="#id27">Message Processing</a><a class="headerlink" href="#message-processing" title="Permalink to this headline"></a></h3>
 1330 <p>Incoming messages are examined for multiple parts. In a multipart/mixed
 1331 message or part, each subpart is extracted and examined.  In a
 1332 multipart/alternative message or part, we look for a text/plain subpart
 1333 and ignore the other parts.  The text/plain subparts are assembled to
 1334 form the textual body of the message, to be stored in the file
 1335 associated with a “msg” class item. Any parts of other types are each
 1336 stored in separate files and given “file” class items that are linked to
 1337 the “msg” item.</p>
 1338 <p>The “summary” property on message items is taken from the first
 1339 non-quoting section in the message body. The message body is divided
 1340 into sections by blank lines. Sections where the second and all
 1341 subsequent lines begin with a “&gt;” or “|” character are considered
 1342 “quoting sections”.  The first line of the first non-quoting section
 1343 becomes the summary of the message.</p>
 1344 <p>All of the addresses in the To: and Cc: headers of the incoming message
 1345 are looked up among the user items, and the corresponding users are
 1346 placed in the “recipients” property on the new “msg” item.  The address
 1347 in the From: header similarly determines the “author” property of the
 1348 new “msg” item. The default handling for addresses that don’t have
 1349 corresponding users is to create new users with no passwords and a
 1350 username equal to the address.  (The web interface does not permit
 1351 logins for users with no passwords.)  If we prefer to reject mail from
 1352 outside sources, we can simply register an auditor on the “user” class
 1353 that prevents the creation of user items with no passwords.</p>
 1354 <p>The subject line of the incoming message is examined to determine
 1355 whether the message is an attempt to create a new issue or to discuss an
 1356 existing issue.  A designator enclosed in square brackets is sought as
 1357 the first thing on the subject line (after skipping any “Fwd:” or “Re:”
 1358 prefixes).</p>
 1359 <p>If an issue designator (class name and id number) is found there, the
 1360 newly created “msg” item is added to the “messages” property for that
 1361 issue, and any new “file” items are added to the “files” property for
 1362 the issue.</p>
 1363 <p>If just an issue class name is found there, we attempt to create a new
 1364 issue of that class with its “messages” property initialized to contain
 1365 the new “msg” item and its “files” property initialized to contain any
 1366 new “file” items.</p>
 1367 <p>Both cases may trigger detectors (in the first case we are calling the
 1368 set() method to add the message to the issue’s spool; in the second case
 1369 we are calling the create() method to create a new item).  If an auditor
 1370 raises an exception, the original message is bounced back to the sender
 1371 with the explanatory message given in the exception.</p>
 1372 </div>
 1373 <div class="section" id="nosy-lists">
 1374 <h3><a class="toc-backref" href="#id28">Nosy Lists</a><a class="headerlink" href="#nosy-lists" title="Permalink to this headline"></a></h3>
 1375 <p>A standard detector is provided that watches for additions to the
 1376 “messages” property.  When a new message is added, the detector sends it
 1377 to all the users on the “nosy” list for the issue that are not already
 1378 on the “recipients” list of the message.  Those users are then appended
 1379 to the “recipients” property on the message, so multiple copies of a
 1380 message are never sent to the same user.  The journal recorded by the
 1381 hyperdatabase on the “recipients” property then provides a log of when
 1382 the message was sent to whom.</p>
 1383 </div>
 1384 <div class="section" id="setting-properties">
 1385 <h3><a class="toc-backref" href="#id29">Setting Properties</a><a class="headerlink" href="#setting-properties" title="Permalink to this headline"></a></h3>
 1386 <p>The e-mail interface also provides a simple way to set properties on
 1387 issues.  At the end of the subject line, <code class="docutils literal"><span class="pre">propname=value</span></code> pairs can be
 1388 specified in square brackets, using the same conventions as for the
 1389 roundup-admin <code class="docutils literal"><span class="pre">set</span></code> shell command.</p>
 1390 </div>
 1391 </div>
 1392 <div class="section" id="web-user-interface">
 1393 <h2><a class="toc-backref" href="#id30">Web User Interface</a><a class="headerlink" href="#web-user-interface" title="Permalink to this headline"></a></h2>
 1394 <p>The web interface is provided by a CGI script that can be run under any
 1395 web server.  A simple web server can easily be built on the standard
 1396 CGIHTTPServer module, and should also be included in the distribution
 1397 for quick out-of-the-box deployment.</p>
 1398 <p>The user interface is constructed from a number of template files
 1399 containing mostly HTML.  Among the HTML tags in templates are
 1400 interspersed some nonstandard tags, which we use as placeholders to be
 1401 replaced by properties and their values.</p>
 1402 <div class="section" id="views-and-view-specifiers">
 1403 <h3><a class="toc-backref" href="#id31">Views and View Specifiers</a><a class="headerlink" href="#views-and-view-specifiers" title="Permalink to this headline"></a></h3>
 1404 <p>There are two main kinds of views: <em>index</em> views and <em>issue</em> views. An
 1405 index view displays a list of issues of a particular class, optionally
 1406 sorted and filtered as requested.  An issue view presents the properties
 1407 of a particular issue for editing and displays the message spool for the
 1408 issue.</p>
 1409 <p>A view specifier is a string that specifies all the options needed to
 1410 construct a particular view. It goes after the URL to the Roundup CGI
 1411 script or the web server to form the complete URL to a view.  When the
 1412 result of selecting a link or submitting a form takes the user to a new
 1413 view, the Web browser should be redirected to a canonical location
 1414 containing a complete view specifier so that the view can be bookmarked.</p>
 1415 </div>
 1416 <div class="section" id="displaying-properties">
 1417 <h3><a class="toc-backref" href="#id32">Displaying Properties</a><a class="headerlink" href="#displaying-properties" title="Permalink to this headline"></a></h3>
 1418 <p>Properties appear in the user interface in three contexts: in indices,
 1419 in editors, and as search filters.  For each type of property, there are
 1420 several display possibilities.  For example, in an index view, a string
 1421 property may just be printed as a plain string, but in an editor view,
 1422 that property should be displayed in an editable field.</p>
 1423 <p>The display of a property is handled by functions in the
 1424 <code class="docutils literal"><span class="pre">cgi.templating</span></code> module.</p>
 1425 <p>Displayer functions are triggered by <code class="docutils literal"><span class="pre">tal:content</span></code> or <code class="docutils literal"><span class="pre">tal:replace</span></code>
 1426 tag attributes in templates.  The value of the attribute provides an
 1427 expression for calling the displayer function. For example, the
 1428 occurrence of:</p>
 1429 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;context/status/plain&quot;</span>
 1430 </pre></div>
 1431 </div>
 1432 <p>in a template triggers a call to:</p>
 1433 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">context</span><span class="p">[</span><span class="s1">&#39;status&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">plain</span><span class="p">()</span>
 1434 </pre></div>
 1435 </div>
 1436 <p>where the context would be an item of the “issue” class.  The displayer
 1437 functions can accept extra arguments to further specify details about
 1438 the widgets that should be generated.</p>
 1439 <p>Some of the standard displayer functions include:</p>
 1440 <table border="1" class="docutils">
 1441 <colgroup>
 1442 <col width="13%" />
 1443 <col width="87%" />
 1444 </colgroup>
 1445 <thead valign="bottom">
 1446 <tr class="row-odd"><th class="head">Function</th>
 1447 <th class="head">Description</th>
 1448 </tr>
 1449 </thead>
 1450 <tbody valign="top">
 1451 <tr class="row-even"><td>plain</td>
 1452 <td>display a String property directly;
 1453 display a Date property in a specified time zone with an
 1454 option to omit the time from the date stamp; for a Link or
 1455 Multilink property, display the key strings of the linked
 1456 items (or the ids if the linked class has no key property)</td>
 1457 </tr>
 1458 <tr class="row-odd"><td>field</td>
 1459 <td>display a property like the plain displayer above, but in a
 1460 text field to be edited</td>
 1461 </tr>
 1462 <tr class="row-even"><td>menu</td>
 1463 <td>for a Link property, display a menu of the available choices</td>
 1464 </tr>
 1465 </tbody>
 1466 </table>
 1467 <p>See the <a class="reference external" href="customizing.html">customisation</a> documentation for the complete list.</p>
 1468 </div>
 1469 <div class="section" id="index-views">
 1470 <h3><a class="toc-backref" href="#id33">Index Views</a><a class="headerlink" href="#index-views" title="Permalink to this headline"></a></h3>
 1471 <p>An index view contains two sections: a filter section and an index
 1472 section. The filter section provides some widgets for selecting which
 1473 issues appear in the index.  The index section is a table of issues.</p>
 1474 <div class="section" id="index-view-specifiers">
 1475 <h4><a class="toc-backref" href="#id34">Index View Specifiers</a><a class="headerlink" href="#index-view-specifiers" title="Permalink to this headline"></a></h4>
 1476 <p>An index view specifier looks like this (whitespace has been added for
 1477 clarity):</p>
 1478 <div class="highlight-default"><div class="highlight"><pre><span></span>/issue?status=unread,in-progress,resolved&amp;
 1479     keyword=security,ui&amp;
 1480     :group=priority,-status&amp;
 1481     :sort=-activity&amp;
 1482     :filters=status,keyword&amp;
 1483     :columns=title,status,fixer
 1484 </pre></div>
 1485 </div>
 1486 <p>The index view is determined by two parts of the specifier: the layout
 1487 part and the filter part. The layout part consists of the query
 1488 parameters that begin with colons, and it determines the way that the
 1489 properties of selected items are displayed. The filter part consists of
 1490 all the other query parameters, and it determines the criteria by which
 1491 items are selected for display.</p>
 1492 <p>The filter part is interactively manipulated with the form widgets
 1493 displayed in the filter section.  The layout part is interactively
 1494 manipulated by clicking on the column headings in the table.</p>
 1495 <p>The filter part selects the union of the sets of issues with values
 1496 matching any specified Link properties and the intersection of the sets
 1497 of issues with values matching any specified Multilink properties.</p>
 1498 <p>The example specifies an index of “issue” items. Only issues with a
 1499 “status” of either “unread” or “in-progres” or “resolved” are displayed,
 1500 and only issues with “keyword” values including both “security” and “ui”
 1501 are displayed.  The items are grouped by priority arranged in ascending
 1502 order and in descending order by status; and within groups, sorted by
 1503 activity, arranged in descending order. The filter section shows
 1504 filters for the “status” and “keyword” properties, and the table includes
 1505 columns for the “title”, “status”, and “fixer” properties.</p>
 1506 <p>Associated with each issue class is a default layout specifier.  The
 1507 layout specifier in the above example is the default layout to be
 1508 provided with the default bug-tracker schema described above in section
 1509 4.4.</p>
 1510 </div>
 1511 <div class="section" id="index-section">
 1512 <h4><a class="toc-backref" href="#id35">Index Section</a><a class="headerlink" href="#index-section" title="Permalink to this headline"></a></h4>
 1513 <p>The template for an index section describes one row of the index table.
 1514 Fragments protected by a <code class="docutils literal"><span class="pre">tal:condition=&quot;request/show/&lt;property&gt;&quot;</span></code> are
 1515 included or omitted depending on whether the view specifier requests a
 1516 column for a particular property. The table cells are filled by the
 1517 <code class="docutils literal"><span class="pre">tal:content=&quot;context/&lt;property&gt;&quot;</span></code> directive, which displays the value
 1518 of the property.</p>
 1519 <p>Here’s a simple example of an index template:</p>
 1520 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">tr</span><span class="o">&gt;</span>
 1521   <span class="o">&lt;</span><span class="n">td</span> <span class="n">tal</span><span class="p">:</span><span class="n">condition</span><span class="o">=</span><span class="s2">&quot;request/show/title&quot;</span>
 1522       <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;contex/title&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1523   <span class="o">&lt;</span><span class="n">td</span> <span class="n">tal</span><span class="p">:</span><span class="n">condition</span><span class="o">=</span><span class="s2">&quot;request/show/status&quot;</span>
 1524       <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;contex/status&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1525   <span class="o">&lt;</span><span class="n">td</span> <span class="n">tal</span><span class="p">:</span><span class="n">condition</span><span class="o">=</span><span class="s2">&quot;request/show/fixer&quot;</span>
 1526       <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;contex/fixer&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1527 <span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
 1528 </pre></div>
 1529 </div>
 1530 </div>
 1531 <div class="section" id="sorting">
 1532 <h4><a class="toc-backref" href="#id36">Sorting</a><a class="headerlink" href="#sorting" title="Permalink to this headline"></a></h4>
 1533 <p>String and Date values are sorted in the natural way. Link properties
 1534 are sorted according to the value of the “order” property on the linked
 1535 items if it is present; or otherwise on the key string of the linked
 1536 items; or finally on the item ids.  Multilink properties are sorted
 1537 according to how many links are present.</p>
 1538 </div>
 1539 </div>
 1540 <div class="section" id="issue-views">
 1541 <h3><a class="toc-backref" href="#id37">Issue Views</a><a class="headerlink" href="#issue-views" title="Permalink to this headline"></a></h3>
 1542 <p>An issue view contains an editor section and a spool section. At the top
 1543 of an issue view, links to superseding and superseded issues are always
 1544 displayed.</p>
 1545 <div class="section" id="issue-view-specifiers">
 1546 <h4><a class="toc-backref" href="#id38">Issue View Specifiers</a><a class="headerlink" href="#issue-view-specifiers" title="Permalink to this headline"></a></h4>
 1547 <p>An issue view specifier is simply the issue’s designator:</p>
 1548 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">/</span><span class="n">patch23</span>
 1549 </pre></div>
 1550 </div>
 1551 </div>
 1552 <div class="section" id="editor-section">
 1553 <h4><a class="toc-backref" href="#id39">Editor Section</a><a class="headerlink" href="#editor-section" title="Permalink to this headline"></a></h4>
 1554 <p>The editor section is generated from a template containing
 1555 <code class="docutils literal"><span class="pre">tal:content=&quot;context/&lt;property&gt;/&lt;widget&gt;&quot;</span></code> directives to insert the
 1556 appropriate widgets for editing properties.</p>
 1557 <p>Here’s an example of a basic editor template:</p>
 1558 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">table</span><span class="o">&gt;</span>
 1559 <span class="o">&lt;</span><span class="n">tr</span><span class="o">&gt;</span>
 1560     <span class="o">&lt;</span><span class="n">td</span> <span class="n">colspan</span><span class="o">=</span><span class="mi">2</span>
 1561         <span class="n">tal</span><span class="p">:</span><span class="n">content</span><span class="o">=</span><span class="s2">&quot;python:context.title.field(size=&#39;60&#39;)&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1562 <span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
 1563 <span class="o">&lt;</span><span class="n">tr</span><span class="o">&gt;</span>
 1564     <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;context/fixer/field&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1565     <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;context/status/menu&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1566 <span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
 1567 <span class="o">&lt;</span><span class="n">tr</span><span class="o">&gt;</span>
 1568     <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;context/nosy/field&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1569     <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;context/priority/menu&quot;</span><span class="o">&gt;&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1570 <span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
 1571 <span class="o">&lt;</span><span class="n">tr</span><span class="o">&gt;</span>
 1572     <span class="o">&lt;</span><span class="n">td</span> <span class="n">colspan</span><span class="o">=</span><span class="mi">2</span><span class="o">&gt;</span>
 1573       <span class="o">&lt;</span><span class="n">textarea</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;:note&quot;</span> <span class="n">rows</span><span class="o">=</span><span class="mi">5</span> <span class="n">cols</span><span class="o">=</span><span class="mi">60</span><span class="o">&gt;&lt;/</span><span class="n">textarea</span><span class="o">&gt;</span>
 1574     <span class="o">&lt;/</span><span class="n">td</span><span class="o">&gt;</span>
 1575 <span class="o">&lt;/</span><span class="n">tr</span><span class="o">&gt;</span>
 1576 <span class="o">&lt;/</span><span class="n">table</span><span class="o">&gt;</span>
 1577 </pre></div>
 1578 </div>
 1579 <p>As shown in the example, the editor template can also include a “:note”
 1580 field, which is a text area for entering a note to go along with a
 1581 change.</p>
 1582 <p>When a change is submitted, the system automatically generates a message
 1583 describing the changed properties. The message displays all of the
 1584 property values on the issue and indicates which ones have changed. An
 1585 example of such a message might be this:</p>
 1586 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">title</span><span class="p">:</span> <span class="n">Polly</span> <span class="n">Parrot</span> <span class="ow">is</span> <span class="n">dead</span>
 1587 <span class="n">priority</span><span class="p">:</span> <span class="n">critical</span>
 1588 <span class="n">status</span><span class="p">:</span> <span class="n">unread</span> <span class="o">-&gt;</span> <span class="ow">in</span><span class="o">-</span><span class="n">progress</span>
 1589 <span class="n">fixer</span><span class="p">:</span> <span class="p">(</span><span class="n">none</span><span class="p">)</span>
 1590 <span class="n">keywords</span><span class="p">:</span> <span class="n">parrot</span><span class="p">,</span><span class="n">plumage</span><span class="p">,</span><span class="n">perch</span><span class="p">,</span><span class="n">nailed</span><span class="p">,</span><span class="n">dead</span>
 1591 </pre></div>
 1592 </div>
 1593 <p>If a note is given in the “:note” field, the note is appended to the
 1594 description.  The message is then added to the issue’s message spool
 1595 (thus triggering the standard detector to react by sending out this
 1596 message to the nosy list).</p>
 1597 </div>
 1598 <div class="section" id="spool-section">
 1599 <h4><a class="toc-backref" href="#id40">Spool Section</a><a class="headerlink" href="#spool-section" title="Permalink to this headline"></a></h4>
 1600 <p>The spool section lists messages in the issue’s “messages” property.
 1601 The index of messages displays the “date”, “author”, and “summary”
 1602 properties on the message items, and selecting a message takes you to
 1603 its content.</p>
 1604 </div>
 1605 </div>
 1606 </div>
 1607 <div class="section" id="access-control">
 1608 <h2><a class="toc-backref" href="#id41">Access Control</a><a class="headerlink" href="#access-control" title="Permalink to this headline"></a></h2>
 1609 <p>At each point that requires an action to be performed, the security
 1610 mechanisms are asked if the current user has permission. This permission
 1611 is defined as a Permission.</p>
 1612 <p>Individual assignment of Permission to user is unwieldy. The concept of
 1613 a Role, which encompasses several Permissions and may be assigned to
 1614 many Users, is quite well developed in many projects. Roundup will take
 1615 this path, and allow the multiple assignment of Roles to Users, and
 1616 multiple Permissions to Roles. These definitions are not persistent -
 1617 they’re defined when the application initialises.</p>
 1618 <p>There will be three levels of Permission. The Class level permissions
 1619 define logical permissions associated with all items of a particular
 1620 class (or all classes). The Item level permissions define logical
 1621 permissions associated with specific items by way of their user-linked
 1622 properties. The Property level permissions define logical permissions
 1623 associated with a specific property of an item.</p>
 1624 <div class="section" id="access-control-interface-specification">
 1625 <h3><a class="toc-backref" href="#id42">Access Control Interface Specification</a><a class="headerlink" href="#access-control-interface-specification" title="Permalink to this headline"></a></h3>
 1626 <p>The security module defines:</p>
 1627 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Permission</span><span class="p">:</span>
 1628     <span class="sd">&#39;&#39;&#39; Defines a Permission with the attributes</span>
 1629 <span class="sd">        - name</span>
 1630 <span class="sd">        - description</span>
 1631 <span class="sd">        - klass (optional)</span>
 1632 <span class="sd">        - properties (optional)</span>
 1633 <span class="sd">        - check function (optional)</span>
 1634 
 1635 <span class="sd">        The klass may be unset, indicating that this permission is</span>
 1636 <span class="sd">        not locked to a particular hyperdb class. There may be</span>
 1637 <span class="sd">        multiple Permissions for the same name for different</span>
 1638 <span class="sd">        classes.</span>
 1639 
 1640 <span class="sd">        If property names are set, permission is restricted to those</span>
 1641 <span class="sd">        properties only.</span>
 1642 
 1643 <span class="sd">        If check function is set, permission is granted only when</span>
 1644 <span class="sd">        the function returns value interpreted as boolean true.</span>
 1645 <span class="sd">        The function is called with arguments db, userid, itemid.</span>
 1646 <span class="sd">    &#39;&#39;&#39;</span>
 1647 
 1648 <span class="k">class</span> <span class="nc">Role</span><span class="p">:</span>
 1649     <span class="sd">&#39;&#39;&#39; Defines a Role with the attributes</span>
 1650 <span class="sd">        - name</span>
 1651 <span class="sd">        - description</span>
 1652 <span class="sd">        - permissions</span>
 1653 <span class="sd">    &#39;&#39;&#39;</span>
 1654 
 1655 <span class="k">class</span> <span class="nc">Security</span><span class="p">:</span>
 1656     <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">db</span><span class="p">):</span>
 1657         <span class="sd">&#39;&#39;&#39; Initialise the permission and role stores, and add in</span>
 1658 <span class="sd">            the base roles (for admin user).</span>
 1659 <span class="sd">        &#39;&#39;&#39;</span>
 1660 
 1661     <span class="k">def</span> <span class="nf">getPermission</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">permission</span><span class="p">,</span> <span class="n">classname</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">properties</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
 1662             <span class="n">check</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 1663         <span class="sd">&#39;&#39;&#39; Find the Permission exactly matching the name, class,</span>
 1664 <span class="sd">            properties list and check function.</span>
 1665 
 1666 <span class="sd">            Raise ValueError if there is no exact match.</span>
 1667 <span class="sd">        &#39;&#39;&#39;</span>
 1668 
 1669     <span class="k">def</span> <span class="nf">hasPermission</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">permission</span><span class="p">,</span> <span class="n">userid</span><span class="p">,</span> <span class="n">classname</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
 1670             <span class="nb">property</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">itemid</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
 1671         <span class="sd">&#39;&#39;&#39; Look through all the Roles, and hence Permissions, and</span>
 1672 <span class="sd">            see if &quot;permission&quot; exists given the constraints of</span>
 1673 <span class="sd">            classname, property and itemid.</span>
 1674 
 1675 <span class="sd">            If classname is specified (and only classname) then the</span>
 1676 <span class="sd">            search will match if there is *any* Permission for that</span>
 1677 <span class="sd">            classname, even if the Permission has additional</span>
 1678 <span class="sd">            constraints.</span>
 1679 
 1680 <span class="sd">            If property is specified, the Permission matched must have</span>
 1681 <span class="sd">            either no properties listed or the property must appear in</span>
 1682 <span class="sd">            the list.</span>
 1683 
 1684 <span class="sd">            If itemid is specified, the Permission matched must have</span>
 1685 <span class="sd">            either no check function defined or the check function,</span>
 1686 <span class="sd">            when invoked, must return a True value.</span>
 1687 
 1688 <span class="sd">            Note that this functionality is actually implemented by the</span>
 1689 <span class="sd">            Permission.test() method.</span>
 1690 <span class="sd">        &#39;&#39;&#39;</span>
 1691 
 1692     <span class="k">def</span> <span class="nf">addPermission</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">propspec</span><span class="p">):</span>
 1693         <span class="sd">&#39;&#39;&#39; Create a new Permission with the properties defined in</span>
 1694 <span class="sd">            &#39;propspec&#39;. See the Permission class for the possible</span>
 1695 <span class="sd">            keyword args.</span>
 1696 <span class="sd">        &#39;&#39;&#39;</span>
 1697 
 1698     <span class="k">def</span> <span class="nf">addRole</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">propspec</span><span class="p">):</span>
 1699         <span class="sd">&#39;&#39;&#39; Create a new Role with the properties defined in</span>
 1700 <span class="sd">            &#39;propspec&#39;</span>
 1701 <span class="sd">        &#39;&#39;&#39;</span>
 1702 
 1703     <span class="k">def</span> <span class="nf">addPermissionToRole</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">rolename</span><span class="p">,</span> <span class="n">permission</span><span class="p">):</span>
 1704         <span class="sd">&#39;&#39;&#39; Add the permission to the role&#39;s permission list.</span>
 1705 
 1706 <span class="sd">            &#39;rolename&#39; is the name of the role to add permission to.</span>
 1707 <span class="sd">        &#39;&#39;&#39;</span>
 1708 </pre></div>
 1709 </div>
 1710 <p>Modules such as <code class="docutils literal"><span class="pre">cgi/client.py</span></code> and <code class="docutils literal"><span class="pre">mailgw.py</span></code> define their own
 1711 permissions like so (this example is <code class="docutils literal"><span class="pre">cgi/client.py</span></code>):</p>
 1712 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">initialiseSecurity</span><span class="p">(</span><span class="n">security</span><span class="p">):</span>
 1713     <span class="sd">&#39;&#39;&#39; Create some Permissions and Roles on the security object</span>
 1714 
 1715 <span class="sd">        This function is directly invoked by</span>
 1716 <span class="sd">        security.Security.__init__() as a part of the Security</span>
 1717 <span class="sd">        object instantiation.</span>
 1718 <span class="sd">    &#39;&#39;&#39;</span>
 1719     <span class="n">p</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;Web Registration&quot;</span><span class="p">,</span>
 1720         <span class="n">description</span><span class="o">=</span><span class="s2">&quot;Anonymous users may register through the web&quot;</span><span class="p">)</span>
 1721     <span class="n">security</span><span class="o">.</span><span class="n">addToRole</span><span class="p">(</span><span class="s1">&#39;Anonymous&#39;</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
 1722 </pre></div>
 1723 </div>
 1724 <p>Detectors may also define roles in their init() function:</p>
 1725 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">db</span><span class="p">):</span>
 1726     <span class="c1"># register an auditor that checks that a user has the &quot;May</span>
 1727     <span class="c1"># Resolve&quot; Permission before allowing them to set an issue</span>
 1728     <span class="c1"># status to &quot;resolved&quot;</span>
 1729     <span class="n">db</span><span class="o">.</span><span class="n">issue</span><span class="o">.</span><span class="n">audit</span><span class="p">(</span><span class="s1">&#39;set&#39;</span><span class="p">,</span> <span class="n">checkresolvedok</span><span class="p">)</span>
 1730     <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="s2">&quot;May Resolve&quot;</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="s2">&quot;issue&quot;</span><span class="p">)</span>
 1731     <span class="n">security</span><span class="o">.</span><span class="n">addToRole</span><span class="p">(</span><span class="s1">&#39;Manager&#39;</span><span class="p">,</span> <span class="n">p</span><span class="p">)</span>
 1732 </pre></div>
 1733 </div>
 1734 <p>The tracker dbinit module then has in <code class="docutils literal"><span class="pre">open()</span></code>:</p>
 1735 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># open the database - it must be modified to init the Security class</span>
 1736 <span class="c1"># from security.py as db.security</span>
 1737 <span class="n">db</span> <span class="o">=</span> <span class="n">Database</span><span class="p">(</span><span class="n">config</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
 1738 
 1739 <span class="c1"># add some extra permissions and associate them with roles</span>
 1740 <span class="n">ei</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="s2">&quot;Edit&quot;</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="s2">&quot;issue&quot;</span><span class="p">,</span>
 1741                 <span class="n">description</span><span class="o">=</span><span class="s2">&quot;User is allowed to edit issues&quot;</span><span class="p">)</span>
 1742 <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">ei</span><span class="p">)</span>
 1743 <span class="n">ai</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="s2">&quot;View&quot;</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="s2">&quot;issue&quot;</span><span class="p">,</span>
 1744                 <span class="n">description</span><span class="o">=</span><span class="s2">&quot;User is allowed to access issues&quot;</span><span class="p">)</span>
 1745 <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">ai</span><span class="p">)</span>
 1746 </pre></div>
 1747 </div>
 1748 <p>In the dbinit <code class="docutils literal"><span class="pre">init()</span></code>:</p>
 1749 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># create the two default users</span>
 1750 <span class="n">user</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s2">&quot;admin&quot;</span><span class="p">,</span> <span class="n">password</span><span class="o">=</span><span class="n">Password</span><span class="p">(</span><span class="n">adminpw</span><span class="p">),</span>
 1751             <span class="n">address</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">ADMIN_EMAIL</span><span class="p">,</span> <span class="n">roles</span><span class="o">=</span><span class="s1">&#39;Admin&#39;</span><span class="p">)</span>
 1752 <span class="n">user</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s2">&quot;anonymous&quot;</span><span class="p">,</span> <span class="n">roles</span><span class="o">=</span><span class="s1">&#39;Anonymous&#39;</span><span class="p">)</span>
 1753 </pre></div>
 1754 </div>
 1755 <p>Then in the code that matters, calls to <code class="docutils literal"><span class="pre">hasPermission</span></code> and
 1756 <code class="docutils literal"><span class="pre">hasItemPermission</span></code> are made to determine if the user has permission
 1757 to perform some action:</p>
 1758 <div class="highlight-default"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">hasPermission</span><span class="p">(</span><span class="s1">&#39;issue&#39;</span><span class="p">,</span> <span class="s1">&#39;Edit&#39;</span><span class="p">,</span> <span class="n">userid</span><span class="p">):</span>
 1759     <span class="c1"># all ok</span>
 1760 
 1761 <span class="k">if</span> <span class="n">db</span><span class="o">.</span><span class="n">security</span><span class="o">.</span><span class="n">hasItemPermission</span><span class="p">(</span><span class="s1">&#39;issue&#39;</span><span class="p">,</span> <span class="n">itemid</span><span class="p">,</span>
 1762                                  <span class="n">assignedto</span><span class="o">=</span><span class="n">userid</span><span class="p">):</span>
 1763     <span class="c1"># all ok</span>
 1764 </pre></div>
 1765 </div>
 1766 <p>Code in the core will make use of these methods, as should code in
 1767 auditors in custom templates. The HTML templating may access the access
 1768 controls through the <em>user</em> attribute of the <em>request</em> variable. It
 1769 exposes a <code class="docutils literal"><span class="pre">hasPermission()</span></code> method:</p>
 1770 <div class="highlight-default"><div class="highlight"><pre><span></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;Edit&#39;, &#39;issue&#39;)&quot;</span>
 1771 </pre></div>
 1772 </div>
 1773 <p>or, if the <em>context</em> is <em>issue</em>, then the following is the same:</p>
 1774 <div class="highlight-default"><div class="highlight"><pre><span></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;Edit&#39;)&quot;</span>
 1775 </pre></div>
 1776 </div>
 1777 </div>
 1778 <div class="section" id="authentication-of-users">
 1779 <h3><a class="toc-backref" href="#id43">Authentication of Users</a><a class="headerlink" href="#authentication-of-users" title="Permalink to this headline"></a></h3>
 1780 <p>Users must be authenticated correctly for the above controls to work.
 1781 This is not done in the current mail gateway at all. Use of digital
 1782 signing of messages could alleviate this problem.</p>
 1783 <p>The exact mechanism of registering the digital signature should be
 1784 flexible, with perhaps a level of trust. Users who supply their
 1785 signature through their first message into the tracker should be at a
 1786 lower level of trust to those who supply their signature to an admin for
 1787 submission to their user details.</p>
 1788 </div>
 1789 <div class="section" id="anonymous-users">
 1790 <h3><a class="toc-backref" href="#id44">Anonymous Users</a><a class="headerlink" href="#anonymous-users" title="Permalink to this headline"></a></h3>
 1791 <p>The “anonymous” user must always exist, and defines the access
 1792 permissions for anonymous users. Unknown users accessing Roundup through
 1793 the web or email interfaces will be logged in as the “anonymous” user.</p>
 1794 </div>
 1795 <div class="section" id="use-cases">
 1796 <h3><a class="toc-backref" href="#id45">Use Cases</a><a class="headerlink" href="#use-cases" title="Permalink to this headline"></a></h3>
 1797 <dl class="docutils">
 1798 <dt>public - end users can submit bugs, request new features, request</dt>
 1799 <dd>support
 1800 The Users would be given the default “User” Role which gives “View”
 1801 and “Edit” Permission to the “issue” class.</dd>
 1802 <dt>developer - developers can fix bugs, implement new features, provide</dt>
 1803 <dd>support
 1804 A new Role “Developer” is created with the Permission “Fixer” which
 1805 is checked for in custom auditors that see whether the issue is
 1806 being resolved with a particular resolution (“fixed”, “implemented”,
 1807 “supported”) and allows that resolution only if the permission is
 1808 available.</dd>
 1809 <dt>manager - approvers/managers can approve new features and signoff bug</dt>
 1810 <dd>fixes
 1811 A new Role “Manager” is created with the Permission “Signoff” which
 1812 is checked for in custom auditors that see whether the issue status
 1813 is being changed similar to the developer example. admin -
 1814 administrators can add users and set user’s roles The existing Role
 1815 “Admin” has the Permissions “Edit” for all classes (including
 1816 “user”) and “Web Roles” which allow the desired actions.</dd>
 1817 <dt>system - automated request handlers running various report/escalation</dt>
 1818 <dd>scripts
 1819 A combination of existing and new Roles, Permissions and auditors
 1820 could be used here.</dd>
 1821 <dt>privacy - issues that are only visible to some users</dt>
 1822 <dd>A new property is added to the issue which marks the user or group
 1823 of users who are allowed to view and edit the issue. An auditor will
 1824 check for edit access, and the template user object can check for
 1825 view access.</dd>
 1826 </dl>
 1827 </div>
 1828 </div>
 1829 <div class="section" id="deployment-scenarios">
 1830 <h2><a class="toc-backref" href="#id46">Deployment Scenarios</a><a class="headerlink" href="#deployment-scenarios" title="Permalink to this headline"></a></h2>
 1831 <p>The design described above should be general enough to permit the use of
 1832 Roundup for bug tracking, managing projects, managing patches, or
 1833 holding discussions.  By using items of multiple types, one could deploy
 1834 a system that maintains requirement specifications, catalogs bugs, and
 1835 manages submitted patches, where patches could be linked to the bugs and
 1836 requirements they address.</p>
 1837 </div>
 1838 <div class="section" id="acknowledgements">
 1839 <h2><a class="toc-backref" href="#id47">Acknowledgements</a><a class="headerlink" href="#acknowledgements" title="Permalink to this headline"></a></h2>
 1840 <p>My thanks are due to Christy Heyl for reviewing and contributing
 1841 suggestions to this paper and motivating me to get it done, and to Jesse
 1842 Vincent, Mark Miller, Christopher Simons, Jeff Dunmall, Wayne Gramlich,
 1843 and Dean Tribble for their assistance with the first-round submission.</p>
 1844 </div>
 1845 <div class="section" id="changes-to-this-document">
 1846 <h2><a class="toc-backref" href="#id48">Changes to this document</a><a class="headerlink" href="#changes-to-this-document" title="Permalink to this headline"></a></h2>
 1847 <ul class="simple">
 1848 <li>Added docs for quiet, default_value and required arguments for properties.</li>
 1849 <li>Added Boolean, Integer and Number types</li>
 1850 <li>Added section Hyperdatabase Implementations</li>
 1851 <li>“Item” has been renamed to “Issue” to account for the more specific
 1852 nature of the Class.</li>
 1853 <li>New Templating</li>
 1854 <li>Access Controls</li>
 1855 <li>Added “actor” property</li>
 1856 </ul>
 1857 </div>
 1858 </div>
 1859 
 1860 
 1861        
 1862     <div class="related related-bottom">
 1863       <ul>
 1864         <li class="right" style="margin-right: 10px">
 1865           <a href="genindex.html" title="General Index"
 1866              accesskey="I">index</a></li>
 1867         <li class="right" >
 1868           <a href="developers.html" title="Developing Roundup"
 1869              accesskey="N">next</a></li>
 1870         <li class="right" >
 1871           <a href="overview.html" title="Roundup: an Issue-Tracking System for Knowledge Workers"
 1872              accesskey="P">previous</a></li>
 1873         <li><a href="index.html">Roundup 2.0.0 documentation</a></li> 
 1874       </ul>
 1875     </div>
 1876     </div>
 1877     <div class="footer">
 1878         &copy; Copyright 2009-2020, Richard Jones, Roundup-Team.
 1879     </div>
 1880   </body>
 1881 </html>