Code

oops, forgot upgrade note
[roundup.git] / doc / design.txt
index 2fd2ae9743d3c50183fe3b06d17760398d2caed5..5d7ac09cd88a9ad8a203aea4285b8eaa631bd52f 100644 (file)
@@ -54,7 +54,7 @@ Hyperdatabase
 The lowest-level component to be implemented is the hyperdatabase.
 The hyperdatabase is intended to be
 a flexible data store that can hold configurable data in
-records which we call nodes.
+records which we call items.
 
 The hyperdatabase is implemented on top of the storage layer,
 an external module for storing its data.  The storage layer could
@@ -189,30 +189,30 @@ Time and the current local time is 19:34:02 on 25 June 2000::
     >>> Date(". + 2d") - Interval("3w")
     <Date 2000-06-07.00:34:02>
 
-Nodes and Classes
+Items and Classes
 ~~~~~~~~~~~~~~~~~
 
-Nodes contain data in properties.  To Python, these
+Items contain data in properties.  To Python, these
 properties are presented as the key-value pairs of a dictionary.
-Each node belongs to a class which defines the names
+Each item belongs to a class which defines the names
 and types of its properties.  The database permits the creation
-and modification of classes as well as nodes.
+and modification of classes as well as items.
 
 Identifiers and Designators
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Each node has a numeric identifier which is unique among
-nodes in its class.  The nodes are numbered sequentially
+Each item has a numeric identifier which is unique among
+items in its class.  The items are numbered sequentially
 within each class in order of creation, starting from 1.
 The designator
-for a node is a way to identify a node in the database, and
-consists of the name of the node's class concatenated with
-the node's numeric identifier.
+for an item is a way to identify an item in the database, and
+consists of the name of the item's class concatenated with
+the item's numeric identifier.
 
 For example, if "spam" and "eggs" are classes, the first
-node created in class "spam" has id 1 and designator "spam1".
-The first node created in class "eggs" also has id 1 but has
-the distinct designator "eggs1".  Node designators are
+item created in class "spam" has id 1 and designator "spam1".
+The first item created in class "eggs" also has id 1 but has
+the distinct designator "eggs1".  Item designators are
 conventionally enclosed in square brackets when mentioned
 in plain text.  This permits a casual mention of, say,
 "[patch37]" in an e-mail message to be turned into an active
@@ -234,11 +234,11 @@ A property may be one of five basic types:
 - Date properties store date-and-time stamps.
   Their values are Timestamp objects.
 
-- A Link property refers to a single other node
+- A Link property refers to a single other item
   selected from a specified class.  The class is part of the property;
-  the value is an integer, the id of the chosen node.
+  the value is an integer, the id of the chosen item.
 
-- A Multilink property refers to possibly many nodes
+- A Multilink property refers to possibly many items
   in a specified class.  The value is a list of integers.
 
 *None* is also a permitted value for any of these property
@@ -275,19 +275,19 @@ specifying what properties belong in classes::
     class Link:
         def __init__(self, classname, do_journal='yes'):
             """An object designating a Link property that links to
-            nodes in a specified class.
+            items in a specified class.
 
             If the do_journal argument is not 'yes' then changes to
-            the property are not journalled in the linked node.
+            the property are not journalled in the linked item.
             """
 
     class Multilink:
         def __init__(self, classname, do_journal='yes'):
             """An object designating a Multilink property that links
-            to nodes in a specified class.
+            to items in a specified class.
 
             If the do_journal argument is not 'yes' then changes to
-            the property are not journalled in the linked node(s).
+            the property are not journalled in the linked item(s).
             """
 
 
@@ -324,7 +324,7 @@ Here is the interface provided by the hyperdatabase::
             """
 
     class Class:
-        """The handle to a particular class of nodes in a hyperdatabase."""
+        """The handle to a particular class of items in a hyperdatabase."""
 
         def __init__(self, db, classname, **properties):
             """Create a new class with a given name and property specification.
@@ -334,10 +334,10 @@ Here is the interface provided by the hyperdatabase::
             must map names to property objects, or a TypeError is raised.
             """
 
-        # Editing nodes:
+        # Editing items:
 
         def create(self, **propvalues):
-            """Create a new node of this class and return its id.
+            """Create a new item of this class and return its id.
 
             The keyword arguments in 'propvalues' map property names to values.
             The values of arguments must be acceptable for the types of their
@@ -346,43 +346,43 @@ Here is the interface provided by the hyperdatabase::
             collide with other key strings or a ValueError is raised.  Any other
             properties on this class that are missing from the 'propvalues'
             dictionary are set to None.  If an id in a link or multilink
-            property does not refer to a valid node, an IndexError is raised.
+            property does not refer to a valid item, an IndexError is raised.
             """
 
-        def get(self, nodeid, propname):
-            """Get the value of a property on an existing node of this class.
+        def get(self, itemid, propname):
+            """Get the value of a property on an existing item of this class.
 
-            'nodeid' must be the id of an existing node of this class or an
+            'itemid' must be the id of an existing item of this class or an
             IndexError is raised.  'propname' must be the name of a property
             of this class or a KeyError is raised.
             """
 
-        def set(self, nodeid, **propvalues):
-            """Modify a property on an existing node of this class.
+        def set(self, itemid, **propvalues):
+            """Modify a property on an existing item of this class.
             
-            'nodeid' must be the id of an existing node of this class or an
+            'itemid' must be the id of an existing item of this class or an
             IndexError is raised.  Each key in 'propvalues' must be the name
             of a property of this class or a KeyError is raised.  All values
             in 'propvalues' must be acceptable types for their corresponding
             properties or a TypeError is raised.  If the value of the key
             property is set, it must not collide with other key strings or a
             ValueError is raised.  If the value of a Link or Multilink
-            property contains an invalid node id, a ValueError is raised.
+            property contains an invalid item id, a ValueError is raised.
             """
 
-        def retire(self, nodeid):
-            """Retire a node.
+        def retire(self, itemid):
+            """Retire an item.
             
-            The properties on the node remain available from the get() method,
-            and the node's id is never reused.  Retired nodes are not returned
-            by the find(), list(), or lookup() methods, and other nodes may
+            The properties on the item remain available from the get() method,
+            and the item's id is never reused.  Retired items are not returned
+            by the find(), list(), or lookup() methods, and other items may
             reuse the values of their key properties.
             """
 
-        def history(self, nodeid):
-            """Retrieve the journal of edits on a particular node.
+        def history(self, itemid):
+            """Retrieve the journal of edits on a particular item.
 
-            'nodeid' must be the id of an existing node of this class or an
+            'itemid' must be the id of an existing item of this class or an
             IndexError is raised.
 
             The returned list contains tuples of the form
@@ -394,42 +394,42 @@ Here is the interface provided by the hyperdatabase::
             'action' may be:
 
                 'create' or 'set' -- 'params' is a dictionary of property values
-                'link' or 'unlink' -- 'params' is (classname, nodeid, propname)
+                'link' or 'unlink' -- 'params' is (classname, itemid, propname)
                 'retire' -- 'params' is None
             """
 
-        # Locating nodes:
+        # Locating items:
 
         def setkey(self, propname):
             """Select a String property of this class to be the key property.
 
             'propname' must be the name of a String property of this class or
             None, or a TypeError is raised.  The values of the key property on
-            all existing nodes must be unique or a ValueError is raised.
+            all existing items must be unique or a ValueError is raised.
             """
 
         def getkey(self):
             """Return the name of the key property for this class or None."""
 
         def lookup(self, keyvalue):
-            """Locate a particular node by its key property and return its id.
+            """Locate a particular item by its key property and return its id.
 
             If this class has no key property, a TypeError is raised.  If the
             'keyvalue' matches one of the values for the key property among
-            the nodes in this class, the matching node's id is returned;
+            the items in this class, the matching item's id is returned;
             otherwise a KeyError is raised.
             """
 
-        def find(self, propname, nodeid):
-            """Get the ids of nodes in this class which link to the given nodes.
+        def find(self, propname, itemid):
+            """Get the ids of items in this class which link to the given items.
 
-            'propspec' consists of keyword args propname={nodeid:1,}   
+            'propspec' consists of keyword args propname={itemid:1,}   
             'propname' must be the name of a property in this class, or a
             KeyError is raised.  That property must be a Link or Multilink
             property, or a TypeError is raised.
 
-            Any node in this class whose 'propname' property links to any of the
-            nodeids will be returned. Used by the full text indexing, which
+            Any item in this class whose 'propname' property links to any of the
+            itemids will be returned. Used by the full text indexing, which
             knows that "foo" occurs in msg1, msg3 and file7, so we have hits
             on these issues:
 
@@ -437,20 +437,20 @@ Here is the interface provided by the hyperdatabase::
             """
 
         def filter(self, search_matches, filterspec, sort, group):
-            ''' Return a list of the ids of the active nodes in this class that
+            ''' Return a list of the ids of the active items in this class that
                 match the 'filter' spec, sorted by the group spec and then the
                 sort spec.
             '''
 
         def list(self):
-            """Return a list of the ids of the active nodes in this class."""
+            """Return a list of the ids of the active items in this class."""
 
         def count(self):
-            """Get the number of nodes in this class.
+            """Get the number of items in this class.
 
-            If the returned integer is 'numnodes', the ids of all the nodes
-            in this class run from 1 to numnodes, and numnodes+1 will be the
-            id of the next node to be created in this class.
+            If the returned integer is 'numitems', the ids of all the items
+            in this class run from 1 to numitems, and numitems+1 will be the
+            id of the next item to be created in this class.
             """
 
         # Manipulating properties:
@@ -467,21 +467,21 @@ Here is the interface provided by the hyperdatabase::
             is raised before any properties have been added.
             """
 
-        def getnode(self, nodeid, cache=1):
-            ''' Return a Node convenience wrapper for the node.
+        def getitem(self, itemid, cache=1):
+            ''' Return a Item convenience wrapper for the item.
 
-            'nodeid' must be the id of an existing node of this class or an
+            'itemid' must be the id of an existing item of this class or an
             IndexError is raised.
 
             'cache' indicates whether the transaction cache should be queried
-            for the node. If the node has been modified and you need to
+            for the item. If the item has been modified and you need to
             determine what its values prior to modification are, you need to
             set cache=0.
             '''
 
-    class Node:
-        ''' A convenience wrapper for the given node. It provides a mapping
-            interface to a single node's properties
+    class Item:
+        ''' A convenience wrapper for the given item. It provides a mapping
+            interface to a single item's properties
         '''
 
 Hyperdatabase Implementations
@@ -563,12 +563,12 @@ Here is an example of how the hyperdatabase module would work in practice::
 
 
 For the purposes of journalling, when a Multilink property is
-set to a new list of nodes, the hyperdatabase compares the old
+set to a new list of items, the hyperdatabase compares the old
 list to the new list.
-The journal records "unlink" events for all the nodes that appear
+The journal records "unlink" events for all the items that appear
 in the old list but not the new list,
 and "link" events for
-all the nodes that appear in the new list but not in the old list.
+all the items that appear in the new list but not in the old list.
 
 
 Roundup Database
@@ -578,19 +578,19 @@ The Roundup database layer is implemented on top of the
 hyperdatabase and mediates calls to the database.
 Some of the classes in the Roundup database are considered
 issue classes.
-The Roundup database layer adds detectors and user nodes,
+The Roundup database layer adds detectors and user items,
 and on issues it provides mail spools, nosy lists, and superseders.
 
 Reserved Classes
 ~~~~~~~~~~~~~~~~
 
 Internal to this layer we reserve three special classes
-of nodes that are not issues.
+of items that are not issues.
 
 Users
 """""
 
-Users are stored in the hyperdatabase as nodes of
+Users are stored in the hyperdatabase as items of
 class "user".  The "user" class has the definition::
 
     hyperdb.Class(db, "user", username=hyperdb.String(),
@@ -601,14 +601,14 @@ class "user".  The "user" class has the definition::
 Messages
 """"""""
 
-E-mail messages are represented by hyperdatabase nodes of class "msg".
+E-mail messages are represented by hyperdatabase items of class "msg".
 The actual text content of the messages is stored in separate files.
 (There's no advantage to be gained by stuffing them into the
 hyperdatabase, and if messages are stored in ordinary text files,
 they can be grepped from the command line.)  The text of a message is
-saved in a file named after the message node designator (e.g. "msg23")
+saved in a file named after the message item designator (e.g. "msg23")
 for the sake of the command interface (see below).  Attachments are
-stored separately and associated with "file" nodes.
+stored separately and associated with "file" items.
 The "msg" class has the definition::
 
     hyperdb.Class(db, "msg", author=hyperdb.Link("user"),
@@ -618,7 +618,7 @@ The "msg" class has the definition::
                              files=hyperdb.Multilink("file"))
 
 The "author" property indicates the author of the message
-(a "user" node must exist in the hyperdatabase for any messages
+(a "user" item must exist in the hyperdatabase for any messages
 that are stored in the system).
 The "summary" property contains a summary of the message for display
 in a message index.
@@ -627,9 +627,9 @@ Files
 """""
 
 Submitted files are represented by hyperdatabase
-nodes of class "file".  Like e-mail messages, the file content
+items of class "file".  Like e-mail messages, the file content
 is stored in files outside the database,
-named after the file node designator (e.g. "file17").
+named after the file item designator (e.g. "file17").
 The "file" class has the definition::
 
     hyperdb.Class(db, "file", user=hyperdb.Link("user"),
@@ -674,7 +674,7 @@ changes and additional methods::
 
     class Database:
         def getuid(self):
-            """Return the id of the "user" node associated with the user
+            """Return the id of the "user" item associated with the user
             that owns this connection to the hyperdatabase."""
 
     class Class:
@@ -682,7 +682,7 @@ changes and additional methods::
 
         def create(self, **propvalues):
         def set(self, **propvalues):
-        def retire(self, nodeid):
+        def retire(self, itemid):
             """These operations trigger detectors and can be vetoed.  Attempts
             to modify the "creation" or "activity" properties cause a KeyError.
             """
@@ -702,25 +702,25 @@ changes and additional methods::
             dictionary attempts to specify any of these properties or a
             "creation" or "activity" property, a ValueError is raised."""
 
-        def get(self, nodeid, propname):
+        def get(self, itemid, propname):
         def getprops(self):
-            """In addition to the actual properties on the node, these
+            """In addition to the actual properties on the item, these
             methods provide the "creation" and "activity" properties."""
 
         # New methods:
 
-        def addmessage(self, nodeid, summary, text):
+        def addmessage(self, itemid, summary, text):
             """Add a message to an issue's mail spool.
 
-            A new "msg" node is constructed using the current date, the
+            A new "msg" item is constructed using the current date, the
             user that owns the database connection as the author, and
             the specified summary text.  The "files" and "recipients"
             fields are left empty.  The given text is saved as the body
-            of the message and the node is appended to the "messages"
+            of the message and the item is appended to the "messages"
             field of the specified issue.
             """
 
-        def sendmessage(self, nodeid, msgid):
+        def sendmessage(self, itemid, msgid):
             """Send a message to the members of an issue's nosy list.
 
             The message is sent only to users on the nosy list who are not
@@ -789,8 +789,8 @@ provide it a chance to register its detectors.
 
 There are two kinds of detectors:
 
-1. an auditor is triggered just before modifying an node
-2. a reactor is triggered just after an node has been modified
+1. an auditor is triggered just before modifying an item
+2. a reactor is triggered just after an item has been modified
 
 When the Roundup database is about to perform a
 ``create()``, ``set()``, or ``retire()``
@@ -808,7 +808,7 @@ Detector Interface Specification
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The ``audit()`` and ``react()`` methods
-register detectors on a given class of nodes::
+register detectors on a given class of items::
 
     class Class:
         def audit(self, event, detector):
@@ -827,15 +827,15 @@ register detectors on a given class of nodes::
 
 Auditors are called with the arguments::
 
-    audit(db, cl, nodeid, newdata)
+    audit(db, cl, itemid, newdata)
 
 where ``db`` is the database, ``cl`` is an
 instance of Class or IssueClass within the database, and ``newdata``
 is a dictionary mapping property names to values.
 
 For a ``create()``
-operation, the ``nodeid`` argument is None and newdata
-contains all of the initial property values with which the node
+operation, the ``itemid`` argument is None and newdata
+contains all of the initial property values with which the item
 is about to be created.
 
 For a ``set()`` operation, newdata
@@ -846,21 +846,21 @@ For a ``retire()`` operation, newdata is None.
 
 Reactors are called with the arguments::
 
-    react(db, cl, nodeid, olddata)
+    react(db, cl, itemid, olddata)
 
 where ``db`` is the database, ``cl`` is an
 instance of Class or IssueClass within the database, and ``olddata``
 is a dictionary mapping property names to values.
 
 For a ``create()``
-operation, the ``nodeid`` argument is the id of the
-newly-created node and ``olddata`` is None.
+operation, the ``itemid`` argument is the id of the
+newly-created item and ``olddata`` is None.
 
 For a ``set()`` operation, ``olddata``
 contains the names and previous values of properties that were changed.
 
-For a ``retire()`` operation, ``nodeid`` is the
-id of the retired node and ``olddata`` is None.
+For a ``retire()`` operation, ``itemid`` is the
+id of the retired item and ``olddata`` is None.
 
 Detector Example
 ~~~~~~~~~~~~~~~~
@@ -901,7 +901,7 @@ a project proceeds when it has three approvals::
         db.project.react("set", approve_project)
 
 Here is another example of a detector that can allow or prevent
-the creation of new nodes.  In this scenario, patches for a software
+the creation of new items.  In this scenario, patches for a software
 project are submitted by sending in e-mail with an attached file,
 and we want to ensure that there are text/plain attachments on
 the message.  The maintainer of the package can then apply the
@@ -963,18 +963,18 @@ and in the printed results:
   time zone, and accepted in the full format or any of the partial
   formats explained above.
 
-- Link values are printed as node designators.  When given as
-  an argument, node designators and key strings are both accepted.
+- Link values are printed as item designators.  When given as
+  an argument, item designators and key strings are both accepted.
 
-- Multilink values are printed as lists of node designators
-  joined by commas.  When given as an argument, node designators
-  and key strings are both accepted; an empty string, a single node,
-  or a list of nodes joined by commas is accepted.
+- Multilink values are printed as lists of item designators
+  joined by commas.  When given as an argument, item designators
+  and key strings are both accepted; an empty string, a single item,
+  or a list of items joined by commas is accepted.
 
-When multiple nodes are specified to the
+When multiple items are specified to the
 roundup get or roundup set
 commands, the specified properties are retrieved or set
-on all the listed nodes.
+on all the listed items.
 
 When multiple results are returned by the roundup get
 or roundup find commands, they are printed one per
@@ -1025,12 +1025,12 @@ extracted and examined.  In a multipart/alternative
 message or part, we look for a text/plain subpart and
 ignore the other parts.  The text/plain subparts are
 assembled to form the textual body of the message, to
-be stored in the file associated with a "msg" class node.
+be stored in the file associated with a "msg" class item.
 Any parts of other types are each stored in separate
-files and given "file" class nodes that are linked to
-the "msg" node.
+files and given "file" class items that are linked to
+the "msg" item.
 
-The "summary" property on message nodes is taken from
+The "summary" property on message items is taken from
 the first non-quoting section in the message body.
 The message body is divided into sections by blank lines.
 Sections where the second and all subsequent lines begin
@@ -1039,18 +1039,18 @@ sections".  The first line of the first non-quoting
 section becomes the summary of the message.
 
 All of the addresses in the To: and Cc: headers of the
-incoming message are looked up among the user nodes, and
+incoming message are looked up among the user items, and
 the corresponding users are placed in the "recipients"
-property on the new "msg" node.  The address in the From:
+property on the new "msg" item.  The address in the From:
 header similarly determines the "author" property of the
-new "msg" node.
+new "msg" item.
 The default handling for
 addresses that don't have corresponding users is to create
 new users with no passwords and a username equal to the
 address.  (The web interface does not permit logins for
 users with no passwords.)  If we prefer to reject mail from
 outside sources, we can simply register an auditor on the
-"user" class that prevents the creation of user nodes with
+"user" class that prevents the creation of user items with
 no passwords.
 
 The subject line of the incoming message is examined to
@@ -1060,19 +1060,19 @@ in square brackets is sought as the first thing on the
 subject line (after skipping any "Fwd:" or "Re:" prefixes).
 
 If an issue designator (class name and id number) is found
-there, the newly created "msg" node is added to the "messages"
-property for that issue, and any new "file" nodes are added to
+there, the newly created "msg" item is added to the "messages"
+property for that issue, and any new "file" items are added to
 the "files" property for the issue.
 
 If just an issue class name is found there, we attempt to
 create a new issue of that class with its "messages" property
-initialized to contain the new "msg" node and its "files"
-property initialized to contain any new "file" nodes.
+initialized to contain the new "msg" item and its "files"
+property initialized to contain any new "file" items.
 
 Both cases may trigger detectors (in the first case we
 are calling the set() method to add the message to the
 issue's spool; in the second case we are calling the
-create() method to create a new node).  If an auditor
+create() method to create a new item).  If an auditor
 raises an exception, the original message is bounced back to
 the sender with the explanatory message given in the exception.
 
@@ -1135,34 +1135,29 @@ Displaying Properties
 ~~~~~~~~~~~~~~~~~~~~~
 
 Properties appear in the user interface in three contexts:
-in indices, in editors, and as filters.  For each type of
+in indices, in editors, and as search filters.  For each type of
 property, there are several display possibilities.  For example,
 in an index view, a string property may just be printed as
 a plain string, but in an editor view, that property should
 be displayed in an editable field.
 
 The display of a property is handled by functions in
-a displayers module.  Each function accepts at
-least three standard arguments -- the database, class name,
-and node id -- and returns a chunk of HTML.
+the ``cgi.templating`` module.
 
-Displayer functions are triggered by <display>
-tags in templates.  The call attribute of the tag
-provides a Python expression for calling the displayer
-function.  The three standard arguments are inserted in
-front of the arguments given.  For example, the occurrence of::
+Displayer functions are triggered by ``tal:content`` or ``tal:replace``
+tag attributes in templates.  The value of the attribute
+provides an expression for calling the displayer function.
+For example, the occurrence of::
 
-    <display call="plain('status', max=30)">
+    tal:content="context/status/plain"
 
 in a template triggers a call to::
     
-    plain(db, "issue", 13, "status", max=30)
+    context['status'].plain()
 
-
-when displaying issue 13 in the "issue" class.  The displayer
+where the context would be an item of the "issue" class.  The displayer
 functions can accept extra arguments to further specify
-details about the widgets that should be generated.  By defining new
-displayer functions, the user interface can be highly customized.
+details about the widgets that should be generated.
 
 Some of the standard displayer functions include:
 
@@ -1172,32 +1167,21 @@ Function  Description
 plain     display a String property directly;
           display a Date property in a specified time zone with an option
           to omit the time from the date stamp; for a Link or Multilink
-          property, display the key strings of the linked nodes (or the
+          property, display the key strings of the linked items (or the
           ids if the linked class has no key property)
-field     display a property like the
-          plain displayer above, but in a text field
-          to be edited
-menu      for a Link property, display
-          a menu of the available choices
-link      for a Link or Multilink property,
-          display the names of the linked nodes, hyperlinked to the
-          issue views on those nodes
-count     for a Multilink property, display
-          a count of the number of links in the list
-reldate   display a Date property in terms
-          of an interval relative to the current date (e.g. "+ 3w", "- 2d").
-download  show a Link("file") or Multilink("file")
-          property using links that allow you to download files
-checklist for a Link or Multilink property,
-          display checkboxes for the available choices to permit filtering
+field     display a property like the plain displayer above, but in a text
+          field to be edited
+menu      for a Link property, display a menu of the available choices
 ========= ====================================================================
 
-TODO: See the htmltemplate pydoc for a complete list of the functions
+See the `customisation`_ documentation for the complete list.
 
 
 Index Views
 ~~~~~~~~~~~
 
+XXX The following needs to be clearer
+
 An index view contains two sections: a filter section
 and an index section.
 The filter section provides some widgets for selecting
@@ -1210,11 +1194,11 @@ Index View Specifiers
 An index view specifier looks like this (whitespace
 has been added for clarity)::
 
-    /issue?status=unread,in-progress,resolved&amp;
-        topic=security,ui&amp;
-        :group=priority&amp;
-        :sort=-activity&amp;
-        :filters=status,topic&amp;
+    /issue?status=unread,in-progress,resolved&
+        topic=security,ui&
+        :group=priority&
+        :sort=-activity&
+        :filters=status,topic&
         :columns=title,status,fixer
 
 
@@ -1222,9 +1206,9 @@ The index view is determined by two parts of the
 specifier: the layout part and the filter part.
 The layout part consists of the query parameters that
 begin with colons, and it determines the way that the
-properties of selected nodes are displayed.
+properties of selected items are displayed.
 The filter part consists of all the other query parameters,
-and it determines the criteria by which node
+and it determines the criteria by which item
 are selected for display.
 
 The filter part is interactively manipulated with
@@ -1238,7 +1222,7 @@ properties and the intersection of the sets
 of issues with values matching any specified Multilink
 properties.
 
-The example specifies an index of "issue" nodes.
+The example specifies an index of "issue" items.
 Only issues with a "status" of either
 "unread" or "in-progres" or "resolved" are displayed,
 and only issues with "topic" values including both
@@ -1256,29 +1240,6 @@ example is the default layout to be provided with
 the default bug-tracker schema described above in
 section 4.4.
 
-Filter Section
-""""""""""""""
-
-The template for a filter section provides the
-filtering widgets at the top of the index view.
-Fragments enclosed in ``<property>...</property>``
-tags are included or omitted depending on whether the
-view specifier requests a filter for a particular property.
-
-Here's a simple example of a filter template::
-
-    <property name=status>
-        <display call="checklist('status')">
-    </property>
-    <br>
-    <property name=priority>
-        <display call="checklist('priority')">
-    </property>
-    <br>
-    <property name=fixer>
-        <display call="menu('fixer')">
-    </property>
-
 Index Section
 """""""""""""
 
@@ -1293,15 +1254,9 @@ to display the values of the issue's properties.
 Here's a simple example of an index template::
 
     <tr>
-        <property name=title>
-            <td><display call="plain('title', max=50)"></td>
-        </property>
-        <property name=status>
-            <td><display call="plain('status')"></td>
-        </property>
-        <property name=fixer>
-            <td><display call="plain('fixer')"></td>
-        </property>
+      <td tal:condition="request/show/title" tal:content="contex/title"></td>
+      <td tal:condition="request/show/status" tal:content="contex/status"></td>
+      <td tal:condition="request/show/fixer" tal:content="contex/fixer"></td>
     </tr>
 
 Sorting
@@ -1309,9 +1264,9 @@ Sorting
 
 String and Date values are sorted in the natural way.
 Link properties are sorted according to the value of the
-"order" property on the linked nodes if it is present; or
-otherwise on the key string of the linked nodes; or
-finally on the node ids.  Multilink properties are
+"order" property on the linked items if it is present; or
+otherwise on the key string of the linked items; or
+finally on the item ids.  Multilink properties are
 sorted according to how many links are present.
 
 Issue Views
@@ -1340,36 +1295,25 @@ Here's an example of a basic editor template::
 
     <table>
     <tr>
-        <td colspan=2>
-            <display call="field('title', size=60)">
-        </td>
+        <td colspan=2 tal:content="python:context.title.field(size='60')"></td>
     </tr>
     <tr>
-        <td>
-            <display call="field('fixer', size=30)">
-        </td>
-        <td>
-            <display call="menu('status')>
-        </td>
+        <td tal:content="context/fixer/field"></td>
+        <td tal:content="context/status/menu"></td>
     </tr>
     <tr>
-        <td>
-            <display call="field('nosy', size=30)">
-        </td>
-        <td>
-            <display call="menu('priority')>
-        </td>
+        <td tal:content="context/nosy/field"></td>
+        <td tal:content="context/priority/menu"></td>
     </tr>
     <tr>
         <td colspan=2>
-            <display call="note()">
+          <textarea name=":note" rows=5 cols=60></textarea>
         </td>
     </tr>
     </table>
 
-As shown in the example, the editor template can also
-request the display of a "note" field, which is a
-text area for entering a note to go along with a change.
+As shown in the example, the editor template can also include a ":note" field,
+which is a text area for entering a note to go along with a change.
 
 When a change is submitted, the system automatically
 generates a message describing the changed properties.
@@ -1383,7 +1327,7 @@ An example of such a message might be this::
     fixer: (none)
     keywords: parrot,plumage,perch,nailed,dead
 
-If a note is given in the "note" field, the note is
+If a note is given in the ":note" field, the note is
 appended to the description.  The message is then added
 to the issue's message spool (thus triggering the standard
 detector to react by sending out this message to the nosy list).
@@ -1393,7 +1337,7 @@ Spool Section
 
 The spool section lists messages in the issue's "messages"
 property.  The index of messages displays the "date", "author",
-and "summary" properties on the message nodes, and selecting a
+and "summary" properties on the message items, and selecting a
 message takes you to its content.
 
 Access Control
@@ -1411,9 +1355,9 @@ Roles. These definitions are not persistent - they're defined when the
 application initialises.
 
 There will be two levels of Permission. The Class level permissions define
-logical permissions associated with all nodes of a particular class (or all
-classes). The Node level permissions define logical permissions associated
-with specific nodes by way of their user-linked properties.
+logical permissions associated with all items of a particular class (or all
+classes). The Item level permissions define logical permissions associated
+with specific items by way of their user-linked properties.
 
 
 Access Control Interface Specification
@@ -1457,13 +1401,13 @@ The security module defines::
                 "permission" is there for the specified classname.
             '''
 
-        def hasNodePermission(self, classname, nodeid, **propspec):
-            ''' Check the named properties of the given node to see if the
+        def hasItemPermission(self, classname, itemid, **propspec):
+            ''' Check the named properties of the given item to see if the
                 userid appears in them. If it does, then the user is granted
                 this permission check.
 
                 'propspec' consists of a set of properties and values that
-                must be present on the given node for access to be granted.
+                must be present on the given item for access to be granted.
 
                 If a property is a Link, the value must match the property
                 value. If a property is a Multilink, the value must appear
@@ -1485,8 +1429,8 @@ The security module defines::
                 'rolename' is the name of the role to add permission to.
             '''
 
-Modules such as ``cgi_client.py`` and ``mailgw.py`` define their own
-permissions like so (this example is ``cgi_client.py``)::
+Modules such as ``cgi/client.py`` and ``mailgw.py`` define their own
+permissions like so (this example is ``cgi/client.py``)::
 
     def initialiseSecurity(security):
         ''' Create some Permissions and Roles on the security object
@@ -1507,11 +1451,11 @@ Detectors may also define roles in their init() function::
         p = db.security.addPermission(name="May Resolve", klass="issue")
         security.addToRole('Manager', p)
 
-The instance dbinit module then has in ``open()``::
+The tracker dbinit module then has in ``open()``::
 
     # open the database - it must be modified to init the Security class
     # from security.py as db.security
-    db = Database(instance_config, name)
+    db = Database(config, name)
 
     # add some extra permissions and associate them with roles
     ei = db.security.addPermission(name="Edit", klass="issue",
@@ -1525,39 +1469,30 @@ In the dbinit ``init()``::
 
     # create the two default users
     user.create(username="admin", password=Password(adminpw),
-                address=instance_config.ADMIN_EMAIL, roles='Admin')
+                address=config.ADMIN_EMAIL, roles='Admin')
     user.create(username="anonymous", roles='Anonymous')
 
 Then in the code that matters, calls to ``hasPermission`` and
-``hasNodePermission`` are made to determine if the user has permission
+``hasItemPermission`` are made to determine if the user has permission
 to perform some action::
 
     if db.security.hasPermission('issue', 'Edit', userid):
         # all ok
 
-    if db.security.hasNodePermission('issue', nodeid, assignedto=userid):
+    if db.security.hasItemPermission('issue', itemid, assignedto=userid):
         # all ok
 
 Code in the core will make use of these methods, as should code in auditors in
-custom templates. The htmltemplate will implement a new tag, ``<require>``
-which has the form::
+custom templates. The HTML templating may access the access controls through
+the *user* attribute of the *request* variable. It exposes a ``hasPermission()``
+method::
 
-  <require permission="name,name,name" assignedto="$userid" status="open">
-   HTML to display if the user has the permission.
-  <else>
-   HTML to display if the user does not have the permission.
-  </require>
+  tal:condition="python:request.user.hasPermission('Edit', 'issue')"
 
-where:
+or, if the *context* is *issue*, then the following is the same::
 
-- the permission attribute gives a comma-separated list of permission names.
-  These are checked in turn using ``hasPermission`` and requires one to
-  be OK.
-- the other attributes are lookups on the node using ``hasNodePermission``. If
-  the attribute value is "$userid" then the current user's userid is tested.
+  tal:condition="python:request.user.hasPermission('Edit')"
 
-Any of these tests must pass or the ``<require>`` check will fail. The section
-of html within the side of the ``<else>`` that fails is remove from processing.
 
 Authentication of Users
 ~~~~~~~~~~~~~~~~~~~~~~~
@@ -1605,8 +1540,7 @@ system - automated request handlers running various report/escalation scripts
 privacy - issues that are only visible to some users
     A new property is added to the issue which marks the user or group of
     users who are allowed to view and edit the issue. An auditor will check
-    for edit access, and the htmltemplate <require> tag can check for view
-    access.
+    for edit access, and the template user object can check for view access.
 
 
 Deployment Scenarios
@@ -1615,7 +1549,7 @@ Deployment Scenarios
 The design described above should be general enough
 to permit the use of Roundup for bug tracking, managing
 projects, managing patches, or holding discussions.  By
-using nodes of multiple types, one could deploy a system
+using items of multiple types, one could deploy a system
 that maintains requirement specifications, catalogs bugs,
 and manages submitted patches, where patches could be
 linked to the bugs and requirements they address.
@@ -1638,5 +1572,13 @@ Changes to this document
 - Added section Hyperdatabase Implementations
 - "Item" has been renamed to "Issue" to account for the more specific nature
   of the Class.
+- New Templating
+- Access Controls
+
+------------------
+
+Back to `Table of Contents`_
 
+.. _`Table of Contents`: index.html
+.. _customisation: customizing.html