comparison doc/design.txt @ 1661:b9c1226cb600

Reflowed text to 72 cols... ...made leading whitespace before headings consistent, and got rid of references to <display> and <property>.
author Jean Jordaan <neaj@users.sourceforge.net>
date Mon, 16 Jun 2003 15:27:15 +0000
parents f5d53a939b67
children eb3c348676ed
comparison
equal deleted inserted replaced
1659:2c4ec168e72f 1661:b9c1226cb600
9 .. contents:: 9 .. contents::
10 10
11 Introduction 11 Introduction
12 --------------- 12 ---------------
13 13
14 This document presents a description of the components 14 This document presents a description of the components of the Roundup
15 of the Roundup system and specifies their interfaces and 15 system and specifies their interfaces and behaviour in sufficient detail
16 behaviour in sufficient detail to guide an implementation. 16 to guide an implementation. For the philosophy and rationale behind the
17 For the philosophy and rationale behind the Roundup design, 17 Roundup design, see the first-round Software Carpentry submission for
18 see the first-round Software Carpentry submission for Roundup. 18 Roundup. This document fleshes out that design as well as specifying
19 This document fleshes out that design as well as specifying
20 interfaces so that the components can be developed separately. 19 interfaces so that the components can be developed separately.
21 20
22 21
23 The Layer Cake 22 The Layer Cake
24 ----------------- 23 -----------------
25 24
26 Lots of software design documents come with a picture of 25 Lots of software design documents come with a picture of a cake.
27 a cake. Everybody seems to like them. I also like cakes 26 Everybody seems to like them. I also like cakes (i think they are
28 (i think they are tasty). So i, too, shall include 27 tasty). So I, too, shall include a picture of a cake here::
29 a picture of a cake here::
30 28
31 _________________________________________________________________________ 29 _________________________________________________________________________
32 | E-mail Client | Web Browser | Detector Scripts | Shell | 30 | E-mail Client | Web Browser | Detector Scripts | Shell |
33 |------------------+-----------------+----------------------+-------------| 31 |------------------+-----------------+----------------------+-------------|
34 | E-mail User | Web User | Detector | Command | 32 | E-mail User | Web User | Detector | Command |
38 | Hyperdatabase Layer | 36 | Hyperdatabase Layer |
39 |-------------------------------------------------------------------------| 37 |-------------------------------------------------------------------------|
40 | Storage Layer | 38 | Storage Layer |
41 ------------------------------------------------------------------------- 39 -------------------------------------------------------------------------
42 40
43 The colourful parts of the cake are part of our system; 41 The colourful parts of the cake are part of our system; the faint grey
44 the faint grey parts of the cake are external components. 42 parts of the cake are external components.
45 43
46 I will now proceed to forgo all table manners and 44 I will now proceed to forgo all table manners and eat from the bottom of
47 eat from the bottom of the cake to the top. You may want 45 the cake to the top. You may want to stand back a bit so you don't get
48 to stand back a bit so you don't get covered in crumbs. 46 covered in crumbs.
49 47
50 48
51 Hyperdatabase 49 Hyperdatabase
52 ------------- 50 -------------
53 51
54 The lowest-level component to be implemented is the hyperdatabase. 52 The lowest-level component to be implemented is the hyperdatabase. The
55 The hyperdatabase is intended to be 53 hyperdatabase is intended to be a flexible data store that can hold
56 a flexible data store that can hold configurable data in 54 configurable data in records which we call items.
57 records which we call items. 55
58 56 The hyperdatabase is implemented on top of the storage layer, an
59 The hyperdatabase is implemented on top of the storage layer, 57 external module for storing its data. The storage layer could be a
60 an external module for storing its data. The storage layer could 58 third-party RDBMS; for a "batteries-included" distribution, implementing
61 be a third-party RDBMS; for a "batteries-included" distribution, 59 the hyperdatabase on the standard bsddb module is suggested.
62 implementing the hyperdatabase on the standard bsddb
63 module is suggested.
64 60
65 Dates and Date Arithmetic 61 Dates and Date Arithmetic
66 ~~~~~~~~~~~~~~~~~~~~~~~~~ 62 ~~~~~~~~~~~~~~~~~~~~~~~~~
67 63
68 Before we get into the hyperdatabase itself, we need a 64 Before we get into the hyperdatabase itself, we need a way of handling
69 way of handling dates. The hyperdatabase module provides 65 dates. The hyperdatabase module provides Timestamp objects for
70 Timestamp objects for 66 representing date-and-time stamps and Interval objects for representing
71 representing date-and-time stamps and Interval objects for 67 date-and-time intervals.
72 representing date-and-time intervals. 68
73 69 As strings, date-and-time stamps are specified with the date in
74 As strings, date-and-time stamps are specified with 70 international standard format (``yyyy-mm-dd``) joined to the time
75 the date in international standard format 71 (``hh:mm:ss``) by a period "``.``". Dates in this form can be easily
76 (``yyyy-mm-dd``) 72 compared and are fairly readable when printed. An example of a valid
77 joined to the time (``hh:mm:ss``) 73 stamp is "``2000-06-24.13:03:59``". We'll call this the "full date
78 by a period "``.``". Dates in 74 format". When Timestamp objects are printed as strings, they appear in
79 this form can be easily compared and are fairly readable 75 the full date format with the time always given in GMT. The full date
80 when printed. An example of a valid stamp is 76 format is always exactly 19 characters long.
81 "``2000-06-24.13:03:59``". 77
82 We'll call this the "full date format". When Timestamp objects are 78 For user input, some partial forms are also permitted: the whole time or
83 printed as strings, they appear in the full date format with 79 just the seconds may be omitted; and the whole date may be omitted or
84 the time always given in GMT. The full date format is always 80 just the year may be omitted. If the time is given, the time is
85 exactly 19 characters long. 81 interpreted in the user's local time zone. The Date constructor takes
86 82 care of these conversions. In the following examples, suppose that
87 For user input, some partial forms are also permitted: 83 ``yyyy`` is the current year, ``mm`` is the current month, and ``dd`` is
88 the whole time or just the seconds may be omitted; and the whole date 84 the current day of the month; and suppose that the user is on Eastern
89 may be omitted or just the year may be omitted. If the time is given, 85 Standard Time.
90 the time is interpreted in the user's local time zone.
91 The Date constructor takes care of these conversions.
92 In the following examples, suppose that ``yyyy`` is the current year,
93 ``mm`` is the current month, and ``dd`` is the current
94 day of the month; and suppose that the user is on Eastern Standard Time.
95 86
96 - "2000-04-17" means <Date 2000-04-17.00:00:00> 87 - "2000-04-17" means <Date 2000-04-17.00:00:00>
97 - "01-25" means <Date yyyy-01-25.00:00:00> 88 - "01-25" means <Date yyyy-01-25.00:00:00>
98 - "2000-04-17.03:45" means <Date 2000-04-17.08:45:00> 89 - "2000-04-17.03:45" means <Date 2000-04-17.08:45:00>
99 - "08-13.22:13" means <Date yyyy-08-14.03:13:00> 90 - "08-13.22:13" means <Date yyyy-08-14.03:13:00>
103 - "8:47:11" means 94 - "8:47:11" means
104 - <Date yyyy-mm-dd.13:47:11> 95 - <Date yyyy-mm-dd.13:47:11>
105 - the special date "." means "right now" 96 - the special date "." means "right now"
106 97
107 98
108 Date intervals are specified using the suffixes 99 Date intervals are specified using the suffixes "y", "m", and "d". The
109 "y", "m", and "d". The suffix "w" (for "week") means 7 days. 100 suffix "w" (for "week") means 7 days. Time intervals are specified in
110 Time intervals are specified in hh:mm:ss format (the seconds 101 hh:mm:ss format (the seconds may be omitted, but the hours and minutes
111 may be omitted, but the hours and minutes may not). 102 may not).
112 103
113 - "3y" means three years 104 - "3y" means three years
114 - "2y 1m" means two years and one month 105 - "2y 1m" means two years and one month
115 - "1m 25d" means one month and 25 days 106 - "1m 25d" means one month and 25 days
116 - "2w 3d" means two weeks and three days 107 - "2w 3d" means two weeks and three days
117 - "1d 2:50" means one day, two hours, and 50 minutes 108 - "1d 2:50" means one day, two hours, and 50 minutes
118 - "14:00" means 14 hours 109 - "14:00" means 14 hours
119 - "0:04:33" means four minutes and 33 seconds 110 - "0:04:33" means four minutes and 33 seconds
120 111
121 112
122 The Date class should understand simple date expressions of the form 113 The Date class should understand simple date expressions of the form
123 *stamp* ``+`` *interval* and *stamp* ``-`` *interval*. 114 *stamp* ``+`` *interval* and *stamp* ``-`` *interval*. When adding or
124 When adding or subtracting intervals involving months or years, the 115 subtracting intervals involving months or years, the components are
125 components are handled separately. For example, when evaluating 116 handled separately. For example, when evaluating "``2000-06-25 + 1m
126 "``2000-06-25 + 1m 10d``", we first add one month to 117 10d``", we first add one month to get 2000-07-25, then add 10 days to
127 get 2000-07-25, then add 10 days to get 118 get 2000-08-04 (rather than trying to decide whether 1m 10d means 38 or
128 2000-08-04 (rather than trying to decide whether 119 40 or 41 days).
129 1m 10d means 38 or 40 or 41 days).
130 120
131 Here is an outline of the Date and Interval classes:: 121 Here is an outline of the Date and Interval classes::
132 122
133 class Date: 123 class Date:
134 def __init__(self, spec, offset): 124 def __init__(self, spec, offset):
165 """Return this interval as a string.""" 155 """Return this interval as a string."""
166 156
167 157
168 158
169 Here are some examples of how these classes would behave in practice. 159 Here are some examples of how these classes would behave in practice.
170 For the following examples, assume that we are on Eastern Standard 160 For the following examples, assume that we are on Eastern Standard Time
171 Time and the current local time is 19:34:02 on 25 June 2000:: 161 and the current local time is 19:34:02 on 25 June 2000::
172 162
173 >>> Date(".") 163 >>> Date(".")
174 <Date 2000-06-26.00:34:02> 164 <Date 2000-06-26.00:34:02>
175 >>> _.local(-5) 165 >>> _.local(-5)
176 "2000-06-25.19:34:02" 166 "2000-06-25.19:34:02"
190 <Date 2000-06-07.00:34:02> 180 <Date 2000-06-07.00:34:02>
191 181
192 Items and Classes 182 Items and Classes
193 ~~~~~~~~~~~~~~~~~ 183 ~~~~~~~~~~~~~~~~~
194 184
195 Items contain data in properties. To Python, these 185 Items contain data in properties. To Python, these properties are
196 properties are presented as the key-value pairs of a dictionary. 186 presented as the key-value pairs of a dictionary. Each item belongs to a
197 Each item belongs to a class which defines the names 187 class which defines the names and types of its properties. The database
198 and types of its properties. The database permits the creation 188 permits the creation and modification of classes as well as items.
199 and modification of classes as well as items.
200 189
201 Identifiers and Designators 190 Identifiers and Designators
202 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 191 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
203 192
204 Each item has a numeric identifier which is unique among 193 Each item has a numeric identifier which is unique among items in its
205 items in its class. The items are numbered sequentially 194 class. The items are numbered sequentially within each class in order
206 within each class in order of creation, starting from 1. 195 of creation, starting from 1. The designator for an item is a way to
207 The designator 196 identify an item in the database, and consists of the name of the item's
208 for an item is a way to identify an item in the database, and 197 class concatenated with the item's numeric identifier.
209 consists of the name of the item's class concatenated with 198
210 the item's numeric identifier. 199 For example, if "spam" and "eggs" are classes, the first item created in
211 200 class "spam" has id 1 and designator "spam1". The first item created in
212 For example, if "spam" and "eggs" are classes, the first 201 class "eggs" also has id 1 but has the distinct designator "eggs1".
213 item created in class "spam" has id 1 and designator "spam1". 202 Item designators are conventionally enclosed in square brackets when
214 The first item created in class "eggs" also has id 1 but has 203 mentioned in plain text. This permits a casual mention of, say,
215 the distinct designator "eggs1". Item designators are 204 "[patch37]" in an e-mail message to be turned into an active hyperlink.
216 conventionally enclosed in square brackets when mentioned
217 in plain text. This permits a casual mention of, say,
218 "[patch37]" in an e-mail message to be turned into an active
219 hyperlink.
220 205
221 Property Names and Types 206 Property Names and Types
222 ~~~~~~~~~~~~~~~~~~~~~~~~ 207 ~~~~~~~~~~~~~~~~~~~~~~~~
223 208
224 Property names must begin with a letter. 209 Property names must begin with a letter.
229 214
230 - Boolean properties are for storing true/false, or yes/no values. 215 - Boolean properties are for storing true/false, or yes/no values.
231 216
232 - Number properties are for storing numeric values. 217 - Number properties are for storing numeric values.
233 218
234 - Date properties store date-and-time stamps. 219 - Date properties store date-and-time stamps. Their values are Timestamp
235 Their values are Timestamp objects. 220 objects.
236 221
237 - A Link property refers to a single other item 222 - A Link property refers to a single other item selected from a
238 selected from a specified class. The class is part of the property; 223 specified class. The class is part of the property; the value is an
239 the value is an integer, the id of the chosen item. 224 integer, the id of the chosen item.
240 225
241 - A Multilink property refers to possibly many items 226 - A Multilink property refers to possibly many items in a specified
242 in a specified class. The value is a list of integers. 227 class. The value is a list of integers.
243 228
244 *None* is also a permitted value for any of these property 229 *None* is also a permitted value for any of these property types. An
245 types. An attempt to store None into a Multilink property stores an empty list. 230 attempt to store None into a Multilink property stores an empty list.
246 231
247 A property that is not specified will return as None from a *get* 232 A property that is not specified will return as None from a *get*
248 operation. 233 operation.
249 234
250 Hyperdb Interface Specification 235 Hyperdb Interface Specification
251 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 236 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
252 237
253 TODO: replace the Interface Specifications with links to the pydoc 238 TODO: replace the Interface Specifications with links to the pydoc
254 239
255 The hyperdb module provides property objects to designate 240 The hyperdb module provides property objects to designate the different
256 the different kinds of properties. These objects are used when 241 kinds of properties. These objects are used when specifying what
257 specifying what properties belong in classes:: 242 properties belong in classes::
258 243
259 class String: 244 class String:
260 def __init__(self, indexme='no'): 245 def __init__(self, indexme='no'):
261 """An object designating a String property.""" 246 """An object designating a String property."""
262 247
297 """A database for storing records containing flexible data types.""" 282 """A database for storing records containing flexible data types."""
298 283
299 def __init__(self, config, journaltag=None): 284 def __init__(self, config, journaltag=None):
300 """Open a hyperdatabase given a specifier to some storage. 285 """Open a hyperdatabase given a specifier to some storage.
301 286
302 The 'storagelocator' is obtained from config.DATABASE. 287 The 'storagelocator' is obtained from config.DATABASE. The
303 The meaning of 'storagelocator' depends on the particular 288 meaning of 'storagelocator' depends on the particular
304 implementation of the hyperdatabase. It could be a file name, 289 implementation of the hyperdatabase. It could be a file
305 a directory path, a socket descriptor for a connection to a 290 name, a directory path, a socket descriptor for a connection
306 database over the network, etc. 291 to a database over the network, etc.
307 292
308 The 'journaltag' is a token that will be attached to the journal 293 The 'journaltag' is a token that will be attached to the
309 entries for any edits done on the database. If 'journaltag' is 294 journal entries for any edits done on the database. If
310 None, the database is opened in read-only mode: the Class.create(), 295 'journaltag' is None, the database is opened in read-only
311 Class.set(), Class.retire(), and Class.restore() methods are 296 mode: the Class.create(), Class.set(), Class.retire(), and
312 disabled. 297 Class.restore() methods are disabled.
313 """ 298 """
314 299
315 def __getattr__(self, classname): 300 def __getattr__(self, classname):
316 """A convenient way of calling self.getclass(classname).""" 301 """A convenient way of calling self.getclass(classname)."""
317 302
379 by the find(), list(), or lookup() methods, and other items may 364 by the find(), list(), or lookup() methods, and other items may
380 reuse the values of their key properties. 365 reuse the values of their key properties.
381 """ 366 """
382 367
383 def restore(self, nodeid): 368 def restore(self, nodeid):
384 '''Restpre a retired node. 369 '''Restore a retired node.
385 370
386 Make node available for all operations like it was before retirement. 371 Make node available for all operations like it was before retirement.
387 ''' 372 '''
388 373
389 def history(self, itemid): 374 def history(self, itemid):
492 ''' 477 '''
493 478
494 Hyperdatabase Implementations 479 Hyperdatabase Implementations
495 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 480 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
496 481
497 Hyperdatabase implementations exist to create the interface described in the 482 Hyperdatabase implementations exist to create the interface described in
498 `hyperdb interface specification`_ 483 the `hyperdb interface specification`_ over an existing storage
499 over an existing storage mechanism. Examples are relational databases, 484 mechanism. Examples are relational databases, \*dbm key-value databases,
500 \*dbm key-value databases, and so on. 485 and so on.
501 486
502 Several implementations are provided - they belong in the roundup.backends 487 Several implementations are provided - they belong in the
503 package. 488 roundup.backends package.
504 489
505 490
506 Application Example 491 Application Example
507 ~~~~~~~~~~~~~~~~~~~ 492 ~~~~~~~~~~~~~~~~~~~
508 493
509 Here is an example of how the hyperdatabase module would work in practice:: 494 Here is an example of how the hyperdatabase module would work in
495 practice::
510 496
511 >>> import hyperdb 497 >>> import hyperdb
512 >>> db = hyperdb.Database("foo.db", "ping") 498 >>> db = hyperdb.Database("foo.db", "ping")
513 >>> db 499 >>> db
514 <hyperdb.Database "foo.db" opened by "ping"> 500 <hyperdb.Database "foo.db" opened by "ping">
567 (<Date 2000-06-28.19:11:04>, "ping", "unlink", ("issue", 5, "status"))] 553 (<Date 2000-06-28.19:11:04>, "ping", "unlink", ("issue", 5, "status"))]
568 >>> db.status.history(2) 554 >>> db.status.history(2)
569 [(<Date 2000-06-28.19:11:04>, "ping", "link", ("issue", 5, "status"))] 555 [(<Date 2000-06-28.19:11:04>, "ping", "link", ("issue", 5, "status"))]
570 556
571 557
572 For the purposes of journalling, when a Multilink property is 558 For the purposes of journalling, when a Multilink property is set to a
573 set to a new list of items, the hyperdatabase compares the old 559 new list of items, the hyperdatabase compares the old list to the new
574 list to the new list. 560 list. The journal records "unlink" events for all the items that appear
575 The journal records "unlink" events for all the items that appear 561 in the old list but not the new list, and "link" events for all the
576 in the old list but not the new list, 562 items that appear in the new list but not in the old list.
577 and "link" events for
578 all the items that appear in the new list but not in the old list.
579 563
580 564
581 Roundup Database 565 Roundup Database
582 ---------------- 566 ----------------
583 567
584 The Roundup database layer is implemented on top of the 568 The Roundup database layer is implemented on top of the hyperdatabase
585 hyperdatabase and mediates calls to the database. 569 and mediates calls to the database. Some of the classes in the Roundup
586 Some of the classes in the Roundup database are considered 570 database are considered issue classes. The Roundup database layer adds
587 issue classes. 571 detectors and user items, and on issues it provides mail spools, nosy
588 The Roundup database layer adds detectors and user items, 572 lists, and superseders.
589 and on issues it provides mail spools, nosy lists, and superseders.
590 573
591 Reserved Classes 574 Reserved Classes
592 ~~~~~~~~~~~~~~~~ 575 ~~~~~~~~~~~~~~~~
593 576
594 Internal to this layer we reserve three special classes 577 Internal to this layer we reserve three special classes of items that
595 of items that are not issues. 578 are not issues.
596 579
597 Users 580 Users
598 """"" 581 """""
599 582
600 Users are stored in the hyperdatabase as items of 583 Users are stored in the hyperdatabase as items of class "user". The
601 class "user". The "user" class has the definition:: 584 "user" class has the definition::
602 585
603 hyperdb.Class(db, "user", username=hyperdb.String(), 586 hyperdb.Class(db, "user", username=hyperdb.String(),
604 password=hyperdb.String(), 587 password=hyperdb.String(),
605 address=hyperdb.String()) 588 address=hyperdb.String())
606 db.user.setkey("username") 589 db.user.setkey("username")
609 """""""" 592 """"""""
610 593
611 E-mail messages are represented by hyperdatabase items of class "msg". 594 E-mail messages are represented by hyperdatabase items of class "msg".
612 The actual text content of the messages is stored in separate files. 595 The actual text content of the messages is stored in separate files.
613 (There's no advantage to be gained by stuffing them into the 596 (There's no advantage to be gained by stuffing them into the
614 hyperdatabase, and if messages are stored in ordinary text files, 597 hyperdatabase, and if messages are stored in ordinary text files, they
615 they can be grepped from the command line.) The text of a message is 598 can be grepped from the command line.) The text of a message is saved
616 saved in a file named after the message item designator (e.g. "msg23") 599 in a file named after the message item designator (e.g. "msg23") for the
617 for the sake of the command interface (see below). Attachments are 600 sake of the command interface (see below). Attachments are stored
618 stored separately and associated with "file" items. 601 separately and associated with "file" items. The "msg" class has the
619 The "msg" class has the definition:: 602 definition::
620 603
621 hyperdb.Class(db, "msg", author=hyperdb.Link("user"), 604 hyperdb.Class(db, "msg", author=hyperdb.Link("user"),
622 recipients=hyperdb.Multilink("user"), 605 recipients=hyperdb.Multilink("user"),
623 date=hyperdb.Date(), 606 date=hyperdb.Date(),
624 summary=hyperdb.String(), 607 summary=hyperdb.String(),
625 files=hyperdb.Multilink("file")) 608 files=hyperdb.Multilink("file"))
626 609
627 The "author" property indicates the author of the message 610 The "author" property indicates the author of the message (a "user" item
628 (a "user" item must exist in the hyperdatabase for any messages 611 must exist in the hyperdatabase for any messages that are stored in the
629 that are stored in the system). 612 system). The "summary" property contains a summary of the message for
630 The "summary" property contains a summary of the message for display 613 display in a message index.
631 in a message index.
632 614
633 Files 615 Files
634 """"" 616 """""
635 617
636 Submitted files are represented by hyperdatabase 618 Submitted files are represented by hyperdatabase items of class "file".
637 items of class "file". Like e-mail messages, the file content 619 Like e-mail messages, the file content is stored in files outside the
638 is stored in files outside the database, 620 database, named after the file item designator (e.g. "file17"). The
639 named after the file item designator (e.g. "file17"). 621 "file" class has the definition::
640 The "file" class has the definition::
641 622
642 hyperdb.Class(db, "file", user=hyperdb.Link("user"), 623 hyperdb.Class(db, "file", user=hyperdb.Link("user"),
643 name=hyperdb.String(), 624 name=hyperdb.String(),
644 type=hyperdb.String()) 625 type=hyperdb.String())
645 626
646 The "user" property indicates the user who submitted the 627 The "user" property indicates the user who submitted the file, the
647 file, the "name" property holds the original name of the file, 628 "name" property holds the original name of the file, and the "type"
648 and the "type" property holds the MIME type of the file as received. 629 property holds the MIME type of the file as received.
649 630
650 Issue Classes 631 Issue Classes
651 ~~~~~~~~~~~~~ 632 ~~~~~~~~~~~~~
652 633
653 All issues have the following standard properties: 634 All issues have the following standard properties:
660 files hyperdb.Multilink("file") 641 files hyperdb.Multilink("file")
661 nosy hyperdb.Multilink("user") 642 nosy hyperdb.Multilink("user")
662 superseder hyperdb.Multilink("issue") 643 superseder hyperdb.Multilink("issue")
663 =========== ========================== 644 =========== ==========================
664 645
665 Also, two Date properties named "creation" and "activity" are 646 Also, two Date properties named "creation" and "activity" are fabricated
666 fabricated by the Roundup database layer. By "fabricated" we 647 by the Roundup database layer. By "fabricated" we mean that no such
667 mean that no such properties are actually stored in the 648 properties are actually stored in the hyperdatabase, but when properties
668 hyperdatabase, but when properties on issues are requested, the 649 on issues are requested, the "creation" and "activity" properties are
669 "creation" and "activity" properties are made available. 650 made available. The value of the "creation" property is the date when an
670 The value of the "creation" property is the date when an issue was 651 issue was created, and the value of the "activity" property is the date
671 created, and the value of the "activity" property is the 652 when any property on the issue was last edited (equivalently, these are
672 date when any property on the issue was last edited (equivalently, 653 the dates on the first and last records in the issue's journal).
673 these are the dates on the first and last records in the issue's journal).
674 654
675 Roundupdb Interface Specification 655 Roundupdb Interface Specification
676 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 656 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
677 657
678 The interface to a Roundup database delegates most method 658 The interface to a Roundup database delegates most method calls to the
679 calls to the hyperdatabase, except for the following 659 hyperdatabase, except for the following changes and additional methods::
680 changes and additional methods::
681 660
682 class Database: 661 class Database:
683 def getuid(self): 662 def getuid(self):
684 """Return the id of the "user" item associated with the user 663 """Return the id of the "user" item associated with the user
685 that owns this connection to the hyperdatabase.""" 664 that owns this connection to the hyperdatabase."""
688 # Overridden methods: 667 # Overridden methods:
689 668
690 def create(self, **propvalues): 669 def create(self, **propvalues):
691 def set(self, **propvalues): 670 def set(self, **propvalues):
692 def retire(self, itemid): 671 def retire(self, itemid):
693 """These operations trigger detectors and can be vetoed. Attempts 672 """These operations trigger detectors and can be vetoed.
694 to modify the "creation" or "activity" properties cause a KeyError. 673 Attempts to modify the "creation" or "activity" properties
674 cause a KeyError.
695 """ 675 """
696 676
697 # New methods: 677 # New methods:
698 678
699 def audit(self, event, detector): 679 def audit(self, event, detector):
702 682
703 class IssueClass(Class): 683 class IssueClass(Class):
704 # Overridden methods: 684 # Overridden methods:
705 685
706 def __init__(self, db, classname, **properties): 686 def __init__(self, db, classname, **properties):
707 """The newly-created class automatically includes the "messages", 687 """The newly-created class automatically includes the
708 "files", "nosy", and "superseder" properties. If the 'properties' 688 "messages", "files", "nosy", and "superseder" properties.
709 dictionary attempts to specify any of these properties or a 689 If the 'properties' dictionary attempts to specify any of
710 "creation" or "activity" property, a ValueError is raised.""" 690 these properties or a "creation" or "activity" property, a
691 ValueError is raised."""
711 692
712 def get(self, itemid, propname): 693 def get(self, itemid, propname):
713 def getprops(self): 694 def getprops(self):
714 """In addition to the actual properties on the item, these 695 """In addition to the actual properties on the item, these
715 methods provide the "creation" and "activity" properties.""" 696 methods provide the "creation" and "activity" properties."""
728 """ 709 """
729 710
730 def sendmessage(self, itemid, msgid): 711 def sendmessage(self, itemid, msgid):
731 """Send a message to the members of an issue's nosy list. 712 """Send a message to the members of an issue's nosy list.
732 713
733 The message is sent only to users on the nosy list who are not 714 The message is sent only to users on the nosy list who are
734 already on the "recipients" list for the message. These users 715 not already on the "recipients" list for the message. These
735 are then added to the message's "recipients" list. 716 users are then added to the message's "recipients" list.
736 """ 717 """
737 718
738 719
739 Default Schema 720 Default Schema
740 ~~~~~~~~~~~~~~ 721 ~~~~~~~~~~~~~~
741 722
742 The default schema included with Roundup turns it into a 723 The default schema included with Roundup turns it into a typical
743 typical software bug tracker. The database is set up like this:: 724 software bug tracker. The database is set up like this::
744 725
745 pri = Class(db, "priority", name=hyperdb.String(), order=hyperdb.String()) 726 pri = Class(db, "priority", name=hyperdb.String(), order=hyperdb.String())
746 pri.setkey("name") 727 pri.setkey("name")
747 pri.create(name="critical", order="1") 728 pri.create(name="critical", order="1")
748 pri.create(name="urgent", order="2") 729 pri.create(name="urgent", order="2")
766 Class(db, "issue", fixer=hyperdb.Multilink("user"), 747 Class(db, "issue", fixer=hyperdb.Multilink("user"),
767 topic=hyperdb.Multilink("keyword"), 748 topic=hyperdb.Multilink("keyword"),
768 priority=hyperdb.Link("priority"), 749 priority=hyperdb.Link("priority"),
769 status=hyperdb.Link("status")) 750 status=hyperdb.Link("status"))
770 751
771 (The "order" property hasn't been explained yet. It 752 (The "order" property hasn't been explained yet. It gets used by the
772 gets used by the Web user interface for sorting.) 753 Web user interface for sorting.)
773 754
774 The above isn't as pretty-looking as the schema specification 755 The above isn't as pretty-looking as the schema specification in the
775 in the first-stage submission, but it could be made just as easy 756 first-stage submission, but it could be made just as easy with the
776 with the addition of a convenience function like Choice 757 addition of a convenience function like Choice for setting up the
777 for setting up the "priority" and "status" classes:: 758 "priority" and "status" classes::
778 759
779 def Choice(name, *options): 760 def Choice(name, *options):
780 cl = Class(db, name, name=hyperdb.String(), order=hyperdb.String()) 761 cl = Class(db, name, name=hyperdb.String(), order=hyperdb.String())
781 for i in range(len(options)): 762 for i in range(len(options)):
782 cl.create(name=option[i], order=i) 763 cl.create(name=option[i], order=i)
784 765
785 766
786 Detector Interface 767 Detector Interface
787 ------------------ 768 ------------------
788 769
789 Detectors are Python functions that are triggered on certain 770 Detectors are Python functions that are triggered on certain kinds of
790 kinds of events. The definitions of the 771 events. The definitions of the functions live in Python modules placed
791 functions live in Python modules placed in a directory set aside 772 in a directory set aside for this purpose. Importing the Roundup
792 for this purpose. Importing the Roundup database module also 773 database module also imports all the modules in this directory, and the
793 imports all the modules in this directory, and the ``init()`` 774 ``init()`` function of each module is called when a database is opened
794 function of each module is called when a database is opened to 775 to provide it a chance to register its detectors.
795 provide it a chance to register its detectors.
796 776
797 There are two kinds of detectors: 777 There are two kinds of detectors:
798 778
799 1. an auditor is triggered just before modifying an item 779 1. an auditor is triggered just before modifying an item
800 2. a reactor is triggered just after an item has been modified 780 2. a reactor is triggered just after an item has been modified
801 781
802 When the Roundup database is about to perform a 782 When the Roundup database is about to perform a ``create()``, ``set()``,
803 ``create()``, ``set()``, ``retire()``, or ``restore`` 783 ``retire()``, or ``restore`` operation, it first calls any *auditors*
804 operation, it first calls any *auditors* that 784 that have been registered for that operation on that class. Any auditor
805 have been registered for that operation on that class. 785 may raise a *Reject* exception to abort the operation.
806 Any auditor may raise a *Reject* exception 786
807 to abort the operation. 787 If none of the auditors raises an exception, the database proceeds to
808 788 carry out the operation. After it's done, it then calls all of the
809 If none of the auditors raises an exception, the database 789 *reactors* that have been registered for the operation.
810 proceeds to carry out the operation. After it's done, it
811 then calls all of the *reactors* that have been registered
812 for the operation.
813 790
814 Detector Interface Specification 791 Detector Interface Specification
815 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 792 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
816 793
817 The ``audit()`` and ``react()`` methods 794 The ``audit()`` and ``react()`` methods register detectors on a given
818 register detectors on a given class of items:: 795 class of items::
819 796
820 class Class: 797 class Class:
821 def audit(self, event, detector): 798 def audit(self, event, detector):
822 """Register an auditor on this class. 799 """Register an auditor on this class.
823 800
824 'event' should be one of "create", "set", "retire", or "restore". 801 'event' should be one of "create", "set", "retire", or
825 'detector' should be a function accepting four arguments. 802 "restore". 'detector' should be a function accepting four
803 arguments.
826 """ 804 """
827 805
828 def react(self, event, detector): 806 def react(self, event, detector):
829 """Register a reactor on this class. 807 """Register a reactor on this class.
830 808
831 'event' should be one of "create", "set", "retire", or "restore". 809 'event' should be one of "create", "set", "retire", or
832 'detector' should be a function accepting four arguments. 810 "restore". 'detector' should be a function accepting four
811 arguments.
833 """ 812 """
834 813
835 Auditors are called with the arguments:: 814 Auditors are called with the arguments::
836 815
837 audit(db, cl, itemid, newdata) 816 audit(db, cl, itemid, newdata)
838 817
839 where ``db`` is the database, ``cl`` is an 818 where ``db`` is the database, ``cl`` is an instance of Class or
840 instance of Class or IssueClass within the database, and ``newdata`` 819 IssueClass within the database, and ``newdata`` is a dictionary mapping
841 is a dictionary mapping property names to values. 820 property names to values.
842 821
843 For a ``create()`` 822 For a ``create()`` operation, the ``itemid`` argument is None and
844 operation, the ``itemid`` argument is None and newdata 823 newdata contains all of the initial property values with which the item
845 contains all of the initial property values with which the item
846 is about to be created. 824 is about to be created.
847 825
848 For a ``set()`` operation, newdata 826 For a ``set()`` operation, newdata contains only the names and values of
849 contains only the names and values of properties that are about 827 properties that are about to be changed.
850 to be changed.
851 828
852 For a ``retire()`` or ``restore()`` operation, newdata is None. 829 For a ``retire()`` or ``restore()`` operation, newdata is None.
853 830
854 Reactors are called with the arguments:: 831 Reactors are called with the arguments::
855 832
856 react(db, cl, itemid, olddata) 833 react(db, cl, itemid, olddata)
857 834
858 where ``db`` is the database, ``cl`` is an 835 where ``db`` is the database, ``cl`` is an instance of Class or
859 instance of Class or IssueClass within the database, and ``olddata`` 836 IssueClass within the database, and ``olddata`` is a dictionary mapping
860 is a dictionary mapping property names to values. 837 property names to values.
861 838
862 For a ``create()`` 839 For a ``create()`` operation, the ``itemid`` argument is the id of the
863 operation, the ``itemid`` argument is the id of the
864 newly-created item and ``olddata`` is None. 840 newly-created item and ``olddata`` is None.
865 841
866 For a ``set()`` operation, ``olddata`` 842 For a ``set()`` operation, ``olddata`` contains the names and previous
867 contains the names and previous values of properties that were changed. 843 values of properties that were changed.
868 844
869 For a ``retire()`` or ``restore()`` operation, ``itemid`` is the id of 845 For a ``retire()`` or ``restore()`` operation, ``itemid`` is the id of
870 the retired or restored item and ``olddata`` is None. 846 the retired or restored item and ``olddata`` is None.
871 847
872 Detector Example 848 Detector Example
873 ~~~~~~~~~~~~~~~~ 849 ~~~~~~~~~~~~~~~~
874 850
875 Here is an example of detectors written for a hypothetical 851 Here is an example of detectors written for a hypothetical
876 project-management application, where users can signal approval 852 project-management application, where users can signal approval of a
877 of a project by adding themselves to an "approvals" list, and 853 project by adding themselves to an "approvals" list, and a project
878 a project proceeds when it has three approvals:: 854 proceeds when it has three approvals::
879 855
880 # Permit users only to add themselves to the "approvals" list. 856 # Permit users only to add themselves to the "approvals" list.
881 857
882 def check_approvals(db, cl, id, newdata): 858 def check_approvals(db, cl, id, newdata):
883 if newdata.has_key("approvals"): 859 if newdata.has_key("approvals"):
905 881
906 def init(db): 882 def init(db):
907 db.project.audit("set", check_approval) 883 db.project.audit("set", check_approval)
908 db.project.react("set", approve_project) 884 db.project.react("set", approve_project)
909 885
910 Here is another example of a detector that can allow or prevent 886 Here is another example of a detector that can allow or prevent the
911 the creation of new items. In this scenario, patches for a software 887 creation of new items. In this scenario, patches for a software project
912 project are submitted by sending in e-mail with an attached file, 888 are submitted by sending in e-mail with an attached file, and we want to
913 and we want to ensure that there are text/plain attachments on 889 ensure that there are text/plain attachments on the message. The
914 the message. The maintainer of the package can then apply the 890 maintainer of the package can then apply the patch by setting its status
915 patch by setting its status to "applied":: 891 to "applied"::
916 892
917 # Only accept attempts to create new patches that come with patch files. 893 # Only accept attempts to create new patches that come with patch files.
918 894
919 def check_new_patch(db, cl, id, newdata): 895 def check_new_patch(db, cl, id, newdata):
920 if not newdata["files"]: 896 if not newdata["files"]:
937 913
938 914
939 Command Interface 915 Command Interface
940 ----------------- 916 -----------------
941 917
942 The command interface is a very simple and minimal interface, 918 The command interface is a very simple and minimal interface, intended
943 intended only for quick searches and checks from the shell prompt. 919 only for quick searches and checks from the shell prompt. (Anything more
944 (Anything more interesting can simply be written in Python using 920 interesting can simply be written in Python using the Roundup database
945 the Roundup database module.) 921 module.)
946 922
947 Command Interface Specification 923 Command Interface Specification
948 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 924 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
949 925
950 A single command, roundup, provides basic access to 926 A single command, roundup, provides basic access to the hyperdatabase
951 the hyperdatabase from the command line:: 927 from the command line::
952 928
953 roundup-admin help 929 roundup-admin help
954 roundup-admin get [-list] designator[, designator,...] propname 930 roundup-admin get [-list] designator[, designator,...] propname
955 roundup-admin set designator[, designator,...] propname=value ... 931 roundup-admin set designator[, designator,...] propname=value ...
956 roundup-admin find [-list] classname propname=value ... 932 roundup-admin find [-list] classname propname=value ...
957 933
958 See ``roundup-admin help commands`` for a complete list of commands. 934 See ``roundup-admin help commands`` for a complete list of commands.
959 935
960 Property values are represented as strings in command arguments 936 Property values are represented as strings in command arguments and in
961 and in the printed results: 937 the printed results:
962 938
963 - Strings are, well, strings. 939 - Strings are, well, strings.
964 940
965 - Numbers are displayed the same as strings. 941 - Numbers are displayed the same as strings.
966 942
967 - Booleans are displayed as 'Yes' or 'No'. 943 - Booleans are displayed as 'Yes' or 'No'.
968 944
969 - Date values are printed in the full date format in the local 945 - Date values are printed in the full date format in the local time
970 time zone, and accepted in the full format or any of the partial 946 zone, and accepted in the full format or any of the partial formats
971 formats explained above. 947 explained above.
972 948
973 - Link values are printed as item designators. When given as 949 - Link values are printed as item designators. When given as an
974 an argument, item designators and key strings are both accepted. 950 argument, item designators and key strings are both accepted.
975 951
976 - Multilink values are printed as lists of item designators 952 - Multilink values are printed as lists of item designators joined by
977 joined by commas. When given as an argument, item designators 953 commas. When given as an argument, item designators and key strings
978 and key strings are both accepted; an empty string, a single item, 954 are both accepted; an empty string, a single item, or a list of items
979 or a list of items joined by commas is accepted. 955 joined by commas is accepted.
980 956
981 When multiple items are specified to the 957 When multiple items are specified to the roundup get or roundup set
982 roundup get or roundup set 958 commands, the specified properties are retrieved or set on all the
983 commands, the specified properties are retrieved or set 959 listed items.
984 on all the listed items. 960
985 961 When multiple results are returned by the roundup get or roundup find
986 When multiple results are returned by the roundup get 962 commands, they are printed one per line (default) or joined by commas
987 or roundup find commands, they are printed one per 963 (with the -list) option.
988 line (default) or joined by commas (with the -list) option.
989 964
990 Usage Example 965 Usage Example
991 ~~~~~~~~~~~~~ 966 ~~~~~~~~~~~~~
992 967
993 To find all messages regarding in-progress issues that 968 To find all messages regarding in-progress issues that contain the word
994 contain the word "spam", for example, you could execute the 969 "spam", for example, you could execute the following command from the
995 following command from the directory where the database 970 directory where the database dumps its files::
996 dumps its files::
997 971
998 shell% for issue in `roundup find issue status=in-progress`; do 972 shell% for issue in `roundup find issue status=in-progress`; do
999 > grep -l spam `roundup get $issue messages` 973 > grep -l spam `roundup get $issue messages`
1000 > done 974 > done
1001 msg23 975 msg23
1016 990
1017 991
1018 E-mail User Interface 992 E-mail User Interface
1019 --------------------- 993 ---------------------
1020 994
1021 The Roundup system must be assigned an e-mail address 995 The Roundup system must be assigned an e-mail address at which to
1022 at which to receive mail. Messages should be piped to 996 receive mail. Messages should be piped to the Roundup mail-handling
1023 the Roundup mail-handling script by the mail delivery 997 script by the mail delivery system (e.g. using an alias beginning with
1024 system (e.g. using an alias beginning with "|" for sendmail). 998 "|" for sendmail).
1025 999
1026 Message Processing 1000 Message Processing
1027 ~~~~~~~~~~~~~~~~~~ 1001 ~~~~~~~~~~~~~~~~~~
1028 1002
1029 Incoming messages are examined for multiple parts. 1003 Incoming messages are examined for multiple parts. In a multipart/mixed
1030 In a multipart/mixed message or part, each subpart is 1004 message or part, each subpart is extracted and examined. In a
1031 extracted and examined. In a multipart/alternative 1005 multipart/alternative message or part, we look for a text/plain subpart
1032 message or part, we look for a text/plain subpart and 1006 and ignore the other parts. The text/plain subparts are assembled to
1033 ignore the other parts. The text/plain subparts are 1007 form the textual body of the message, to be stored in the file
1034 assembled to form the textual body of the message, to 1008 associated with a "msg" class item. Any parts of other types are each
1035 be stored in the file associated with a "msg" class item. 1009 stored in separate files and given "file" class items that are linked to
1036 Any parts of other types are each stored in separate
1037 files and given "file" class items that are linked to
1038 the "msg" item. 1010 the "msg" item.
1039 1011
1040 The "summary" property on message items is taken from 1012 The "summary" property on message items is taken from the first
1041 the first non-quoting section in the message body. 1013 non-quoting section in the message body. The message body is divided
1042 The message body is divided into sections by blank lines. 1014 into sections by blank lines. Sections where the second and all
1043 Sections where the second and all subsequent lines begin 1015 subsequent lines begin with a ">" or "|" character are considered
1044 with a ">" or "|" character are considered "quoting 1016 "quoting sections". The first line of the first non-quoting section
1045 sections". The first line of the first non-quoting 1017 becomes the summary of the message.
1046 section becomes the summary of the message. 1018
1047 1019 All of the addresses in the To: and Cc: headers of the incoming message
1048 All of the addresses in the To: and Cc: headers of the 1020 are looked up among the user items, and the corresponding users are
1049 incoming message are looked up among the user items, and 1021 placed in the "recipients" property on the new "msg" item. The address
1050 the corresponding users are placed in the "recipients" 1022 in the From: header similarly determines the "author" property of the
1051 property on the new "msg" item. The address in the From: 1023 new "msg" item. The default handling for addresses that don't have
1052 header similarly determines the "author" property of the 1024 corresponding users is to create new users with no passwords and a
1053 new "msg" item. 1025 username equal to the address. (The web interface does not permit
1054 The default handling for 1026 logins for users with no passwords.) If we prefer to reject mail from
1055 addresses that don't have corresponding users is to create 1027 outside sources, we can simply register an auditor on the "user" class
1056 new users with no passwords and a username equal to the 1028 that prevents the creation of user items with no passwords.
1057 address. (The web interface does not permit logins for 1029
1058 users with no passwords.) If we prefer to reject mail from 1030 The subject line of the incoming message is examined to determine
1059 outside sources, we can simply register an auditor on the 1031 whether the message is an attempt to create a new issue or to discuss an
1060 "user" class that prevents the creation of user items with 1032 existing issue. A designator enclosed in square brackets is sought as
1061 no passwords. 1033 the first thing on the subject line (after skipping any "Fwd:" or "Re:"
1062 1034 prefixes).
1063 The subject line of the incoming message is examined to 1035
1064 determine whether the message is an attempt to create a new 1036 If an issue designator (class name and id number) is found there, the
1065 issue or to discuss an existing issue. A designator enclosed 1037 newly created "msg" item is added to the "messages" property for that
1066 in square brackets is sought as the first thing on the 1038 issue, and any new "file" items are added to the "files" property for
1067 subject line (after skipping any "Fwd:" or "Re:" prefixes). 1039 the issue.
1068 1040
1069 If an issue designator (class name and id number) is found 1041 If just an issue class name is found there, we attempt to create a new
1070 there, the newly created "msg" item is added to the "messages" 1042 issue of that class with its "messages" property initialized to contain
1071 property for that issue, and any new "file" items are added to 1043 the new "msg" item and its "files" property initialized to contain any
1072 the "files" property for the issue. 1044 new "file" items.
1073 1045
1074 If just an issue class name is found there, we attempt to 1046 Both cases may trigger detectors (in the first case we are calling the
1075 create a new issue of that class with its "messages" property 1047 set() method to add the message to the issue's spool; in the second case
1076 initialized to contain the new "msg" item and its "files" 1048 we are calling the create() method to create a new item). If an auditor
1077 property initialized to contain any new "file" items. 1049 raises an exception, the original message is bounced back to the sender
1078 1050 with the explanatory message given in the exception.
1079 Both cases may trigger detectors (in the first case we
1080 are calling the set() method to add the message to the
1081 issue's spool; in the second case we are calling the
1082 create() method to create a new item). If an auditor
1083 raises an exception, the original message is bounced back to
1084 the sender with the explanatory message given in the exception.
1085 1051
1086 Nosy Lists 1052 Nosy Lists
1087 ~~~~~~~~~~ 1053 ~~~~~~~~~~
1088 1054
1089 A standard detector is provided that watches for additions 1055 A standard detector is provided that watches for additions to the
1090 to the "messages" property. When a new message is added, the 1056 "messages" property. When a new message is added, the detector sends it
1091 detector sends it to all the users on the "nosy" list for the 1057 to all the users on the "nosy" list for the issue that are not already
1092 issue that are not already on the "recipients" list of the 1058 on the "recipients" list of the message. Those users are then appended
1093 message. Those users are then appended to the "recipients" 1059 to the "recipients" property on the message, so multiple copies of a
1094 property on the message, so multiple copies of a message 1060 message are never sent to the same user. The journal recorded by the
1095 are never sent to the same user. The journal recorded by 1061 hyperdatabase on the "recipients" property then provides a log of when
1096 the hyperdatabase on the "recipients" property then provides 1062 the message was sent to whom.
1097 a log of when the message was sent to whom.
1098 1063
1099 Setting Properties 1064 Setting Properties
1100 ~~~~~~~~~~~~~~~~~~ 1065 ~~~~~~~~~~~~~~~~~~
1101 1066
1102 The e-mail interface also provides a simple way to set 1067 The e-mail interface also provides a simple way to set properties on
1103 properties on issues. At the end of the subject line, 1068 issues. At the end of the subject line, ``propname=value`` pairs can be
1104 ``propname=value`` pairs can be 1069 specified in square brackets, using the same conventions as for the
1105 specified in square brackets, using the same conventions 1070 roundup ``set`` shell command.
1106 as for the roundup ``set`` shell command.
1107 1071
1108 1072
1109 Web User Interface 1073 Web User Interface
1110 ------------------ 1074 ------------------
1111 1075
1112 The web interface is provided by a CGI script that can be 1076 The web interface is provided by a CGI script that can be run under any
1113 run under any web server. A simple web server can easily be 1077 web server. A simple web server can easily be built on the standard
1114 built on the standard CGIHTTPServer module, and 1078 CGIHTTPServer module, and should also be included in the distribution
1115 should also be included in the distribution for quick 1079 for quick out-of-the-box deployment.
1116 out-of-the-box deployment. 1080
1117 1081 The user interface is constructed from a number of template files
1118 The user interface is constructed from a number of template 1082 containing mostly HTML. Among the HTML tags in templates are
1119 files containing mostly HTML. Among the HTML tags in templates 1083 interspersed some nonstandard tags, which we use as placeholders to be
1120 are interspersed some nonstandard tags, which we use as 1084 replaced by properties and their values.
1121 placeholders to be replaced by properties and their values.
1122 1085
1123 Views and View Specifiers 1086 Views and View Specifiers
1124 ~~~~~~~~~~~~~~~~~~~~~~~~~ 1087 ~~~~~~~~~~~~~~~~~~~~~~~~~
1125 1088
1126 There are two main kinds of views: *index* views and *issue* views. 1089 There are two main kinds of views: *index* views and *issue* views. An
1127 An index view displays a list of issues of a particular class, 1090 index view displays a list of issues of a particular class, optionally
1128 optionally sorted and filtered as requested. An issue view 1091 sorted and filtered as requested. An issue view presents the properties
1129 presents the properties of a particular issue for editing 1092 of a particular issue for editing and displays the message spool for the
1130 and displays the message spool for the issue. 1093 issue.
1131 1094
1132 A view specifier is a string that specifies 1095 A view specifier is a string that specifies all the options needed to
1133 all the options needed to construct a particular view. 1096 construct a particular view. It goes after the URL to the Roundup CGI
1134 It goes after the URL to the Roundup CGI script or the 1097 script or the web server to form the complete URL to a view. When the
1135 web server to form the complete URL to a view. When the 1098 result of selecting a link or submitting a form takes the user to a new
1136 result of selecting a link or submitting a form takes 1099 view, the Web browser should be redirected to a canonical location
1137 the user to a new view, the Web browser should be redirected 1100 containing a complete view specifier so that the view can be bookmarked.
1138 to a canonical location containing a complete view specifier
1139 so that the view can be bookmarked.
1140 1101
1141 Displaying Properties 1102 Displaying Properties
1142 ~~~~~~~~~~~~~~~~~~~~~ 1103 ~~~~~~~~~~~~~~~~~~~~~
1143 1104
1144 Properties appear in the user interface in three contexts: 1105 Properties appear in the user interface in three contexts: in indices,
1145 in indices, in editors, and as search filters. For each type of 1106 in editors, and as search filters. For each type of property, there are
1146 property, there are several display possibilities. For example, 1107 several display possibilities. For example, in an index view, a string
1147 in an index view, a string property may just be printed as 1108 property may just be printed as a plain string, but in an editor view,
1148 a plain string, but in an editor view, that property should 1109 that property should be displayed in an editable field.
1149 be displayed in an editable field. 1110
1150 1111 The display of a property is handled by functions in the
1151 The display of a property is handled by functions in 1112 ``cgi.templating`` module.
1152 the ``cgi.templating`` module.
1153 1113
1154 Displayer functions are triggered by ``tal:content`` or ``tal:replace`` 1114 Displayer functions are triggered by ``tal:content`` or ``tal:replace``
1155 tag attributes in templates. The value of the attribute 1115 tag attributes in templates. The value of the attribute provides an
1156 provides an expression for calling the displayer function. 1116 expression for calling the displayer function. For example, the
1157 For example, the occurrence of:: 1117 occurrence of::
1158 1118
1159 tal:content="context/status/plain" 1119 tal:content="context/status/plain"
1160 1120
1161 in a template triggers a call to:: 1121 in a template triggers a call to::
1162 1122
1163 context['status'].plain() 1123 context['status'].plain()
1164 1124
1165 where the context would be an item of the "issue" class. The displayer 1125 where the context would be an item of the "issue" class. The displayer
1166 functions can accept extra arguments to further specify 1126 functions can accept extra arguments to further specify details about
1167 details about the widgets that should be generated. 1127 the widgets that should be generated.
1168 1128
1169 Some of the standard displayer functions include: 1129 Some of the standard displayer functions include:
1170 1130
1171 ========= ==================================================================== 1131 ========= ==============================================================
1172 Function Description 1132 Function Description
1173 ========= ==================================================================== 1133 ========= ==============================================================
1174 plain display a String property directly; 1134 plain display a String property directly;
1175 display a Date property in a specified time zone with an option 1135 display a Date property in a specified time zone with an
1176 to omit the time from the date stamp; for a Link or Multilink 1136 option to omit the time from the date stamp; for a Link or
1177 property, display the key strings of the linked items (or the 1137 Multilink property, display the key strings of the linked
1178 ids if the linked class has no key property) 1138 items (or the ids if the linked class has no key property)
1179 field display a property like the plain displayer above, but in a text 1139 field display a property like the plain displayer above, but in a
1180 field to be edited 1140 text field to be edited
1181 menu for a Link property, display a menu of the available choices 1141 menu for a Link property, display a menu of the available choices
1182 ========= ==================================================================== 1142 ========= ==============================================================
1183 1143
1184 See the `customisation`_ documentation for the complete list. 1144 See the `customisation`_ documentation for the complete list.
1185 1145
1186 1146
1187 Index Views 1147 Index Views
1188 ~~~~~~~~~~~ 1148 ~~~~~~~~~~~
1189 1149
1190 An index view contains two sections: a filter section 1150 An index view contains two sections: a filter section and an index
1191 and an index section. 1151 section. The filter section provides some widgets for selecting which
1192 The filter section provides some widgets for selecting 1152 issues appear in the index. The index section is a table of issues.
1193 which issues appear in the index. The index section is
1194 a table of issues.
1195 1153
1196 Index View Specifiers 1154 Index View Specifiers
1197 """"""""""""""""""""" 1155 """""""""""""""""""""
1198 1156
1199 An index view specifier looks like this (whitespace 1157 An index view specifier looks like this (whitespace has been added for
1200 has been added for clarity):: 1158 clarity)::
1201 1159
1202 /issue?status=unread,in-progress,resolved& 1160 /issue?status=unread,in-progress,resolved&
1203 topic=security,ui& 1161 topic=security,ui&
1204 :group=priority& 1162 :group=priority&
1205 :sort=-activity& 1163 :sort=-activity&
1206 :filters=status,topic& 1164 :filters=status,topic&
1207 :columns=title,status,fixer 1165 :columns=title,status,fixer
1208 1166
1209 1167
1210 The index view is determined by two parts of the 1168 The index view is determined by two parts of the specifier: the layout
1211 specifier: the layout part and the filter part. 1169 part and the filter part. The layout part consists of the query
1212 The layout part consists of the query parameters that 1170 parameters that begin with colons, and it determines the way that the
1213 begin with colons, and it determines the way that the 1171 properties of selected items are displayed. The filter part consists of
1214 properties of selected items are displayed. 1172 all the other query parameters, and it determines the criteria by which
1215 The filter part consists of all the other query parameters, 1173 items are selected for display.
1216 and it determines the criteria by which items 1174
1217 are selected for display. 1175 The filter part is interactively manipulated with the form widgets
1218 1176 displayed in the filter section. The layout part is interactively
1219 The filter part is interactively manipulated with 1177 manipulated by clicking on the column headings in the table.
1220 the form widgets displayed in the filter section. The 1178
1221 layout part is interactively manipulated by clicking 1179 The filter part selects the union of the sets of issues with values
1222 on the column headings in the table. 1180 matching any specified Link properties and the intersection of the sets
1223 1181 of issues with values matching any specified Multilink properties.
1224 The filter part selects the union of the 1182
1225 sets of issues with values matching any specified Link 1183 The example specifies an index of "issue" items. Only issues with a
1226 properties and the intersection of the sets 1184 "status" of either "unread" or "in-progres" or "resolved" are displayed,
1227 of issues with values matching any specified Multilink 1185 and only issues with "topic" values including both "security" and "ui"
1228 properties. 1186 are displayed. The issues are grouped by priority, arranged in
1229 1187 ascending order; and within groups, sorted by activity, arranged in
1230 The example specifies an index of "issue" items. 1188 descending order. The filter section shows filters for the "status" and
1231 Only issues with a "status" of either 1189 "topic" properties, and the table includes columns for the "title",
1232 "unread" or "in-progres" or "resolved" are displayed, 1190 "status", and "fixer" properties.
1233 and only issues with "topic" values including both 1191
1234 "security" and "ui" are displayed. The issues 1192 Associated with each issue class is a default layout specifier. The
1235 are grouped by priority, arranged in ascending order; 1193 layout specifier in the above example is the default layout to be
1236 and within groups, sorted by activity, arranged in 1194 provided with the default bug-tracker schema described above in section
1237 descending order. The filter section shows filters 1195 4.4.
1238 for the "status" and "topic" properties, and the
1239 table includes columns for the "title", "status", and
1240 "fixer" properties.
1241
1242 Associated with each issue class is a default
1243 layout specifier. The layout specifier in the above
1244 example is the default layout to be provided with
1245 the default bug-tracker schema described above in
1246 section 4.4.
1247 1196
1248 Index Section 1197 Index Section
1249 """"""""""""" 1198 """""""""""""
1250 1199
1251 The template for an index section describes one row of 1200 The template for an index section describes one row of the index table.
1252 the index table. 1201 Fragments protected by a ``tal:condition="request/show/<property>"`` are
1253 Fragments enclosed in ``<property>...</property>`` 1202 included or omitted depending on whether the view specifier requests a
1254 tags are included or omitted depending on whether the 1203 column for a particular property. The table cells are filled by the
1255 view specifier requests a column for a particular property. 1204 ``tal:content="context/<property>"`` directive, which displays the value
1256 The table cells should contain <display> tags 1205 of the property.
1257 to display the values of the issue's properties.
1258 1206
1259 Here's a simple example of an index template:: 1207 Here's a simple example of an index template::
1260 1208
1261 <tr> 1209 <tr>
1262 <td tal:condition="request/show/title" tal:content="contex/title"></td> 1210 <td tal:condition="request/show/title"
1263 <td tal:condition="request/show/status" tal:content="contex/status"></td> 1211 tal:content="contex/title"></td>
1264 <td tal:condition="request/show/fixer" tal:content="contex/fixer"></td> 1212 <td tal:condition="request/show/status"
1213 tal:content="contex/status"></td>
1214 <td tal:condition="request/show/fixer"
1215 tal:content="contex/fixer"></td>
1265 </tr> 1216 </tr>
1266 1217
1267 Sorting 1218 Sorting
1268 """"""" 1219 """""""
1269 1220
1270 String and Date values are sorted in the natural way. 1221 String and Date values are sorted in the natural way. Link properties
1271 Link properties are sorted according to the value of the 1222 are sorted according to the value of the "order" property on the linked
1272 "order" property on the linked items if it is present; or 1223 items if it is present; or otherwise on the key string of the linked
1273 otherwise on the key string of the linked items; or 1224 items; or finally on the item ids. Multilink properties are sorted
1274 finally on the item ids. Multilink properties are 1225 according to how many links are present.
1275 sorted according to how many links are present.
1276 1226
1277 Issue Views 1227 Issue Views
1278 ~~~~~~~~~~~ 1228 ~~~~~~~~~~~
1279 1229
1280 An issue view contains an editor section and a spool section. 1230 An issue view contains an editor section and a spool section. At the top
1281 At the top of an issue view, links to superseding and superseded 1231 of an issue view, links to superseding and superseded issues are always
1282 issues are always displayed. 1232 displayed.
1283 1233
1284 Issue View Specifiers 1234 Issue View Specifiers
1285 """"""""""""""""""""" 1235 """""""""""""""""""""
1286 1236
1287 An issue view specifier is simply the issue's designator:: 1237 An issue view specifier is simply the issue's designator::
1290 1240
1291 1241
1292 Editor Section 1242 Editor Section
1293 """""""""""""" 1243 """"""""""""""
1294 1244
1295 The editor section is generated from a template 1245 The editor section is generated from a template containing
1296 containing <display> tags to insert 1246 ``tal:content="context/<property>/<widget>"`` directives to insert the
1297 the appropriate widgets for editing properties. 1247 appropriate widgets for editing properties.
1298 1248
1299 Here's an example of a basic editor template:: 1249 Here's an example of a basic editor template::
1300 1250
1301 <table> 1251 <table>
1302 <tr> 1252 <tr>
1315 <textarea name=":note" rows=5 cols=60></textarea> 1265 <textarea name=":note" rows=5 cols=60></textarea>
1316 </td> 1266 </td>
1317 </tr> 1267 </tr>
1318 </table> 1268 </table>
1319 1269
1320 As shown in the example, the editor template can also include a ":note" field, 1270 As shown in the example, the editor template can also include a ":note"
1321 which is a text area for entering a note to go along with a change. 1271 field, which is a text area for entering a note to go along with a
1322 1272 change.
1323 When a change is submitted, the system automatically 1273
1324 generates a message describing the changed properties. 1274 When a change is submitted, the system automatically generates a message
1325 The message displays all of the property values on the 1275 describing the changed properties. The message displays all of the
1326 issue and indicates which ones have changed. 1276 property values on the issue and indicates which ones have changed. An
1327 An example of such a message might be this:: 1277 example of such a message might be this::
1328 1278
1329 title: Polly Parrot is dead 1279 title: Polly Parrot is dead
1330 priority: critical 1280 priority: critical
1331 status: unread -> in-progress 1281 status: unread -> in-progress
1332 fixer: (none) 1282 fixer: (none)
1333 keywords: parrot,plumage,perch,nailed,dead 1283 keywords: parrot,plumage,perch,nailed,dead
1334 1284
1335 If a note is given in the ":note" field, the note is 1285 If a note is given in the ":note" field, the note is appended to the
1336 appended to the description. The message is then added 1286 description. The message is then added to the issue's message spool
1337 to the issue's message spool (thus triggering the standard 1287 (thus triggering the standard detector to react by sending out this
1338 detector to react by sending out this message to the nosy list). 1288 message to the nosy list).
1339 1289
1340 Spool Section 1290 Spool Section
1341 """"""""""""" 1291 """""""""""""
1342 1292
1343 The spool section lists messages in the issue's "messages" 1293 The spool section lists messages in the issue's "messages" property.
1344 property. The index of messages displays the "date", "author", 1294 The index of messages displays the "date", "author", and "summary"
1345 and "summary" properties on the message items, and selecting a 1295 properties on the message items, and selecting a message takes you to
1346 message takes you to its content. 1296 its content.
1347 1297
1348 Access Control 1298 Access Control
1349 -------------- 1299 --------------
1350 1300
1351 At each point that requires an action to be performed, the security mechanisms 1301 At each point that requires an action to be performed, the security
1352 are asked if the current user has permission. This permission is defined as a 1302 mechanisms are asked if the current user has permission. This permission
1353 Permission. 1303 is defined as a Permission.
1354 1304
1355 Individual assignment of Permission to user is unwieldy. The concept of a 1305 Individual assignment of Permission to user is unwieldy. The concept of
1356 Role, which encompasses several Permissions and may be assigned to many Users, 1306 a Role, which encompasses several Permissions and may be assigned to
1357 is quite well developed in many projects. Roundup will take this path, and 1307 many Users, is quite well developed in many projects. Roundup will take
1358 allow the multiple assignment of Roles to Users, and multiple Permissions to 1308 this path, and allow the multiple assignment of Roles to Users, and
1359 Roles. These definitions are not persistent - they're defined when the 1309 multiple Permissions to Roles. These definitions are not persistent -
1360 application initialises. 1310 they're defined when the application initialises.
1361 1311
1362 There will be two levels of Permission. The Class level permissions define 1312 There will be two levels of Permission. The Class level permissions
1363 logical permissions associated with all items of a particular class (or all 1313 define logical permissions associated with all items of a particular
1364 classes). The Item level permissions define logical permissions associated 1314 class (or all classes). The Item level permissions define logical
1365 with specific items by way of their user-linked properties. 1315 permissions associated with specific items by way of their user-linked
1316 properties.
1366 1317
1367 1318
1368 Access Control Interface Specification 1319 Access Control Interface Specification
1369 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1320 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1370 1321
1374 ''' Defines a Permission with the attributes 1325 ''' Defines a Permission with the attributes
1375 - name 1326 - name
1376 - description 1327 - description
1377 - klass (optional) 1328 - klass (optional)
1378 1329
1379 The klass may be unset, indicating that this permission is not 1330 The klass may be unset, indicating that this permission is
1380 locked to a particular hyperdb class. There may be multiple 1331 not locked to a particular hyperdb class. There may be
1381 Permissions for the same name for different classes. 1332 multiple Permissions for the same name for different
1333 classes.
1382 ''' 1334 '''
1383 1335
1384 class Role: 1336 class Role:
1385 ''' Defines a Role with the attributes 1337 ''' Defines a Role with the attributes
1386 - name 1338 - name
1388 - permissions 1340 - permissions
1389 ''' 1341 '''
1390 1342
1391 class Security: 1343 class Security:
1392 def __init__(self, db): 1344 def __init__(self, db):
1393 ''' Initialise the permission and role stores, and add in the 1345 ''' Initialise the permission and role stores, and add in
1394 base roles (for admin user). 1346 the base roles (for admin user).
1395 ''' 1347 '''
1396 1348
1397 def getPermission(self, permission, classname=None): 1349 def getPermission(self, permission, classname=None):
1398 ''' Find the Permission matching the name and for the class, if the 1350 ''' Find the Permission matching the name and for the class,
1399 classname is specified. 1351 if the classname is specified.
1400 1352
1401 Raise ValueError if there is no exact match. 1353 Raise ValueError if there is no exact match.
1402 ''' 1354 '''
1403 1355
1404 def hasPermission(self, permission, userid, classname=None): 1356 def hasPermission(self, permission, userid, classname=None):
1405 ''' Look through all the Roles, and hence Permissions, and see if 1357 ''' Look through all the Roles, and hence Permissions, and
1406 "permission" is there for the specified classname. 1358 see if "permission" is there for the specified
1359 classname.
1407 ''' 1360 '''
1408 1361
1409 def hasItemPermission(self, classname, itemid, **propspec): 1362 def hasItemPermission(self, classname, itemid, **propspec):
1410 ''' Check the named properties of the given item to see if the 1363 ''' Check the named properties of the given item to see if
1411 userid appears in them. If it does, then the user is granted 1364 the userid appears in them. If it does, then the user is
1412 this permission check. 1365 granted this permission check.
1413 1366
1414 'propspec' consists of a set of properties and values that 1367 'propspec' consists of a set of properties and values
1415 must be present on the given item for access to be granted. 1368 that must be present on the given item for access to be
1416 1369 granted.
1417 If a property is a Link, the value must match the property 1370
1418 value. If a property is a Multilink, the value must appear 1371 If a property is a Link, the value must match the
1419 in the Multilink list. 1372 property value. If a property is a Multilink, the value
1373 must appear in the Multilink list.
1420 ''' 1374 '''
1421 1375
1422 def addPermission(self, **propspec): 1376 def addPermission(self, **propspec):
1423 ''' Create a new Permission with the properties defined in 1377 ''' Create a new Permission with the properties defined in
1424 'propspec' 1378 'propspec'
1425 ''' 1379 '''
1426 1380
1427 def addRole(self, **propspec): 1381 def addRole(self, **propspec):
1428 ''' Create a new Role with the properties defined in 'propspec' 1382 ''' Create a new Role with the properties defined in
1383 'propspec'
1429 ''' 1384 '''
1430 1385
1431 def addPermissionToRole(self, rolename, permission): 1386 def addPermissionToRole(self, rolename, permission):
1432 ''' Add the permission to the role's permission list. 1387 ''' Add the permission to the role's permission list.
1433 1388
1438 permissions like so (this example is ``cgi/client.py``):: 1393 permissions like so (this example is ``cgi/client.py``)::
1439 1394
1440 def initialiseSecurity(security): 1395 def initialiseSecurity(security):
1441 ''' Create some Permissions and Roles on the security object 1396 ''' Create some Permissions and Roles on the security object
1442 1397
1443 This function is directly invoked by security.Security.__init__() 1398 This function is directly invoked by
1444 as a part of the Security object instantiation. 1399 security.Security.__init__() as a part of the Security
1400 object instantiation.
1445 ''' 1401 '''
1446 p = security.addPermission(name="Web Registration", 1402 p = security.addPermission(name="Web Registration",
1447 description="Anonymous users may register through the web") 1403 description="Anonymous users may register through the web")
1448 security.addToRole('Anonymous', p) 1404 security.addToRole('Anonymous', p)
1449 1405
1450 Detectors may also define roles in their init() function:: 1406 Detectors may also define roles in their init() function::
1451 1407
1452 def init(db): 1408 def init(db):
1453 # register an auditor that checks that a user has the "May Resolve" 1409 # register an auditor that checks that a user has the "May
1454 # Permission before allowing them to set an issue status to "resolved" 1410 # Resolve" Permission before allowing them to set an issue
1411 # status to "resolved"
1455 db.issue.audit('set', checkresolvedok) 1412 db.issue.audit('set', checkresolvedok)
1456 p = db.security.addPermission(name="May Resolve", klass="issue") 1413 p = db.security.addPermission(name="May Resolve", klass="issue")
1457 security.addToRole('Manager', p) 1414 security.addToRole('Manager', p)
1458 1415
1459 The tracker dbinit module then has in ``open()``:: 1416 The tracker dbinit module then has in ``open()``::
1485 # all ok 1442 # all ok
1486 1443
1487 if db.security.hasItemPermission('issue', itemid, assignedto=userid): 1444 if db.security.hasItemPermission('issue', itemid, assignedto=userid):
1488 # all ok 1445 # all ok
1489 1446
1490 Code in the core will make use of these methods, as should code in auditors in 1447 Code in the core will make use of these methods, as should code in
1491 custom templates. The HTML templating may access the access controls through 1448 auditors in custom templates. The HTML templating may access the access
1492 the *user* attribute of the *request* variable. It exposes a ``hasPermission()`` 1449 controls through the *user* attribute of the *request* variable. It
1493 method:: 1450 exposes a ``hasPermission()`` method::
1494 1451
1495 tal:condition="python:request.user.hasPermission('Edit', 'issue')" 1452 tal:condition="python:request.user.hasPermission('Edit', 'issue')"
1496 1453
1497 or, if the *context* is *issue*, then the following is the same:: 1454 or, if the *context* is *issue*, then the following is the same::
1498 1455
1500 1457
1501 1458
1502 Authentication of Users 1459 Authentication of Users
1503 ~~~~~~~~~~~~~~~~~~~~~~~ 1460 ~~~~~~~~~~~~~~~~~~~~~~~
1504 1461
1505 Users must be authenticated correctly for the above controls to work. This is 1462 Users must be authenticated correctly for the above controls to work.
1506 not done in the current mail gateway at all. Use of digital signing of 1463 This is not done in the current mail gateway at all. Use of digital
1507 messages could alleviate this problem. 1464 signing of messages could alleviate this problem.
1508 1465
1509 The exact mechanism of registering the digital signature should be flexible, 1466 The exact mechanism of registering the digital signature should be
1510 with perhaps a level of trust. Users who supply their signature through their 1467 flexible, with perhaps a level of trust. Users who supply their
1511 first message into the tracker should be at a lower level of trust to those 1468 signature through their first message into the tracker should be at a
1512 who supply their signature to an admin for submission to their user details. 1469 lower level of trust to those who supply their signature to an admin for
1470 submission to their user details.
1513 1471
1514 1472
1515 Anonymous Users 1473 Anonymous Users
1516 ~~~~~~~~~~~~~~~ 1474 ~~~~~~~~~~~~~~~
1517 1475
1521 1479
1522 1480
1523 Use Cases 1481 Use Cases
1524 ~~~~~~~~~ 1482 ~~~~~~~~~
1525 1483
1526 public - end users can submit bugs, request new features, request support 1484 public - end users can submit bugs, request new features, request
1527 The Users would be given the default "User" Role which gives "View" and 1485 support
1528 "Edit" Permission to the "issue" class. 1486 The Users would be given the default "User" Role which gives "View"
1529 developer - developers can fix bugs, implement new features, provide support 1487 and "Edit" Permission to the "issue" class.
1530 A new Role "Developer" is created with the Permission "Fixer" which is 1488 developer - developers can fix bugs, implement new features, provide
1531 checked for in custom auditors that see whether the issue is being 1489 support
1532 resolved with a particular resolution ("fixed", "implemented", 1490 A new Role "Developer" is created with the Permission "Fixer" which
1491 is checked for in custom auditors that see whether the issue is
1492 being resolved with a particular resolution ("fixed", "implemented",
1533 "supported") and allows that resolution only if the permission is 1493 "supported") and allows that resolution only if the permission is
1534 available. 1494 available.
1535 manager - approvers/managers can approve new features and signoff bug fixes 1495 manager - approvers/managers can approve new features and signoff bug
1536 A new Role "Manager" is created with the Permission "Signoff" which is 1496 fixes
1537 checked for in custom auditors that see whether the issue status is being 1497 A new Role "Manager" is created with the Permission "Signoff" which
1538 changed similar to the developer example. 1498 is checked for in custom auditors that see whether the issue status
1539 admin - administrators can add users and set user's roles 1499 is being changed similar to the developer example. admin -
1540 The existing Role "Admin" has the Permissions "Edit" for all classes 1500 administrators can add users and set user's roles The existing Role
1541 (including "user") and "Web Roles" which allow the desired actions. 1501 "Admin" has the Permissions "Edit" for all classes (including
1542 system - automated request handlers running various report/escalation scripts 1502 "user") and "Web Roles" which allow the desired actions.
1543 A combination of existing and new Roles, Permissions and auditors could 1503 system - automated request handlers running various report/escalation
1544 be used here. 1504 scripts
1505 A combination of existing and new Roles, Permissions and auditors
1506 could be used here.
1545 privacy - issues that are only visible to some users 1507 privacy - issues that are only visible to some users
1546 A new property is added to the issue which marks the user or group of 1508 A new property is added to the issue which marks the user or group
1547 users who are allowed to view and edit the issue. An auditor will check 1509 of users who are allowed to view and edit the issue. An auditor will
1548 for edit access, and the template user object can check for view access. 1510 check for edit access, and the template user object can check for
1511 view access.
1549 1512
1550 1513
1551 Deployment Scenarios 1514 Deployment Scenarios
1552 -------------------- 1515 --------------------
1553 1516
1554 The design described above should be general enough 1517 The design described above should be general enough to permit the use of
1555 to permit the use of Roundup for bug tracking, managing 1518 Roundup for bug tracking, managing projects, managing patches, or
1556 projects, managing patches, or holding discussions. By 1519 holding discussions. By using items of multiple types, one could deploy
1557 using items of multiple types, one could deploy a system 1520 a system that maintains requirement specifications, catalogs bugs, and
1558 that maintains requirement specifications, catalogs bugs, 1521 manages submitted patches, where patches could be linked to the bugs and
1559 and manages submitted patches, where patches could be 1522 requirements they address.
1560 linked to the bugs and requirements they address.
1561 1523
1562 1524
1563 Acknowledgements 1525 Acknowledgements
1564 ---------------- 1526 ----------------
1565 1527
1566 My thanks are due to Christy Heyl for 1528 My thanks are due to Christy Heyl for reviewing and contributing
1567 reviewing and contributing suggestions to this paper 1529 suggestions to this paper and motivating me to get it done, and to Jesse
1568 and motivating me to get it done, and to 1530 Vincent, Mark Miller, Christopher Simons, Jeff Dunmall, Wayne Gramlich,
1569 Jesse Vincent, Mark Miller, Christopher Simons, 1531 and Dean Tribble for their assistance with the first-round submission.
1570 Jeff Dunmall, Wayne Gramlich, and Dean Tribble for
1571 their assistance with the first-round submission.
1572 1532
1573 Changes to this document 1533 Changes to this document
1574 ------------------------ 1534 ------------------------
1575 1535
1576 - Added Boolean and Number types 1536 - Added Boolean and Number types
1577 - Added section Hyperdatabase Implementations 1537 - Added section Hyperdatabase Implementations
1578 - "Item" has been renamed to "Issue" to account for the more specific nature 1538 - "Item" has been renamed to "Issue" to account for the more specific
1579 of the Class. 1539 nature of the Class.
1580 - New Templating 1540 - New Templating
1581 - Access Controls 1541 - Access Controls
1582 1542
1583 ------------------ 1543 ------------------
1584 1544

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