00ccea6e9a020c3f28bba503258bd0cc2787a20b
1 ===================
2 Customising Roundup
3 ===================
5 :Version: $Revision: 1.25 $
7 .. This document borrows from the ZopeBook section on ZPT. The original is at:
8 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
10 .. contents::
13 What You Can Do
14 ---------------
16 Customisation of Roundup can take one of five forms:
18 1. `tracker configuration`_ file changes
19 2. database, or `tracker schema`_ changes
20 3. "definition" class `database content`_ changes
21 4. behavioural changes, through detectors_
22 5. `access controls`_
24 The third case is special because it takes two distinctly different forms
25 depending upon whether the tracker has been initialised or not. The other two
26 may be done at any time, before or after tracker initialisation. Yes, this
27 includes adding or removing properties from classes.
30 Trackers in a Nutshell
31 ----------------------
33 Trackers have the following structure:
35 +-------------------+--------------------------------------------------------+
36 |config.py |Holds the basic `tracker configuration`_ |
37 +-------------------+--------------------------------------------------------+
38 |dbinit.py |Holds the `tracker schema`_ |
39 +-------------------+--------------------------------------------------------+
40 |interfaces.py |Defines the Web and E-Mail interfaces for the tracker |
41 +-------------------+--------------------------------------------------------+
42 |select_db.py |Selects the database back-end for the tracker |
43 +-------------------+--------------------------------------------------------+
44 |db/ |Holds the tracker's database |
45 +-------------------+--------------------------------------------------------+
46 |db/files/ |Holds the tracker's upload files and messages |
47 +-------------------+--------------------------------------------------------+
48 |detectors/ |Auditors and reactors for this tracker |
49 +-------------------+--------------------------------------------------------+
50 |html/ |Web interface templates, images and style sheets |
51 +-------------------+--------------------------------------------------------+
53 Tracker Configuration
54 ---------------------
56 The config.py located in your tracker home contains the basic
57 configuration for the web and e-mail components of roundup's interfaces. This
58 file is a Python module. The configuration variables available are:
60 **TRACKER_HOME** - ``os.path.split(__file__)[0]``
61 The tracker home directory. The above default code will automatically
62 determine the tracker home for you.
64 **MAILHOST** - ``'localhost'``
65 The SMTP mail host that roundup will use to send e-mail.
67 **MAIL_DOMAIN** - ``'your.tracker.email.domain.example'``
68 The domain name used for email addresses.
70 **DATABASE** - ``os.path.join(TRACKER_HOME, 'db')``
71 This is the directory that the database is going to be stored in. By default
72 it is in the tracker home.
74 **TEMPLATES** - ``os.path.join(TRACKER_HOME, 'html')``
75 This is the directory that the HTML templates reside in. By default they are
76 in the tracker home.
78 **TRACKER_NAME** - ``'Roundup issue tracker'``
79 A descriptive name for your roundup tracker. This is sent out in e-mails and
80 appears in the heading of CGI pages.
82 **TRACKER_EMAIL** - ``'issue_tracker@%s'%MAIL_DOMAIN``
83 The email address that e-mail sent to roundup should go to. Think of it as the
84 tracker's personal e-mail address.
86 **TRACKER_WEB** - ``'http://your.tracker.url.example/'``
87 The web address that the tracker is viewable at. This will be included in
88 information sent to users of the tracker.
90 **ADMIN_EMAIL** - ``'roundup-admin@%s'%MAIL_DOMAIN``
91 The email address that roundup will complain to if it runs into trouble.
93 **MESSAGES_TO_AUTHOR** - ``'yes'`` or``'no'``
94 Send nosy messages to the author of the message.
96 **ADD_AUTHOR_TO_NOSY** - ``'new'``, ``'yes'`` or ``'no'``
97 Does the author of a message get placed on the nosy list automatically?
98 If ``'new'`` is used, then the author will only be added when a message
99 creates a new issue. If ``'yes'``, then the author will be added on followups
100 too. If ``'no'``, they're never added to the nosy.
102 **ADD_RECIPIENTS_TO_NOSY** - ``'new'``, ``'yes'`` or ``'no'``
103 Do the recipients (To:, Cc:) of a message get placed on the nosy list?
104 If ``'new'`` is used, then the recipients will only be added when a message
105 creates a new issue. If ``'yes'``, then the recipients will be added on
106 followups too. If ``'no'``, they're never added to the nosy.
108 **EMAIL_SIGNATURE_POSITION** - ``'top'``, ``'bottom'`` or ``'none'``
109 Where to place the email signature in messages that Roundup generates.
111 **EMAIL_KEEP_QUOTED_TEXT** - ``'yes'`` or ``'no'``
112 Keep email citations. Citations are the part of e-mail which the sender has
113 quoted in their reply to previous e-mail.
115 **EMAIL_LEAVE_BODY_UNCHANGED** - ``'no'``
116 Preserve the email body as is. Enabiling this will cause the entire message
117 body to be stored, including all citations and signatures. It should be
118 either ``'yes'`` or ``'no'``.
120 **MAIL_DEFAULT_CLASS** - ``'issue'`` or ``''``
121 Default class to use in the mailgw if one isn't supplied in email
122 subjects. To disable, comment out the variable below or leave it blank.
124 The default config.py is given below - as you
125 can see, the MAIL_DOMAIN must be edited before any interaction with the
126 tracker is attempted.::
128 # roundup home is this package's directory
129 TRACKER_HOME=os.path.split(__file__)[0]
131 # The SMTP mail host that roundup will use to send mail
132 MAILHOST = 'localhost'
134 # The domain name used for email addresses.
135 MAIL_DOMAIN = 'your.tracker.email.domain.example'
137 # This is the directory that the database is going to be stored in
138 DATABASE = os.path.join(TRACKER_HOME, 'db')
140 # This is the directory that the HTML templates reside in
141 TEMPLATES = os.path.join(TRACKER_HOME, 'html')
143 # A descriptive name for your roundup tracker
144 TRACKER_NAME = 'Roundup issue tracker'
146 # The email address that mail to roundup should go to
147 TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
149 # The web address that the tracker is viewable at
150 TRACKER_WEB = 'http://your.tracker.url.example/'
152 # The email address that roundup will complain to if it runs into trouble
153 ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
155 # Send nosy messages to the author of the message
156 MESSAGES_TO_AUTHOR = 'no' # either 'yes' or 'no'
158 # Does the author of a message get placed on the nosy list automatically?
159 # If 'new' is used, then the author will only be added when a message
160 # creates a new issue. If 'yes', then the author will be added on followups
161 # too. If 'no', they're never added to the nosy.
162 ADD_AUTHOR_TO_NOSY = 'new' # one of 'yes', 'no', 'new'
164 # Do the recipients (To:, Cc:) of a message get placed on the nosy list?
165 # If 'new' is used, then the recipients will only be added when a message
166 # creates a new issue. If 'yes', then the recipients will be added on followups
167 # too. If 'no', they're never added to the nosy.
168 ADD_RECIPIENTS_TO_NOSY = 'new' # either 'yes', 'no', 'new'
170 # Where to place the email signature
171 EMAIL_SIGNATURE_POSITION = 'bottom' # one of 'top', 'bottom', 'none'
173 # Keep email citations
174 EMAIL_KEEP_QUOTED_TEXT = 'no' # either 'yes' or 'no'
176 # Preserve the email body as is
177 EMAIL_LEAVE_BODY_UNCHANGED = 'no' # either 'yes' or 'no'
179 # Default class to use in the mailgw if one isn't supplied in email
180 # subjects. To disable, comment out the variable below or leave it blank.
181 # Examples:
182 MAIL_DEFAULT_CLASS = 'issue' # use "issue" class by default
183 #MAIL_DEFAULT_CLASS = '' # disable (or just comment the var out)
185 Tracker Schema
186 --------------
188 Note: if you modify the schema, you'll most likely need to edit the
189 `web interface`_ HTML template files and `detectors`_ to reflect
190 your changes.
192 A tracker schema defines what data is stored in the tracker's database.
193 The
194 schemas shipped with Roundup turn it into a typical software bug tracker or
195 help desk.
197 XXX make sure we ship the help desk
199 Schemas are defined using Python code in the ``dbinit.py`` module of your
200 tracker. The "classic" schema looks like this::
202 pri = Class(db, "priority", name=String(), order=String())
203 pri.setkey("name")
204 pri.create(name="critical", order="1")
205 pri.create(name="urgent", order="2")
206 pri.create(name="bug", order="3")
207 pri.create(name="feature", order="4")
208 pri.create(name="wish", order="5")
210 stat = Class(db, "status", name=String(), order=String())
211 stat.setkey("name")
212 stat.create(name="unread", order="1")
213 stat.create(name="deferred", order="2")
214 stat.create(name="chatting", order="3")
215 stat.create(name="need-eg", order="4")
216 stat.create(name="in-progress", order="5")
217 stat.create(name="testing", order="6")
218 stat.create(name="done-cbb", order="7")
219 stat.create(name="resolved", order="8")
221 keyword = Class(db, "keyword", name=String())
222 keyword.setkey("name")
224 user = Class(db, "user", username=String(), password=String(),
225 address=String(), realname=String(), phone=String(),
226 organisation=String())
227 user.setkey("username")
228 user.create(username="admin", password=adminpw,
229 address=config.ADMIN_EMAIL)
231 msg = FileClass(db, "msg", author=Link("user"), recipients=Multilink
232 ("user"), date=Date(), summary=String(), files=Multilink("file"))
234 file = FileClass(db, "file", name=String(), type=String())
236 issue = IssueClass(db, "issue", assignedto=Link("user"),
237 topic=Multilink("keyword"), priority=Link("priority"), status=Link
238 ("status"))
239 issue.setkey('title')
241 XXX security definitions
243 Classes and Properties - creating a new information store
244 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246 In the tracker above, we've defined 7 classes of information:
248 priority
249 Defines the possible levels of urgency for issues.
251 status
252 Defines the possible states of processing the issue may be in.
254 keyword
255 Initially empty, will hold keywords useful for searching issues.
257 user
258 Initially holding the "admin" user, will eventually have an entry for all
259 users using roundup.
261 msg
262 Initially empty, will all e-mail messages sent to or generated by
263 roundup.
265 file
266 Initially empty, will all files attached to issues.
268 issue
269 Initially empty, this is where the issue information is stored.
271 We define the "priority" and "status" classes to allow two things: reduction in
272 the amount of information stored on the issue and more powerful, accurate
273 searching of issues by priority and status. By only requiring a link on the
274 issue (which is stored as a single number) we reduce the chance that someone
275 mis-types a priority or status - or simply makes a new one up.
277 Class and Items
278 :::::::::::::::
280 A Class defines a particular class (or type) of data that will be stored in the
281 database. A class comprises one or more properties, which given the information
282 about the class items.
283 The actual data entered into the database, using class.create() are called
284 items. They have a special immutable property called id. We sometimes refer to
285 this as the itemid.
287 Properties
288 ::::::::::
290 A Class is comprised of one or more properties of the following types:
292 * String properties are for storing arbitrary-length strings.
293 * Password properties are for storing encoded arbitrary-length strings. The
294 default encoding is defined on the roundup.password.Password class.
295 * Date properties store date-and-time stamps. Their values are Timestamp
296 objects.
297 * Number properties store numeric values.
298 * Boolean properties store on/off, yes/no, true/false values.
299 * A Link property refers to a single other item selected from a specified
300 class. The class is part of the property; the value is an integer, the id
301 of the chosen item.
302 * A Multilink property refers to possibly many items in a specified class.
303 The value is a list of integers.
305 FileClass
306 :::::::::
308 FileClasses save their "content" attribute off in a separate file from the rest
309 of the database. This reduces the number of large entries in the database,
310 which generally makes databases more efficient, and also allows us to use
311 command-line tools to operate on the files. They are stored in the files sub-
312 directory of the db directory in your tracker.
314 IssueClass
315 ::::::::::
317 IssueClasses automatically include the "messages", "files", "nosy", and
318 "superseder" properties.
319 The messages and files properties list the links to the messages and files
320 related to the issue. The nosy property is a list of links to users who wish to
321 be informed of changes to the issue - they get "CC'ed" e-mails when messages
322 are sent to or generated by the issue. The nosy reactor (in the detectors
323 directory) handles this action. The superceder link indicates an issue which
324 has superceded this one.
325 They also have the dynamically generated "creation", "activity" and "creator"
326 properties.
327 The value of the "creation" property is the date when an item was created, and
328 the value of the "activity" property is the date when any property on the item
329 was last edited (equivalently, these are the dates on the first and last
330 records in the item's journal). The "creator" property holds a link to the user
331 that created the issue.
333 setkey(property)
334 ::::::::::::::::
336 Select a String property of the class to be the key property. The key property
337 muse be unique, and allows references to the items in the class by the content
338 of the key property. That is, we can refer to users by their username, e.g.
339 let's say that there's an issue in roundup, issue 23. There's also a user,
340 richard who happens to be user 2. To assign an issue to him, we could do either
341 of::
343 roundup-admin set issue assignedto=2
345 or::
347 roundup-admin set issue assignedto=richard
349 Note, the same thing can be done in the web and e-mail interfaces.
351 create(information)
352 :::::::::::::::::::
354 Create an item in the database. This is generally used to create items in the
355 "definitional" classes like "priority" and "status".
358 Examples of adding to your schema
359 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
361 TODO
364 Detectors - adding behaviour to your tracker
365 --------------------------------------------
366 .. _detectors:
368 The detectors in your tracker fire before (*auditors*) and after (*reactors*)
369 changes to the contents of your database. They are Python modules that sit in
370 your tracker's ``detectors`` directory. You will have some installed by
371 default - have a look. You can write new detectors or modify the existing
372 ones. The existing detectors installed for you are:
374 **nosyreaction.py**
375 This provides the automatic nosy list maintenance and email sending. The nosy
376 reactor (``nosyreaction``) fires when new messages are added to issues.
377 The nosy auditor (``updatenosy``) fires when issues are changed and figures
378 what changes need to be made to the nosy list (like adding new authors etc)
379 **statusauditor.py**
380 This provides the ``chatty`` auditor which changes the issue status from
381 ``unread`` or ``closed`` to ``chatting`` if new messages appear. It also
382 provides the ``presetunread`` auditor which pre-sets the status to
383 ``unread`` on new items if the status isn't explicitly defined.
385 See the detectors section in the `design document`__ for details of the
386 interface for detectors.
388 __ design.html
390 Sample additional detectors that have been found useful will appear in the
391 ``detectors`` directory of the Roundup distribution:
393 **newissuecopy.py**
394 This detector sends an email to a team address whenever a new issue is
395 created. The address is hard-coded into the detector, so edit it before you
396 use it (look for the text 'team@team.host') or you'll get email errors!
398 XXX give the example here.
401 Database Content
402 ----------------
404 Note: if you modify the content of definitional classes, you'll most likely
405 need to edit the tracker `detectors`_ to reflect your changes.
407 Customisation of the special "definitional" classes (eg. status, priority,
408 resolution, ...) may be done either before or after the tracker is
409 initialised. The actual method of doing so is completely different in each
410 case though, so be careful to use the right one.
412 **Changing content before tracker initialisation**
413 Edit the dbinit module in your tracker to alter the items created in using
414 the create() methods.
417 **Changing content after tracker initialisation**
418 Use the roundup-admin interface's create, set and retire methods to add,
419 alter or remove items from the classes in question.
421 XXX example
424 Web Interface
425 -------------
427 The web is provided by the roundup.cgi.client module and is used by
428 roundup.cgi, roundup-server and ZRoundup.
429 In all cases, we determine which tracker is being accessed
430 (the first part of the URL path inside the scope of the CGI handler) and pass
431 control on to the tracker interfaces.Client class - which uses the Client class
432 from roundup.cgi.client - which handles the rest of
433 the access through its main() method. This means that you can do pretty much
434 anything you want as a web interface to your tracker.
436 Repurcussions of changing the tracker schema
437 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
439 If you choose to change the `tracker schema`_ you will need to ensure the web
440 interface knows about it:
442 1. Index, item and search pages for the relevant classes may need to have
443 properties added or removed,
444 2. The "page" template may require links to be changed, as might the "home"
445 page's content arguments.
447 How requests are processed
448 ~~~~~~~~~~~~~~~~~~~~~~~~~~
450 The basic processing of a web request proceeds as follows:
452 1. figure out who we are, defaulting to the "anonymous" user
453 2. figure out what the request is for - we call this the "context"
454 3. handle any requested action (item edit, search, ...)
455 4. render a template, resulting in HTML output
457 In some situations, exceptions occur:
459 - HTTP Redirect (generally raised by an action)
460 - SendFile (generally raised by determine_context)
461 here we serve up a FileClass "content" property
462 - SendStaticFile (generally raised by determine_context)
463 here we serve up a file from the tracker "html" directory
464 - Unauthorised (generally raised by an action)
465 here the action is cancelled, the request is rendered and an error
466 message is displayed indicating that permission was not
467 granted for the action to take place
468 - NotFound (raised wherever it needs to be)
469 this exception percolates up to the CGI interface that called the client
471 Determining web context
472 ~~~~~~~~~~~~~~~~~~~~~~~
474 To determine the "context" of a request, we look at the URL and the special
475 request variable ``:template``. The URL path after the tracker identifier
476 is examined. Typical URL paths look like:
478 1. ``/tracker/issue``
479 2. ``/tracker/issue1``
480 3. ``/tracker/_file/style.css``
481 4. ``/cgi-bin/roundup.cgi/tracker/file1``
482 5. ``/cgi-bin/roundup.cgi/tracker/file1/kitten.png``
484 where the "tracker identifier" is "tracker" in the above cases. That means
485 we're looking at "issue", "issue1", "_file/style.css", "file1" and
486 "file1/kitten.png" in the cases above. The path is generally only one
487 entry long - longer paths are handled differently.
489 a. if there is no path, then we are in the "home" context.
490 b. if the path starts with "_file" (as in example 3,
491 "/tracker/_file/style.css"), then the additional path entry,
492 "style.css" specifies the filename of a static file we're to serve up
493 from the tracker "html" directory. Raises a SendStaticFile
494 exception.
495 c. if there is something in the path (as in example 1, "issue"), it identifies
496 the tracker class we're to display.
497 d. if the path is an item designator (as in examples 2 and 4, "issue1" and
498 "file1"), then we're to display a specific item.
499 e. if the path starts with an item designator and is longer than
500 one entry (as in example 5, "file1/kitten.png"), then we're assumed
501 to be handling an item of a
502 FileClass, and the extra path information gives the filename
503 that the client is going to label the download with (ie
504 "file1/kitten.png" is nicer to download than "file1"). This
505 raises a SendFile exception.
507 Both b. and e. stop before we bother to
508 determine the template we're going to use. That's because they
509 don't actually use templates.
511 The template used is specified by the ``:template`` CGI variable,
512 which defaults to:
514 - only classname suplied: "index"
515 - full item designator supplied: "item"
518 Performing actions in web requests
519 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
521 When a user requests a web page, they may optionally also request for an
522 action to take place. As described in `how requests are processed`_, the
523 action is performed before the requested page is generated. Actions are
524 triggered by using a ``:action`` CGI variable, where the value is one of:
526 login
527 Attempt to log a user in.
528 logout
529 Log the user out - make them "anonymous".
530 register
531 Attempt to create a new user based on the contents of the form and then log
532 them in.
533 edit
534 Perform an edit of an item in the database. There are some special form
535 elements you may use:
537 :link=designator:property and :multilink=designator:property
538 The value specifies an item designator and the property on that
539 item to add _this_ item to as a link or multilink.
540 :note
541 Create a message and attach it to the current item's
542 "messages" property.
543 :file
544 Create a file and attach it to the current item's
545 "files" property. Attach the file to the message created from
546 the :note if it's supplied.
547 :required=property,property,...
548 The named properties are required to be filled in the form.
550 new
551 Add a new item to the database. You may use the same special form elements
552 as in the "edit" action.
554 editCSV
555 Performs an edit of all of a class' items in one go. See also the
556 *class*.csv templating method which generates the CSV data to be edited, and
557 the "_generic.index" template which uses both of these features.
559 search
560 Mangle some of the form variables.
562 Set the form ":filter" variable based on the values of the
563 filter variables - if they're set to anything other than
564 "dontcare" then add them to :filter.
566 Also handle the ":queryname" variable and save off the query to
567 the user's query list.
569 Each of the actions is implemented by a corresponding *actionAction* (where
570 "action" is the name of the action) method on
571 the roundup.cgi.Client class, which also happens to be in your tracker as
572 interfaces.Client. So if you need to define new actions, you may add them
573 there (see `definining new web actions`_).
575 Each action also has a corresponding *actionPermission* (where
576 "action" is the name of the action) method which determines
577 whether the action is permissible given the current user. The base permission
578 checks are:
580 login
581 Determine whether the user has permission to log in.
582 Base behaviour is to check the user has "Web Access".
583 logout
584 No permission checks are made.
585 register
586 Determine whether the user has permission to register
587 Base behaviour is to check the user has "Web Registration".
588 edit
589 Determine whether the user has permission to edit this item.
590 Base behaviour is to check the user can edit this class. If we're
591 editing the "user" class, users are allowed to edit their own
592 details. Unless it's the "roles" property, which requires the
593 special Permission "Web Roles".
594 new
595 Determine whether the user has permission to create (edit) this item.
596 Base behaviour is to check the user can edit this class. No
597 additional property checks are made. Additionally, new user items
598 may be created if the user has the "Web Registration" Permission.
599 editCSV
600 Determine whether the user has permission to edit this class.
601 Base behaviour is to check the user can edit this class.
602 search
603 Determine whether the user has permission to search this class.
604 Base behaviour is to check the user can view this class.
607 Default templates
608 ~~~~~~~~~~~~~~~~~
610 Most customisation of the web view can be done by modifying the templates in
611 the tracker **html** directory. There are several types of files in there:
613 page
614 defines the overall look of your tracker. When you
615 view an issue, it appears inside this template. When you view an index, it
616 also appears inside this template.
617 home
618 the default page displayed when no other page is indicated by the user
619 home.classlist
620 a special version of the default page that lists the classes in the tracker
621 *classname*.item
622 displays an item of the *classname* class
623 *classname*.index
624 displays a list of *classname* items
625 *classname*.search
626 displays a search page for *classname* items
627 _generic.index
628 used to display a list of items where there is no *classname*.index available
629 _generic.help
630 used to display a "class help" page where there is no *classname*.help
631 user.register
632 a special page just for the user class that renders the registration page
633 style.css
634 a static file that is served up as-is
636 Overall Look - "page" template
637 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
639 XXX
641 How the templates work
642 ~~~~~~~~~~~~~~~~~~~~~~
644 Roundup's templates consist of special attributes on your template tags. These
645 attributes form the Template Attribute Language, or TAL. The commands are:
648 tal:define="variable expression; variable expression; ..."
649 Define a new variable that is local to this tag and its contents. For
650 example::
652 <html tal:define="title request/description">
653 <head><title tal:content="title"></title></head>
654 </html>
656 In the example, the variable "title" is defined as being the result of the
657 expression "request/description". The tal:content command inside the <html>
658 tag may then use the "title" variable.
660 tal:condition="expression"
661 Only keep this tag and its contents if the expression is true. For example::
663 <p tal:condition="python:request.user.hasPermission('View', 'issue')">
664 Display some issue information.
665 </p>
667 In the example, the <p> tag and its contents are only displayed if the
668 user has the View permission for issues. We consider the number zero, a
669 blank string, an empty list, and the built-in variable nothing to be false
670 values. Nearly every other value is true, including non-zero numbers, and
671 strings with anything in them (even spaces!).
673 tal:repeat="variable expression"
674 Repeat this tag and its contents for each element of the sequence that the
675 expression returns, defining a new local variable and a special "repeat"
676 variable for each element. For example::
678 <tr tal:repeat="u user/list">
679 <td tal:content="u/id"></td>
680 <td tal:content="u/username"></td>
681 <td tal:content="u/realname"></td>
682 </tr>
684 The example would iterate over the sequence of users returned by
685 "user/list" and define the local variable "u" for each entry.
687 tal:replace="expression"
688 Replace this tag with the result of the expression. For example::
690 <span tal:replace="request/user/realname"></span>
692 The example would replace the <span> tag and its contents with the user's
693 realname. If the user's realname was "Bruce" then the resultant output
694 would be "Bruce".
696 tal:content="expression"
697 Replace the contents of this tag with the result of the expression. For
698 example::
700 <span tal:content="request/user/realname">user's name appears here</span>
702 The example would replace the contents of the <span> tag with the user's
703 realname. If the user's realname was "Bruce" then the resultant output
704 would be "<span>Bruce</span>".
706 tal:attributes="attribute expression; attribute expression; ..."
707 Set attributes on this tag to the results of expressions. For example::
709 <a tal:attributes="href string:user${request/user/id}">My Details</a>
711 In the example, the "href" attribute of the <a> tag is set to the value of
712 the "string:user${request/user/id}" expression, which will be something
713 like "user123".
715 tal:omit-tag="expression"
716 Remove this tag (but not its contents) if the expression is true. For
717 example::
719 <span tal:omit-tag="python:1">Hello, world!</span>
721 would result in output of::
723 Hello, world!
725 Note that the commands on a given tag are evaulated in the order above, so
726 *define* comes before *condition*, and so on.
728 Additionally, a tag is defined, tal:block, which is removed from output. Its
729 content is not, but the tag itself is (so don't go using any tal:attributes
730 commands on it). This is useful for making arbitrary blocks of HTML
731 conditional or repeatable (very handy for repeating multiple table rows,
732 which would othewise require an illegal tag placement to effect the repeat).
734 The expressions you may use in the attibute values may be one of the following
735 three forms:
737 Path Expressions - eg. ``item/status/checklist``
738 These are object attribute / item accesses. Roughly speaking, the path
739 ``item/status/checklist`` is broken into parts ``item``, ``status``
740 and ``checklist``. The ``item`` part is the root of the expression.
741 We then look for a ``status`` attribute on ``item``, or failing that, a
742 ``status`` item (as in ``item['status']``). If that
743 fails, the path expression fails. When we get to the end, the object we're
744 left with is evaluated to get a string - methods are called, objects are
745 stringified. Path expressions may have an optional ``path:`` prefix, though
746 they are the default expression type, so it's not necessary.
748 XXX | components of expressions
750 XXX "nothing" and "default"
752 String Expressions - eg. ``string:hello ${user/name}``
753 These expressions are simple string interpolations (though they can be just
754 plain strings with no interpolation if you want. The expression in the
755 ``${ ... }`` is just a path expression as above.
757 Python Expressions - eg. ``python: 1+1``
758 These expressions give the full power of Python. All the "root level"
759 variables are available, so ``python:item.status.checklist()`` would be
760 equivalent to ``item/status/checklist``, assuming that ``checklist`` is
761 a method.
763 Information available to templates
764 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
766 The following variables are available to templates.
768 .. taken from roundup.cgi.templating.RoundupPageTemplate docstring
770 *context*
771 The current context. This is either None, a wrapper around a
772 hyperdb class (an HTMLClass) or a wrapper around a hyperdb item (an
773 HTMLItem).
774 *request*
775 Includes information about the current request, including:
776 - the url
777 - the current index information (``filterspec``, ``filter`` args,
778 ``properties``, etc) parsed out of the form.
779 - methods for easy filterspec link generation
780 - *user*, the current user item as an HTMLItem instance
781 - *form*
782 The current CGI form information as a mapping of form argument
783 name to value
784 *tracker*
785 The current tracker
786 *db*
787 The current database, through which db.config may be reached.
788 *nothing*
789 XXX a special variable
790 *default*
791 XXX a special variable
793 The context variable
794 ::::::::::::::::::::
796 The *context* variable is one of three things based on the current context
797 (see `determining web context`_ for how we figure this out):
799 1. if we're looking at a "home" page, then it's None
800 2. if we're looking at a specific hyperdb class, it's an HTMLClass instance
801 3. if we're looking at a specific hyperdb item, it's an HTMLItem instance
803 If the context is not None, we can access the properties of the class or item.
804 The only real difference between cases 2 and 3 above are:
806 1. the properties may have a real value behind them, and this will appear if
807 the property is displayed through ``context/property`` or
808 ``context/property/field``.
809 2. the context's "id" property will be a false value in the second case, but
810 a real, or true value in the third. Thus we can determine whether we're
811 looking at a real item from the hyperdb by testing "context/id".
814 The request variable
815 ::::::::::::::::::::
817 The request variable is packed with information about the current request.
819 .. taken from roundup.cgi.templating.HTMLRequest docstring
821 =========== ================================================================
822 Variable Holds
823 =========== ================================================================
824 form the CGI form as a cgi.FieldStorage
825 env the CGI environment variables
826 url the current URL path for this request
827 base the base URL for this tracker
828 user a HTMLUser instance for this user
829 classname the current classname (possibly None)
830 template the current template (suffix, also possibly None)
831 form the current CGI form variables in a FieldStorage
832 =========== ================================================================
834 **Index page specific variables (indexing arguments)**
836 =========== ================================================================
837 Variable Holds
838 =========== ================================================================
839 columns dictionary of the columns to display in an index page
840 show a convenience access to columns - request/show/colname will
841 be true if the columns should be displayed, false otherwise
842 sort index sort column (direction, column name)
843 group index grouping property (direction, column name)
844 filter properties to filter the index on
845 filterspec values to filter the index on
846 search_text text to perform a full-text search on for an index
847 =========== ================================================================
850 Displaying Properties
851 ~~~~~~~~~~~~~~~~~~~~~
853 Properties appear in the user interface in three contexts: in indices, in
854 editors, and as search arguments.
855 For each type of property, there are several display possibilities.
856 For example, in an index view, a string property may just be
857 printed as a plain string, but in an editor view, that property may be
858 displayed in an editable field.
861 Index Views
862 ~~~~~~~~~~~
864 This is one of the class context views. It is also the default view for
865 classes. The template used is "*classname*.index".
867 Index View Specifiers
868 :::::::::::::::::::::
870 An index view specifier (URL fragment) looks like this (whitespace has been
871 added for clarity)::
873 /issue?status=unread,in-progress,resolved&
874 topic=security,ui&
875 :group=+priority&
876 :sort=-activity&
877 :filters=status,topic&
878 :columns=title,status,fixer
880 The index view is determined by two parts of the specifier: the layout part and
881 the filter part. The layout part consists of the query parameters that begin
882 with colons, and it determines the way that the properties of selected items
883 are displayed. The filter part consists of all the other query parameters, and
884 it determines the criteria by which items are selected for display.
885 The filter part is interactively manipulated with the form widgets displayed in
886 the filter section. The layout part is interactively manipulated by clicking on
887 the column headings in the table.
889 The filter part selects the union of the sets of items with values matching any
890 specified Link properties and the intersection of the sets of items with values
891 matching any specified Multilink properties.
893 The example specifies an index of "issue" items. Only items with a "status" of
894 either "unread" or "in-progres" or "resolved" are displayed, and only items
895 with "topic" values including both "security" and "ui" are displayed. The items
896 are grouped by priority, arranged in ascending order; and within groups, sorted
897 by activity, arranged in descending order. The filter section shows filters for
898 the "status" and "topic" properties, and the table includes columns for the
899 "title", "status", and "fixer" properties.
901 Filtering of indexes
902 ::::::::::::::::::::
904 TODO
906 Searching Views
907 ~~~~~~~~~~~~~~~
909 This is one of the class context views. The template used is typically
910 "*classname*.search".
912 TODO
914 Item Views
915 ~~~~~~~~~~
917 The basic view of a hyperdb item is provided by the "*classname*.item"
918 template. It generally has three sections; an "editor", a "spool" and a
919 "history" section.
923 Editor Section
924 ::::::::::::::
926 The editor section is used to manipulate the item - it may be a
927 static display if the user doesn't have permission to edit the item.
929 Here's an example of a basic editor template (this is the default "classic"
930 template issue item edit form - from the "issue.item" template)::
932 <table class="form">
933 <tr>
934 <th nowrap>Title</th>
935 <td colspan=3 tal:content="structure python:context.title.field(size=60)">title</td>
936 </tr>
938 <tr>
939 <th nowrap>Priority</th>
940 <td tal:content="structure context/priority/menu">priority</td>
941 <th nowrap>Status</th>
942 <td tal:content="structure context/status/menu">status</td>
943 </tr>
945 <tr>
946 <th nowrap>Superseder</th>
947 <td>
948 <span tal:replace="structure python:context.superseder.field(showid=1, size=20)" />
949 <span tal:replace="structure python:db.issue.classhelp('id,title', label='list', width=500)" />
950 <span tal:condition="context/superseder">
951 <br>View: <span tal:replace="structure python:context.superseder.link(showid=1)" />
952 </span>
953 </td>
954 <th nowrap>Nosy List</th>
955 <td>
956 <span tal:replace="structure context/nosy/field" />
957 <span tal:replace="structure python:db.user.classhelp('username,realname,address,phone', label='list', width=500)" />
958 </td>
959 </tr>
961 <tr>
962 <th nowrap>Assigned To</th>
963 <td tal:content="structure context/assignedto/menu">
964 assignedto menu
965 </td>
966 <td> </td>
967 <td> </td>
968 </tr>
970 <tr>
971 <th nowrap>Change Note</th>
972 <td colspan=3>
973 <textarea name=":note" wrap="hard" rows="5" cols="60"></textarea>
974 </td>
975 </tr>
977 <tr>
978 <th nowrap>File</th>
979 <td colspan=3><input type="file" name=":file" size="40"></td>
980 </tr>
982 <tr>
983 <td> </td>
984 <td colspan=3 tal:content="structure context/submit">
985 submit button will go here
986 </td>
987 </tr>
988 </table>
991 When a change is submitted, the system automatically generates a message
992 describing the changed properties. As shown in the example, the editor
993 template can use the ":note" and ":file" fields, which are added to the
994 standard change note message generated by Roundup.
996 Spool Section
997 :::::::::::::
999 The spool section lists related information like the messages and files of
1000 an issue.
1002 TODO
1005 History Section
1006 :::::::::::::::
1008 The final section displayed is the history of the item - its database journal.
1009 This is generally generated with the template::
1011 <tal:block tal:replace="structure context/history" />
1013 *To be done:*
1015 *The actual history entries of the item may be accessed for manual templating
1016 through the "journal" method of the item*::
1018 <tal:block tal:repeat="entry context/journal">
1019 a journal entry
1020 </tal:block>
1022 *where each journal entry is an HTMLJournalEntry.*
1025 Access Controls
1026 ---------------
1028 A set of Permissions are built in to the security module by default:
1030 - Edit (everything)
1031 - View (everything)
1033 The default interfaces define:
1035 - Web Registration
1036 - Web Access
1037 - Web Roles
1038 - Email Registration
1039 - Email Access
1041 These are hooked into the default Roles:
1043 - Admin (Edit everything, View everything, Web Roles)
1044 - User (Web Access, Email Access)
1045 - Anonymous (Web Registration, Email Registration)
1047 And finally, the "admin" user gets the "Admin" Role, and the "anonymous" user
1048 gets the "Anonymous" assigned when the database is initialised on installation.
1049 The two default schemas then define:
1051 - Edit issue, View issue (both)
1052 - Edit file, View file (both)
1053 - Edit msg, View msg (both)
1054 - Edit support, View support (extended only)
1056 and assign those Permissions to the "User" Role. New users are assigned the
1057 Roles defined in the config file as:
1059 - NEW_WEB_USER_ROLES
1060 - NEW_EMAIL_USER_ROLES
1062 You may alter the configuration variables to change the Role that new web or
1063 email users get, for example to not give them access to the web interface if
1064 they register through email.
1066 You may use the ``roundup-admin`` "``security``" command to display the
1067 current Role and Permission configuration in your tracker.
1069 Adding a new Permission
1070 ~~~~~~~~~~~~~~~~~~~~~~~
1072 When adding a new Permission, you will need to:
1074 1. add it to your tracker's dbinit so it is created
1075 2. enable it for the Roles that should have it (verify with
1076 "``roundup-admin security``")
1077 3. add it to the relevant HTML interface templates
1078 4. add it to the appropriate xxxPermission methods on in your tracker
1079 interfaces module
1083 -----------------
1085 Back to `Table of Contents`_
1087 .. _`Table of Contents`: index.html