comparison doc/customizing.stx @ 633:7875cd9af1cb

documentation in structured text source form
author Richard Jones <richard@users.sourceforge.net>
date Thu, 21 Feb 2002 06:22:00 +0000
parents
children 35cdc70e6a96
comparison
equal deleted inserted replaced
632:71bf8f97fe30 633:7875cd9af1cb
1 Customising Roundup
2 ===================
3
4 Instances have the following structure:
5
6 +-------------------+--------------------------------------------------------+
7 |instance_config.py |Holds the basic instance_configuration |
8 +-------------------+--------------------------------------------------------+
9 |dbinit.py |Holds the instance_schema |
10 +-------------------+--------------------------------------------------------+
11 |interfaces.py |Defines the Web and E-Mail interfaces for the instance |
12 +-------------------+--------------------------------------------------------+
13 |select_db.py |Selects the database back-end for the instance |
14 +-------------------+--------------------------------------------------------+
15 |db/ |Holds the instance's database |
16 +-------------------+--------------------------------------------------------+
17 |db/files/ |Holds the instance's upload files and messages |
18 +-------------------+--------------------------------------------------------+
19 |detectors/ |Auditors and reactors for this instance |
20 +-------------------+--------------------------------------------------------+
21 |html/ |Web interface templates, images and style sheets |
22 +-------------------+--------------------------------------------------------+
23
24 Instance Configuration
25 ----------------------
26
27 The instance_config.py located in your instance home contains the basic
28 configuration for the web and e-mail components of roundup's interfaces. This
29 file is a Python module. The default instance_config.py is given below - as you
30 can see, the MAIL_DOMAIN must be edited before any interaction with the
31 instance is attempted.::
32
33 MAIL_DOMAIN=MAILHOST=HTTP_HOST=None
34 HTTP_PORT=0
35
36 # roundup home is this package's directory
37 INSTANCE_HOME=os.path.split(__file__)[0]
38
39 # The SMTP mail host that roundup will use to send mail
40 if not MAILHOST:
41 MAILHOST = 'localhost'
42
43 # The domain name used for email addresses.
44 if not MAIL_DOMAIN:
45 MAIL_DOMAIN = 'fill.me.in.'
46
47 # the next two are only used for the standalone HTTP server.
48 if not HTTP_HOST:
49 HTTP_HOST = ''
50 if not HTTP_PORT:
51 HTTP_PORT = 9080
52
53 # This is the directory that the database is going to be stored in
54 DATABASE = os.path.join(INSTANCE_HOME, 'db')
55
56 # This is the directory that the HTML templates reside in
57 TEMPLATES = os.path.join(INSTANCE_HOME, 'html')
58
59 # The email address that mail to roundup should go to
60 ISSUE_TRACKER_EMAIL = 'issue_tracker@%s'%MAIL_DOMAIN
61
62 # The web address that the instance is viewable at
63 ISSUE_TRACKER_WEB = 'http://some.useful.url/'
64
65 # The email address that roundup will complain to if it runs into trouble
66 ADMIN_EMAIL = 'roundup-admin@%s'%MAIL_DOMAIN
67
68 # Somewhere for roundup to log stuff internally sent to stdout or stderr
69 LOG = os.path.join(INSTANCE_HOME, 'roundup.log')
70
71 # Where to place the web filtering HTML on the index page
72 FILTER_POSITION = 'bottom' # one of 'top', 'bottom', 'top and bottom'
73
74 # Deny or allow anonymous access to the web interface
75 ANONYMOUS_ACCESS = 'deny'
76
77 # Deny or allow anonymous users to register through the web interface
78 ANONYMOUS_REGISTER = 'deny'
79
80 # Send nosy messages to the author of the message
81 MESSAGES_TO_AUTHOR = 'no' # either 'yes' or 'no'
82
83
84 Instance Schema
85 ---------------
86
87 Note: if you modify the schema, you'll most likely need to web_interface_to
88 reflect_your_changes.
89 An instance schema defines what data is stored in the instance's database. The
90 two schemas shipped with Roundup turn it into a typical software bug tracker
91 (the extended schema allowing for support issues as well as bugs). Schemas are
92 defined using Python code. The "classic" schema looks like this::
93
94 pri = Class(db, "priority", name=String(), order=String())
95 pri.setkey("name")
96 pri.create(name="critical", order="1")
97 pri.create(name="urgent", order="2")
98 pri.create(name="bug", order="3")
99 pri.create(name="feature", order="4")
100 pri.create(name="wish", order="5")
101
102 stat = Class(db, "status", name=String(), order=String())
103 stat.setkey("name")
104 stat.create(name="unread", order="1")
105 stat.create(name="deferred", order="2")
106 stat.create(name="chatting", order="3")
107 stat.create(name="need-eg", order="4")
108 stat.create(name="in-progress", order="5")
109 stat.create(name="testing", order="6")
110 stat.create(name="done-cbb", order="7")
111 stat.create(name="resolved", order="8")
112
113 keyword = Class(db, "keyword", name=String())
114 keyword.setkey("name")
115
116 user = Class(db, "user", username=String(), password=String(),
117 address=String(), realname=String(), phone=String(),
118 organisation=String())
119 user.setkey("username")
120 user.create(username="admin", password=adminpw,
121 address=instance_config.ADMIN_EMAIL)
122
123 msg = FileClass(db, "msg", author=Link("user"), recipients=Multilink
124 ("user"), date=Date(), summary=String(), files=Multilink("file"))
125
126 file = FileClass(db, "file", name=String(), type=String())
127
128 issue = IssueClass(db, "issue", assignedto=Link("user"),
129 topic=Multilink("keyword"), priority=Link("priority"), status=Link
130 ("status"))
131 issue.setkey('title')
132
133 Classes and Properties - creating a new information store
134 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
135
136 In the instance above, we've defined 7 classes of information:
137
138 priority
139 Defines the possible levels of urgency for issues.
140
141 status
142 Defines the possible states of processing the issue may be in.
143
144 keyword
145 Initially empty, will hold keywords useful for searching issues.
146
147 user
148 Initially holding the "admin" user, will eventually have an entry for all
149 users using roundup.
150
151 msg
152 Initially empty, will all e-mail messages sent to or generated by
153 roundup.
154
155 file
156 Initially empty, will all files attached to issues.
157
158 issue
159 Initially emtyp, this is where the issue information is stored.
160
161 We define the "priority" and "status" classes to allow two things: reduction in
162 the amount of information stored on the issue and more powerful, accurate
163 searching of issues by priority and status. By only requiring a link on the
164 issue (which is stored as a single number) we reduce the chance that someone
165 mis-types a priority or status - or simply makes a new one up.
166
167 Class and Nodes
168 :::::::::::::::
169
170 A Class defines a particular class (or type) of data that will be stored in the
171 database. A class comprises one or more properties, which given the information
172 about the class nodes.
173 The actual data entered into the database, using class.create() are called
174 nodes. They have a special immutable property called id. We sometimes refer to
175 this as the nodeid.
176
177 Properties
178 ::::::::::
179
180 A Class is comprised of one or more properties of the following types:
181 * String properties are for storing arbitrary-length strings.
182 * Password properties are for storing encoded arbitrary-length strings. The
183 default encoding is defined on the roundup.password.Password class.
184 * Date properties store date-and-time stamps. Their values are Timestamp
185 objects.
186 * A Link property refers to a single other node selected from a specified
187 class. The class is part of the property; the value is an integer, the id
188 of the chosen node.
189 * A Multilink property refers to possibly many nodes in a specified class.
190 The value is a list of integers.
191
192 FileClass
193 :::::::::
194
195 FileClasses save their "content" attribute off in a separate file from the rest
196 of the database. This reduces the number of large entries in the database,
197 which generally makes databases more efficient, and also allows us to use
198 command-line tools to operate on the files. They are stored in the files sub-
199 directory of the db directory in your instance.
200
201 IssueClass
202 ::::::::::
203
204 IssueClasses automatically include the "messages", "files", "nosy", and
205 "superseder" properties.
206 The messages and files properties list the links to the messages and files
207 related to the issue. The nosy property is a list of links to users who wish to
208 be informed of changes to the issue - they get "CC'ed" e-mails when messages
209 are sent to or generated by the issue. The nosy reactor (in the detectors
210 directory) handles this action. The superceder link indicates an issue which
211 has superceded this one.
212 They also have the dynamically generated "creation", "activity" and "creator"
213 properties.
214 The value of the "creation" property is the date when a node was created, and
215 the value of the "activity" property is the date when any property on the node
216 was last edited (equivalently, these are the dates on the first and last
217 records in the node's journal). The "creator" property holds a link to the user
218 that created the issue.
219
220 setkey(property)
221 ::::::::::::::::
222
223 Select a String property of the class to be the key property. The key property
224 muse be unique, and allows references to the nodes in the class by the content
225 of the key property. That is, we can refer to users by their username, e.g.
226 let's say that there's an issue in roundup, issue 23. There's also a user,
227 richard who happens to be user 2. To assign an issue to him, we could do either
228 of::
229
230 roundup-admin set issue assignedto=2
231
232 or::
233
234 roundup-admin set issue assignedto=richard
235
236 Note, the same thing can be done in the web and e-mail interfaces.
237
238 create(information)
239 :::::::::::::::::::
240
241 Create a node in the database. This is generally used to create nodes in the
242 "definitional" classes like "priority" and "status".
243
244 Web Interface
245 -------------
246
247 The web interface works behind the cgi-bin/roundup.cgi or roundup-server
248 scripts. In both cases, the scripts determine which instance is being accessed
249 (the first part of the URL path inside the scope of the CGI handler) and pass
250 control on to the instance interfaces.Client class which handles the rest of
251 the access through its main() method. This means that you can do pretty much
252 anything you want as a web interface to your instance.
253 Most customisation of the web view can be done by modifying the templates in
254 the instance html directory. These are divided into index, item and newitem
255 views. The newitem view is optional - the item view will be used if the newitem
256 view doesn't exist.
257
258 Repurcussions of changing the instance schema
259 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
260
261 If you choose to change_the_instance_schema you will need to ensure the web
262 interface knows about it:
263
264 1. Index, item and filter pages for the relevant classes may need to have
265 properties added or removed,
266 2. The default page header relies on the existence of, and some values of
267 the priority, status, assignedto and activity classes. If you change any
268 of these (specifically if you remove any of the classes or their default
269 values) you will need to implement your own pagehead() method in your
270 instance's interfaces.py module.
271
272 Displaying Properties
273 ~~~~~~~~~~~~~~~~~~~~~
274
275 Properties appear in the user interface in three contexts: in indices, in
276 editors, and as filters. For each type of property, there are several display
277 possibilities. For example, in an index view, a string property may just be
278 printed as a plain string, but in an editor view, that property should be
279 displayed in an editable field.
280
281 The display of a property is handled by functions in the htmltemplate module.
282 Displayer functions are triggered by <display> tags in templates. The call
283 attribute of the tag provides a Python expression for calling the displayer
284 function. The three standard arguments are inserted in front of the arguments
285 given. For example, the occurrence of::
286
287 <display call="plain('status')">
288
289 in a template triggers a call the "plain" function. The displayer functions can
290 accept extra arguments to further specify details about the widgets that should
291 be generated. By defining new displayer functions, the user interface can be
292 highly customized.
293
294 +-----------------------------------------------------------------------------+
295 |The displayer functions are |
296 +---------+-------------------------------------------------------------------+
297 |plain |Display a String property directly. |
298 | |Display a Date property in a specified time zone with an option to |
299 | |omit the time from the date stamp. |
300 | |For a Link or Multilink property, display the key strings of the |
301 | |linked nodes (or the ids if the linked class has no key property). |
302 | |Options: |
303 | |escape (boolean) - HTML-escape the resulting text. |
304 +---------+-------------------------------------------------------------------+
305 |field |Display a property like the plain displayer above, but in a form |
306 | |field to be edited. Strings, Dates and Intervals use TEXT fields, |
307 | |Links use SELECT fields and Multilinks use SELECT MULTIPLE fields. |
308 | |Options: |
309 | |size (number) - width of TEXT fields. |
310 | |height (number) - number of nows in SELECT MULTIPLE tags. |
311 | |showid (boolean) - true includes the id of linked nodes in the |
312 | |SELECT MULTIPLE fields. |
313 +---------+-------------------------------------------------------------------+
314 |menu |For a Links and Multilinks, display the same field as would be |
315 | |generated using field. |
316 +---------+-------------------------------------------------------------------+
317 |link |For a Link or Multilink property, display the names of the linked |
318 | |nodes, hyperlinked to the item views on those nodes. |
319 | |For other properties, link to this node with the property as the |
320 | |text. |
321 | |Options: |
322 | |property (property name) - the property to use in the second case. |
323 +---------+-------------------------------------------------------------------+
324 |count |For a Multilink property, display a count of the number of links in|
325 | |the list. |
326 | |Arguments: |
327 | |property (property name) - the property to use. |
328 +---------+-------------------------------------------------------------------+
329 |reldate |Display a Date property in terms of an interval relative to the |
330 | |current date (e.g. "+ 3w", "- 2d"). |
331 | |Arguments: |
332 | |property (property name) - the property to use. |
333 | |Options: |
334 | |pretty (boolean) - display the relative date in an English form. |
335 +---------+-------------------------------------------------------------------+
336 |download |For a Link or Multilink property, display the names of the linked |
337 | |nodes, hyperlinked to the item views on those nodes. |
338 | |For other properties, link to this node with the property as the |
339 | |text. |
340 | |In all cases, append the name (key property) of the item to the |
341 | |path so it is the name of the file being downloaded. |
342 | |Arguments: |
343 | |property (property name) - the property to use. |
344 +---------+-------------------------------------------------------------------+
345 |checklist|For a Link or Multilink property, display checkboxes for the |
346 | |available choices to permit filtering. |
347 | |Arguments: |
348 | |property (property name) - the property to use. |
349 +---------+-------------------------------------------------------------------+
350 |note |Display the special notes field, which is a text area for entering |
351 | |a note to go along with a change. |
352 +---------+-------------------------------------------------------------------+
353 |list |List the nodes specified by property using the standard index for |
354 | |the class. |
355 | |Arguments: |
356 | |property (property name) - the property to use. |
357 +---------+-------------------------------------------------------------------+
358 |history |List the history of the item. |
359 +---------+-------------------------------------------------------------------+
360 |submit |Add a submit button for the item. |
361 +---------+-------------------------------------------------------------------+
362
363
364 Index Views
365 ~~~~~~~~~~~
366
367 An index view contains two sections: a filter section and an index section. The
368 filter section provides some widgets for selecting which items appear in the
369 index. The index section is a table of items.
370
371 Index View Specifiers
372 :::::::::::::::::::::
373
374 An index view specifier (URL fragment) looks like this (whitespace has been
375 added for clarity)::
376
377 /issue?status=unread,in-progress,resolved&
378 topic=security,ui&
379 :group=+priority&
380 :sort=-activity&
381 :filters=status,topic&
382 :columns=title,status,fixer
383
384 The index view is determined by two parts of the specifier: the layout part and
385 the filter part. The layout part consists of the query parameters that begin
386 with colons, and it determines the way that the properties of selected nodes
387 are displayed. The filter part consists of all the other query parameters, and
388 it determines the criteria by which nodes are selected for display.
389 The filter part is interactively manipulated with the form widgets displayed in
390 the filter section. The layout part is interactively manipulated by clicking on
391 the column headings in the table.
392
393 The filter part selects the union of the sets of items with values matching any
394 specified Link properties and the intersection of the sets of items with values
395 matching any specified Multilink properties.
396
397 The example specifies an index of "issue" nodes. Only items with a "status" of
398 either "unread" or "in-progres" or "resolved" are displayed, and only items
399 with "topic" values including both "security" and "ui" are displayed. The items
400 are grouped by priority, arranged in ascending order; and within groups, sorted
401 by activity, arranged in descending order. The filter section shows filters for
402 the "status" and "topic" properties, and the table includes columns for the
403 "title", "status", and "fixer" properties.
404
405 Associated with each item class is a default layout specifier. The layout
406 specifier in the above example is the default layout to be provided with the
407 default bug-tracker schema described above in section 4.4.
408
409 Filter Section
410 ::::::::::::::
411
412 The template for a filter section provides the filtering widgets at the top of
413 the index view. Fragments enclosed in <property>...</property> tags are
414 included or omitted depending on whether the view specifier requests a filter
415 for a particular property.
416
417 A property must appear in the filter template for it to be available as a
418 filter.
419
420 Here's a simple example of a filter template.::
421
422 <property name=status>
423 <display call="checklist('status')">
424 </property>
425 <br>
426 <property name=priority>
427 <display call="checklist('priority')">
428 </property>
429 <br>
430 <property name=fixer>
431 <display call="menu('fixer')">
432 </property>
433
434 The standard index generation code appends a section to the index pages which
435 allows selection of the filters - from those which are defined in the filter
436 template.
437
438 Index Section
439 :::::::::::::
440
441 The template for an index section describes one row of the index table.
442 Fragments enclosed in <property>...</property> tags are included or omitted
443 depending on whether the view specifier requests a column for a particular
444 property. The table cells should contain <display> tags to display the values
445 of the item's properties.
446
447 Here's a simple example of an index template.::
448
449 <tr>
450 <property name=title>
451 <td><display call="plain('title', max=50)"></td>
452 </property>
453 <property name=status>
454 <td><display call="plain('status')"></td>
455 </property>
456 <property name=fixer>
457 <td><display call="plain('fixer')"></td>
458 </property>
459 </tr>
460
461 Sorting
462 :::::::
463
464 String and Date values are sorted in the natural way. Link properties are
465 sorted according to the value of the "order" property on the linked nodes if it
466 is present; or otherwise on the key string of the linked nodes; or finally on
467 the node ids. Multilink properties are sorted according to how many links are
468 present.
469
470 Item Views
471 ~~~~~~~~~~
472
473 An item view contains an editor section and a spool section. At the top of an
474 item view, links to superseding and superseded items are always displayed.
475
476 Editor Section
477 ::::::::::::::
478
479 The editor section is generated from a template containing <display> tags to
480 insert the appropriate widgets for editing properties.
481
482 Here's an example of a basic editor template.::
483
484 <table>
485 <tr>
486 <td colspan=2>
487 <display call="field('title', size=60)">
488 </td>
489 </tr>
490 <tr>
491 <td>
492 <display call="field('fixer', size=30)">
493 </td>
494 <td>
495 <display call="menu('status')>
496 </td>
497 </tr>
498 <tr>
499 <td>
500 <display call="field('nosy', size=30)">
501 </td>
502 <td>
503 <display call="menu('priority')>
504 </td>
505 </tr>
506 <tr>
507 <td colspan=2>
508 <display call="note()">
509 </td>
510 </tr>
511 </table>
512
513 As shown in the example, the editor template can also request the display of a
514 "note" field, which is a text area for entering a note to go along with a
515 change.
516
517 When a change is submitted, the system automatically generates a message
518 describing the changed properties.
519
520 If a note is given in the "note" field, the note is appended to the
521 description. The message is then added to the item's message spool (thus
522 triggering the standard detector to react by sending out this message to the
523 nosy list).
524
525 The message also displays all of the property values on the item and indicates
526 which ones have changed. An example of such a message might be this::
527
528 Polly's taken a turn for the worse - this is now really important!
529 -----
530 title: Polly Parrot is dead
531 priority: critical
532 status: unread -> in-progress
533 fixer: terry
534 keywords: parrot,plumage,perch,nailed,dead
535
536 Spool Section
537 :::::::::::::
538
539 The spool section lists messages in the item's "messages" property. The index
540 of messages displays the "date", "author", and "summary" properties on the
541 message nodes, and selecting a message takes you to its content.
542
543 The <property> tag used in the index may also be used here - it checks to see
544 if the nominated Multilink property has any entries. This can be used to
545 eliminate sections of the spool section if the property has no entries.::
546
547 <property name="files">
548 <tr class="strong-header">
549 <td><b>Files</b></td>
550 </tr>
551
552 <tr>
553 <td><display call="list('files')"></td>
554 </tr>
555 </property>
556
557

Roundup Issue Tracker: http://roundup-tracker.org/