comparison doc/reference.txt @ 8416:370689471a08 issue2550923_computed_property

merge from default branch accumulated changes since Nov 2023
author John Rouillard <rouilj@ieee.org>
date Sun, 17 Aug 2025 16:12:25 -0400
parents 0663a7bcef6c
children 056061cfe135
comparison
equal deleted inserted replaced
7693:78585199552a 8416:370689471a08
11 Roundup Reference 11 Roundup Reference
12 ================= 12 =================
13 13
14 .. admonition:: Welcome 14 .. admonition:: Welcome
15 15
16 This document used to be part of the `customisation document`_. The 16 This document was part of the `customisation document`_. The
17 customisation document was getting large and unwieldy. It was a 17 customisation document was getting large and unwieldy. The
18 combination of examples and internal information that made finding 18 combination of examples and internal information that made finding
19 information difficult. We often had questions on the mailing list that 19 information difficult. Questions raised on the mailing list were
20 were well answered in the customisation document, but finding the info 20 well answered in the customisation document, but finding the info
21 was difficult. 21 was difficult.
22 22
23 The documentation is slowly being reorganized using the `Diataxis 23 The documentation is slowly being reorganized using the `Diataxis
24 framework`_. Help with the reorganization is welcome. 24 framework`_. Help with the reorganization is welcome.
25 25
27 or how-tos in the customisation document. 27 or how-tos in the customisation document.
28 28
29 .. _customisation document: customizing.html 29 .. _customisation document: customizing.html
30 .. _diataxis framework: https://diataxis.fr/ 30 .. _diataxis framework: https://diataxis.fr/
31 31
32 .. This document borrows from the ZopeBook section on ZPT. The original is at: 32 .. This document borrows from the ZopeBook section on ZPT. The original was at:
33 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx 33 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
34 34
35 .. contents:: 35 .. contents::
36 :depth: 2 36 :depth: 2
37 :local: 37 :local:
47 single: tracker; structure extensions directory 47 single: tracker; structure extensions directory
48 single: tracker; structure html directory 48 single: tracker; structure html directory
49 single: tracker; structure html directory 49 single: tracker; structure html directory
50 single: tracker; structure lib directory 50 single: tracker; structure lib directory
51 51
52 =================== ======================================================== 52 .. table::
53 Tracker File Description 53 :class: valign-top
54 =================== ======================================================== 54
55 config.ini Holds the basic `tracker configuration`_ 55 =================== ========================================================
56 schema.py Holds the `tracker schema`_ 56 Tracker File Description
57 initial_data.py Holds any data to be entered into the database when the 57 =================== ========================================================
58 tracker is initialised (optional) 58 config.ini Holds the basic `tracker configuration`_
59 interfaces.py Allows `modifying the core of Roundup`_ (optional) 59 schema.py Holds the `tracker schema`_
60 db/ Holds the tracker's database 60 initial_data.py Loads initial data into the tracker (status,
61 db/files/ Holds the tracker's upload files and messages 61 priority ...) when initializing the tracker (optional)
62 db/backend_name Names the database back-end for the tracker (obsolete). 62 interfaces.py Allows `modifying the core of Roundup`_ (optional)
63 Use the ``backend`` setting in the ``[rdbms]`` 63 db/ Holds the tracker's database
64 section of ``config.ini`` instead. 64 db/files/ Holds the tracker's uploaded files and message
65 detectors/ `Auditors and reactors`_ for this tracker 65 db/backend_name Names the database back-end for the tracker (obsolete).
66 extensions/ Additional `actions`_ and `templating utilities`_ 66 Use the ``backend`` setting in the ``[rdbms]``
67 html/ Web interface templates, images and style sheets 67 section of ``config.ini`` instead.
68 lib/ optional common imports for detectors and extensions 68 detectors/ `Auditors and reactors`_ for this tracker
69 =================== ======================================================== 69 extensions/ Additional `actions`_ and `templating utilities`_
70 html/ Web interface templates, images and style sheets
71 lib/ optional common imports for detectors and extensions
72 =================== ========================================================
70 73
71 74
72 .. index:: config.ini 75 .. index:: config.ini
73 .. index:: configuration; see config.ini 76 .. index:: configuration; see config.ini
74 77
76 ===================== 79 =====================
77 80
78 The ``config.ini`` located in your tracker home contains the basic 81 The ``config.ini`` located in your tracker home contains the basic
79 configuration for the web and e-mail components of Roundup's interfaces. 82 configuration for the web and e-mail components of Roundup's interfaces.
80 83
81 Changes to the data captured by your tracker is controlled by the `tracker 84 The `tracker schema`_ defines the data captured by your tracker. It
82 schema`_. Some configuration is also performed using permissions - see the 85 also defines the permissions used when accessing the data: see the
83 `security / access controls`_ section. For example, to allow users to 86 `security / access controls`_ section. For example, you must grant the
84 automatically register through the email interface, you must grant the 87 "Anonymous" Role the "Email Access" Permission to allow users to
85 "Anonymous" Role the "Email Access" Permission. 88 automatically register through the email interface,.
86 89
87 .. index:: 90 .. index::
88 single: config.ini; sections 91 single: config.ini; sections
89 see: configuration; config.ini 92 see: configuration; config.ini
90 93
108 dir = frob 111 dir = frob
109 112
110 would resolve the "%(dir)s" to the value of "dir" ("frob" in this case) 113 would resolve the "%(dir)s" to the value of "dir" ("frob" in this case)
111 resulting in "foodir" being "frob/whatever". 114 resulting in "foodir" being "frob/whatever".
112 115
116 The reference above discusses using the ``[DEFAULT]`` section and
117 interpolation. For example::
118
119 [DEFAULT]
120 local_admin_email = admin@example.com
121
122 [main]
123 admin_email = %(local_admin_email)s
124
125 will set the admin_email setting. This works when running the
126 tracker. When upgrading Roundup using ``updateconfig`` to create
127 a new ``config.ini``, the ``DEFAULT`` section is not preserved
128 and interpolation tokens (e.g. ``%(local_admin_email)s`` are
129 replaced with their values (``admin@example.com``). This may be
130 fixed in a future release of Roundup.
131
132 Note that you can not reference settings in the ``DEFAULT``
133 section from Roundup. They are only useful when interpolated into
134 a defined setting.
135
113 __ https://docs.python.org/2/library/configparser.html 136 __ https://docs.python.org/2/library/configparser.html
114 137
115 Example configuration settings are below. This is a partial 138 A default ``config.ini`` file broken into sections is shown below.
116 list. Documentation on all the settings is included in the
117 ``config.ini`` file.
118 139
119 .. .comment out. file generation needs more work include:: tracker_config.txt 140 .. include:: tracker_config.txt
120 141
121 .. index:: config.ini; sections main 142 Additional notes:
122 143
123 Section **main** 144 The ``[rdbms]`` service defines the Connection Service for your
124 database -- ``db`` 145 PostgreSQL connection when using a system-wide pg_service.conf or
125 Database directory path. The path may be either absolute or relative 146 ~/.pg_service.conf as discussed in
126 to the directory containig this config file. 147 https://www.postgresql.org/docs/current/libpq-pgservice.html.
127 148
128 templates -- ``html`` 149 Setting this to the name of the service allows different trackers to
129 Path to the HTML templates directory. The path may be either absolute 150 connect to different services when running multiple trackers under one
130 or relative to the directory containing this config file. 151 Roundup server. If you are only running one tracker, you can set the
131 152 PGSERVICE environment variable. Note that other settings specified in
132 static_files -- default *blank* 153 this file (rdbms: user, password, port, host, (db)name) will override
133 A list of space separated directory paths (or a single directory). 154 the corresponding connection service setting.
134 These directories hold additional static files available via Web UI.
135 These directories may contain sitewide images, CSS stylesheets etc. If
136 a '-' is included, the list processing ends and the TEMPLATES
137 directory is not searched after the specified directories. If this
138 option is not set, all static files are taken from the TEMPLATES
139 directory.
140
141 admin_email -- ``roundup-admin``
142 Email address that roundup will complain to if it runs into trouble. If
143 the email address doesn't contain an ``@`` part, the MAIL_DOMAIN defined
144 below is used.
145
146 dispatcher_email -- ``roundup-admin``
147 The 'dispatcher' is a role that can get notified when errors occur
148 while sending email to a user. It is used by the ERROR_MESSAGES_TO config
149 setting. If the email address doesn't contain an ``@`` part, the
150 MAIL_DOMAIN defined below is used.
151
152 email_from_tag -- default *blank*
153 Additional text to include in the "name" part of the From: address used
154 in nosy messages. If the sending user is "Foo Bar", the From: line
155 is usually: ``"Foo Bar" <issue_tracker@tracker.example>``
156 the EMAIL_FROM_TAG goes inside the "Foo Bar" quotes like so:
157 ``"Foo Bar EMAIL_FROM_TAG" <issue_tracker@tracker.example>``
158
159 new_web_user_roles -- ``User``
160 Roles that a user gets when they register with Web User Interface.
161 This is a comma-separated list of role names (e.g. ``Admin,User``).
162
163 new_email_user_roles -- ``User``
164 Roles that a user gets when they register with Email Gateway.
165 This is a comma-separated string of role names (e.g. ``Admin,User``).
166
167 error_messages_to -- ``user``
168 Send error message emails to the ``dispatcher``, ``user``, or ``both``?
169 The dispatcher is configured using the DISPATCHER_EMAIL setting.
170 Allowed values: ``dispatcher``, ``user``, or ``both``
171
172 html_version -- ``html4``
173 This setting should be left at the default value of html4.
174 Support is ending for xhtml mode.
175 HTML version to generate. The templates are ``html4`` by default.
176 If you wish to make them xhtml, then you'll need to change this
177 var to ``xhtml`` too so all auto-generated HTML is compliant.
178 Allowed values: ``html4``, ``xhtml``
179
180 timezone -- ``0``
181 Numeric timezone offset used when users do not choose their own
182 in their settings.
183
184 instant_registration -- ``yes``
185 Register new users instantly, or require confirmation via
186 email?
187 Allowed values: ``yes``, ``no``
188
189 email_registration_confirmation -- ``yes``
190 Offer registration confirmation by email or only through the web?
191 Allowed values: ``yes``, ``no``
192
193 indexer_stopwords -- default *blank*
194 Additional stop-words for the full-text indexer specific to
195 your tracker. See the indexer source for the default list of
196 stop-words (e.g. ``A,AND,ARE,AS,AT,BE,BUT,BY, ...``).
197
198 umask -- ``02``
199 Defines the file creation mode mask.
200
201 csv_field_size -- ``131072``
202 Maximum size of a csv-field during import. Roundup's export
203 format is a csv (comma separated values) variant. The csv
204 reader has a limit on the size of individual fields
205 starting with python 2.5. Set this to a higher value if you
206 get the error 'Error: field larger than field limit' during
207 import.
208
209 .. index:: config.ini; sections tracker
210
211 Section **tracker**
212 name -- ``Roundup issue tracker``
213 A descriptive name for your Roundup instance.
214
215 web -- ``http://host.example/demo/``
216 The web address that the tracker is viewable at.
217 This will be included in information sent to users of the tracker.
218 The URL MUST include the cgi-bin part or anything else
219 that is required to get to the home page of the tracker.
220 You MUST include a trailing '/' in the URL.
221
222 email -- ``issue_tracker``
223 Email address that mail to Roundup should go to.
224
225 language -- default *blank*
226 Default locale name for this tracker. If this option is not set, the
227 language is determined by the environment variable LANGUAGE, LC_ALL,
228 LC_MESSAGES, or LANG, in that order of preference.
229
230 .. index:: config.ini; sections web
231
232 Section **web**
233 allow_html_file -- ``no``
234 Setting this option enables Roundup to serve uploaded HTML
235 file content *as HTML*. This is a potential security risk
236 and is therefore disabled by default. Set to 'yes' if you
237 trust *all* users uploading content to your tracker.
238
239 http_auth -- ``yes``
240 Whether to use HTTP Basic Authentication, if present.
241 Roundup will use either the REMOTE_USER or HTTP_AUTHORIZATION
242 variables supplied by your web server (in that order).
243 Set this option to 'no' if you do not wish to use HTTP Basic
244 Authentication in your web interface.
245
246 use_browser_language -- ``yes``
247 Whether to use HTTP Accept-Language, if present.
248 Browsers send a language-region preference list.
249 It's usually set in the client's browser or in their
250 Operating System.
251 Set this option to 'no' if you want to ignore it.
252
253 debug -- ``no``
254 Setting this option makes Roundup display error tracebacks
255 in the user's browser rather than emailing them to the
256 tracker admin."),
257
258 .. index:: config.ini; sections rdbms
259 single: config.ini; database settings
260
261 Section **rdbms**
262 Settings in this section are used to set the backend and configure
263 addition settings needed by RDBMs like SQLite, Postgresql and
264 MySQL backends.
265
266 .. index::
267 single: postgres; select backend in config.ini
268 single: mysql; select backend in config.ini
269 single: sqlite; select backend in config.ini
270 single: anydbm; select backend in config.ini
271 see: database; postgres
272 see: database; mysql
273 see: database; sqlite
274 see: database; anydbm
275
276 backend -- set to value by init
277 The database backend such as anydbm, sqlite, mysql or postgres.
278
279 name -- ``roundup``
280 Name of the database to use.
281
282 host -- ``localhost``
283 Database server host.
284
285 port -- default *blank*
286 TCP port number of the database server. Postgresql usually resides on
287 port 5432 (if any), for MySQL default port number is 3306. Leave this
288 option empty to use backend default.
289
290 user -- ``roundup``
291 Database user name that Roundup should use.
292
293 password -- ``roundup``
294 Database user password.
295
296 read_default_file -- ``~/.my.cnf``
297 Name of the MySQL defaults file. Only used in MySQL connections.
298
299 read_default_group -- ``roundup``
300 Name of the group to use in the MySQL defaults file. Only used in
301 MySQL connections.
302
303 .. index::
304 single: sqlite; lock timeout
305
306 sqlite_timeout -- ``30``
307 Number of seconds to wait when the SQLite database is locked.
308 Used only for SQLite.
309
310 cache_size -- `100`
311 Size of the node cache (in elements) used to keep most recently used
312 data in memory.
313
314 .. index:: config.ini; sections logging
315 see: logging; config.ini, sections logging
316
317 Section **logging**
318 config -- default *blank*
319 Path to configuration file for standard Python logging module. If this
320 option is set, logging configuration is loaded from specified file;
321 options 'filename' and 'level' in this section are ignored. The path may
322 be either absolute or relative to the directory containig this config file.
323
324 filename -- default *blank*
325 Log file name for minimal logging facility built into Roundup. If no file
326 name specified, log messages are written on stderr. If above 'config'
327 option is set, this option has no effect. The path may be either absolute
328 or relative to the directory containig this config file.
329
330 level -- ``ERROR``
331 Minimal severity level of messages written to log file. If above 'config'
332 option is set, this option has no effect.
333 Allowed values: ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``
334
335 .. index:: config.ini; sections mail
336
337 Section **mail**
338 Outgoing email options. Used for nosy messages, password reset and
339 registration approval requests.
340
341 domain -- ``localhost``
342 Domain name used for email addresses.
343
344 host -- default *blank*
345 SMTP mail host that Roundup will use to send mail
346
347 username -- default *blank*
348 SMTP login name. Set this if your mail host requires authenticated access.
349 If username is not empty, password (below) MUST be set!
350
351 password -- default *blank*
352 SMTP login password.
353 Set this if your mail host requires authenticated access.
354
355 port -- default *25*
356 SMTP port on mail host.
357 Set this if your mail host runs on a different port.
358
359 local_hostname -- default *blank*
360 The fully qualified domain name (FQDN) to use during SMTP sessions. If left
361 blank, the underlying SMTP library will attempt to detect your FQDN. If your
362 mail host requires something specific, specify the FQDN to use.
363
364 tls -- ``no``
365 If your SMTP mail host provides or requires TLS (Transport Layer Security)
366 then you may set this option to 'yes'.
367 Allowed values: ``yes``, ``no``
368
369 tls_keyfile -- default *blank*
370 If TLS is used, you may set this option to the name of a PEM formatted
371 file that contains your private key. The path may be either absolute or
372 relative to the directory containig this config file.
373
374 tls_certfile -- default *blank*
375 If TLS is used, you may set this option to the name of a PEM formatted
376 certificate chain file. The path may be either absolute or relative
377 to the directory containig this config file.
378
379 charset -- utf-8
380 Character set to encode email headers with. We use utf-8 by default, as
381 it's the most flexible. Some mail readers (eg. Eudora) can't cope with
382 that, so you might need to specify a more limited character set
383 (eg. iso-8859-1).
384
385 debug -- default *blank*
386 Setting this option makes Roundup to write all outgoing email messages
387 to this file *instead* of sending them. This option has the same effect
388 as environment variable SENDMAILDEBUG. Environment variable takes
389 precedence. The path may be either absolute or relative to the directory
390 containig this config file.
391
392 add_authorinfo -- ``yes``
393 Add a line with author information at top of all messages send by
394 Roundup.
395
396 add_authoremail -- ``yes``
397 Add the mail address of the author to the author information at the
398 top of all messages. If this is false but add_authorinfo is true,
399 only the name of the actor is added which protects the mail address
400 of the actor from being exposed at mail archives, etc.
401
402 .. index:: config.ini; sections mailgw
403 single: mailgw; config
404 see: mail gateway; mailgw
405
406 Section **mailgw**
407 Roundup Mail Gateway options
408
409 keep_quoted_text -- ``yes``
410 Keep email citations when accepting messages. Setting this to ``no`` strips
411 out "quoted" text from the message. Signatures are also stripped.
412 Allowed values: ``yes``, ``no``
413
414 leave_body_unchanged -- ``no``
415 Preserve the email body as is - that is, keep the citations *and*
416 signatures.
417 Allowed values: ``yes``, ``no``
418
419 default_class -- ``issue``
420 Default class to use in the mailgw if one isn't supplied in email subjects.
421 To disable, leave the value blank.
422
423 language -- default *blank*
424 Default locale name for the tracker mail gateway. If this option is
425 not set, mail gateway will use the language of the tracker instance.
426
427 subject_prefix_parsing -- ``strict``
428 Controls the parsing of the [prefix] on subject lines in incoming emails.
429 ``strict`` will return an error to the sender if the [prefix] is not
430 recognised. ``loose`` will attempt to parse the [prefix] but just
431 pass it through as part of the issue title if not recognised. ``none``
432 will always pass any [prefix] through as part of the issue title.
433
434 subject_suffix_parsing -- ``strict``
435 Controls the parsing of the [suffix] on subject lines in incoming emails.
436 ``strict`` will return an error to the sender if the [suffix] is not
437 recognised. ``loose`` will attempt to parse the [suffix] but just
438 pass it through as part of the issue title if not recognised. ``none``
439 will always pass any [suffix] through as part of the issue title.
440
441 subject_suffix_delimiters -- ``[]``
442 Defines the brackets used for delimiting the commands suffix in a subject
443 line.
444
445 subject_content_match -- ``always``
446 Controls matching of the incoming email subject line against issue titles
447 in the case where there is no designator [prefix]. ``never`` turns off
448 matching. ``creation + interval`` or ``activity + interval`` will match
449 an issue for the interval after the issue's creation or last activity.
450 The interval is a standard Roundup interval.
451
452 subject_updates_title -- ``yes``
453 Update issue title if incoming subject of email is different.
454 Setting this to ``no`` will ignore the title part of
455 the subject of incoming email messages.
456
457 refwd_re -- ``(\s*\W?\s*(fw|fwd|re|aw|sv|ang)\W)+``
458 Regular expression matching a single reply or forward prefix
459 prepended by the mailer. This is explicitly stripped from the
460 subject during parsing. Value is Python Regular Expression
461 (UTF8-encoded).
462
463 origmsg_re -- `` ^[>|\s]*-----\s?Original Message\s?-----$``
464 Regular expression matching start of an original message if quoted
465 in the body. Value is Python Regular Expression (UTF8-encoded).
466
467 sign_re -- ``^[>|\s]*-- ?$``
468 Regular expression matching the start of a signature in the message
469 body. Value is Python Regular Expression (UTF8-encoded).
470
471 eol_re -- ``[\r\n]+``
472 Regular expression matching end of line. Value is Python Regular
473 Expression (UTF8-encoded).
474
475 blankline_re -- ``[\r\n]+\s*[\r\n]+``
476 Regular expression matching a blank line. Value is Python Regular
477 Expression (UTF8-encoded).
478
479 ignore_alternatives -- ``no``
480 When parsing incoming mails, Roundup uses the first
481 text/plain part it finds. If this part is inside a
482 multipart/alternative, and this option is set, all other
483 parts of the multipart/alternative are ignored. The default
484 is to keep all parts and attach them to the issue.
485
486 .. index:: config.ini; sections pgp
487
488 Section **pgp**
489 OpenPGP mail processing options
490
491 enable -- ``no``
492 Enable PGP processing. Requires gpg.
493
494 roles -- default *blank*
495 If specified, a comma-separated list of roles to perform PGP
496 processing on. If not specified, it happens for all users.
497
498 homedir -- default *blank*
499 Location of PGP directory. Defaults to $HOME/.gnupg if not
500 specified.
501
502
503 .. index:: config.ini; sections nosy
504
505 Section **nosy**
506 Nosy messages sending
507
508 messages_to_author -- ``no``
509 Send nosy messages to the author of the message.
510 If ``yes`` is used, then messages are sent to the author
511 even if not on the nosy list, same for ``new`` (but only for new messages).
512 When set to ``nosy``, the nosy list controls sending messages to the author.
513 Allowed values: ``yes``, ``no``, ``new``, ``nosy``
514
515 signature_position -- ``bottom``
516 Where to place the email signature.
517 Allowed values: ``top``, ``bottom``, ``none``
518
519 add_author -- ``new``
520 Does the author of a message get placed on the nosy list automatically?
521 If ``new`` is used, then the author will only be added when a message
522 creates a new issue. If ``yes``, then the author will be added on
523 followups too. If ``no``, they're never added to the nosy.
524 Allowed values: ``yes``, ``no``, ``new``
525
526 add_recipients -- ``new``
527 Do the recipients (``To:``, ``Cc:``) of a message get placed on the nosy
528 list? If ``new`` is used, then the recipients will only be added when a
529 message creates a new issue. If ``yes``, then the recipients will be added
530 on followups too. If ``no``, they're never added to the nosy.
531 Allowed values: ``yes``, ``no``, ``new``
532
533 email_sending -- ``single``
534 Controls the email sending from the nosy reactor. If ``multiple`` then
535 a separate email is sent to each recipient. If ``single`` then a single
536 email is sent with each recipient as a CC address.
537
538 max_attachment_size -- ``2147483647``
539 Attachments larger than the given number of bytes won't be attached
540 to nosy mails. They will be replaced by a link to the tracker's
541 download page for the file.
542
543 155
544 .. index:: single: roundup-admin; config.ini update 156 .. index:: single: roundup-admin; config.ini update
545 single: roundup-admin; config.ini create 157 single: roundup-admin; config.ini create
546 single: config.ini; create 158 single: config.ini; create
547 single: config.ini; update 159 single: config.ini; update
549 You may generate a new default config file using the ``roundup-admin 161 You may generate a new default config file using the ``roundup-admin
550 genconfig`` command. You can generate a new config file merging in 162 genconfig`` command. You can generate a new config file merging in
551 existing settings using the ``roundup-admin updateconfig`` command. 163 existing settings using the ``roundup-admin updateconfig`` command.
552 164
553 Configuration variables may be referred to in lower or upper case. In code, 165 Configuration variables may be referred to in lower or upper case. In code,
554 variables not in the "main" section are referred to using their section and 166 refer to variables not in the "main" section using their section and
555 name, so "domain" in the section "mail" becomes MAIL_DOMAIN. 167 name, so "domain" in the section "mail" becomes MAIL_DOMAIN.
556 168
557 .. index:: pair: configuration; extensions 169 .. index:: pair: configuration; extensions
558 pair: configuration; detectors 170 pair: configuration; detectors
559 171
561 -------------------------------- 173 --------------------------------
562 174
563 You can't add new variables to the config.ini file in the tracker home but 175 You can't add new variables to the config.ini file in the tracker home but
564 you can add two new config.ini files: 176 you can add two new config.ini files:
565 177
566 - a config.ini in the ``extensions`` directory will be loaded and attached 178 - a config.ini in the ``extensions`` directory is loaded and attached
567 to the config variable as "ext". 179 to the config variable as "ext".
568 - a config.ini in the ``detectors`` directory will be loaded and attached 180 - a config.ini in the ``detectors`` directory is loaded and attached
569 to the config variable as "detectors". 181 to the config variable as "detectors".
182
183 These configuration files support the same operations as the main
184 ``config.ini`` file. This included a ``DEFAULT`` section and
185 interpolation. Note that you can not reference settings in the
186 ``DEFAULT`` section from Roundup. They can only be used for
187 interpolation.
570 188
571 For example, the following in ``detectors/config.ini``:: 189 For example, the following in ``detectors/config.ini``::
572 190
573 [main] 191 [main]
574 qa_recipients = email@example.com 192 qa_recipients = email@example.com
589 in these config files are not validated. For example: a setting that 207 in these config files are not validated. For example: a setting that
590 is supposed to be an integer value (e.g. 4) could be the word 208 is supposed to be an integer value (e.g. 4) could be the word
591 "foo". If you are writing Python code that uses these settings, you 209 "foo". If you are writing Python code that uses these settings, you
592 should expect to handle invalid values. 210 should expect to handle invalid values.
593 211
594 Also, incorrect values aren't discovered until the config setting is 212 Also, incorrect values are discovered when the config setting is
595 used. This can be long after the tracker is started and the error may 213 used not set. This can be long after the tracker is
596 not be seen in the logs. 214 started and the error may not be seen in the logs.
597 215
598 It is possible to validate these settings. Validation involves calling 216 It's possible to validate these settings. Validation involves calling
599 the ``update_options`` method on the configuration option. This can be 217 the ``update_options`` method on the configuration option. This can be
600 done from the ``init()`` function in the Python files implementing 218 done by the ``init()`` function in the Python files implementing
601 extensions_ or detectors_. 219 extensions_ or detectors_.
602 220
603 As an example, adding the following to an extension:: 221 As an example, adding the following to an extension::
604 222
605 from roundup.configuration import SecretMandatoryOption 223 from roundup.configuration import SecretMandatoryOption
628 Running ``roundup-admin -i tracker_home display user1`` will validate 246 Running ``roundup-admin -i tracker_home display user1`` will validate
629 the settings for both config.ini`s. Otherwise detector options are not 247 the settings for both config.ini`s. Otherwise detector options are not
630 validated until the first request to the web interface (or email 248 validated until the first request to the web interface (or email
631 gateway). 249 gateway).
632 250
633 There are 4 arguments for ``update_option``: 251 ``update_option`` takes 4 arguments:
634 252
635 1. config setting name - string (positional, mandatory) 253 1. config setting name - string (positional, mandatory)
636 2. option type - Option derived class from configuration.py 254 2. option type - Option derived class from configuration.py
637 (positional, mandatory) 255 (positional, mandatory)
638 3. default value - string (optional, named default) 256 3. default value - string (optional, named default)
640 258
641 The first argument is the config setting name as described at the 259 The first argument is the config setting name as described at the
642 beginning of this section. 260 beginning of this section.
643 261
644 The second argument is a class in the roundup.configuration module. 262 The second argument is a class in the roundup.configuration module.
645 There are a number of these classes: BooleanOption, 263 There are many of these classes: BooleanOption,
646 IntegerNumberOption, RegExpOption.... Please see the configuration 264 IntegerNumberOption, RegExpOption.... Please see the configuration
647 module for all Option validators and their descriptions. You can also 265 module for all Option validators and their descriptions. You can also
648 define your own custom validator in `interfaces.py`_. 266 define your own custom validator in `interfaces.py`_.
649 267
650 The third and fourth arguments are strings and are optional. They are 268 The third and fourth arguments are optional strings. They are printed
651 printed if there is an error and may help the user correct the problem. 269 when there is an error and may help the user correct the problem.
652 270
653 .. index:: ! schema 271 .. index:: ! schema
654 272
655 Tracker Schema 273 Tracker Schema
656 ============== 274 ==============
698 property. 316 property.
699 317
700 .. [1] If you shut down the tracker, `export the database`_, modify the 318 .. [1] If you shut down the tracker, `export the database`_, modify the
701 exported csv property data to be compatible with the new type, 319 exported csv property data to be compatible with the new type,
702 change the property type in the schema, and finally import the 320 change the property type in the schema, and finally import the
703 changed exported data, you can change the property type. It is 321 changed exported data, you can change the property type. This is
704 not trivial nor for the faint of heart. But it can be done. 322 not trivial nor for the faint of heart. But it can be done.
705 323
706 .. _export the database: admin_guide.html#using-roundup-admin 324 .. _export the database: admin_guide.html#using-roundup-admin
707 325
708 The ``schema.py`` and ``initial_data.py`` modules 326 The ``schema.py`` and ``initial_data.py`` modules
758 .. index:: schema; classes and properties 376 .. index:: schema; classes and properties
759 377
760 Classes and Properties - creating a new information store 378 Classes and Properties - creating a new information store
761 --------------------------------------------------------- 379 ---------------------------------------------------------
762 380
763 In the tracker above, we've defined 7 classes of information: 381 The tracker above, defines 7 classes of information:
764 382
765 priority 383 priority
766 Defines the possible levels of urgency for issues. 384 Defines the possible levels of urgency for issues.
767 385
768 status 386 status
783 Initially empty, will hold all files attached to issues. 401 Initially empty, will hold all files attached to issues.
784 402
785 issue 403 issue
786 Initially empty, this is where the issue information is stored. 404 Initially empty, this is where the issue information is stored.
787 405
788 We define the "priority" and "status" classes to allow two things: 406 It defines the "priority" and "status" classes to allow two things:
789 407
790 1. reduction in the amount of information stored on the issue 408 1. reduction in the amount of information stored on the issue
791 2. more powerful, accurate searching of issues by priority and status 409 2. more powerful, accurate searching of issues by priority and status
792 410
793 By only requiring a link on the issue (which is stored as a single 411 By requiring a link on the issue (stored as a single
794 number) we reduce the chance that someone mis-types a priority or 412 number) the chance that someone mis-types a priority or
795 status - or simply makes a new one up. 413 status - or makes a new one up is reduced.
796 414
797 Class names are used to access items of that class in the `REST api`_ 415 Class names access items of that class in the `REST api`_
798 interface. The classic tracker was created before the REST interface 416 interface. The classic tracker was created before the REST interface
799 was added. It uses the single form (i.e. issue and user not issues and 417 was added. It uses the single form (i.e. issue and user not issues and
800 users) for its classes. Most REST documentation suggests using plural 418 users) for its classes. Most REST documentation suggests using plural
801 forms. However, to make your API consistent, use singular forms for 419 forms. However, to make your API consistent, use singular forms for
802 classes that you add. 420 classes that you add.
820 .. index:: schema; property types 438 .. index:: schema; property types
821 439
822 Properties 440 Properties
823 ~~~~~~~~~~ 441 ~~~~~~~~~~
824 442
825 A Class is comprised of one or more properties of the following types: 443 A Class consists of one or more properties of the following types:
826 444
827 String 445 Boolean
828 properties are for storing arbitrary-length strings. 446 properties store on/off, yes/no, true/false values.
829 Password
830 properties are for storing encoded arbitrary-length strings.
831 The default encoding is defined on the ``roundup.password.Password``
832 class.
833 Date 447 Date
834 properties store date-and-time stamps. Their values are Timestamp 448 properties store date-and-time stamps. Their values are Timestamp
835 objects. 449 objects.
450 Integer
451 properties store integer values. (Number can store real/float values.)
836 Interval 452 Interval
837 properties store time periods rather than absolute dates. For 453 properties store time periods rather than absolute dates. For
838 example 2 hours. 454 example 2 hours.
839 Integer 455 Link
840 properties store integer values. (Number can store real/float values.) 456 properties refers to a single item selected from a
457 specified class. The class is part of the property; the value is an
458 integer, the id of the chosen item.
459 Multilink
460 properties refer to one or more items in a specified
461 class. The value is a list of integers.
841 Number 462 Number
842 properties store numeric values. There is an option to use 463 properties store numeric values. There is an option to use
843 double-precision floating point numbers. 464 double-precision floating point numbers.
844 Boolean 465 Password
845 properties store on/off, yes/no, true/false values. 466 properties store encoded arbitrary-length strings.
846 Link 467 The default encoding is defined in the ``roundup.password.Password``
847 properties refers to a single other item selected from a 468 class.
848 specified class. The class is part of the property; the value is an 469 String
849 integer, the id of the chosen item. 470 properties store arbitrary-length strings.
850 Multilink 471
851 properties refer to possibly many items in a specified 472 Properties have attributes to change the default behaviour:
852 class. The value is a list of integers.
853
854 Properties can have additional attributes to change the default
855 behaviour:
856 473
857 .. index:: triple: schema; property attributes; required 474 .. index:: triple: schema; property attributes; required
858 triple: schema; property attributes; default_value 475 triple: schema; property attributes; default_value
859 triple: schema; property attributes; quiet 476 triple: schema; property attributes; quiet
860 477
862 479
863 - ``required``: see `design documentation`_. Adds the property to 480 - ``required``: see `design documentation`_. Adds the property to
864 the list returned by calling get_required_props for the class. 481 the list returned by calling get_required_props for the class.
865 - ``default_value``: see `design documentation`_ Sets the default 482 - ``default_value``: see `design documentation`_ Sets the default
866 value if the property is not set. 483 value if the property is not set.
867 - ``quiet``: see `design documentation`_. Suppresses user visible 484 - ``quiet``: see `design documentation`_. Suppresses reporting user
868 to changes to this property. The property change is not reported: 485 visible changes to this property. The property change is not reported:
869 486
870 - in the change feedback/confirmation message in the web 487 - in the change feedback/confirmation message in the web
871 interface 488 interface
872 - the property change section of the nosy email 489 - the property change section of the nosy email
873 - the web history at the bottom of an item's page 490 - the web history at the bottom of an item's page
874 491
875 This can be used to store state of the user interface (e.g. the 492 This is useful when storing the state of the user interface (e.g. the
876 names of elements that are collapsed or hidden from the 493 names of elements that are collapsed or hidden from the
877 user). Making properties that are updated as an indirect result of 494 user). Properties updates as an indirect result of
878 a user's change (e.g. updating a blockers property, counting 495 a user's change (e.g. updating a blockers property, counting
879 number of times an issue was reopened or reassigned etc.) should 496 number of times an issue is reopened or reassigned etc.) should
880 not be displayed to the user as they can be confusing. 497 not be displayed to the user as they can be confusing.
881 498
882 .. index:: triple: schema; property attributes; indexme 499 .. index:: triple: schema; property attributes; indexme
883 500
884 * String properties can have an ``indexme`` attribute that defines if the 501 * String properties have an ``indexme`` attribute. The default is
885 property should be part of the full text index. The default is 'no' but this 502 'no'. Setting it to 'yes' includes the property in the full text
886 can be set to 'yes' to allow a property's contents to be in the full 503 index.
887 text index.
888 504
889 .. index:: triple: schema; property attributes; use_double 505 .. index:: triple: schema; property attributes; use_double
890 506
891 * Number properties can have a ``use_double`` attribute that, when set 507 * Number properties can have a ``use_double`` attribute that, when set
892 to ``True``, will use double precision floating point in the database. 508 to ``True``, will use double precision floating point in the database.
901 and unlink events to prevent the journal from clogged with these 517 and unlink events to prevent the journal from clogged with these
902 events. 518 events.
903 519
904 .. index:: triple: schema; property attributes; try_id_parsing 520 .. index:: triple: schema; property attributes; try_id_parsing
905 521
906 - ``try_id_parsing`` is turned on by default. If entering a number 522 - ``try_id_parsing`` is turned on by default. If a number is entered
907 into a Link or Multilink field, Roundup interprets this number as an 523 into a Link or Multilink field, Roundup interprets this number as
908 ID of the item to link to. Sometimes items can have numeric names 524 an ID of the item to link to. Sometimes items can have numeric
909 (like, e.g., product codes). For these Roundup needs to match the 525 names (e.g., product codes). For these Roundup needs to
910 numeric name and should never match an ID. In this case you can set 526 match the numeric name and should never match an ID. In this case
911 ``try_id_parsing='no'``. 527 you can set ``try_id_parsing='no'``.
912 528
913 .. index:: triple: schema; property attributes; rev_multilink 529 .. index:: triple: schema; property attributes; rev_multilink
914 530
915 - The ``rev_multilink`` option takes a property name to be inserted 531 - The ``rev_multilink`` option takes a property name to be inserted
916 into the linked-to class. This property is a Multilink property that 532 into the linked-to class. This property is a Multilink property that
920 using the "filter" method of the Class. This means it can be used 536 using the "filter" method of the Class. This means it can be used
921 like other Multilink properties when searching (in an index 537 like other Multilink properties when searching (in an index
922 template) or via the REST and XMLRPC APIs. 538 template) or via the REST and XMLRPC APIs.
923 539
924 As a example, suppose you want to group multiple issues into a 540 As a example, suppose you want to group multiple issues into a
925 super issue. Each issue can be part of only one super issue. It is 541 super issue. Each issue can be part of one super issue. It is
926 inefficient to find all of the issues that are part of the 542 inefficient to find all of the issues linked to the super issue by
927 super issue by searching through all issues in the system looking 543 searching through all issues in the system looking at the part_of
928 at the part_of link property. To make this more efficient, you 544 link property. To make this more efficient, you can declare an
929 can declare an issue's part_of property as:: 545 issue's part_of property as::
930 546
931 issue = IssueClass(db, "issue", 547 issue = IssueClass(db, "issue",
932 ... 548 ...
933 part_of = Link("issue", rev_multilink="components"), 549 part_of = Link("issue", rev_multilink="components"),
934 ... ) 550 ... )
953 automatically adds "1234" to the ``components`` property on 569 automatically adds "1234" to the ``components`` property on
954 issue3456. You can search the ``components`` multilink just like a 570 issue3456. You can search the ``components`` multilink just like a
955 regular multilink, but you can't explicitly assign to it. 571 regular multilink, but you can't explicitly assign to it.
956 Another difference of reverse multilinks to normal multilinks 572 Another difference of reverse multilinks to normal multilinks
957 is that when a linked node is retired, the node vanishes from the 573 is that when a linked node is retired, the node vanishes from the
958 multilink, e.g. in the example above, if an issue with ``part_of`` 574 multilink. In the example above, when issue 1234 with ``part_of``
959 set to another issue is retired this issue vanishes from the 575 set to issue 5678 is retired, 1234 vanishes from the
960 ``components`` multilink of the other issue. 576 ``components`` multilink of issue 5678.
961 577
962 You can also link between different classes. So you can modify 578 You can also link between different classes. If the issue
963 the issue definition to include:: 579 definition includes::
964 580
965 issue = IssueClass(db, "issue", 581 issue = IssueClass(db, "issue",
966 ... 582 ...
967 assigned_to = Link("user", rev_multilink="responsibleFor"), 583 assigned_to = Link("user", rev_multilink="responsibleFor"),
968 ... ) 584 ... )
994 links to the user class and you want to add a header:: 610 links to the user class and you want to add a header::
995 611
996 X-Roundup-issue-assigned_to: ... 612 X-Roundup-issue-assigned_to: ...
997 613
998 so that the mail recipients can filter emails where 614 so that the mail recipients can filter emails where
999 ``X-Roundup-issue-assigned_to: name`` that contains their 615 ``X-Roundup-issue-assigned_to: name`` contains their
1000 username. The user class is defined as:: 616 username. The user class is defined as::
1001 617
1002 user = Class(db, "user", 618 user = Class(db, "user",
1003 username=String(), 619 username=String(),
1004 password=Password(), 620 password=Password(),
1009 alternate_addresses=String(), 625 alternate_addresses=String(),
1010 queries=Multilink('query'), 626 queries=Multilink('query'),
1011 roles=String(), # comma-separated string of Role names 627 roles=String(), # comma-separated string of Role names
1012 timezone=String()) 628 timezone=String())
1013 629
1014 Because there is no ``name`` parameter for the user class, there 630 Because the user class does not have a ``name`` parameter, no
1015 will be no header. However setting:: 631 header will be written. Setting::
1016 632
1017 assigned_to=Link("user", msg_header_property="username") 633 assigned_to=Link("user", msg_header_property="username")
1018 634
1019 will make the mail gateway generate an ``X-Roundup-issue-assigned_to`` 635 will make the mail gateway generate an ``X-Roundup-issue-assigned_to``
1020 using the username property of the linked user. 636 using the username property of the linked user.
1029 645
1030 X-Roundup-issue-assigned_to: joe_user 646 X-Roundup-issue-assigned_to: joe_user
1031 647
1032 for emails sent on issues where joe_user has been assigned to the issue. 648 for emails sent on issues where joe_user has been assigned to the issue.
1033 649
1034 If this property is set to the empty string "", it will prevent 650 If this property is set to the empty string "", no header will be
1035 the header from being generated on outgoing mail. 651 generated on outgoing mail.
1036 652
1037 .. index:: triple: schema; class property; creator 653 .. index:: triple: schema; class property; creator
1038 triple: schema; class property; creation 654 triple: schema; class property; creation
1039 triple: schema; class property; actor 655 triple: schema; class property; actor
1040 triple: schema; class property; activity 656 triple: schema; class property; activity
1041 657
1042 All Classes automatically have a number of properties by default: 658 All Classes automatically have four properties by default:
1043 659
1044 *creator* 660 *creator*
1045 Link to the user that created the item. 661 Link to the user that created the item.
1046 *creation* 662 *creation*
1047 Date the item was created. 663 Date the item was created.
1063 setkey(property) 679 setkey(property)
1064 :::::::::::::::: 680 ::::::::::::::::
1065 681
1066 .. index:: roundup-admin; setting assignedto on an issue 682 .. index:: roundup-admin; setting assignedto on an issue
1067 683
1068 Select a String property of the class to be the key property. The key 684 Set the key property of a class to a string property. The key property
1069 property must be unique, and allows references to the items in the class 685 must be unique. References to the items in the class can be done by
1070 by the content of the key property. That is, we can refer to users by 686 the content of the key property. For example, you can refer to users by
1071 their username: for example, let's say that there's an issue in Roundup, 687 their username. Let's say that there's an issue in
1072 issue 23. There's also a user, richard, who happens to be user 2. To 688 Roundup, issue 23. There's also a user, richard, who happens to be
1073 assign an issue to him, we could do either of:: 689 user 2. To assign an issue to him, we could do use::
1074 690
1075 roundup-admin set issue23 assignedto=2 691 roundup-admin set issue23 assignedto=2
1076 692
1077 or:: 693 or::
1078 694
1084 700
1085 setlabelprop(property) 701 setlabelprop(property)
1086 :::::::::::::::::::::: 702 ::::::::::::::::::::::
1087 703
1088 Select a property of the class to be the label property. The label 704 Select a property of the class to be the label property. The label
1089 property is used whereever an item should be uniquely identified, e.g., 705 property is used whenever an item should be uniquely identified, e.g.,
1090 when displaying a link to an item. If setlabelprop is not specified for 706 when displaying a link to an item. If setlabelprop is not specified for
1091 a class, the following values are tried for the label: 707 a class, the following values are tried for the label:
1092 708
1093 * the key of the class (see the `setkey(property)`_ section above) 709 * the key of the class (see the `setkey(property)`_ section above)
1094 * the "name" property 710 * the "name" property
1095 * the "title" property 711 * the "title" property
1096 * the first property from the sorted property name list 712 * the first property from the sorted property name list
1097 713
1098 So in most cases you can get away without specifying setlabelprop 714 In most cases you can get away without specifying setlabelprop
1099 explicitly. 715 explicitly.
1100 716
1101 You should make sure that users have View access to this property or 717 Users should have View access to this property or the id property for
1102 the id property for a class. If the property can not be viewed by a 718 a class. If the property can not be viewed by a user, looping over
1103 user, looping over items in the class (e.g. messages attached to an 719 items in the class (e.g. messages attached to an issue) will not work.
1104 issue) will not work.
1105 720
1106 .. index:: triple: schema; class method; setorderprop 721 .. index:: triple: schema; class method; setorderprop
1107 722
1108 setorderprop(property) 723 setorderprop(property)
1109 :::::::::::::::::::::: 724 ::::::::::::::::::::::
1110 725
1111 Select a property of the class to be the order property. The order 726 Select a property of the class to be the order property. The order
1112 property is used whenever using a default sort order for the class, 727 property is used whenever using a default sort order for the class,
1113 e.g., when grouping or sorting class A by a link to class B in the user 728 e.g., when grouping or sorting class A by a link to class B in the user
1114 interface, the order property of class B is used for sorting. If 729 interface, the order property of class B is used for sorting. If
1115 setorderprop is not specified for a class, the following values are tried 730 setorderprop is not specified for a class, the following values are tried
1116 for the order property: 731 for the order property:
1117 732
1118 * the property named "order" 733 * the property named "order"
1119 * the label property (see `setlabelprop(property)`_ above) 734 * the label property (see `setlabelprop(property)`_ above)
1120 735
1121 So in most cases you can get away without specifying setorderprop 736 Usually you can get away without specifying setorderprop
1122 explicitly. 737 explicitly.
1123 738
1124 .. index:: triple: schema; class method; create 739 .. index:: triple: schema; class method; create
1125 740
1126 create(information) 741 create(information)
1127 ::::::::::::::::::: 742 :::::::::::::::::::
1128 743
1129 Create an item in the database. This is generally used to create items 744 Create an item in the database. This is used to create items
1130 in the :term:`definitional class` like "priority" and "status". 745 in the :term:`definitional class` like "priority" and "status".
746
747 .. index:: triple: schema; class property; messages
748 triple: schema; class property; files
749 triple: schema; class property; nosy
750 triple: schema; class property; superseder
1131 751
1132 IssueClass 752 IssueClass
1133 ~~~~~~~~~~ 753 ~~~~~~~~~~
1134 754
1135 IssueClasses automatically include the "messages", "files", "nosy", and 755 IssueClass automatically includes the "messages", "files", "nosy", and
1136 "superseder" properties. 756 "superseder" properties.
1137 757
1138 The messages and files properties list the links to the messages and 758 The messages and files properties list the links to the messages and
1139 files related to the issue. The nosy property is a list of links to 759 files related to the issue. The nosy property is a list of links to
1140 users who wish to be informed of changes to the issue - they get "CC'ed" 760 users to tell about changes to the issue. They get "CC'ed"
1141 e-mails when messages are sent to or generated by the issue. The nosy 761 e-mails when messages are sent to or generated by the issue. The nosy
1142 reactor (in the ``'detectors'`` directory) handles this action. The 762 reactor (in the ``'detectors'`` directory) handles this action. The
1143 superseder link indicates an issue which has superseded this one. 763 superseder link indicates an issue which has superseded this one.
1144 764 It is better described in the
1145 They also have the dynamically generated "creation", "activity" and 765 `original document <original_overview.html#roundupdb>`_.
1146 "creator" properties. 766
767 They also have the default "creation", "activity" and "creator"
768 properties.
1147 769
1148 The value of the "creation" property is the date when an item was 770 The value of the "creation" property is the date when an item was
1149 created, and the value of the "activity" property is the date when any 771 created. The value of the "activity" property is the date when any
1150 property on the item was last edited (equivalently, these are the dates 772 property on the item was last edited (equivalently, these are the dates
1151 on the first and last records in the item's journal). The "creator" 773 on the first and last records in the item's journal). The "creator"
1152 property holds a link to the user that created the issue. 774 property holds a link to the user that created the issue.
1153 775
1154 .. index:: triple: schema; class property; content 776 .. index:: triple: schema; class property; content
1157 FileClass 779 FileClass
1158 ~~~~~~~~~ 780 ~~~~~~~~~
1159 781
1160 FileClasses save their "content" attribute off in a separate file from 782 FileClasses save their "content" attribute off in a separate file from
1161 the rest of the database. This reduces the number of large entries in 783 the rest of the database. This reduces the number of large entries in
1162 the database, which generally makes databases more efficient, and also 784 the database, which makes databases more efficient. Also web servers,
1163 allows us to use command-line tools to operate on the files. They are 785 image processing applications, and command line tools can operate on
1164 stored in the files sub-directory of the ``'db'`` directory in your 786 the files. The content is stored in the ``files`` sub-directory of the
1165 tracker. FileClasses also have a "type" attribute to store the MIME 787 ``'db'`` directory in your tracker. FileClasses also have a "type"
1166 type of the file. 788 attribute to store the file's MIME type.
1167 789
1168 Roundup by default considers the contents of the file immutable. This 790 Roundup, by default, considers the contents of the file
1169 is to assist in maintaining an accurate record of correspondence. The 791 immutable. This assists in maintaining an accurate record of
1170 distributed tracker templates do not enforce this. So if you have 792 correspondence. The distributed tracker templates do not enforce
1171 access to the Roundup tracker directory, you can edit the files (make 793 this. If you have access to the Roundup tracker directory, you can
1172 sure to preserve mode, owner and group) to remove information (e.g. if 794 edit the files (make sure to preserve mode, owner and group) to remove
1173 somebody includes a password or you need to redact proprietary 795 information. You may need to do this if somebody includes a password
1174 information). Obviously the journal for the message/file will not 796 or you need to redact proprietary information. The journal for the
1175 report that the file has changed. 797 message/file won't report that the file has changed.
1176 798
1177 Best practice is to remove offending material and leave a 799 Best practice is to remove offending material and leave a
1178 placeholder. E.G. replace a password with the text:: 800 placeholder. E.G. replace a password with the text::
1179 801
1180 [password has been deleted 2020-12-02 --myname] 802 [password has been deleted 2020-12-02 --myname]
1228 where ``hello`` is a file on local disk. 850 where ``hello`` is a file on local disk.
1229 851
1230 You can enforce immutability in your tracker by adding an auditor (see 852 You can enforce immutability in your tracker by adding an auditor (see
1231 detectors_) for the file/msg class that rejects changes to the content 853 detectors_) for the file/msg class that rejects changes to the content
1232 property. The auditor could also add a journal entry so that a change 854 property. The auditor could also add a journal entry so that a change
1233 via the Roundup mechanism is reported. Using a mixin (see: 855 via the Roundup mechanism is reported. Using a mixin (see:
1234 https://wiki.roundup-tracker.org/MixinClassFileClass) to augment the 856 https://wiki.roundup-tracker.org/MixinClassFileClass) to augment the
1235 file class allows for other possibilities including signing the file, or 857 file class allows for other possibilities including:
1236 recording a checksum in the database and validating the file contents 858
1237 at the time it gets read. This allows detection of changes done on the 859 * signing the file,
1238 filesystem outside of the Roundup mechanism. 860 * recording a checksum in the database and validating the file
1239 861 contents at the time it gets read. This allows detection of changes
1240 .. index:: triple: schema; class property; messages 862 done on the filesystem outside of the Roundup mechanism.
1241 triple: schema; class property; files 863 * keeping multiple revisions of the file.
1242 triple: schema; class property; nosy
1243 triple: schema; class property; superseder
1244 864
1245 .. index:: schema; item ordering 865 .. index:: schema; item ordering
1246 866
1247 A note about ordering 867 A note about ordering
1248 ~~~~~~~~~~~~~~~~~~~~~ 868 ~~~~~~~~~~~~~~~~~~~~~
1249 869
1250 When we sort items in the hyperdb, we use one of a number of methods, 870 When we sort items in the hyperdb, we use one of three methods,
1251 depending on the properties being sorted on: 871 depending on the property type:
1252 872
1253 1. If it's a String, Integer, Number, Date or Interval property, we 873 1. String, Integer, Number, Date or Interval property, sort the scalar
1254 just sort the scalar value of the property. Strings are sorted 874 value of the property. Strings sort case-sensitively.
1255 case-sensitively. 875 2. a Link property, sort by either the linked item's "order"
1256 2. If it's a Link property, we sort by either the linked item's "order"
1257 property (if it has one) or the linked item's "id". 876 property (if it has one) or the linked item's "id".
1258 3. Mulitlinks sort similar to #2, but we start with the first Multilink 877 3. Mulitlinks sort similar to #2, starting with the first Multilink
1259 list item, and if they're the same, we sort by the second item, and 878 list item, and if they are the same, sort by the second item, and
1260 so on. 879 so on.
1261 880
1262 Note that if an "order" property is defined on a Class that is used for 881 Note that if an "order" property is defined for a class, all items of
1263 sorting, all items of that Class *must* have a value against the "order" 882 that Class *must* have a value for the "order" property, or
1264 property, or sorting will result in random ordering. 883 sorting will result in random ordering.
1265 884
1266 885
1267 Examples of adding to your schema 886 Examples of adding to your schema
1268 --------------------------------- 887 ---------------------------------
1269 888
1270 Some examples are in the :ref:`CustomExamples` section. 889 See :ref:`CustomExamples` for examples.
1271 890
1272 Also you can start with `Roundup wiki CategorySchema`_ to see a list 891 The `Roundup wiki CategorySchema`_ provides a list of additional
1273 of additional examples of how schemas can be customised to add new 892 examples of how to customize schemas to add new functionality.
1274 functionality.
1275 893
1276 .. _Roundup wiki CategorySchema: 894 .. _Roundup wiki CategorySchema:
1277 https://wiki.roundup-tracker.org/CategorySchema 895 https://wiki.roundup-tracker.org/CategorySchema
1278 896
1279 .. index:: !detectors 897 .. index:: !detectors
1284 Schema Integrity 902 Schema Integrity
1285 ---------------- 903 ----------------
1286 904
1287 There is a table in all SQL based schemas called ``schema``. It 905 There is a table in all SQL based schemas called ``schema``. It
1288 contains a representation of the current schema and the current 906 contains a representation of the current schema and the current
1289 Roundup schema version. Roundup will exit the version is not supported 907 Roundup schema version. Roundup will exit if the version is not supported
1290 by the release. E.G. Roundup 2.1.0 will not work with a database 908 by the release. E.G. Roundup 2.1.0 will not work with a database
1291 created by 2.3.0 as db version 8 used by 2.3.0 is not supported by 909 created by 2.3.0 as db version 8 used by 2.3.0 is not supported by
1292 2.1.0. 910 2.1.0.
1293 911
1294 The current schema representation is automatically updated whenever a 912 The current schema representation is automatically updated whenever a
1323 version. 941 version.
1324 942
1325 Detectors - adding behaviour to your tracker 943 Detectors - adding behaviour to your tracker
1326 ============================================ 944 ============================================
1327 945
1328 Detectors are initialised every time you open your tracker database, so 946 Detectors are Python modules that sit in your tracker's ``detectors``
1329 you're free to add and remove them any time, even after the database is 947 directory. You are free to add and remove them any time, even after
1330 initialised via the ``roundup-admin initialise`` command. 948 the database is initialised via the ``roundup-admin initialise``
1331 949 command.
1332 The detectors in your tracker fire *before* (**auditors**) and *after* 950
1333 (**reactors**) changes to the contents of your database. They are Python 951 There are two types of detectors:
1334 modules that sit in your tracker's ``detectors`` directory. You will 952
1335 have some installed by default - have a look. You can write new 953 1. *auditors* are run before changes are made to the database
1336 detectors or modify the existing ones. The existing detectors installed 954 2. *reactors* are run after the change has been committed to the database
1337 for you are: 955
956 .. index:: auditors; rules for use
957 single: reactors; rules for use
958
959 Auditor or Reactor?
960 -------------------
961
962 Generally speaking, you should observe the following rules:
963
964 **Auditors**
965 Are used for `vetoing creation of or changes to items`_. They might
966 also make automatic changes to item properties. They can raise the
967 ``Reject`` or ``CheckId`` exceptions to control database changes.
968 **Reactors**
969 Detect changes in the database and react accordingly. They should avoid
970 making changes to the database where possible, as this could create
971 detector loops.
972
973
974 Detectors Installed by Default
975 ------------------------------
976
977 You will have some detectors installed by default - have a look in the
978 ``detectors`` subdirectory of your tracker home. You can write new
979 detectors or modify the existing ones. The existing detectors
980 installed for you are:
1338 981
1339 .. index:: detectors; installed 982 .. index:: detectors; installed
1340 983
1341 **nosyreaction.py** 984 **nosyreaction.py**
1342 This provides the automatic nosy list maintenance and email sending. 985 This provides the automatic nosy list maintenance and email sending.
1343 The nosy reactor (``nosyreaction``) fires when new messages are added 986 The nosy reactor (``nosyreaction``) fires when new messages are added
1344 to issues. The nosy auditor (``updatenosy``) fires when issues are 987 to issues. The nosy auditor (``updatenosy``) fires when issues are
1345 changed, and figures out what changes need to be made to the nosy list 988 changed, and figures out what changes need to be made to the nosy list
1346 (such as adding new authors, etc.) 989 (such as adding new authors, etc.)
990
991 If you are running a tracker started with ``roundup-demo`` or the
992 ``demo.py`` script, this detector will be missing.This is
993 intentional to prevent email from being sent from a demo
994 tracker. You can find the nosyreaction.py detector in the
995 :term:`template directory (meaning 3) <template>` and copy it into
996 your tracker if you want email to be sent.
1347 **statusauditor.py** 997 **statusauditor.py**
1348 This provides the ``chatty`` auditor which changes the issue status 998 This provides the ``chatty`` auditor which changes the issue status
1349 from ``unread`` or ``closed`` to ``chatting`` if new messages appear. 999 from ``unread`` or ``closed`` to ``chatting`` if new messages appear.
1350 It also provides the ``presetunread`` auditor which pre-sets the 1000 It also provides the ``presetunread`` auditor which pre-sets the
1351 status to ``unread`` on new items if the status isn't explicitly 1001 status to ``unread`` on new items if the status isn't explicitly
1355 content. 1005 content.
1356 **userauditor.py** 1006 **userauditor.py**
1357 Verifies the content of some of the user fields (email addresses and 1007 Verifies the content of some of the user fields (email addresses and
1358 roles lists). 1008 roles lists).
1359 1009
1360 If you don't want this default behaviour, you're completely free to change 1010 If you don't want this default behaviour, you are completely free to change
1361 or remove these detectors. 1011 or remove these detectors.
1362 1012
1363 See the detectors section in the `design document`__ for details of the 1013 The rest of this section includes much of the information from the
1364 interface for detectors. 1014 `detectors section in the design document`_. But there are some
1365 1015 details of the detector interface that are only in the design
1366 __ design.html 1016 document. Also the design document `includes examples`_ of a project
1367 1017 that requires three approvals before it can be processed and rejecting
1018 an email to create an issue if it doesn't have an attached patch.
1019
1020 .. _`detectors section in the design document`: design.html#detector-interface
1021
1022 .. _`includes examples`: design.html#detector-example
1023
1024 Registering Detectors
1025 ---------------------
1026
1027 Detectors are registered using the ``audit`` or ``react`` methods of a
1028 database schema class. Each detector file must define an ``init(db)``
1029 function. This function is run to register the detectors. For example
1030 this registers two auditors for changes made to the user class in the
1031 database::
1032
1033 def init(db):
1034 # fire before changes are made
1035 db.user.audit('set', audit_user_fields)
1036 db.user.audit('create', audit_user_fields)
1037
1038 while this registers two auditors and two reactors for the issue
1039 class::
1040
1041 def init(db):
1042 db.issue.react('create', nosyreaction)
1043 db.issue.react('set', nosyreaction)
1044 db.issue.audit('create', updatenosy)
1045 db.issue.audit('set', updatenosy)
1046
1047 The arguments for ``audit`` and ``react`` are the same:
1048
1049 * operation - one of ``create``, ``set``, ``retire``, or ``restore``
1050 * function name - use the function name without ``()`` after
1051 it. (You want the function name not the result of calling the
1052 function.)
1053 * priority - (optional default 100) the priority allows you to order
1054 the application order of the detectors.
1055
1056 A detector with a priority of 110 will run after a detector with
1057 the default priority of 100. A detector with a priority of 90 will
1058 run before a detector with the default priority of 100.
1059
1060 Detectors with the same priority are run in an undefined
1061 order. All the examples above use the default priority of 100.
1062
1063 If no auditor raises an exception, the changes are committed to the
1064 database. Then all the reactors registered for the operation are run.
1368 1065
1369 .. index:: detectors; writing api 1066 .. index:: detectors; writing api
1067 .. _detector_api:
1370 1068
1371 Detector API 1069 Detector API
1372 ------------ 1070 ------------
1373 1071
1374 .. index:: pair: detectors; auditors 1072 .. index:: pair: detectors; auditors
1376 single: auditors; defining 1074 single: auditors; defining
1377 single: auditors; arguments 1075 single: auditors; arguments
1378 1076
1379 Auditors are called with the arguments:: 1077 Auditors are called with the arguments::
1380 1078
1381 audit(db, cl, itemid, newdata) 1079 an_auditor(db, cl, itemid, newdata)
1382 1080
1383 where ``db`` is the database, ``cl`` is an instance of Class or 1081 where ``db`` is the database, ``cl`` is an instance of Class or
1384 IssueClass within the database, and ``newdata`` is a dictionary mapping 1082 IssueClass within the database, and ``newdata`` is a dictionary mapping
1385 property names to values. 1083 property names to values.
1386 1084
1387 For a ``create()`` operation, the ``itemid`` argument is None and 1085 For a ``create()`` operation, the ``itemid`` argument is None and
1388 newdata contains all of the initial property values with which the item 1086 ``newdata`` contains all the initial property values that will be
1389 is about to be created. 1087 used to create the item
1390 1088
1391 For a ``set()`` operation, newdata contains only the names and values of 1089 For a ``set()`` operation, ``newdata`` contains only the names and
1392 properties that are about to be changed. 1090 values of properties that are about to be changed.
1393 1091
1394 For a ``retire()`` or ``restore()`` operation, newdata is None. 1092 For a ``retire()`` or ``restore()`` operation, ``newdata`` is None.
1395 1093
1396 .. index:: pair: detectors; reactor 1094 .. index:: pair: detectors; reactor
1397 single: reactors; function signature 1095 single: reactors; function signature
1398 single: reactors; defining 1096 single: reactors; defining
1399 single: reactors; arguments 1097 single: reactors; arguments
1400 1098
1401 Reactors are called with the arguments:: 1099 Reactors are called with the arguments::
1402 1100
1403 react(db, cl, itemid, olddata) 1101 a_reactor(db, cl, itemid, olddata)
1404 1102
1405 where ``db`` is the database, ``cl`` is an instance of Class or 1103 where ``db`` is the database, ``cl`` is an instance of Class or
1406 IssueClass within the database, and ``olddata`` is a dictionary mapping 1104 IssueClass within the database, and ``olddata`` is a dictionary mapping
1407 property names to values. 1105 property names to values.
1408 1106
1409 For a ``create()`` operation, the ``itemid`` argument is the id of the 1107 For a ``create()`` operation, the ``itemid`` argument is the id of the
1410 newly-created item and ``olddata`` is None. 1108 newly created item and ``olddata`` is None.
1411 1109
1412 For a ``set()`` operation, ``olddata`` contains the names and previous 1110 For a ``set()`` operation, ``olddata`` contains the names and previous
1413 values of properties that were changed. 1111 values of properties that were changed.
1414 1112
1415 For a ``retire()`` or ``restore()`` operation, ``itemid`` is the id of 1113 For a ``retire()`` or ``restore()`` operation, ``itemid`` is the id of
1416 the retired or restored item and ``olddata`` is None. 1114 the retired or restored item and ``olddata`` is None.
1115
1116 Your auditor can raise one of two exceptions:
1117
1118 ``Reject('Reason for rejection')``
1119 indicates that the change is rejected. The user should see the same
1120 page they used to make the change with a the 'Reason for rejection'
1121 message displayed in the error feedback section of the page. See
1122 :ref:`vetoing creation of or changes to items` for an example.
1123 ``Reauth('Reason for confirmation')``
1124 indicates that the user needs to enter their password or other
1125 identity confirming information (e.g. a one time key) before the
1126 change will be committed. This can be used when a user's password or
1127 email address are changed. This can prevent an attacker from changing
1128 the information by providing confirmation of the person making the
1129 change. This addition confirmation step is recommended in the `OWASP
1130 Authentication Cheat Sheet`_. An example can be found at
1131 :ref:`sensitive_changes`. See :ref:`Confirming the User` for details
1132 and warnings.
1133
1134 .. _`OWASP Authentication Cheat Sheet`:
1135 https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html#require-re-authentication-for-sensitive-features
1417 1136
1418 .. index:: detectors; additional 1137 .. index:: detectors; additional
1419 1138
1420 Additional Detectors Ready For Use 1139 Additional Detectors Ready For Use
1421 ---------------------------------- 1140 ----------------------------------
1425 to use one, copy it to the ``'detectors'`` of your tracker instance: 1144 to use one, copy it to the ``'detectors'`` of your tracker instance:
1426 1145
1427 **irker.py** 1146 **irker.py**
1428 This detector sends notification on IRC through an irker daemon 1147 This detector sends notification on IRC through an irker daemon
1429 (http://www.catb.org/esr/irker/) when issues are created or messages 1148 (http://www.catb.org/esr/irker/) when issues are created or messages
1430 are added. In order to use it you need to install irker, start the 1149 are added. To use it you need to install irker, start the
1431 irkerd daemon, and add an ``[irker]`` section in ``detectors/config.ini`` 1150 irkerd daemon, and add an ``[irker]`` section in ``detectors/config.ini``
1432 that contains a comma-separated list of channels where the messages should 1151 that contains a comma-separated list of channels where the messages should
1433 be sent, e.g. ``channels = irc://chat.freenode.net/channelname``. 1152 be sent, e.g. ``channels = irc://chat.freenode.net/channelname``.
1434 **newissuecopy.py** 1153 **newissuecopy.py**
1435 This detector sends an email to a team address whenever a new issue is 1154 This detector sends an email to a team address whenever a new issue is
1436 created. The address is hard-coded into the detector, so edit it 1155 created. The address is hard-coded into the detector, so edit it
1437 before you use it (look for the text 'team@team.host') or you'll get 1156 before you use it (look for the text 'team@team.host') or you'll get
1438 email errors! 1157 email errors!
1439 **creator_resolution.py** 1158 **creator_resolution.py**
1440 Catch attempts to set the status to "resolved" - if the assignedto 1159 When the status is set to "resolved" this auditor checks the user
1441 user isn't the creator, then set the status to "confirm-done". Note that 1160 performing the action. If the user is not the creator, it sets the
1442 "classic" Roundup doesn't have that status, so you'll have to add it. If 1161 status to "confirm-done". Note that "classic" Roundup doesn't have
1443 you don't want to though, it'll just use "in-progress" instead. 1162 that status, so you'll have to add it. If you don't want to though,
1163 it'll just use "in-progress" instead.
1444 **email_auditor.py** 1164 **email_auditor.py**
1445 If a file added to an issue is of type message/rfc822, we tack on the 1165 If a file added to an issue is of type message/rfc822, tack on the
1446 extension .eml. 1166 extension .eml.
1447 The reason for this is that Microsoft Internet Explorer will not open 1167 The reason for this is that Microsoft Internet Explorer will not open
1448 things with a .eml attachment, as they deem it 'unsafe'. Worse yet, 1168 things with a .eml attachment, as they deem it 'unsafe'. Worse yet,
1449 they'll just give you an incomprehensible error message. For more 1169 they'll just give you an incomprehensible error message. For more
1450 information, see the detector code - it has a lengthy explanation. 1170 information, see the detector code - it has a lengthy explanation.
1451 1171
1452 1172
1453 .. index:: auditors; rules for use 1173 .. _`Vetoing creation of or changes to items`:
1454 single: reactors; rules for use
1455
1456 Auditor or Reactor?
1457 -------------------
1458
1459 Generally speaking, the following rules should be observed:
1460
1461 **Auditors**
1462 Are used for `vetoing creation of or changes to items`_. They might
1463 also make automatic changes to item properties.
1464 **Reactors**
1465 Detect changes in the database and react accordingly. They should avoid
1466 making changes to the database where possible, as this could create
1467 detector loops.
1468
1469 1174
1470 Vetoing creation of or changes to items 1175 Vetoing creation of or changes to items
1471 --------------------------------------- 1176 ---------------------------------------
1472 1177
1473 Auditors may raise the ``Reject`` exception to prevent the creation of 1178 Auditors may raise the ``Reject`` exception to prevent the creation of
1474 or changes to items in the database. The mail gateway, for example, will 1179 or changes to items in the database. The mail gateway, for example, will
1475 not attach files or messages to issues when the creation of those files or 1180 not attach files or messages to issues when the creation of those files or
1476 messages are prevented through the ``Reject`` exception. It'll also not create 1181 messages are prevented through the ``Reject`` exception. It'll also not create
1477 users if that creation is ``Reject``'ed too. 1182 users if that creation is ``Reject``'ed too.
1478 1183
1479 To use, simply add at the top of your auditor:: 1184 To use, simply add at the top of your auditor::
1480 1185
1481 from roundup.exceptions import Reject 1186 from roundup.exceptions import Reject
1482 1187
1483 And then when your rejection criteria have been detected, simply:: 1188 And then when your rejection criteria have been detected, use::
1484 1189
1485 raise Reject('Description of error') 1190 raise Reject('Description of error')
1486 1191
1487 Error messages raised with ``Reject`` automatically have any HTML content 1192 Error messages raised with ``Reject`` automatically have any HTML
1488 escaped before being displayed to the user. To display an error message to the 1193 content escaped before being displayed to the user. To display an
1489 user without performing any HTML escaping the ``RejectRaw`` should be used. All 1194 error message to the user without performing any HTML escaping
1490 security implications should be carefully considering before using 1195 the ``RejectRaw`` should be used. All security implications
1491 ``RejectRaw``. 1196 should be carefully considering before using ``RejectRaw``.
1492 1197
1198 .. _`Confirming the User`:
1199
1200 Confirming the User
1201 -------------------
1202
1203 Being able to add a user confirmation step in a workflow is useful.
1204 In an auditor adding::
1205
1206 from roundup.cgi.exceptions import Reauth
1207
1208 at the top of the file and then adding::
1209
1210 if 'password' in newvalues and not hasattr(db, 'reauth_done'):
1211 raise Reauth('Add an optional message to the user')
1212
1213 will present the user with an authorization page. The optional message
1214 will be shown at the top of the page. The user will enter their
1215 password (or other verification token) and submit the page to commit
1216 the change. This section describes the mechanism used.
1217
1218 The ``Reauth`` exception is handled by the core code in the
1219 ``Client.reauth()`` method. It modifies the current request's context
1220 cleaning up some fields and saving the current action and template for
1221 later use. Then it sets the template to ``reauth`` which is used to
1222 render the next page.
1223
1224 The page is rendered using the standard template mechanism. You can
1225 create a ``user.reauth.html`` template that is displayed when
1226 requiring reauth for a user. However most users will probably just use
1227 the default ``_generic.reauth.html`` template provided with Roundup.
1228
1229 Look at the generic template to understand what has to be in a new
1230 template. The basic idea is to get the password from the user into the
1231 ``@reauth_password`` input field. Also the form that is generated
1232 embeds a bunch of hidden fields that record the information that
1233 triggered the reauth request.
1234
1235 If you are not using reauth in a workflow that can upload files, you
1236 are all set. The embedding of the hidden fields just works.
1237
1238 If you need to support reauth on a form that allows file uploads, the
1239 generic template supports handling file uploads. It requires
1240 JavaScript in the browser to support files. Since browsers don't allow
1241 a server to assign values to a file input, the template uses a
1242 workaround. The reauth template encodes the contents of each uploaded
1243 file as a base64 encoded string. It then embeds this string inside a
1244 hidden ``<pre>`` tag. This encoded string is about 1/3 larger than the
1245 size of the original file(s).
1246
1247 When the page is loaded, a Javascript function runs and turns the
1248 tagged base64 strings back into file objects with their original
1249 content. It then creates a file input element and assigns these files
1250 to it. This allows the files to be submitted with the rest of the
1251 form. If JavaScript is not enabled, these files will not be submitted
1252 to the server.
1253
1254 **Future ideas for handling disabled JavaScript** - The `server could
1255 detect disabled JavaScript on the browser
1256 <https://wiki.roundup-tracker.org/IsJavascriptAvailable>`_ and
1257 generate a warning. Alternatively, allowing the browser to submit all
1258 the file data by replacing the ``<pre>`` tag with a ``<textarea>`` tag
1259 and a name attribute like ``@filecontents-1``,
1260 ``@filecontents-2``. Along with this, the current ``data-``
1261 attributes on the ``<pre>`` tag need to move to hidden inputs with
1262 names like: ``@filecontents-1.mimetype``,
1263 ``@filecontents-1.filename``. Submitting the form will include all
1264 this data that Roundup could use to pretend the files were submitted
1265 as a proper file input.
1266
1267 When the reauth page is submitted, it invokes the ``reauth`` action
1268 (using the ``@action`` parameter). Verification is done by the
1269 :ref:`ReauthAction <ReauthAction_pydoc>` class in
1270 ``roundup.cgi.actions``. By default
1271 ``ReauthAction.verifyPassword()`` calls::
1272
1273 roundup.cgi.actions:LoginAction::verifyPassword()
1274
1275 to verify the user's password against the one stored in the database.
1276
1277 You can change the verification command using `interfaces.py`_. Adding
1278 the following code to ``interfaces.py``::
1279
1280 from roundup.cgi.actions import ReauthAction
1281
1282 old_verify = ReauthAction.verifyPassword
1283
1284 def new_verify_password(self):
1285 if self.form['@reauth_password'].value == 'LetMeIn':
1286 return True
1287
1288 return old_verify(self)
1289
1290 ReauthAction.verifyPassword = new_verify_password
1291
1292 will accept the passphrase ``LetMeIn`` as well as the user's
1293 password. This example (which you should not use as is) could be
1294 adapted to verify a `Time-based One-Time Password (TOTP)`_. An example
1295 of `implementing a TOTP for Roundup is available on the wiki`_.
1296
1297 .. _`Time-based One-Time Password (TOTP)`:
1298 https://en.wikipedia.org/wiki/Time-based_One-Time_Password
1299
1300 .. _`implementing a TOTP for Roundup is available on the wiki`:
1301 https://wiki.roundup-tracker.org/OneTimePasswords
1302
1303 If the verification succeeds, the original action (e.g. edit) is
1304 invoked on the data sent with the reauth request. To prevent the
1305 auditor from triggering another Reauth, the attribute ``reauth_done``
1306 is added to the db object. As a result, the ``hasattr`` call shown
1307 above will return True and the Reauth exception is not raised. (Note
1308 that the value of the ``reauth_done`` attribute is True, so
1309 ``getattr(db, "reauth_done", False)`` will return True when reauth is
1310 done and the defaul value of False if the attribute is missing. If the
1311 default is not set, `getattr` raises an ``AttributeError`` which might
1312 be useful for flow control.)
1313
1314 There is only one reauth for a submitted change. You cannot Reauth
1315 multiple properties separately. If you need to reauth multiple
1316 properties separately, you need to reject the change and force the
1317 user to submit each sensitive property separately. For example::
1318
1319 if 'password' in newvalues and 'realname' in newvalues:
1320 raise Reject('Changing the username and the realname '
1321 'at the same time is not allowed. Please '
1322 'submit two changes.')
1323
1324 if 'password' in newvalues and not hasattr(db, 'reauth_done'):
1325 raise Reauth()
1326
1327 if 'realname' in newvalues and not hasattr(db, 'reauth_done'):
1328 raise Reauth()
1329
1330 See also: client.py:Client:reauth(self, exception) which can be
1331 changed using interfaces.py in your tracker if you have some special
1332 handling that must be done.
1493 1333
1494 Generating email from Roundup 1334 Generating email from Roundup
1495 ----------------------------- 1335 -----------------------------
1496 1336
1497 The module ``roundup.mailer`` contains most of the nuts-n-bolts required 1337 The module ``roundup.mailer`` contains most of the nuts-n-bolts required
1498 to generate email messages from Roundup. 1338 to generate email messages from Roundup.
1499 1339
1500 In addition, the ``IssueClass`` methods ``nosymessage()`` and 1340 Also, the ``IssueClass`` methods ``nosymessage()`` and
1501 ``send_message()`` are used to generate nosy messages, and may generate 1341 ``send_message()`` generate nosy messages, and may generate
1502 messages which only consist of a change note (ie. the message id parameter 1342 messages which only consist of a change note (i.e. the message id
1503 is not required - this is referred to as a "System Message" because it 1343 parameter is not required - this is referred to as a "System
1504 comes from "the system" and not a user). 1344 Message" because it comes from "the system" and not a user).
1505 1345
1506 1346
1507 .. index:: extensions 1347 .. index:: extensions
1508 .. index:: extensions; add python functions to tracker 1348 .. index:: extensions; add python functions to tracker
1509 .. _extensions: 1349 .. _extensions:
1512 Extensions - adding capabilities to your tracker 1352 Extensions - adding capabilities to your tracker
1513 ================================================ 1353 ================================================
1514 1354
1515 While detectors_ add new behavior by reacting to changes in tracked 1355 While detectors_ add new behavior by reacting to changes in tracked
1516 objects, `extensions` add new actions and utilities to Roundup, which 1356 objects, `extensions` add new actions and utilities to Roundup, which
1517 are mostly used to enhance web interface. 1357 are mostly used to enhance the web interface.
1518 1358
1519 You can create an extension by creating Python file in your tracker 1359 You can create an extension by creating Python file in your
1520 ``extensions`` directory. All files from this dir are loaded when 1360 tracker ``extensions`` directory. The tracker loads all the files
1521 tracker instance is created, at which point it calls ``init(instance)`` 1361 from this directory, at which point it calls ``init(instance)`` from
1522 from each file supplying itself as a first argument. 1362 each file supplying itself as a first argument.
1523 1363
1524 Note that at this point web interface is not loaded, but extensions still 1364 Note that at this point web interface is not loaded, but
1525 can register actions for in tracker instance. This may be fixed in 1365 extensions still can register actions for it in the tracker
1526 Roundup 1.6 by introducing ``init_web(client)`` callback or a more 1366 instance. This may be fixed in Roundup 1.6 by introducing
1527 flexible extension point mechanism. 1367 ``init_web(client)`` callback or a more flexible extension point
1368 mechanism.
1528 1369
1529 * ``instance.registerUtil`` is used for adding `templating utilities`_ 1370 * ``instance.registerUtil`` is used for adding `templating utilities`_
1530 (see `adding a time log to your issues 1371 (see `adding a time log to your issues
1531 <customizing.html#adding-a-time-log-to-your-issues-4>`_ for an example) 1372 <customizing.html#adding-a-time-log-to-your-issues-4>`_ for an example)
1532 1373
1533 * ``instance.registerAction`` is used to add more actions to instance 1374 * ``instance.registerUtilMethod`` is also used for adding `templating
1534 and to web interface. See `Defining new web actions`_ for details. 1375 utilities`_, and provides a TemplatingUtils instance by default to
1535 Generic action can be added by inheriting from ``action.Action`` 1376 the function. This makes more complex templating actions easier to
1536 instead of ``cgi.action.Action``. 1377 use. (see :ref:`dynamic_csp` for an example)
1378
1379 * ``instance.registerAction`` is used to add more actions to the
1380 instance and to web interface. See `Defining new web actions`_
1381 for details. Generic action can be added by inheriting from
1382 ``action.Action`` instead of ``cgi.action.Action``.
1537 1383
1538 .. _interfaces.py: 1384 .. _interfaces.py:
1539 .. _modifying the core of Roundup: 1385 .. _modifying the core of Roundup:
1386
1387 .. index:: single: interfaces.py; hooking into the roundup core
1540 1388
1541 interfaces.py - hooking into the core of Roundup 1389 interfaces.py - hooking into the core of Roundup
1542 ================================================ 1390 ================================================
1543 1391
1544 There is a magic trick for hooking into the core of Roundup. Using 1392 There is a magic trick for hooking into the core of Roundup. Using
1550 * add new rest endpoints 1398 * add new rest endpoints
1551 * enable experimental or future features 1399 * enable experimental or future features
1552 1400
1553 but with great power comes great responsibility. 1401 but with great power comes great responsibility.
1554 1402
1555 Interfaces.py has been around since the earliest releases of Roundup 1403 Interfaces.py has existed since the earliest releases of Roundup
1556 and used to be the main way to get a lot of customisation done. In 1404 and was the main way to get a lot of customisation done. In
1557 modern Roundup, the extensions_ mechanism is used to `add actions 1405 modern Roundup, the extensions_ mechanism is used to `add actions
1558 <#defining-new-web-actions>`_ and `templating utilities`_. But there are 1406 <#defining-new-web-actions>`_ and `templating utilities`_. But
1559 places where interfaces.py is still useful. Note that the tracker 1407 there are places where interfaces.py is still useful. Note that
1560 directories are not on the Python system path when interfaces.py is 1408 the tracker directories are not on the Python system path when
1561 evaluated. You need to add library directories explictly by 1409 interfaces.py is evaluated. You need to add library directories
1562 modifying sys.path. 1410 explicitly by modifying sys.path.
1563 1411
1564 Interfaces.py allows you to interact with any part of Roundup's 1412 Interfaces.py allows you to interact with any part of Roundup's
1565 internals. These internals are not as stable as defined interfaces 1413 internals. These internals are not as stable as defined interfaces
1566 (e.g. extensions. detectors, schema). So the code in interfaces.py is 1414 (e.g. extensions. detectors, schema). So the code in interfaces.py is
1567 more likely to need modification when upgrading from version to 1415 more likely to need modification when upgrading from version to
1568 version. While the developers attempt to keep the examples working, 1416 version. While the developers attempt to keep the examples working,
1569 it may make more sense to change the internals to make the code 1417 it may make more sense to change the internals to make the code
1570 clearer, add more features etc. 1418 clearer, add more features etc.
1571 1419
1572 See `Changing How the Core Code Works 1420 See `Changing How the Core Code Works
1573 <customizing.html#changing-how-the-core-code-works>`_ for examples 1421 <customizing.html#changing-how-the-core-code-works>`_ for examples
1582 a definitional class. (E.g. if a detector checks to see if an issue 1430 a definitional class. (E.g. if a detector checks to see if an issue
1583 has a status of "open", and you change the "open" definition to be 1431 has a status of "open", and you change the "open" definition to be
1584 "working", you need to change the check.) 1432 "working", you need to change the check.)
1585 1433
1586 Customisation of the special :term:`definitional classes <definitional 1434 Customisation of the special :term:`definitional classes <definitional
1587 class>` (eg. status, 1435 class>` (e.g. status,
1588 priority, resolution, ...) may be done either before or after the 1436 priority, resolution, ...) may be done either before or after the
1589 tracker is initialised. The actual method of doing so is completely 1437 tracker is initialised. The actual method of doing so is completely
1590 different in each case though, so be careful to use the right one. 1438 different in each case though, so be careful to use the right one.
1591 1439
1592 **Changing content before tracker initialisation** 1440 **Changing content before tracker initialisation**
1630 Anonymous users access to the email interface. When granted to the 1478 Anonymous users access to the email interface. When granted to the
1631 Anonymous user, they will be automatically registered by the email 1479 Anonymous user, they will be automatically registered by the email
1632 interface (see also the ``new_email_user_roles`` configuration option). 1480 interface (see also the ``new_email_user_roles`` configuration option).
1633 1481
1634 Web Access 1482 Web Access
1635 If defined, the user may use the web interface. This is usually 1483 If defined, the user may use the web interface. This is
1636 assigned to the Anonymous role as well to allow authorized users to 1484 assigned to the Anonymous role to allow authorized users to
1637 access the form based login. If some other authorization mode (basic 1485 access the form based login. If your tracker uses some other
1638 auth, SSO, etc.) is used Web Access can be removed from the 1486 authorization mode (basic auth, Single Sign On (SSO), etc.) Web
1639 Anonymous user. 1487 Access can be removed from the Anonymous user.
1640 1488
1641 Web Roles 1489 Web Roles
1642 Controls user access to editing the "roles" property of the "user" class. 1490 Controls user access to editing the "roles" property of the "user" class.
1643 TODO: deprecate in favour of a property-based control. 1491 TODO: deprecate in favour of a property-based control.
1644 1492
1647 roles have these by default in the classic tracker. See the 1495 roles have these by default in the classic tracker. See the
1648 `directions in the rest interface documentation`_ and the 1496 `directions in the rest interface documentation`_ and the
1649 `xmlrpc interface documentation`_. 1497 `xmlrpc interface documentation`_.
1650 1498
1651 Register 1499 Register
1652 This is assigned to the anonymous user and allows automatic user 1500 This enables automatic user registration by email or web. It is
1653 registration by email or web. 1501 assigned to the anonymous user.
1654 1502
1655 These are hooked into the default Roles: 1503 These are assigned into the default Roles:
1656 1504
1657 - Admin (Create, Edit, Retire, Restore, Search, View for everything; Web Roles) 1505 - Admin (Create, Edit, Retire, Restore, Search, View for everything; Web Roles)
1658 - User (Web Access; Email Access) 1506 - User (Web Access; Email Access)
1659 - Anonymous (Web Access) 1507 - Anonymous (Web Access)
1660 1508
1661 Finally, the "admin" user gets the "Admin" Role, and the "anonymous" 1509 Finally, the "admin" user gets the "Admin" Role, and the "anonymous"
1662 user gets the "Anonymous" Role assigned when the tracker is installed. 1510 user gets the "Anonymous" Role. The "Admin" and "Anonymous" roles
1511 are created when the tracker is initialized.
1663 1512
1664 For the "User" Role, the "classic" tracker defines: 1513 For the "User" Role, the "classic" tracker defines:
1665 1514
1666 - Create, Edit and View issue, file, msg, query, keyword 1515 - Create, Edit and View issue, file, msg, query, keyword
1667 - View priority, status 1516 - View priority, status
1668 - View user 1517 - View user (limited properties)
1518 - View their own user record
1669 - Edit their own user record 1519 - Edit their own user record
1670 1520 - Search queries
1671 And the "Anonymous" Role is defined as: 1521
1522 And the "Anonymous" Role has the following permissions:
1672 1523
1673 - Web interface access 1524 - Web interface access
1674 - Register user (for registration) 1525 - Register user (for registration)
1675 - View issue, file, msg, query, keyword, priority, status 1526 - View issue, file, msg, query, keyword, priority, status
1676 1527
1797 cause baffling permission issues. 1648 cause baffling permission issues.
1798 1649
1799 Automatic Permission Checks 1650 Automatic Permission Checks
1800 --------------------------- 1651 ---------------------------
1801 1652
1802 Permissions are automatically checked when information is rendered 1653 Permissions are automatically checked when rendering information
1803 through the web. This includes: 1654 through the web. This includes:
1804 1655
1805 1. View checks for properties when being rendered via the ``plain()`` or 1656 1. View checks for properties when rendered via the ``plain()`` or
1806 similar methods. If the check fails, the text "[hidden]" will be 1657 similar methods. If the check fails, the text "[hidden]" is
1807 displayed. 1658 displayed.
1808 2. Edit checks for properties when the edit field is being rendered via 1659 2. Edit checks for properties when the edit field is rendered via
1809 the ``field()`` or similar methods. If the check fails, the property 1660 the ``field()`` or similar methods. If the check fails, the property
1810 will be rendered via the ``plain()`` method (see point 1. for subsequent 1661 is rendered via the ``plain()`` method (see point 1. for subsequent
1811 checking performed) 1662 checking performed)
1812 3. View checks are performed in index pages for each item being displayed 1663 3. View checks are performed in index pages for each item being displayed
1813 such that if the user does not have permission, the row is not rendered. 1664 such that if the user does not have permission, the row is not rendered.
1814 4. View checks are performed at the top of item pages for the Item being 1665 4. View checks are performed at the top of item pages for the Item being
1815 displayed. If the user does not have permission, the text "You are not 1666 displayed. If the user does not have permission, the text "You are not
1816 allowed to view this page." will be displayed. 1667 allowed to view this page." is displayed.
1817 5. View checks are performed at the top of index pages for the Class being 1668 5. View checks are performed at the top of index pages for the Class being
1818 displayed. If the user does not have permission, the text "You are not 1669 displayed. If the user does not have permission, the text "You are not
1819 allowed to view this page." will be displayed. 1670 allowed to view this page." is displayed.
1820 1671
1821 1672
1822 New User Roles 1673 New User Roles
1823 -------------- 1674 --------------
1824 1675
1841 1692
1842 You may use the ``roundup-admin`` "``security``" command to display the 1693 You may use the ``roundup-admin`` "``security``" command to display the
1843 current Role and Permission configuration in your tracker. 1694 current Role and Permission configuration in your tracker.
1844 1695
1845 1696
1846 Adding a new Permission 1697 Adding a New Permission
1847 ~~~~~~~~~~~~~~~~~~~~~~~ 1698 ~~~~~~~~~~~~~~~~~~~~~~~
1848 1699
1849 When adding a new Permission, you will need to: 1700 When adding a new Permission, you need to:
1850 1701
1851 1. add it to your tracker's ``schema.py`` so it is created, using 1702 1. create it in your tracker's ``schema.py`` using
1852 ``security.addPermission``, for example:: 1703 ``security.addPermission``. For example::
1853 1704
1854 db.security.addPermission(name="View", klass='frozzle', 1705 db.security.addPermission(name="View", klass='frozzle',
1855 description="User is allowed to access frozzles") 1706 description="User is allowed to access frozzles")
1856 1707
1857 will set up a new "View" permission on the Class "frozzle". 1708 will set up a new "View" permission on the Class "frozzle".
1858 2. enable it for the Roles that should have it (verify with 1709 2. enable it for the Roles that should have it (verify with
1859 "``roundup-admin security``") 1710 "``roundup-admin security``")
1860 3. add it to the relevant HTML interface templates 1711 3. check it in the relevant HTML interface templates
1861 4. add it to the appropriate xxxPermission methods on in your tracker 1712 4. check it in the appropriate hasPermission methods in your tracker's
1862 interfaces module 1713 extensions/detectors/interfaces.py modules
1863 1714
1864 The ``addPermission`` method takes a few optional parameters: 1715 The ``addPermission`` method takes a four optional parameters:
1716
1717 **check**
1718 A function to be executed which returns boolean determining whether
1719 the Permission is allowed. If it returns True, the permission is
1720 allowed, if it returns False the permission is denied. The function
1721 can have one of two signatures::
1722
1723 check(db, userid, itemid)
1724
1725 or::
1726
1727 check(db, userid, itemid, **ctx)
1728
1729 where ``db`` is a handle on the open database, ``userid`` is
1730 the user attempting access and ``itemid`` is the specific item being
1731 accessed. If the second form is used the ``ctx`` dictionary is
1732 defined with the following values::
1733
1734 ctx['property'] the name of the property being checked or None if
1735 it's a class check.
1736
1737 ctx['classname'] the name of the class that is being checked
1738 (issue, query ....).
1739
1740 ctx['permission'] the name of the permission (e.g. View, Edit...).
1741
1742 The second form is preferred as it makes it easier to implement more
1743 complex permission schemes. An `example in upgrading.html
1744 <upgrading.html#enhancement-to-check-command-for-permissions>`_
1745 shows the use of ``ctx``.
1746
1747 Note that the check option is not supported for the Search
1748 permission. When searching there is no item defined, so a check
1749 function does not make any sense.
1750
1751 **filter**
1752 This optional function returns parameters for the ``filter`` method
1753 when getting ``Class`` items (users, issues etc.) from the
1754 database. It filters items at the database level (using SQL where
1755 possible). This pre-filters the number of items returned from the
1756 database when displaying results in an ``index`` template. This
1757 filtering is usually faster than calling a ``check`` method (see
1758 previous argument) on *each individual result*.
1759
1760 The ``filter`` method has the signature::
1761
1762 filter(db, userid, klass)
1763
1764 where ``db`` is the database handle, ``userid`` is the user attempting
1765 access and ``klass`` is the ``Class`` in the schema.
1766
1767 The ``filter`` function must return a *list* of dictionaries of
1768 parameters of the
1769 `Class.filter <design.html#:~:text=search_matches>`_ call.
1770 This includes filterspec, retired and exact_match_specs.
1771 Note that sort and group parameters of the filter call should
1772 not be set by filter method (they will be overwritten) and the
1773 parameter search_matches must not be set.
1774
1775 The query executed by an index template is modified by the
1776 parameters computed by the ``filter`` function. An
1777 empty list of filter parameters (``[]``) indicates no access. When
1778 using a filter, a check function is still needed to test each
1779 individual item for visibility. When the filter function is defined
1780 but a check function is not defined, a check function is
1781 manufactured automatically from the ``filter`` function.
1782
1783 Note that the filter option is not supported for the Search
1784 permission. Since the filter function is called *after* the search was
1785 already performed a filter function does not make any sense.
1786
1787 An example ``filter`` function for the ``view_query`` check function
1788 in the query checks above would look like::
1789
1790 def filter_query(db, userid, klass):
1791 return [{'filterspec': {
1792 'private_for': ['-1', userid]
1793 }}]
1794
1795 This would be called by the framework for all queries found when
1796 displaying queries. It filters for all queries where the
1797 ``private_for`` field is the userid or empty. This matches the
1798 definition of the ``view_query`` function above where permission is
1799 granted if the ``private_for`` field indicates the query is owned by
1800 the user, or the ``private_for`` field is empty indicating that the
1801 query is public. If we want to modify the check to also allow acess if
1802 the user is the ``creator`` of a query we would change the filter
1803 function to::
1804
1805 def filter_query(db, userid, klass):
1806 f1 = {'filterspec': {'private_for': ['-1', userid]}}
1807 f2 = {'filterspec': {'creator': userid}}
1808 return [f1, f2]
1809
1810 This is an example where we need multiple filter calls to model an
1811 "or" condition, the user has access if either the ``private_for``
1812 check passes *or* the user is the creator of the query.
1813
1814 Consider an example where we have a class structure where both the
1815 ``issue`` class and the ``user`` class include a reference to an
1816 ``organization`` class. Users are permitted to view only those
1817 issues that are associated with their respective organizations. A
1818 check function or this could look like::
1819
1820 def view_issue(db, userid, itemid):
1821 user = db.user.getnode(userid)
1822 if not user.organisation:
1823 return False
1824 issue = db.issue.getnode(itemid)
1825 if user.organisation == issue.organisation:
1826 return True
1827
1828 The corresponding ``filter`` function::
1829
1830 def filter_issue(db, userid, klass):
1831 user = db.user.getnode(userid)
1832 if not user.organisation:
1833 return []
1834 return [{'filterspec': {
1835 'organisation': user.organisation
1836 }}]
1837
1838 This filters for all issues where the organisation is the same as the
1839 organisation of the user. Note how the filter fails early returning an
1840 empty list (meaning "no access") if the user happens to not have an
1841 organisation.
1865 1842
1866 **properties** 1843 **properties**
1867 A sequence of property names that are the only properties to apply the 1844 A sequence of property names that are the only properties to apply the
1868 new Permission to (eg. ``... klass='user', properties=('name', 1845 new Permission to (eg. ``... klass='user', properties=('name',
1869 'email') ...``) 1846 'email') ...``)
1872 in Roundup 1.6. 1849 in Roundup 1.6.
1873 A permission defined using: 1850 A permission defined using:
1874 1851
1875 ``properties=('list', 'of', 'property', 'names')`` 1852 ``properties=('list', 'of', 'property', 'names')``
1876 1853
1877 is used to determine access for things other than just those 1854 determines access for things other than just those
1878 properties. For example a check for View permission on the issue 1855 properties. For example a check for View permission on the
1879 class or an issue item can use any View permission for the issue 1856 issue class or an issue item can use any View permission for
1880 class even if that permission has a property list. This can be 1857 the issue class even if that permission has a property
1881 confusing and surprising as you would think that a permission 1858 list. This makes sense if you understand that a user can't
1882 including properties would be used only for determining the 1859 access the properties of a class if they can't access the
1883 access permission for those properties. 1860 class. The ability to access class properties implies class
1861 access.
1862
1863 This eliminates the need to create a duplicate View permission
1864 without properties to allow access to the View properties
1865 permission. Even though it makes sense, it can be confusing and
1866 surprising.
1867
1868 You would think that a permission including properties would be
1869 used only for determining the access permission when checking
1870 properties. But that is not the case.
1871
1872 Setting ``props_only=True`` will prevent the permission
1873 from being used unless the check include properties.
1874
1875 If you use a lot of permissions with property checks, it can be
1876 difficult to change all of them. Calling the function:
1877
1878 db.security.set_props_only_default(True)
1879
1880 at the top of ``schema.py`` will make every permission creation
1881 behave as though props_only is True. Note that you may
1882 need to add new View permissions without properties to allow
1883 property only checks to take effect.
1884 1884
1885 ``roundup-admin security`` will report invalid properties for the 1885 ``roundup-admin security`` will report invalid properties for the
1886 class. For example a permission with an invalid summary property is 1886 class. For example a permission with an invalid summary property is
1887 presented as:: 1887 presented as::
1888 1888
1889 Allowed to see content of object regardless of spam status 1889 Allowed to see content of object regardless of spam status
1890 (View for "file": ('content', 'summary') only) 1890 (View for "file": ('content', 'summary') only)
1891 1891
1892 **Invalid properties for file: ['summary'] 1892 **Invalid properties for file: ['summary']
1893 1893
1894 Setting ``props_only=True`` will make the permission valid only for
1895 those properties.
1896
1897 If you use a lot of permissions with property checks, it can be
1898 difficult to change all of them. Calling the function:
1899
1900 db.security.set_props_only_default(True)
1901
1902 at the top of ``schema.py`` will make every permission creation
1903 behave as though props_only was set to True. It is expected that the
1904 default of True will become the default in a future Roundup release.
1905 **check**
1906 A function to be executed which returns boolean determining whether
1907 the Permission is allowed. If it returns True, the permission is
1908 allowed, if it returns False the permission is denied. The function
1909 can have one of two signatures::
1910
1911 check(db, userid, itemid)
1912
1913 or::
1914
1915 check(db, userid, itemid, **ctx)
1916
1917 where ``db`` is a handle on the open database, ``userid`` is
1918 the user attempting access and ``itemid`` is the specific item being
1919 accessed. If the second form is used the ``ctx`` dictionary is
1920 defined with the following values::
1921
1922 ctx['property'] the name of the property being checked or None if
1923 it's a class check.
1924
1925 ctx['classname'] the name of the class that is being checked
1926 (issue, query ....).
1927
1928 ctx['permission'] the name of the permission (e.g. View, Edit...).
1929
1930 The second form is preferred as it makes it easier to implement more
1931 complex permission schemes. An `example in upgrading.html
1932 <upgrading.html#enhancement-to-check-command-for-permissions>`_
1933 shows the use of ``ctx``.
1934 1894
1935 Example Scenarios 1895 Example Scenarios
1936 ~~~~~~~~~~~~~~~~~ 1896 ~~~~~~~~~~~~~~~~~
1937 1897
1938 See the `examples <customizing.html#examples>`_ section for longer 1898 See the `examples <customizing.html#examples>`_ section for longer
1952 **automatic registration of users in the e-mail gateway** 1912 **automatic registration of users in the e-mail gateway**
1953 By giving the "anonymous" user the ("Register", "user") Permission, any 1913 By giving the "anonymous" user the ("Register", "user") Permission, any
1954 unidentified user will automatically be registered with the tracker 1914 unidentified user will automatically be registered with the tracker
1955 (with no password, so they won't be able to log in through 1915 (with no password, so they won't be able to log in through
1956 the web until an admin sets their password). By default new Roundup 1916 the web until an admin sets their password). By default new Roundup
1957 trackers don't allow this as it opens them up to spam. It may be enabled 1917 trackers don't enable "Email Access" for "anonymous" as it opens
1918 them up to spam. It may be enabled
1958 by uncommenting the appropriate addPermissionToRole in your tracker's 1919 by uncommenting the appropriate addPermissionToRole in your tracker's
1959 ``schema.py`` file. The new user is given the Roles list defined in the 1920 ``schema.py`` file. The new user is given the Roles list defined in the
1960 "new_email_user_roles" config variable. 1921 "new_email_user_roles" config variable.
1961 1922
1962 **only developers may be assigned issues** 1923 **only developers may be assigned issues**
1971 **only managers may sign off issues as complete** 1932 **only managers may sign off issues as complete**
1972 Create a new Permission called "Closer" for the "issue" class. Create a 1933 Create a new Permission called "Closer" for the "issue" class. Create a
1973 new Role "Manager" which has that Permission, and assign that to the 1934 new Role "Manager" which has that Permission, and assign that to the
1974 appropriate users. In your web interface, only display the "resolved" 1935 appropriate users. In your web interface, only display the "resolved"
1975 issue state option when the user has the "Closer" Permissions. Enforce 1936 issue state option when the user has the "Closer" Permissions. Enforce
1976 the Permission with an auditor. This is very similar to the previous 1937 the Permission with an auditor. This is similar to the previous
1977 example, except that the web interface check would look like:: 1938 example, except that the web interface check would look like::
1978 1939
1979 <option tal:condition="python:request.user.hasPermission('Closer')" 1940 <option tal:condition="python:request.user.hasPermission('Closer')"
1980 value="resolved">Resolved</option> 1941 value="resolved">Resolved</option>
1981 1942
2002 .. contents:: 1963 .. contents::
2003 :local: 1964 :local:
2004 1965
2005 The web interface is provided by the ``roundup.cgi.client`` module and 1966 The web interface is provided by the ``roundup.cgi.client`` module and
2006 is used by ``roundup.cgi``, ``roundup-server`` and ``ZRoundup`` 1967 is used by ``roundup.cgi``, ``roundup-server`` and ``ZRoundup``
2007 (``ZRoundup`` is broken, until further notice). In all cases, we 1968 (``ZRoundup`` is broken, until further notice). In all cases, Roundup
2008 determine which tracker is being accessed (the first part of the URL 1969 determines which tracker is accessed (the first part of the URL
2009 path inside the scope of the CGI handler) and pass control on to the 1970 path inside the scope of the CGI handler) and pass control on to the
2010 ``roundup.cgi.client.Client`` class - which handles the rest of the 1971 :py:class:`roundup.cgi.client.Client` class - which handles the rest of the
2011 access through its ``main()`` method. This means that you can do pretty 1972 access through its ``main()`` method. This means that you can do pretty
2012 much anything you want as a web interface to your tracker. 1973 much anything you want as a web interface to your tracker.
2013 1974
2014 1975
2015 1976
2019 If you choose to change the `tracker schema`_ you will need to ensure 1980 If you choose to change the `tracker schema`_ you will need to ensure
2020 the web interface knows about it: 1981 the web interface knows about it:
2021 1982
2022 1. Index, item and search pages for the relevant classes may need to 1983 1. Index, item and search pages for the relevant classes may need to
2023 have properties added or removed, 1984 have properties added or removed,
2024 2. The "page" template may require links to be changed, as might the 1985 2. The "page" template may require changing links, as might the
2025 "home" page's content arguments. 1986 "home" page's content arguments.
2026 1987
2027 1988
2028 How requests are processed 1989 How requests are processed
2029 -------------------------- 1990 --------------------------
2061 2022
2062 1. ``/`` 2023 1. ``/``
2063 2. ``/index`` 2024 2. ``/index``
2064 3. ``/home`` 2025 3. ``/home``
2065 2026
2066 The following prefix is used to access static resources: 2027 The following prefix accesses static resources:
2067 2028
2068 4. ``/@@file/`` 2029 4. ``/@@file/``
2069 2030
2070 Two additional url's are used for the API's. 2031 Two url's are used for the API's.
2071 The `REST api`_ is accessed via: 2032 The `REST api`_ is accessed via:
2072 2033
2073 5. ``/rest/`` 2034 5. ``/rest/``
2074 2035
2075 .. _`REST api`: rest.html 2036 .. _`REST api`: rest.html
2084 Each class receives two URLs - one for the class itself and another 2045 Each class receives two URLs - one for the class itself and another
2085 for specific items of that class. Example for class URL: 2046 for specific items of that class. Example for class URL:
2086 2047
2087 7. ``/issue`` 2048 7. ``/issue``
2088 2049
2089 This is usually used to show listings of class items. The URL for 2050 Shows a listings of class items, usually in a table. The URL for
2090 for specific object of issue class with id 1 will look like: 2051 for specific object of issue class with id 1 will look like:
2091 2052
2092 8. ``/issue1`` 2053 8. ``/issue1``
2093 2054
2094 .. _strip_zeros: 2055 .. _strip_zeros:
2095 2056
2096 Note that a leading string of 0's will be stripped from the id part of 2057 Note that Roundup strips a leading string of 0's from the id part of
2097 the object :term:`designator` in the URL. E.G. ``/issue001`` is the 2058 the object :term:`designator` in the URL. E.G. ``/issue001`` is the
2098 same as ``/issue1``. Similarly for ``/file01`` etc. However you 2059 same as ``/issue1``. Similarly for ``/file01`` etc. However you
2099 should generate URL's without the extra zeros. 2060 should generate URL's without the extra zeros.
2100 2061
2101 Determining web context 2062 Determining web context
2102 ----------------------- 2063 -----------------------
2103 2064
2104 To determine the "context" of a request (what request is for), we look at 2065 To determine the "context" of a request (what request is for),
2105 the URL path after the tracker root and at ``@template`` request 2066 Roundup looks at the URL path after the tracker root and at
2106 parameter. Typical URL paths look like: 2067 ``@template`` request parameter. Typical URL paths look like:
2107 2068
2108 1. ``/tracker/issue`` 2069 1. ``/tracker/``
2109 2. ``/tracker/issue1`` 2070 2. ``/tracker/issue``
2110 3. ``/tracker/@@file/style.css`` 2071 3. ``/tracker/issue1``
2111 4. ``/cgi-bin/roundup.cgi/tracker/file1`` 2072 4. ``/tracker/@@file/style.css``
2112 5. ``/cgi-bin/roundup.cgi/tracker/file1/kitten.png`` 2073 5. ``/cgi-bin/roundup.cgi/tracker/file1``
2074 6. ``/cgi-bin/roundup.cgi/tracker/file1/kitten.png``
2113 2075
2114 where tracker root is ``/tracker/`` or ``/cgi-bin/roundup.cgi/tracker/`` 2076 where tracker root is ``/tracker/`` or ``/cgi-bin/roundup.cgi/tracker/``
2115 We're looking at "issue", "issue1", "@@file/style.css", "file1" and 2077 We're looking at "issue", "issue1", "@@file/style.css", "file1" and
2116 "file1/kitten.png" in the cases above. 2078 "file1/kitten.png" in the cases above.
2117 2079
2118 1. with is no path we are in the "home" context. See `the "home" 2080 1. with no path Roundup is in the "home" context. See `the "home"
2119 context`_ below for details. "index" or "home" paths may also be used 2081 context`_ below for details. "index" or "home" paths may also be used
2120 to switch into "home" context. 2082 to switch into "home" context.
2121 2. for paths starting with "@@file" the additional path entry ("style.css" 2083 2. if there is something in the path (as in example 2, "issue"), it
2084 identifies the tracker class to display.
2085 3. if the path is an item designator (as in examples 3 and 5, "issue1"
2086 and "file1"), then we're to display a specific item.
2087 :ref:`Note. <strip_zeros>`
2088 4. for paths starting with "@@file" the additional path entry ("style.css"
2122 in the example above) specifies the static file to be served 2089 in the example above) specifies the static file to be served
2123 from the tracker TEMPLATES directory (or STATIC_FILES, if configured). 2090 from the tracker TEMPLATES directory (or STATIC_FILES, if configured).
2124 This is usually the tracker's "html" directory. Internally this works 2091 The TEMPLATES directory is usually the tracker's "html"
2125 by raising SendStaticFile exception. 2092 directory. Internally this works by raising SendStaticFile exception.
2126 3. if there is something in the path (as in example 1, "issue"), it 2093 5. A file can have additional path components (as in example
2127 identifies the tracker class to display. 2094 6). Without the additional components, the metadata for the
2128 4. if the path is an item designator (as in examples 2 and 4, "issue1" 2095 file is displayed.
2129 and "file1"), then we're to display a specific item. 2096 6. if the path starts with an item designator and is longer than one
2130 :ref:`Note. <strip_zeros>`
2131 5. if the path starts with an item designator and is longer than one
2132 entry (as in example 5, "file1/kitten.png"), then we're assumed to be 2097 entry (as in example 5, "file1/kitten.png"), then we're assumed to be
2133 handling an item of a ``FileClass``, and the extra path information 2098 handling an item of a ``FileClass``, and the extra path information
2134 gives the filename that the client is going to label the download 2099 gives the filename that the client is going to label the download
2135 with (i.e. "file1/kitten.png" is nicer to download than "file1"). 2100 with (i.e. "file1/kitten.png" is nicer to download than "file1").
2136 This raises a ``SendFile`` exception. 2101 This raises a ``SendFile`` exception.
2137 2102
2138 Neither 2. or 5. use templates and stop before the template is 2103 Neither 4. or 6. use templates and stop before the template is
2139 determined. For other contexts the template used is specified by the 2104 determined. For other contexts the template used is specified by the
2140 ``@template`` variable, which defaults to: 2105 ``@template`` variable, which defaults to:
2141 2106
2142 - only classname supplied: "index" 2107 - only classname supplied: "index"
2143 - full item designator supplied: "item" 2108 - full item designator supplied: "item"
2145 2110
2146 The "home" Context 2111 The "home" Context
2147 ------------------ 2112 ------------------
2148 2113
2149 The "home" context is special because it allows you to add templated 2114 The "home" context is special because it allows you to add templated
2150 pages to your tracker that don't rely on a class or item (ie. an issues 2115 pages to your tracker that don't rely on a class or item (e.g. an issues
2151 list or specific issue). 2116 list or specific issue).
2152 2117
2153 Let's say you wish to add frames to control the layout of your tracker's 2118 Let's say you wish to add frames to control the layout of your tracker's
2154 interface. You'd probably have: 2119 interface. You'd probably have:
2155 2120
2199 log them in. 2164 log them in.
2200 2165
2201 **edit** 2166 **edit**
2202 Perform an edit of an item in the database. There are some `special form 2167 Perform an edit of an item in the database. There are some `special form
2203 variables`_ you may use. Also you can set the ``__redirect_to`` form 2168 variables`_ you may use. Also you can set the ``__redirect_to`` form
2204 variable to the URL that should be displayed after the edit is succesfully 2169 variable to the URL to display after the edit is successfully
2205 completed. If you wanted to edit a sequence of issues, users etc. this 2170 completed. If you wanted to edit a sequence of issues, users etc. this
2206 could be used to display the next item in the sequence to the user. 2171 could be used to display the next item in the sequence to the user.
2207 2172
2208 **new** 2173 **new**
2209 Add a new item to the database. You may use the same `special form 2174 Add a new item to the database. You may use the same `special form
2210 variables`_ as in the "edit" action. Also you can set the 2175 variables`_ as in the "edit" action. Also you can set the
2211 ``__redirect_to`` form variable to the URL that should be displayed after 2176 ``__redirect_to`` form variable to the URL to display after
2212 the new item is created. This is useful if you want to create another 2177 the new item is created. This is useful if you want to create another
2213 item rather than edit the newly created item. 2178 item rather than edit the newly created item.
2214 2179
2215 **retire** 2180 **retire**
2216 Retire the item in the database. 2181 Retire the item in the database.
2223 2188
2224 **search** 2189 **search**
2225 Mangle some of the form variables: 2190 Mangle some of the form variables:
2226 2191
2227 - Set the form ":filter" variable based on the values of the filter 2192 - Set the form ":filter" variable based on the values of the filter
2228 variables - if they're set to anything other than "dontcare" then add 2193 variables - if they are set to anything other than "dontcare" then add
2229 them to :filter. 2194 them to :filter.
2230 2195
2231 - Also handle the ":queryname" variable and save off the query to the 2196 - Also handle the ":queryname" variable and save off the query to the
2232 user's query list. 2197 user's query list.
2233 2198
2264 Protecting users from web application attacks 2229 Protecting users from web application attacks
2265 --------------------------------------------- 2230 ---------------------------------------------
2266 2231
2267 There is a class of attacks known as Cross Site Request Forgeries 2232 There is a class of attacks known as Cross Site Request Forgeries
2268 (CSRF). Malicious code running in the browser can making a 2233 (CSRF). Malicious code running in the browser can making a
2269 request to Roundup while you are logged into Roundup. The 2234 request to Roundup while you are logged into Roundup. The
2270 malicious code piggy backs on your existing Roundup session to 2235 malicious code piggy backs on your existing Roundup session to
2271 make changes without your knowledge. Roundup 1.6 has support for 2236 make changes without your knowledge. Roundup 1.6 has support for
2272 defending against this by analyzing the 2237 defending against this by analyzing the
2273 2238
2274 * Referer, 2239 * Referer,
2279 HTTP headers. It compares the headers to the value of the web setting 2244 HTTP headers. It compares the headers to the value of the web setting
2280 in the [tracker] section of the tracker's ``config.ini``. 2245 in the [tracker] section of the tracker's ``config.ini``.
2281 2246
2282 Also a per form token (also called a nonce) can be enabled for 2247 Also a per form token (also called a nonce) can be enabled for
2283 the tracker using the ``csrf_enforce_token`` option in 2248 the tracker using the ``csrf_enforce_token`` option in
2284 config.ini. When enabled, Roundup will validate a hidden form 2249 config.ini. When enabled, Roundup will check a hidden form field
2285 field called ``@csrf``. If the validation fails (or the token 2250 called ``@csrf``. If the field's value matches a token in the
2286 is used more than once) the request is rejected. The ``@csrf`` 2251 database, the validation passes and the token is deleted. If the
2287 input field is added automatically by calling the ``submit`` 2252 validation fails because the token is not found (e.g. if the
2288 function/path. It can also be added manually by calling 2253 token is used more than once) the request is rejected. The
2289 anti_csrf_nonce() directly. For example:: 2254 ``@csrf`` input field is added automatically when calling the
2255 ``submit`` function/path. It can also be added manually by
2256 calling anti_csrf_nonce() directly. For example::
2290 2257
2291 <input name="@csrf" type="hidden" 2258 <input name="@csrf" type="hidden"
2292 tal:attributes="value python:utils.anti_csrf_nonce(lifetime=10)"> 2259 tal:attributes="value python:utils.anti_csrf_nonce(lifetime=10)">
2293 2260
2294 By default a nonce lifetime is 2 weeks. However the lifetime (in 2261 By default a nonce lifetime is 2 weeks. However the lifetime (in
2295 minutes) can be set by passing a lifetime argument as shown 2262 minutes) can be set by passing a lifetime argument as shown
2296 above. The example above makes the nonce lifetime 10 minutes. 2263 above. The example above makes the nonce lifetime 10 minutes.
2297 2264
2298 Search for @csrf in this document for more examples. There are 2265 Search for @csrf in this document for more examples. More
2299 more examples and information in ``upgrading.txt``. 2266 examples and information is provided in ``upgrading.txt``.
2300 2267
2301 The token protects you because malicious code supplied by another 2268 The token protects you because malicious code supplied by another
2302 site is unable to obtain the token. Thus many attempts they make 2269 site is unable to obtain the token. Thus any attempt they make
2303 to submit a request are rejected. 2270 to submit a request is rejected.
2304 2271
2305 The protection on the xmlrpc interface is untested, but is based 2272 The protection on the xmlrpc interface is untested, but is based
2306 on a valid header check against the Roundup url and the presence 2273 on a valid header check against the Roundup URL and the presence
2307 of the ``X-REQUESTED-WITH`` header. Work to improve this is a 2274 of the ``X-REQUESTED-WITH`` header. Work to improve this is a
2308 future project after the 1.6 release. 2275 future project after the 1.6 release.
2309 2276
2310 The enforcement levels can be modified in ``config.ini``. Refer to 2277 The enforcement levels can be modified in ``config.ini``. Refer to
2311 that file for details. 2278 that file for details.
2333 ``@action`` variable) is "edit" or "new". 2300 ``@action`` variable) is "edit" or "new".
2334 2301
2335 In the following, <bracketed> values are variable, "@" may be 2302 In the following, <bracketed> values are variable, "@" may be
2336 either ":" or "@", and other text "required" is fixed. 2303 either ":" or "@", and other text "required" is fixed.
2337 2304
2305 .. index::
2306 single: i18n; set from web interface
2307 single: internationalization; set from web interface
2308 single: language; set from web interface
2309
2338 Two special form variables are used to specify user language preferences: 2310 Two special form variables are used to specify user language preferences:
2339 2311
2340 ``@language`` 2312 ``@language``
2341 value may be locale name or ``none``. If this variable is set to 2313 value may be locale name or ``none``. If this variable is set to
2342 locale name, web interface language is changed to given value 2314 locale name, web interface language is changed to given value
2343 (provided that appropriate translation is available), the value 2315 (if the appropriate translation is available). The value
2344 is stored in the browser cookie and will be used for all following 2316 is stored in a browser cookie and is used for all following
2345 requests. If value is ``none`` the cookie is removed and the 2317 requests. If value is ``none`` the cookie is removed and the
2346 language is changed to the tracker default, set up in the tracker 2318 language is changed to the tracker default, set up in the tracker
2347 configuration or OS environment. 2319 configuration or OS environment.
2348 2320
2349 ``@charset`` 2321 ``@charset``
2350 value may be character set name or ``none``. Character set name 2322 value may be character set name or ``none``. Character set name
2351 is stored in the browser cookie and sets output encoding for all 2323 is stored in a browser cookie and sets output encoding for all
2352 HTML pages generated by Roundup. If value is ``none`` the cookie 2324 HTML pages generated by Roundup. If value is ``none`` the cookie
2353 is removed and HTML output is reset to Roundup internal encoding 2325 is removed and HTML output is reset to Roundup internal encoding
2354 (UTF-8). 2326 (UTF-8). This is unlikely to be needed with modern web browsers
2327 and is left over from the early days of the web. It will
2328 be removed at some future date.
2355 2329
2356 Most properties are specified as form variables: 2330 Most properties are specified as form variables:
2357 2331
2358 ``<propname>`` 2332 ``<propname>``
2359 property on the current context item 2333 property on the current context item
2371 submission is successful, a new item of <classname> is 2345 submission is successful, a new item of <classname> is
2372 created. Within the submitted form, a particular 2346 created. Within the submitted form, a particular
2373 designator of this form always refers to the same new 2347 designator of this form always refers to the same new
2374 item. 2348 item.
2375 2349
2376 Once we have determined the "propname", we look at it to see 2350 Once we have determined the "propname", we check to see
2377 if it's special: 2351 if it's special:
2378 2352
2379 ``@required`` 2353 ``@required``
2380 The associated form value is a comma-separated list of 2354 The associated form value is a comma-separated list of
2381 property names that must be specified when the form is 2355 property names that must be specified when the form is
2389 The "@required" specifier must come before any of the 2363 The "@required" specifier must come before any of the
2390 properties it refers to are assigned in the form. 2364 properties it refers to are assigned in the form.
2391 2365
2392 ``@remove@<propname>=id(s)`` or ``@add@<propname>=id(s)`` 2366 ``@remove@<propname>=id(s)`` or ``@add@<propname>=id(s)``
2393 The "@add@" and "@remove@" edit actions apply only to 2367 The "@add@" and "@remove@" edit actions apply only to
2394 Multilink properties. The form value must be a 2368 Multilink properties. The form value must be a
2395 comma-separate list of keys for the class specified by 2369 comma-separate list of keys for the class specified by
2396 the simple form variable. The listed items are added 2370 the simple form variable. The listed items are added
2397 to (respectively, removed from) the specified 2371 to (respectively, removed from) the specified
2398 property. 2372 property.
2399 2373
2400 ``@link@<propname>=<designator>`` 2374 ``@link@<propname>=<designator>``
2401 If the edit action is "@link@", the simple form 2375 If the edit action is "@link@", the simple form
2402 variable must specify a Link or Multilink property. 2376 variable must specify a Link or Multilink property.
2403 The form value is a comma-separated list of 2377 The form value is a comma-separated list of
2404 designators. The item corresponding to each 2378 designators. The item corresponding to each
2405 designator is linked to the property given by simple 2379 designator is linked to the property given by simple
2406 form variable. 2380 form variable.
2407 2381
2408 None of the above (ie. just a simple form value) 2382 None of the above (i.e. just a simple form value)
2409 The value of the form variable is converted 2383 The value of the form variable is converted
2410 appropriately, depending on the type of the property. 2384 appropriately, depending on the type of the property.
2411 2385
2412 For a Link('klass') property, the form value is a 2386 For a Link('klass') property, the form value is a
2413 single key for 'klass', where the key field is 2387 single key (or id number) for 'klass',
2414 specified in schema.py. 2388 where the key field is specified in schema.py.
2415 2389
2416 For a Multilink('klass') property, the form value is a 2390 For a Multilink('klass') property, the form value is a
2417 comma-separated list of keys for 'klass', where the 2391 comma-separated list of keys (or id nummber) for 'klass', where the
2418 key field is specified in schema.py. 2392 key field is specified in schema.py.
2419 2393
2420 Note that for simple-form-variables specifiying Link 2394 Note that for simple-form-variables specifying Link
2421 and Multilink properties, the linked-to class must 2395 and Multilink properties, the linked-to class must
2422 have a key field. 2396 have a key field.
2423 2397
2424 For a String() property specifying a filename, the 2398 For a String() property specifying a filename, the
2425 file named by the form value is uploaded. This means we 2399 file named by the form value is uploaded. This means we
2426 try to set additional properties "filename" and "type" (if 2400 try to set additional properties "filename" and "type" (if
2427 they are valid for the class). Otherwise, the property 2401 they are defined for the class). Otherwise, the property
2428 is set to the form value. 2402 is set to the form value.
2429 2403
2430 For Date(), Interval(), Boolean(), Integer() and Number() 2404 For Date(), Interval(), Boolean(), Integer() and Number()
2431 properties, the form value is converted to the 2405 properties, the form value is converted to the
2432 appropriate value. 2406 appropriate value.
2433 2407
2434 Any of the form variables may be prefixed with a classname or 2408 Any of the form variables may be prefixed with a classname or
2435 designator. 2409 designator.
2436 2410
2437 Setting the form variable: ``__redirect_to=`` to a url when 2411 Setting the form variable: ``__redirect_to=`` to a url when
2438 @action=new redirects the user to the specified url after successfully 2412 ``@action=new`` redirects the user to the specified url after
2439 creating the new item. This is useful if you want the user to create 2413 successfully creating the new item. This is useful if you want
2440 another item rather than edit the newly created item. Note that the 2414 the user to create another item rather than edit the newly
2441 url assigned to ``__redirect_to`` must be url encoded/quoted and be 2415 created item. Note that the url assigned to ``__redirect_to``
2442 under the tracker's base url. If the base_url uses http, you can set 2416 must be url encoded/quoted and be under the tracker's base
2443 the url to https. 2417 url. If the base_url uses http, you can set the url to https.
2444 2418
2445 Two special form values are supported for backwards compatibility: 2419 Two special form values are supported for backwards compatibility:
2446 2420
2447 @note 2421 @note
2448 This is equivalent to:: 2422 This is equivalent to::
2497 Most customisation of the web view can be done by modifying the 2471 Most customisation of the web view can be done by modifying the
2498 templates in the tracker ``'html'`` directory. There are several types 2472 templates in the tracker ``'html'`` directory. There are several types
2499 of files in there. The *minimal* template includes: 2473 of files in there. The *minimal* template includes:
2500 2474
2501 **page.html** 2475 **page.html**
2502 This template usually defines the overall look of your tracker. When 2476 This template defines the overall look of your tracker. When
2503 you view an issue, it appears inside this template. When you view an 2477 you view an issue, it appears inside this template. When you view an
2504 index, it also appears inside this template. This template defines a 2478 index, it also appears inside this template. This template defines a
2505 macro called "icing" which is used by almost all other templates as a 2479 macro called "icing" which is used by almost all other templates as a
2506 coating for their content, using its "content" slot. It also defines 2480 coating for their content, using its "content" slot. It also defines
2507 the "head_title" and "body_title" slots to allow setting of the page 2481 the "head_title" and "body_title" slots to allow setting of the page
2508 title. 2482 title.
2483
2484 This page also defines macros for use in search pages.
2485
2486 * th_label - defines a label for a search field
2487 * search_input - defines a text input field
2488 * search_date - defines a text input field with popup calendar link
2489 * search_popup - defines a text input with popup classhelper link
2490 * search_select - defines a select/dropdown element for selecting
2491 a single item from a class
2492 * search_select_keywords - defines a dropdown with a keyword
2493 search expression builder link
2494 * search_select_translated - like search_Select but it translates
2495 the items in the dropdown
2496 * search_multiselect - text input with multiselect classhelper
2497 popup link
2498 * search_checkboxes - display selection items as checkbox items
2499 * column_input - a checkbox element used to select an element for
2500 display in a search result (sets the @columns property)
2501 * sort_input - a radiobutton element used to select sorting
2502 * group_input - a radiobutton element used to select grouping
2503
2504 and the user.item.html page:
2505
2506 * user_src_input - takes a long name and splits it into parts (first/last)
2507 * user_normal_input - takes a name without splitting it for reuse
2508 * user_pw_input - a password input for the user
2509 * user_confirm_input - a password input marked so the back end
2510 confirms it against the password submitted through the user_pw_input
2511
2509 **home.html** 2512 **home.html**
2510 the default page displayed when no other page is indicated by the user 2513 the default page displayed when in `the "home" context`_ and no
2514 other page is requested using the ``@template`` parameter
2511 **home.classlist.html** 2515 **home.classlist.html**
2512 a special version of the default page that lists the classes in the 2516 a special version of the default page that lists the classes in the
2513 tracker 2517 tracker. It is requested in the "home" context using ``@template=classlist``
2514 **classname.item.html** 2518 **classname.item.html**
2515 displays an item of the *classname* class 2519 displays an item of the *classname* class given a :term:`designator`
2516 **classname.index.html** 2520 **classname.index.html**
2517 displays a list of *classname* items 2521 displays a list of *classname* items
2518 **classname.search.html** 2522 **classname.search.html**
2519 displays a search page for *classname* items 2523 displays a search page for *classname* items
2520 **_generic.index.html** 2524 **_generic.index.html**
2521 used to display a list of items where there is no 2525 used to display a list of items when there is no
2522 ``*classname*.index`` available 2526 ``*classname*.index`` available
2523 **_generic.help.html** 2527 **_generic.help.html**
2524 used to display a "class help" page where there is no 2528 used to display a "class help" page when there is no
2525 ``*classname*.help`` 2529 ``*classname*.help``
2526 **user.register.html** 2530 **user.register.html**
2527 a special page just for the user class, that renders the registration 2531 a special page just for the user class, that renders the registration
2528 page 2532 page
2529 **style.css** 2533 **style.css**
2531 2535
2532 The *classic* template has a number of additional templates. 2536 The *classic* template has a number of additional templates.
2533 2537
2534 Remember that you can create any template extension you want to, 2538 Remember that you can create any template extension you want to,
2535 so if you just want to play around with the templating for new issues, 2539 so if you just want to play around with the templating for new issues,
2536 you can copy the current "issue.item" template to "issue.test", and then 2540 you can copy the current "issue.item.html" template to
2541 "issue.test" (or "issue.test.html"), and then
2537 access the test template using the "@template" URL argument:: 2542 access the test template using the "@template" URL argument::
2538 2543
2539 http://your.tracker.example/tracker/issue?@template=test 2544 http://your.tracker.example/tracker/issue?@template=test
2540 2545
2541 and it won't affect your users using the "issue.item" template. 2546 and it won't affect your users using the "issue.item" template.
2555 2560
2556 Many item templates allow you to edit the item. They contain 2561 Many item templates allow you to edit the item. They contain
2557 code that renders edit boxes if the user has edit permissions. 2562 code that renders edit boxes if the user has edit permissions.
2558 Otherwise the template will just display the item information. 2563 Otherwise the template will just display the item information.
2559 2564
2560 In some cases you want to do a modal edit. The user has to take some 2565 However, you may want a modal edit. A modal edit requires the
2561 action (click a button or follow a link) to shift from display mode to 2566 user to take some action (click a button or follow a link) to
2562 edit mode. When the changes are submitted, ending the edit mode, 2567 shift from display mode to edit mode. Submitting the changes
2563 the user is returned to display mode. 2568 ends edit mode and the user returns to display
2564 2569 mode.
2565 Modal workflows usually slow things down and are not implemented by 2570
2566 default templates. However for some workflows a modal edit is useful. 2571 To build a modal edit for an item, move the (editable)
2567 For example a batch edit mode that allows the user to edit a number of 2572 issue.item.html template to issue.item_edit.html. Then create a new
2568 issues all from one form could be implemented as a modal workflow of: 2573 issue.item.html template that only displays information. Add an
2569 2574 edit link that calls the display url, but adds ``@template=item_edit``
2570 * search for issues to modify 2575 to the link.
2571 * switch to edit mode and change values 2576
2572 * exit back to the results of the search 2577 This will now display the edit page. On the edit page you want to
2573 2578 add a hidden text field to your form named ``@template`` with the
2574 To implement the modal edit, assume you have an issue.edit.html 2579 value: ``item|item_edit``. When the form is submitted, it is
2575 template that implements an edit form. On the display page (a version 2580 validated. If the form is correct the user will see the item
2576 of issue.item.html modified to only display information) add a link 2581 rendered using the item template. If there is an error
2577 that calls the display url, but adds ``@template=edit`` to the link. 2582 (validation failed) the item will be rendered using the
2578 2583 ``item_edit`` template. The rendered ``item_edit`` template will
2579 This will now display the edit page. On the edit page you want to add 2584 display all the changes that the user made to the form before it
2580 a hidden text field to your form named ``@template`` with the value: 2585 was submitted. The user can correct the error and resubmit the
2581 ``item|edit``. When the form is submitted it is validated. If the 2586 changes until the form validates.
2582 form is correct the user will see the item rendered using the item
2583 template. If there is an error (validation failed) the item will be
2584 rendered using the edit template. The edit template that is rendered
2585 will display all the changes that the user made to the form before it
2586 was submitted. The user can correct the error and resubmit the changes
2587 until the form validates.
2588 2587
2589 If the form failed to validate but the ``@template`` field had the 2588 If the form failed to validate but the ``@template`` field had the
2590 value ``item`` the user would still see the error, but all of the data 2589 value ``item`` the user would still see the error, but all of the data
2591 the user entered would be discarded. The user would have to redo all 2590 the user entered would be discarded. The user would have to redo all
2592 the edits again. 2591 the edits again.
2593 2592
2593 In general, modal workflows are not implemented by the default
2594 templates because they slow down the edit cycle. For some
2595 specific workflows a modal edit is useful. For example, a batch
2596 edit mode allows the user to edit multiple issues in one
2597 form. It can result in a modal workflow of:
2598
2599 * search for issues to modify
2600 * switch to edit mode and change values
2601 * exit back to the results of the search
2602
2594 2603
2595 How the templates work 2604 How the templates work
2596 ---------------------- 2605 ----------------------
2597 2606
2598 2607
2603 2612
2604 * the original `Template Attribute Language`_ (TAL) engine from Zope 2613 * the original `Template Attribute Language`_ (TAL) engine from Zope
2605 * the standalone Chameleon templating engine. Chameleon is intended 2614 * the standalone Chameleon templating engine. Chameleon is intended
2606 as a replacement for the original TAL engine, and supports the 2615 as a replacement for the original TAL engine, and supports the
2607 same syntax, but they are not 100% compatible. The major (and most 2616 same syntax, but they are not 100% compatible. The major (and most
2608 likely the only) incompatibility is the default expression type being 2617 likely the only) incompatibility is the default expression type of
2609 ``python:`` instead of ``path:``. See also "Incompatibilities and 2618 ``python:`` instead of ``path:``. See also "Incompatibilities and
2610 differences" section of `Chameleon documentation`__. 2619 differences" section of `Chameleon documentation`__.
2611 2620
2612 Version 1.5.0 added experimental support for the `jinja2`_ templating 2621 Version 1.5.0 added support for the `jinja2`_ templating
2613 language. You must install the `jinja2`_ module in order to use it. The 2622 language. You must install the `jinja2`_ module to use it. The
2614 ``jinja2`` template supplied with Roundup has the templates rewritten 2623 ``jinja2`` template supplied with Roundup has the templates rewritten
2615 to use ``jinja2`` rather than TAL. A number of trackers are running 2624 to use ``jinja2`` rather than TAL. A number of trackers are running
2616 using ``jinja2`` templating so it is considered less experimental than 2625 using ``jinja2`` templating so it is less experimental than
2617 Chameleon templating. 2626 Chameleon templating.
2618 2627
2619 .. _jinja2: https://palletsprojects.com/p/jinja/ 2628 .. _jinja2: https://palletsprojects.com/projects/jinja/
2620 2629
2621 2630
2622 **NOTE1**: For historical reasons, examples given below assumes path 2631 **NOTE1**: For historical reasons, examples given below assumes path
2623 expression as default expression type. With Chameleon you have to manually 2632 expression as default expression type. With Chameleon you have to manually
2624 resolve the path expressions. A Chameleon-based, z3c.pt, that is fully 2633 resolve the path expressions. A Chameleon-based, z3c.pt, that is fully
2625 compatible with the old TAL implementation, is planned to be included in a 2634 compatible with the old TAL implementation, is planned for a
2626 future release. 2635 future release.
2627 2636
2628 **NOTE2**: As of 1.4.20 Chameleon support is highly experimental and **not** 2637 **NOTE2**: As of 1.4.20 Chameleon support is highly experimental and **not**
2629 recommended for production use. 2638 recommended for production use.
2630 2639
2644 Roundup's templates consist of special attributes on the HTML tags. 2653 Roundup's templates consist of special attributes on the HTML tags.
2645 These attributes form the **Template Attribute Language**, or TAL. 2654 These attributes form the **Template Attribute Language**, or TAL.
2646 The basic TAL commands are: 2655 The basic TAL commands are:
2647 2656
2648 **tal:define="variable expression; variable expression; ..."** 2657 **tal:define="variable expression; variable expression; ..."**
2649 Define a new variable that is local to this tag and its contents. For 2658 Define a new local variable for this tag and its contents. For
2650 example:: 2659 example::
2651 2660
2652 <html tal:define="title request/description"> 2661 <html tal:define="title request/description">
2653 <head><title tal:content="title"></title></head> 2662 <head><title tal:content="title"></title></head>
2654 </html> 2663 </html>
2655 2664
2656 In this example, the variable "title" is defined as the result of the 2665 In this example, the variable "title" is defined by the
2657 expression "request/description". The "tal:content" command inside the 2666 expression "request/description". The "tal:content" command
2658 <html> tag may then use the "title" variable. 2667 inside the <html> tag may then use the "title" variable.
2659 2668
2660 **tal:condition="expression"** 2669 **tal:condition="expression"**
2661 Only keep this tag and its contents if the expression is true. For 2670 Keep this tag and its contents if the expression is true. For
2662 example:: 2671 example::
2663 2672
2664 <p tal:condition="python:request.user.hasPermission('View', 'issue')"> 2673 <p tal:condition="python:request.user.hasPermission('View', 'issue')">
2665 Display some issue information. 2674 Display some issue information.
2666 </p> 2675 </p>
2667 2676
2668 In the example, the <p> tag and its contents are only displayed if 2677 In the example, the <p> tag and its contents are displayed
2669 the user has the "View" permission for issues. We consider the number 2678 only if the user has the "View" permission for issues. We
2670 zero, a blank string, an empty list, and the built-in variable 2679 consider the number zero, a blank string, an empty list, and
2671 nothing to be false values. Nearly every other value is true, 2680 the built-in variable nothing to be false values. Nearly every
2672 including non-zero numbers, and strings with anything in them (even 2681 other value is true, including non-zero numbers, and strings
2673 spaces!). 2682 with anything in them (even spaces!).
2674 2683
2675 **tal:repeat="variable expression"** 2684 **tal:repeat="variable expression"**
2676 Repeat this tag and its contents for each element of the sequence 2685 Repeat this tag and its contents for each element of the sequence
2677 that the expression returns, defining a new local variable and a 2686 that the expression returns, defining a new local variable and a
2678 special "repeat" variable for each element. For example:: 2687 special "repeat" variable for each element. For example::
2690 below on `the repeat variable`_. 2699 below on `the repeat variable`_.
2691 2700
2692 **tal:replace="expression"** 2701 **tal:replace="expression"**
2693 Replace this tag with the result of the expression. For example:: 2702 Replace this tag with the result of the expression. For example::
2694 2703
2695 <span tal:replace="request/user/realname" /> 2704 <span tal:replace="request/user/id" />
2696 2705
2697 The example would replace the <span> tag and its contents with the 2706 The example would replace the <span> tag and its contents with the
2698 user's realname. If the user's realname was "Bruce", then the 2707 user's id. If the user's id was "3" the resulting output would be
2699 resultant output would be "Bruce". 2708 "3".
2709
2710 You need to be a little careful with ``tal:replace``. Unlike
2711 ``tal:content``, it doesn't always escape the output. For example
2712 if you used::
2713
2714 <tal:x tal:replace="request/user/realname" />
2715
2716 it would replace the contents with the value of the user's
2717 realname. The realname is something the user can control. The user
2718 could include something like::
2719
2720 Bruce<script>alert("hello there");</script>
2721
2722 This would result in an alert box popping up when the page was
2723 loaded. Attackers could use this `XSS exploit`_ for malicious
2724 purposes.
2725
2726 Generally you would use tal:replace when calling a utility function
2727 using a :ref:`Python expression <python expression>` that generates
2728 trusted HTML.
2729
2730 If you are inserting untrusted content, it is better to use
2731 ``tal:content`` with tags that disappear as described below.
2732
2733 .. _`XSS exploit`: https://owasp.org/www-community/attacks/xss/
2700 2734
2701 **tal:content="expression"** 2735 **tal:content="expression"**
2702 Replace the contents of this tag with the result of the expression. 2736 Replace the contents of this tag (but not the tag itself) with the
2703 For example:: 2737 result of the expression. For example::
2704 2738
2705 <span tal:content="request/user/realname">user's name appears here 2739 <span tal:content="request/user/realname">user's name appears here
2706 </span> 2740 </span>
2707 2741
2708 The example would replace the contents of the <span> tag with the 2742 This example would replace the contents of the ``<span>`` tag with the
2709 user's realname. If the user's realname was "Bruce" then the 2743 user's realname. If the user's realname was "Bruce" then the
2710 resultant output would be "<span>Bruce</span>". 2744 output will be ``<span>Bruce</span>``.
2745
2746 ``tal:content`` replaces special HTML claracters like ``<`` with an
2747 HTML entitity ``&lt;``. This makes it safer to use when inserting
2748 untrusted data. To have ``tal:content`` insert unescaped HTML, you
2749 need to use the `structure modifier`_.
2750
2751 If the tag is an unknown ``tal:`` tag, TAL removes the tag. So
2752 evaulating:
2753
2754 <tal:x tal:replace="request/user/realname" />
2755
2756 results in ``Bruce``.
2711 2757
2712 **tal:attributes="attribute expression; attribute expression; ..."** 2758 **tal:attributes="attribute expression; attribute expression; ..."**
2713 Set attributes on this tag to the results of expressions. For 2759 Set attributes on this tag to the results of expressions. For
2714 example:: 2760 example::
2715 2761
2716 <a tal:attributes="href string:user${request/user/id}">My Details</a> 2762 <a tal:attributes="href string:user${request/user/id}">My Details</a>
2717 2763
2718 In the example, the "href" attribute of the <a> tag is set to the 2764 In the example, the "href" attribute of the ``<a>`` tag is set
2719 value of the "string:user${request/user/id}" expression, which will 2765 to the value of the expression "string:user${request/user/id}",
2720 be something like "user123". 2766 which will look like "user123".
2721 2767
2722 **tal:omit-tag="expression"** 2768 **tal:omit-tag="expression"**
2723 Remove this tag (but not its contents) if the expression is true. For 2769 Remove this tag (but not its contents) if the expression is true. For
2724 example:: 2770 example::
2725 2771
2727 2773
2728 would result in output of:: 2774 would result in output of::
2729 2775
2730 Hello, world! 2776 Hello, world!
2731 2777
2732 Note that the commands on a given tag are evaulated in the order above, 2778 Note that TAL evaluates the commands on a given tag in the order above.
2733 so *define* comes before *condition*, and so on. 2779 *define* is evaluated before *condition*, and so on.
2734 2780
2735 Additionally, you may include tags such as <tal:block>, which are 2781 Additionally, you may include tags such as <tal:block>, which are
2736 removed from output. Its content is kept, but the tag itself is not (so 2782 removed from output. Its content is kept, but the tag itself is not (so
2737 don't go using any "tal:attributes" commands on it). This is useful for 2783 don't go using any "tal:attributes" commands on it). This is useful for
2738 making arbitrary blocks of HTML conditional or repeatable (very handy 2784 making arbitrary blocks of HTML conditional or repeatable (very handy
2741 2787
2742 2788
2743 Templating Expressions 2789 Templating Expressions
2744 ~~~~~~~~~~~~~~~~~~~~~~ 2790 ~~~~~~~~~~~~~~~~~~~~~~
2745 2791
2746 Templating Expressions are covered by `Template Attribute Language 2792 Templating Expressions are covered by `Template Attribute
2747 Expression Syntax`_, or TALES. The expressions you may use in the 2793 Language Expression Syntax`_ (TALES). The expressions you use in
2748 attribute values may be one of the following forms: 2794 attribute values may be one of the following forms:
2749 2795
2750 **Path Expressions** - eg. ``item/status/checklist`` 2796 **Path Expressions** - e.g. ``item/status/checklist``
2751 These are object attribute / item accesses. Roughly speaking, the 2797 These are object attribute / item accesses. Roughly speaking, the
2752 path ``item/status/checklist`` is broken into parts ``item``, 2798 path ``item/status/checklist`` is broken into parts ``item``,
2753 ``status`` and ``checklist``. The ``item`` part is the root of the 2799 ``status`` and ``checklist``. The ``item`` part is the root of the
2754 expression. We then look for a ``status`` attribute on ``item``, or 2800 expression. It then looks for a ``status`` attribute on ``item``, or
2755 failing that, a ``status`` item (as in ``item['status']``). If that 2801 failing that, a ``status`` item (as in ``item['status']``). If that
2756 fails, the path expression fails. When we get to the end, the object 2802 fails, the path expression fails. When we get to the end, the object
2757 we're left with is evaluated to get a string - if it is a method, it 2803 we're left with is evaluated to get a string - if it is a method, it
2758 is called; if it is an object, it is stringified. Path expressions 2804 is called; if it is an object, it is stringified. Path expressions
2759 may have an optional ``path:`` prefix, but they are the default 2805 may have an optional ``path:`` prefix, but path is the default
2760 expression type, so it's not necessary. 2806 expression type for TAL. In Chameleon you must include the
2807 ``path:`` prefix.
2808
2809 If an element in the path may not exist, you can use the ``|``
2810 operator in the expression to provide an alternative. The
2811 expression ``request/form/foo/value | default`` would simply
2812 leave the current HTML in place if the "foo" form variable
2813 doesn't exist.
2761 2814
2762 If an expression evaluates to ``default``, then the expression is 2815 If an expression evaluates to ``default``, then the expression is
2763 "cancelled" - whatever HTML already exists in the template will 2816 "cancelled" - whatever HTML already exists in the template will
2764 remain (tag content in the case of ``tal:content``, attributes in the 2817 remain (tag content in the case of ``tal:content``, attributes in the
2765 case of ``tal:attributes``). 2818 case of ``tal:attributes``).
2767 If an expression evaluates to ``nothing`` then the target of the 2820 If an expression evaluates to ``nothing`` then the target of the
2768 expression is removed (tag content in the case of ``tal:content``, 2821 expression is removed (tag content in the case of ``tal:content``,
2769 attributes in the case of ``tal:attributes`` and the tag itself in 2822 attributes in the case of ``tal:attributes`` and the tag itself in
2770 the case of ``tal:replace``). 2823 the case of ``tal:replace``).
2771 2824
2772 If an element in the path may not exist, then you can use the ``|``
2773 operator in the expression to provide an alternative. So, the
2774 expression ``request/form/foo/value | default`` would simply leave
2775 the current HTML in place if the "foo" form variable doesn't exist.
2776
2777 You may use the python function ``path``, as in 2825 You may use the python function ``path``, as in
2778 ``path("item/status")``, to embed path expressions in Python 2826 ``path("item/status")``, to embed path expressions in Python
2779 expressions. 2827 expressions.
2780 2828
2781 **String Expressions** - eg. ``string:hello ${user/name}`` 2829 **String Expressions** - e.g. ``string:hello ${user/name}`` These
2782 These expressions are simple string interpolations - though they can 2830 expressions are string interpolations - though they can be
2783 be just plain strings with no interpolation if you want. The 2831 just plain strings with no interpolation if you want. The
2784 expression in the ``${ ... }`` is just a path expression as above. 2832 expression in the interpolation decorator ``${ ... }`` is a
2785 2833 path expression as above.
2786 **Python Expressions** - eg. ``python: 1+1`` 2834
2835 .. _`python expression`:
2836
2837 **Python Expressions** - e.g. ``python: 1+1``
2787 These expressions give the full power of Python. All the "root level" 2838 These expressions give the full power of Python. All the "root level"
2788 variables are available, so ``python:item.status.checklist()`` would 2839 variables are available, so ``python:item.status.checklist()`` is
2789 be equivalent to ``item/status/checklist``, assuming that 2840 the same as ``item/status/checklist``, assuming that
2790 ``checklist`` is a method. 2841 ``checklist`` is a method.
2791 2842
2792 Modifiers: 2843 Modifiers:
2793 2844
2794 **structure** - eg. ``structure python:msg.content.plain(hyperlink=1)`` 2845 .. _`structure modifier`:
2795 The result of expressions are normally *escaped* to be safe for HTML 2846
2796 display (all "<", ">" and "&" are turned into special entities). The 2847 **structure** - e.g. ``structure python:msg.content.plain(hyperlink=1)``
2797 ``structure`` expression modifier turns off this escaping - the 2848 The result of expressions are *escaped* to be safe for HTML
2798 result of the expression is now assumed to be HTML, which is passed 2849 display (all "<", ">" and "&" are replaced with entities
2799 to the web browser for rendering. 2850 (e.g. ``&lt;``). The ``structure`` expression modifier turns
2851 off this escaping - the result of the expression is now
2852 assumed to be HTML, which is passed to the web browser for
2853 rendering.
2800 2854
2801 **not:** - eg. ``not:python:1=1`` 2855 **not:** - eg. ``not:python:1=1``
2802 This simply inverts the logical true/false value of another 2856 This inverts the logical true/false value of another
2803 expression. 2857 expression.
2804 2858
2805 .. _TALES: 2859 .. _TALES:
2806 .. _Template Attribute Language Expression Syntax: 2860 .. _Template Attribute Language Expression Syntax:
2807 https://pagetemplates.readthedocs.io/en/latest/history/TALESSpecification13.html 2861 https://pagetemplates.readthedocs.io/en/latest/history/TALESSpecification13.html
2808 2862
2809 2863
2810 Template Macros 2864 Template Macros
2811 ~~~~~~~~~~~~~~~ 2865 ~~~~~~~~~~~~~~~
2812 2866
2813 Macros are used in Roundup to save us from repeating the same common 2867 Roundup uses macros to save us from repeating the same common
2814 page stuctures over and over. The most common (and probably only) macro 2868 page structures over and over. The most common (and probably only) macro
2815 you'll use is the "icing" macro defined in the "page" template. 2869 you'll use is the "icing" macro defined in the "page" template.
2816 2870
2817 Macros are generated and used inside your templates using special 2871 Macros are generated and used inside your templates using special
2818 attributes similar to the `basic templating actions`_. In this case, 2872 attributes similar to the `basic templating actions`_. In this case,
2819 though, the attributes belong to the `Macro Expansion Template 2873 though, the attributes belong to the `Macro Expansion Template
2820 Attribute Language`_, or METAL. The macro commands are: 2874 Attribute Language`_, (METAL). The macro commands are:
2821 2875
2822 **metal:define-macro="macro name"** 2876 **metal:define-macro="macro name"**
2823 Define that the tag and its contents are now a macro that may be 2877 Define that the tag and its contents are now a macro that may be
2824 inserted into other templates using the *use-macro* command. For 2878 inserted into other templates using the *use-macro* command. For
2825 example:: 2879 example::
2827 <html metal:define-macro="page"> 2881 <html metal:define-macro="page">
2828 ... 2882 ...
2829 </html> 2883 </html>
2830 2884
2831 defines a macro called "page" using the ``<html>`` tag and its 2885 defines a macro called "page" using the ``<html>`` tag and its
2832 contents. Once defined, macros are stored on the template they're 2886 contents. Once defined, macros are stored in the ``macros``
2833 defined on in the ``macros`` attribute. You can access them later on 2887 attribute of the template they are defined on. You can access
2834 through the ``templates`` variable, eg. the most common 2888 them later on through the ``templates`` variable. Use the path
2835 ``templates/page/macros/icing`` to access the "page" macro of the 2889 expression ``templates/page/macros/icing`` to access the
2836 "page" template. 2890 "icing" macro defined in the "page.html" template.
2837 2891
2838 **metal:use-macro="path expression"** 2892 **metal:use-macro="path expression"**
2839 Use a macro, which is identified by the path expression (see above). 2893 Use a macro, identified by the path expression. This replaces
2840 This will replace the current tag with the identified macro contents. 2894 the current tag with the identified macro contents. For
2841 For example:: 2895 example::
2842 2896
2843 <tal:block metal:use-macro="templates/page/macros/icing"> 2897 <tal:block metal:use-macro="templates/page/macros/icing">
2844 ... 2898 ...
2845 </tal:block> 2899 </tal:block>
2846 2900
2847 will replace the tag and its contents with the "page" macro of the 2901 will replace the tag and its contents with the "icing" macro
2848 "page" template. 2902 from the "page" template.
2849 2903
2850 **metal:define-slot="slot name"** and **metal:fill-slot="slot name"** 2904 **metal:define-slot="slot name"** and **metal:fill-slot="slot name"**
2851 To define *dynamic* parts of the macro, you define "slots" which may 2905 To define *dynamic* parts of the macro, you define "slots"
2852 be filled when the macro is used with a *use-macro* command. For 2906 which are filled when the macro is used with a *use-macro*
2853 example, the ``templates/page/macros/icing`` macro defines a slot like 2907 command. For example, the ``templates/page/macros/icing`` macro
2854 so:: 2908 defines a ``head_title`` slot like so::
2855 2909
2856 <title metal:define-slot="head_title">title goes here</title> 2910 <title metal:define-slot="head_title">title goes here</title>
2857 2911
2858 In your *use-macro* command, you may now use a *fill-slot* command 2912 In your *use-macro* command, you may now use a *fill-slot* command
2859 like this:: 2913 like this::
2860 2914
2861 <title metal:fill-slot="head_title">My Title</title> 2915 <tal:block metal:use-macro="templates/page/macros/icing">
2916 <title class="big" metal:fill-slot="head_title">My Title</title>
2917 </tal:block>
2862 2918
2863 where the tag that fills the slot completely replaces the one defined 2919 where the tag that fills the slot completely replaces the one defined
2864 as the slot in the macro. 2920 as the slot in the macro.
2865 2921
2866 Note that you may not mix `METAL`_ and `TAL`_ commands on the same tag, but 2922 Note that you may not mix `METAL`_ and `TAL`_ commands on the
2867 TAL commands may be used freely inside METAL-using tags (so your 2923 same tag. But TAL commands can be used freely inside METAL-using
2868 *fill-slots* tags may have all manner of TAL inside them). 2924 tags (so your *fill-slots* tags may have all manner of TAL inside
2925 them).
2869 2926
2870 .. _METAL: 2927 .. _METAL:
2871 .. _Macro Expansion Template Attribute Language: 2928 .. _Macro Expansion Template Attribute Language:
2872 https://pagetemplates.readthedocs.io/en/latest/history/TALESSpecification13.html 2929 https://pagetemplates.readthedocs.io/en/latest/history/TALESSpecification13.html
2873 2930
2874 Information available to templates 2931 Information available to templates
2875 ---------------------------------- 2932 ----------------------------------
2876 2933
2877 This is implemented by ``roundup.cgi.templating.RoundupPageTemplate`` 2934 This is implemented by
2935 ``roundup.cgi.templating.RoundupPageTemplate``. Documentation in
2936 the installed file ``roundup/cgi/templating.py`` supplements this
2937 documentation.
2878 2938
2879 The following variables are available to templates. 2939 The following variables are available to templates.
2880 2940
2881 **context** 2941 **context**
2882 The current context. This is either None, a `hyperdb class wrapper`_ 2942 The current context. This is either None, a `hyperdb class wrapper`_
2884 2944
2885 **request** 2945 **request**
2886 Includes information about the current request, including: 2946 Includes information about the current request, including:
2887 2947
2888 - the current index information (``filterspec``, ``filter`` 2948 - the current index information (``filterspec``, ``filter``
2889 args, ``properties``, etc) parsed out of the form. 2949 arguments, ``properties``, etc) parsed out of the form.
2890 - methods for easy filterspec link generation 2950 - methods for filterspec link generation (indexargs_url)
2891 - "form" 2951 - "form"
2892 The current CGI form information as a mapping of form argument name 2952 The current CGI form information as a mapping of form argument name
2893 to value (specifically a cgi.FieldStorage) 2953 to value (specifically a cgi.FieldStorage)
2894 - "env" the CGI environment variables 2954 - "env" the CGI environment variables
2895 - "base" the base URL for this instance 2955 - "base" the base URL of this instance
2896 - "user" a HTMLItem instance for the current user 2956 - "user" a HTMLItem instance for the current user
2897 - "language" as determined by the browser or config 2957 - "language" as determined by the browser or configuration
2898 - "classname" the current classname (possibly None) 2958 - "classname" the current classname (possibly None)
2899 - "template" the current template (suffix, also possibly None) 2959 - "template" the current template (e.g. for the ``issue.item.html``
2960 template the template would be the ``item`` suffix on the
2961 classname. It can also be the empty string (e.g. with the
2962 ``home.html`` template).
2900 **config** 2963 **config**
2901 This variable holds all the values defined in the tracker config.ini 2964 This variable holds all the values defined in the tracker config.ini
2902 file (eg. TRACKER_NAME, etc.) 2965 file (e.g. TRACKER_NAME, etc.)
2903 **db** 2966 **db**
2904 The current database, used to access arbitrary database items. 2967 The current database, used to access arbitrary database items.
2905 **templates** 2968 **templates**
2906 Access to all the tracker templates by name. Used mainly in 2969 Access to all the tracker templates by name. Used mainly in
2907 *use-macro* commands. 2970 *use-macro* commands.
2908 **utils** 2971 **utils**
2909 This variable makes available some utility functions like batching. 2972 This variable makes available some utility functions like batching.
2910 **nothing** 2973 **nothing**
2911 This is a special variable - if an expression evaluates to this, then 2974 This is a special variable - if an expression evaluates to
2912 the tag (in the case of a ``tal:replace``), its contents (in the case 2975 this, then the tag (when used with ``tal:replace``), its
2913 of ``tal:content``) or some attributes (in the case of 2976 contents (in the case of ``tal:content``) or some attributes
2914 ``tal:attributes``) will not appear in the the output. So, for 2977 (when used with ``tal:attributes``) will not appear in the
2915 example:: 2978 output. For example::
2916 2979
2917 <span tal:attributes="class nothing">Hello, World!</span> 2980 <span tal:attributes="class nothing">Hello, World!</span>
2918 2981
2919 would result in:: 2982 would result in::
2920 2983
2921 <span>Hello, World!</span> 2984 <span>Hello, World!</span>
2922
2923 **default** 2985 **default**
2924 Also a special variable - if an expression evaluates to this, then the 2986 Also a special variable - if an expression evaluates to this, then the
2925 existing HTML in the template will not be replaced or removed, it will 2987 existing HTML in the template will not be replaced or removed, it will
2926 remain. So:: 2988 remain. So::
2927 2989
2929 2991
2930 would result in:: 2992 would result in::
2931 2993
2932 <span>Hello, World!</span> 2994 <span>Hello, World!</span>
2933 2995
2996 and::
2997
2998 <a href="foo" tal:attributes"href nope | default">H</a>
2999
3000 when ``nope`` is not defined results in::
3001
3002 <a href="foo">H</a>
2934 **true**, **false** 3003 **true**, **false**
2935 Boolean constants that may be used in `templating expressions`_ 3004 Boolean constants that may be used in `templating expressions`_
2936 instead of ``python:1`` and ``python:0``. 3005 instead of ``python:1`` and ``python:0``.
2937 **i18n** 3006 **i18n**
2938 Internationalization service, providing two string translation methods: 3007 Internationalization service, providing two string translation methods:
2947 return plural otherwise. 3016 return plural otherwise.
2948 3017
2949 The context variable 3018 The context variable
2950 ~~~~~~~~~~~~~~~~~~~~ 3019 ~~~~~~~~~~~~~~~~~~~~
2951 3020
2952 The *context* variable is one of three things based on the current 3021 The *context* variable can contain one of three things based on the
2953 context (see `determining web context`_ for how we figure this out): 3022 current context (see `determining web context`_ for how Roundup figures
2954 3023 this out). If Roundup is:
2955 1. if we're looking at a "home" page, then it's None 3024
2956 2. if we're looking at a specific hyperdb class, it's a 3025 1. at a "home" page, then it's None
2957 `hyperdb class wrapper`_. 3026 2. at a specific hyperdb class, it's a `hyperdb class wrapper`_.
2958 3. if we're looking at a specific hyperdb item, it's a 3027 3. at a specific hyperdb item, it's a `hyperdb item wrapper`_.
2959 `hyperdb item wrapper`_. 3028
2960 3029 If the context is not None, you can access the properties of the class or
2961 If the context is not None, we can access the properties of the class or 3030 item. The only real difference between cases 2 and 3 are:
2962 item. The only real difference between cases 2 and 3 above are:
2963 3031
2964 1. the properties may have a real value behind them, and this will 3032 1. the properties may have a real value behind them, and this will
2965 appear if the property is displayed through ``context/property`` or 3033 appear if the property is displayed through ``context/property`` or
2966 ``context/property/field``. 3034 ``context/property/field``.
2967 2. the context's "id" property will be a false value in the second case, 3035 2. the context's "id" property will be a false value in case 2,
2968 but a real, or true value in the third. Thus we can determine whether 3036 but a real, or true value in case 3. Thus we can determine whether
2969 we're looking at a real item from the hyperdb by testing 3037 we're looking at a real item from the hyperdb by testing
2970 "context/id". 3038 "context/id".
2971 3039
2972 Hyperdb class wrapper 3040 Hyperdb class wrapper
2973 ::::::::::::::::::::: 3041 :::::::::::::::::::::
2974 3042
2975 This is implemented by the ``roundup.cgi.templating.HTMLClass`` 3043 This is implemented by the ``roundup.cgi.templating.HTMLClass``
2976 class. 3044 class.
2977 3045
2978 This wrapper object provides access to a hyperdb class. It is used 3046 This wrapper object provides access to a hyperdb class. It is used
2979 primarily in both index view and new item views, but it's also usable 3047 primarily in both index view and new item views, but it is usable
2980 anywhere else that you wish to access information about a class, or the 3048 anywhere else that you wish to access information about a class, or the
2981 items of a class, when you don't have a specific item of that class in 3049 items of a class, when you don't have a specific item of that class in
2982 mind. 3050 mind.
2983 3051
2984 We allow access to properties. There will be no "id" property. The value 3052 We allow access to properties. There will be no "id" property. The value
2985 accessed through the property will be the current value of the same name 3053 accessed through the property will be the current value of the same name
2986 from the CGI form. 3054 from the CGI form.
2987 3055
2988 There are several methods available on these wrapper objects: 3056 There are several methods available on these wrapper objects:
2989 3057
2990 =========== ============================================================= 3058 .. table::
2991 Method Description 3059 :class: valign-top
2992 =========== ============================================================= 3060
2993 properties return a `hyperdb property wrapper`_ for all of this class's 3061 =========== =============================================================
2994 properties that are searchable by the user. You can use 3062 Method Description
2995 the argument cansearch=False to get all properties. 3063 =========== =============================================================
2996 list lists all of the active (not retired) items in the class. 3064 properties return a `hyperdb property wrapper`_ for all of this class's
2997 csv return the items of this class as a chunk of CSV text. 3065 properties that are searchable by the user. You can use
2998 propnames lists the names of the properties of this class. 3066 the argument cansearch=False to get all properties.
2999 filter lists of items from this class, filtered and sorted. Two 3067 list lists all of the active (not retired) items in the class.
3000 options are available for sorting: 3068 csv return the items of this class as a chunk of CSV text.
3001 3069 propnames lists the names of the properties of this class.
3002 1. by the current *request* filterspec/filter/sort/group args 3070 filter lists of items from this class, filtered and sorted. Two
3003 2. by the "filterspec", "sort" and "group" keyword args. 3071 options are available for sorting:
3004 "filterspec" is ``{propname: value(s)}``. "sort" and 3072
3005 "group" are an optionally empty list ``[(dir, prop)]`` 3073 1. by the current *request* filterspec/filter/sort/group args
3006 where dir is '+', '-' or None 3074 2. by the "filterspec", "sort" and "group" keyword args.
3007 and prop is a prop name or None. 3075 "filterspec" is ``{propname: value(s)}``. "sort" and
3008 3076 "group" are an optionally empty list ``[(dir, prop)]``
3009 The propname in filterspec and prop in a sort/group spec 3077 where dir is '+', '-' or None
3010 may be transitive, i.e., it may contain properties of 3078 and prop is a prop name or None.
3011 the form link.link.link.name. 3079
3012 3080 The propname in filterspec and prop in a sort/group spec
3013 eg. All issues with a priority of "1" with messages added in 3081 may be transitive, i.e., it may contain properties of
3014 the last week, sorted by activity date: 3082 the form link.link.link.name.
3015 ``issue.filter(filterspec={"priority": "1", 3083
3016 'messages.creation' : '.-1w;'}, sort=[('activity', '+')])`` 3084 e.g. All issues with a priority of "1" with messages added in
3017 3085 the last week, sorted by activity date:
3018 Note that when searching for Link and Multilink values, the 3086 ``issue.filter(filterspec={"priority": "1",
3019 special value '-1' searches for empty Link or Multilink 3087 'messages.creation' : '.-1w;'}, sort=[('activity', '+')])``
3020 values. For both, Links and Multilinks, multiple values 3088
3021 given in a filter call are combined with 'OR' by default. 3089 Note that when searching for Link and Multilink values, the
3022 For Multilinks a postfix expression syntax using negative ID 3090 special value '-1' searches for empty Link or Multilink
3023 numbers (as strings) as operators is supported. Each 3091 values. For both Links and Multilinks, multiple values
3024 non-negative number (or '-1') is pushed on an operand stack. 3092 given in a filter call are combined with 'OR' by default.
3025 A negative number pops the required number of arguments from 3093
3026 the stack, applies the operator, and pushes the result. The 3094 Both Link and Multilinks support a postfix
3027 following operators are supported: 3095 expression syntax using negative ID numbers (as
3028 3096 strings) as operators. Each
3029 - '-2' stands for 'NOT' and takes one argument 3097 non-negative number (or '-1') is pushed on an
3030 - '-3' stands for 'AND' and takes two arguments 3098 operand stack. A negative number pops the required
3031 - '-4' stands for 'OR' and takes two arguments 3099 number of arguments from the stack, applies the
3032 3100 operator, and pushes the result. The following
3033 Note that this special handling of ID arguments is applied only 3101 operators are supported:
3034 when a negative number smaller than -1 is encountered as an ID 3102
3035 in the filter call. Otherwise the implicit OR default 3103 - '-2' stands for 'NOT' and takes one argument
3036 applies. 3104 - '-3' stands for 'AND' and takes two arguments
3037 Examples of using Multilink expressions would be 3105 - '-4' stands for 'OR' and takes two arguments
3038 3106
3039 - '1', '2', '-4', '3', '4', '-4', '-3' 3107 Note that this special handling of ID arguments is
3040 would search for IDs (1 or 2) and (3 or 4) 3108 applied only when a negative number smaller than -1
3041 - '-1' '-2' would search for all non-empty Multilinks 3109 is encountered as an ID in the filter
3042 3110 call. Otherwise the implicit OR default applies.
3043 filter_sql **Only in SQL backends** 3111 Examples of using Multilink expressions would be
3044 3112
3045 Lists the items that match the SQL provided. The SQL is a 3113 - '1', '2', '-4', '3', '4', '-4', '-3'
3046 complete "select" statement. 3114 would search for IDs (1 or 2) and (3 or 4)
3047 3115 - '-1' '-2' would search for all non-empty Multilinks
3048 The SQL select must include the item id as the first column. 3116 - The URL fragment
3049 3117 ``filter=assignedto&assignedto=-1,-2``
3050 This function **does not** filter out retired items, add 3118 would find all issues that are assigned (where
3051 on a where clause "__retired__ <> 1" if you don't want 3119 the assignedto field is not empty).
3052 retired nodes. 3120
3053 3121 Note that 'NOT', (``-2``) is the only useful
3054 classhelp display a link to a javascript popup containing this class' 3122 operand for links. By default, a multi-value search
3055 "help" template. 3123 uses 'OR', so '-4' is redundant. Since a link only
3056 3124 has a single value, the 'AND' operand will return
3057 This generates a link to a popup window which displays the 3125 an empty result.
3058 properties indicated by "properties" of the class named by 3126
3059 "classname". The "properties" should be a comma-separated list 3127 filter_sql **Only in SQL backends**
3060 (eg. 'id,name,description'). Properties defaults to all the 3128
3061 properties of a class (excluding id, creator, created and 3129 Lists the items that match the SQL provided. The SQL is a
3062 activity). 3130 complete "select" statement.
3063 3131
3064 You may optionally override the "label" displayed, the "width", 3132 The SQL select must include the item id as the first column.
3065 the "height", the number of items per page ("pagesize") and 3133
3066 the field on which the list is sorted ("sort"). 3134 This function **does not** filter out retired items, add
3067 3135 on a where clause "__retired__ <> 1" if you don't want
3068 With the "filter" arg it is possible to specify a filter for 3136 retired nodes.
3069 which items are supposed to be displayed. It has to be of 3137
3070 the format "<field>=<values>;<field>=<values>;...". 3138 classhelp display a link to a JavaScript popup containing this class'
3071 3139 "help" template.
3072 The popup window will be resizable and scrollable. 3140
3073 3141 This generates a link to a popup window which displays the
3074 If the "property" arg is given, it's passed through to the 3142 properties indicated by "properties" of the class named by
3075 javascript help_window function. This allows updating of a 3143 "classname". The "properties" should be a comma-separated list
3076 property in the calling HTML page. 3144 (e.g. 'id,name,description'). Properties defaults to all the
3077 3145 properties of a class (excluding id, creator, created and
3078 If the "form" arg is given, it's passed through to the 3146 activity).
3079 javascript help_window function - it's the name of the form 3147
3080 the "property" belongs to. 3148 You may optionally override the "label" displayed, the "width",
3081 3149 the "height", the number of items per page ("pagesize") and
3082 submit generate a submit button (and action and @csrf hidden elements) 3150 the field on which the list is sorted ("sort").
3083 renderWith render this class with the given template. 3151
3084 history returns 'New node - no history' :) 3152 With the "filter" arg it is possible to specify a filter for
3085 is_edit_ok is the user allowed to Edit the current class? 3153 which items are supposed to be displayed. It has to be of
3086 is_view_ok is the user allowed to View the current class? 3154 the format "<field>=<values>;<field>=<values>;...".
3087 =========== ============================================================= 3155
3156 The popup window is resizable and scrollable.
3157
3158 If the "property" arg is given, it's passed through to
3159 the JavaScript help_window function. This allows
3160 updating of a property in the calling HTML
3161 page. "property" is optional. If not provided, the
3162 resulting window will be read only. This is useful for
3163 Link properties where selection can be done by drop-down,
3164 but descriptions of the values can be seen in the popup.
3165 Note that some tracker templates may generate an error
3166 if the property is missing. Version 2.4.0 of Roundup
3167 fixed these templates.
3168
3169 If the "form" arg is given, it's passed through to the
3170 JavaScript help_window function - it's the name of the form
3171 the "property" belongs to.
3172
3173 submit generate a submit button (and action and @csrf hidden elements)
3174 renderWith render this class with the given template.
3175 history returns 'New node - no history' :)
3176 is_edit_ok is the user allowed to Edit the current class?
3177 is_view_ok is the user allowed to View the current class?
3178 =========== =============================================================
3088 3179
3089 Note that if you have a property of the same name as one of the above 3180 Note that if you have a property of the same name as one of the above
3090 methods, you'll need to access it using a python "item access" 3181 methods, you'll need to access it using a python "item access"
3091 expression. For example:: 3182 expression. For example::
3092 3183
3107 accessed through the property will be the current value of the same name 3198 accessed through the property will be the current value of the same name
3108 from the CGI form. 3199 from the CGI form.
3109 3200
3110 There are several methods available on these wrapper objects: 3201 There are several methods available on these wrapper objects:
3111 3202
3112 =============== ======================================================== 3203 .. table::
3113 Method Description 3204 :class: valign-top
3114 =============== ======================================================== 3205
3115 submit generate a submit button (and action and @csrf hidden elements) 3206 =============== ========================================================
3116 journal return the journal of the current item (**not 3207 Method Description
3117 implemented**) 3208 =============== ========================================================
3118 history render the journal of the current item as 3209 submit generate a submit button (and action and @csrf hidden elements)
3119 HTML. By default properties marked as "quiet" (see 3210 journal return the journal of the current item (**not
3120 `design documentation`_) are not shown unless the 3211 implemented**)
3121 function is called with the showall=True parameter. 3212 history render the journal of the current item as
3122 Properties that are not Viewable to the user are not 3213 HTML. By default properties marked as "quiet" (see
3123 shown. 3214 `design documentation`_) are not shown unless the
3124 renderQueryForm specific to the "query" class - render the search form 3215 function is called with the ``showall=True`` parameter.
3125 for the query 3216 Properties that are not Viewable to the user are not
3126 hasPermission specific to the "user" class - determine whether the 3217 shown.
3127 user has a Permission. The signature is:: 3218 renderQueryForm specific to the "query" class - render the search form
3128 3219 for the query
3129 hasPermission(self, permission, [classname=], 3220 hasPermission specific to the "user" class - determine whether the
3130 [property=], [itemid=]) 3221 user has a Permission. The signature is::
3131 3222
3132 where the classname defaults to the current context. 3223 hasPermission(self, permission, [classname=],
3133 hasRole specific to the "user" class - determine whether the 3224 [property=], [itemid=])
3134 user has a Role. The signature is:: 3225
3135 3226 where the classname defaults to the current context.
3136 hasRole(self, rolename) 3227 hasRole specific to the "user" class - determine whether the
3137 3228 user has a Role. The signature is::
3138 is_edit_ok is the user allowed to Edit the current item? 3229
3139 is_view_ok is the user allowed to View the current item? 3230 hasRole(self, rolename)
3140 is_retired is the item retired? 3231
3141 download_url generate a url-quoted link for download of FileClass 3232 is_edit_ok is the user allowed to Edit the current item?
3142 item contents (ie. file<id>/<name>) 3233 is_view_ok is the user allowed to View the current item?
3143 copy_url generate a url-quoted link for creating a copy 3234 is_retired is the item retired?
3144 of this item. By default, the copy will acquire 3235 download_url generate a url-quoted link for download of FileClass
3145 all properties of the current item except for 3236 item contents (ie. file<id>/<name>)
3146 ``messages`` and ``files``. This can be overridden 3237 copy_url generate a url-quoted link for creating a copy
3147 by passing ``exclude`` argument which contains a list 3238 of this item. By default, the copy will acquire
3148 (or any iterable) of property names that shall not be 3239 all properties of the current item except for
3149 copied. Database-driven properties like ``id`` or 3240 ``messages`` and ``files``. This can be overridden
3150 ``activity`` cannot be copied. 3241 by passing ``exclude`` argument which contains a list
3151 =============== ======================================================== 3242 (or any iterable) of property names that shall not be
3243 copied. Database-driven properties like ``id`` or
3244 ``activity`` cannot be copied.
3245 =============== ========================================================
3152 3246
3153 Note that if you have a property of the same name as one of the above 3247 Note that if you have a property of the same name as one of the above
3154 methods, you'll need to access it using a python "item access" 3248 methods, you'll need to access it using a python "item access"
3155 expression. For example:: 3249 expression. For example::
3156 3250
3167 ``HTMLNumberProperty``, and so on). 3261 ``HTMLNumberProperty``, and so on).
3168 3262
3169 This wrapper object provides access to a single property of a class. Its 3263 This wrapper object provides access to a single property of a class. Its
3170 value may be either: 3264 value may be either:
3171 3265
3172 1. if accessed through a `hyperdb item wrapper`_, then it's a value from 3266 1. if accessed through a `hyperdb item wrapper`_, then it is a value from
3173 the hyperdb 3267 the hyperdb
3174 2. if access through a `hyperdb class wrapper`_, then it's a value from 3268 2. if access through a `hyperdb class wrapper`_, then it is a value from
3175 the CGI form 3269 the CGI form
3176 3270
3177 3271
3178 The property wrapper has some useful attributes: 3272 The property wrapper has some useful attributes:
3179 3273
3180 =============== ======================================================== 3274 .. table::
3181 Attribute Description 3275 :class: valign-top
3182 =============== ======================================================== 3276
3183 _name the name of the property 3277 =============== ========================================================
3184 _value the value of the property if any - this is the actual 3278 Attribute Description
3185 value retrieved from the hyperdb for this property 3279 =============== ========================================================
3186 =============== ======================================================== 3280 _name the name of the property
3281 _value the value of the property if any - this is the actual
3282 value retrieved from the hyperdb for this property
3283 =============== ========================================================
3187 3284
3188 There are several methods available on these wrapper objects: 3285 There are several methods available on these wrapper objects:
3189 3286
3190 =========== ================================================================ 3287 .. table::
3191 Method Description 3288 :class: valign-top
3192 =========== ================================================================ 3289
3193 plain render a "plain" representation of the property. This method 3290 =========== ================================================================
3194 may take two arguments: 3291 Method Description
3195 3292 =========== ================================================================
3196 escape 3293 plain render a "plain" representation of the property. This method
3197 If true, escape the text so it is HTML safe (default: no). The 3294 may take two arguments:
3198 reason this defaults to off is that text is usually escaped 3295
3199 at a later stage by the TAL commands, unless the "structure" 3296 escape
3200 option is used in the template. The following ``tal:content`` 3297 If true, escape the text so it is HTML safe (default: no). The
3201 expressions are all equivalent:: 3298 reason this defaults to off is that text is usually escaped
3299 at a later stage by the TAL commands, unless the "structure"
3300 option is used in the template. The following ``tal:content``
3301 expressions are all equivalent::
3302
3303 "structure python:msg.content.plain(escape=1)"
3304 "python:msg.content.plain()"
3305 "msg/content/plain"
3306 "msg/content"
3307
3308 Usually you'll only want to use the escape option in a
3309 complex expression.
3310
3311 hyperlink
3312 If true, turn URLs, email addresses and hyperdb item
3313 designators in the text into hyperlinks (default: no). Note
3314 that you'll need to use the "structure" TAL option if you
3315 want to use this ``tal:content`` expression::
3316
3317 "structure python:msg.content.plain(hyperlink=1)"
3318
3319 The text is automatically HTML-escaped before the hyperlinking
3320 transformation done in the plain() method.
3321
3322 hyperlinked The same as msg.content.plain(hyperlink=1), but nicer::
3323
3324 "structure msg/content/hyperlinked"
3325
3326 wrapped Wraps long lines on the nearest whitespace. Like
3327 plain(), it takes ``escape`` and ``hyperlink``
3328 arguments. However, the defaults are to enable both
3329 escape and hyperlinks. It also takes a ``columns``
3330 argument set by default to 80.
3202 3331
3203 "structure python:msg.content.plain(escape=1)" 3332 field render an appropriate form edit field for the property - for
3204 "python:msg.content.plain()" 3333 most types this is a text entry box, but for
3205 "msg/content/plain" 3334 Booleans it is a
3206 "msg/content" 3335 tri-state yes/no/neither selection. This method may take some
3207 3336 arguments:
3208 Usually you'll only want to use the escape option in a 3337
3209 complex expression. 3338 display_time (Date properties only)
3210 3339 By default this uses the display_time paramter of the
3211 hyperlink 3340 Date property (which by default is True) and displays
3212 If true, turn URLs, email addresses and hyperdb item 3341 date and time for Date properties. You can set this to
3213 designators in the text into hyperlinks (default: no). Note 3342 False for displaying only the date.
3214 that you'll need to use the "structure" TAL option if you 3343
3215 want to use this ``tal:content`` expression:: 3344 form (Date properties only)
3216 3345 When using a popup calendar (see popcal below) and the
3217 "structure python:msg.content.plain(hyperlink=1)" 3346 enclosing form name is different from "itemSynopsis",
3218 3347 the form name must be specified for the field.
3219 The text is automatically HTML-escaped before the hyperlinking 3348
3220 transformation done in the plain() method. 3349 format (Date properties only)
3221 3350 Sets the format of the date in the field - uses the
3222 hyperlinked The same as msg.content.plain(hyperlink=1), but nicer:: 3351 same format string argument as supplied to the
3223 3352 ``pretty`` method below. If you use this, it will
3224 "structure msg/content/hyperlinked" 3353 prevent the use of browser native date inputs. It is
3225 3354 useful if you want partial dates. For example using
3226 field render an appropriate form edit field for the property - for 3355 ``format="%Y-%m"`` with ``type="text"`` will display a
3227 most types this is a text entry box, but for Booleans it's a 3356 text edit box with the year and month part of your
3228 tri-state yes/no/neither selection. This method may take some 3357 date.
3229 arguments: 3358
3230 3359 labelfirst (Boolean properties only)
3231 size 3360 place the labels before the radio buttons
3232 Sets the width in characters of the edit field 3361
3233 3362 popcal (Date properties only)
3234 format (Date properties only) 3363 Include a link to the JavaScript-based popup calendar
3235 Sets the format of the date in the field - uses the same 3364 for date selection. Defaults to off/False when browser
3236 format string argument as supplied to the ``pretty`` method 3365 native dates are in use and on/True otherwise because
3237 below. 3366 browser native dates support a date popup on most
3238 3367 browsers.
3239 popcal (Date properties only) 3368
3240 Include the Javascript-based popup calendar for date 3369 size (default 30)
3241 selection. Defaults to on. 3370 Sets the width in characters of the edit field
3242 3371
3243 stext only on String properties - render the value of the property 3372 type (depends on property type)
3244 as StructuredText (requires the StructureText module to be 3373 Sets the type property of the input. To change a date
3245 installed separately) 3374 property field from a native date input to a text
3246 multiline only on String properties - render a multiline form edit 3375 input you would use ``type="text"``. For Date properties
3247 field for the property 3376 the type cannot be set by the user and is enforced via
3248 email only on String properties - render the value of the property 3377 the configuration (if browser native date input should
3249 as an obscured email address 3378 be used).
3250 url_quote only on String properties. It quotes any characters in the 3379
3251 string so it is safe to use in a url. E.G. a space is 3380 y_label, n_label, u_label (Boolean properties only)
3252 replaced with %20. 3381 Set the labels for the true/false/undefined
3253 confirm only on Password properties - render a second form edit field 3382 states. If u_label is defined, it produces a
3254 for the property, used for confirmation that the user typed 3383 tri-state radio button selector. Otherwise, it
3255 the password correctly. Generates a field with name 3384 allows selection of true/yes or false/no only.
3256 "name:confirm". 3385
3257 now only on Date properties - return the current date as a new 3386 Other arguments are added as properties directly on the
3258 property 3387 input tag. For example::
3259 reldate only on Date properties - render the interval between the date 3388
3260 and now 3389 field(size=30, id='myid', required=None)
3261 local only on Date properties - return this date as a new property 3390
3262 with some timezone offset, for example:: 3391 produces::
3263 3392
3264 python:context.creation.local(10) 3393 <input id="myid" size="30" required>
3265 3394
3266 will render the date with a +10 hour offset. 3395 Note that using ``None`` as the value results in an
3267 pretty Date properties - render the date as "dd Mon YYYY" (eg. "19 3396 attribute without a value. This is useful for boolean
3268 Mar 2004"). Takes an optional format argument, for example:: 3397 properties like ``required``.
3269 3398
3270 python:context.activity.pretty('%Y-%m-%d') 3399 rst only on String properties - render the value of the property
3271 3400 as ReStructuredText (requires the :ref:`Docutils
3272 Will format as "2004-03-19" instead. 3401 module to be installed separately<install/docutils>`).
3273 3402
3274 Interval properties - render the interval in a pretty 3403 stext only on String properties - render the value of the property
3275 format (eg. "yesterday"). The format arguments are those used 3404 as StructuredText (requires the StructureText module to be
3276 in the standard ``strftime`` call (see the `Python Library 3405 installed separately) (deprecated, to be removed
3277 Reference: time module`__) 3406 use rst or markdown instead).
3278 3407 markdown only on String properties - render the value of the property
3279 Number properties - takes a printf style format argument 3408 as Markdown (requires a :ref:`Markdown module to be
3280 (default: '%0.3f') and formats the number accordingly. 3409 installed separately<install/markdown>`).
3281 If the value can't be converted, '' is returned if the 3410
3282 value is ``None`` otherwise it is converted to a string. 3411 multiline only on String properties - render a multiline form edit
3283 popcal Generate a link to a popup calendar which may be used to 3412 field for the property
3284 edit the date field, for example:: 3413
3285 3414 email only on String properties - render the value of the property
3286 <span tal:replace="structure context/due/popcal" /> 3415 as an obscured email address
3287 3416
3288 you still need to include the ``field`` for the property, so 3417 url_quote only on String properties. It quotes any characters in the
3289 typically you'd have:: 3418 string so it is safe to use in a url. E.G. a space is
3290 3419 replaced with %20.
3291 <span tal:replace="structure context/due/field" /> 3420
3292 <span tal:replace="structure context/due/popcal" /> 3421 confirm only on Password properties - render a second form edit field
3293 3422 for the property, used for confirmation that the user typed
3294 menu only on Link and Multilink properties - render a form select 3423 the password correctly. Generates a field with name
3295 list for this property. Takes a number of optional arguments 3424 "name:confirm".
3296 3425
3297 size 3426 now only on Date properties - return the current date as a new
3298 is used to limit the length of the list labels 3427 property
3299 height 3428
3300 is used to set the <select> tag's "size" attribute 3429 reldate only on Date properties - render the interval between the date
3301 showid 3430 and now
3302 includes the item ids in the list labels 3431
3303 additional 3432 local only on Date properties - return this date as a new property
3304 lists properties which should be included in the label 3433 with some timezone offset, for example::
3305 sort_on 3434
3306 indicates the property to sort the list on as (direction, 3435 python:context.creation.local(10)
3307 (direction, property) where direction is '+' or '-'. A 3436
3308 single string with the direction prepended may be used. 3437 will render the date with a +10 hour offset.
3309 For example: ('-', 'order'), '+name'. 3438
3310 value 3439 pretty Date properties - render the date as "dd Mon YYYY" (eg. "19
3311 gives a default value to preselect in the menu 3440 Mar 2004"). Takes an optional format argument, for example::
3312 3441
3313 The remaining keyword arguments are used as conditions for 3442 python:context.activity.pretty('%Y-%m-%d')
3314 filtering the items in the list - they're passed as the 3443
3315 "filterspec" argument to a Class.filter() call. For example:: 3444 Will format as "2004-03-19" instead.
3316 3445
3317 <span tal:replace="structure context/status/menu" /> 3446 Interval properties - render the interval in a
3318 3447 pretty format (e.g. "yesterday"). The format
3319 <span tal:replace="python:context.status.menu(order='+name", 3448 arguments are those used in the standard
3320 value='chatting', 3449 ``strftime`` call (see the `Python Library
3321 filterspec={'status': '1,2,3,4'}" /> 3450 Reference: time module`__)
3322 3451
3323 sorted only on Multilink properties - produce a list of the linked 3452 Number properties - takes a printf style format
3324 items sorted by some property, for example:: 3453 argument (default: '%0.3f') and formats the number
3325 3454 accordingly. If the value can't be converted, ''
3326 python:context.files.sorted('creation') 3455 is returned if the value is ``None`` otherwise it
3327 3456 is converted to a string.
3328 Will list the files by upload date. While:: 3457
3329 3458 popcal This is deprecated with Roundup 2.5 which either uses the
3330 python:context.files.sorted('creation', reverse=True) 3459 native HTML5 date input or can generate a date popup with
3331 3460 the popcal option of the ``field`` method. The native date
3332 Will list the files by upload date in reverse order from 3461 input includes a calendar popup on modern broswers.
3333 the prior example. If the property can be unset, you can 3462
3334 use the ``NoneFirst`` parameter to sort the None/Unset 3463 Generate a link to a popup calendar which may be used to
3335 values at the front or the end of the list. For example:: 3464 edit the date field, for example::
3336 3465
3337 python:context.files.sorted('creation', NoneFirst=True) 3466 <span tal:replace="structure context/due/popcal" />
3338 3467
3339 will sort files by creation date with files missing a 3468 you still need to include the ``field`` for the property, so
3340 creation date at the start of the list. The default for 3469 typically you'd have::
3341 ``NoneFirst`` is False so these files will sort at the end 3470
3342 by default. (Note creation date is never unset, but you 3471 <span tal:replace="structure context/due/field" />
3343 get the idea.) If you combine NoneFirst with 3472 <span tal:replace="structure context/due/popcal" />
3344 ``reverse=True`` the meaning of NoneFirst is inverted: 3473
3345 True sorts None/unset at the end and False sorts at the 3474 Since the ``field`` by default already produces a popup
3346 beginning. 3475 calendar this use is deprecated.
3347 reverse only on Multilink properties - produce a list of the linked 3476
3348 items in reverse order 3477 menu only on Link and Multilink properties - render a form select
3349 isset returns True if the property has been set to a value 3478 list for this property. Takes a number of optional arguments
3350 =========== ================================================================ 3479
3480 size
3481 is used to limit the length of the list labels
3482 height
3483 is used to set the <select> tag's "size" attribute
3484 showid
3485 includes the item ids in the list labels
3486 additional
3487 lists properties which should be included in the label
3488 sort_on
3489 indicates the property to sort the list on as (direction,
3490 (direction, property) where direction is '+' or '-'. A
3491 single string with the direction prepended may be used.
3492 For example: ('-', 'order'), '+name'.
3493 value
3494 gives a default value to preselect in the menu
3495
3496 The remaining keyword arguments are used as conditions for
3497 filtering the items in the list - they're passed as the
3498 "filterspec" argument to a Class.filter() call. For example::
3499
3500 <span tal:replace="structure context/status/menu" />
3501
3502 <span tal:replace="python:context.status.menu(order='+name",
3503 value='chatting',
3504 filterspec={'status': '1,2,3,4'}" />
3505
3506 sorted only on Multilink properties - produce a list of the linked
3507 items sorted by some property, for example::
3508
3509 python:context.files.sorted('creation')
3510
3511 Will list the files by upload date. While::
3512
3513 python:context.files.sorted('creation', reverse=True)
3514
3515 Will list the files by upload date in reverse order from
3516 the prior example. If the property can be unset, you can
3517 use the ``NoneFirst`` parameter to sort the None/Unset
3518 values at the front or the end of the list. For example::
3519
3520 python:context.files.sorted('creation', NoneFirst=True)
3521
3522 will sort files by creation date with files missing a
3523 creation date at the start of the list. The default for
3524 ``NoneFirst`` is False so these files will sort at the end
3525 by default. (Note creation date is never unset, but you
3526 get the idea.) If you combine NoneFirst with
3527 ``reverse=True`` the meaning of NoneFirst is inverted:
3528 True sorts None/unset at the end and False sorts at the
3529 beginning.
3530
3531 reverse only on Multilink properties - produce a list of the linked
3532 items in reverse order
3533
3534 isset returns True if the property has been set to a value
3535 =========== ================================================================
3351 3536
3352 __ https://docs.python.org/2/library/time.html 3537 __ https://docs.python.org/2/library/time.html
3353 3538
3354 All of the above functions perform checks for permissions required to 3539 All the above functions perform checks for permissions required to
3355 display or edit the data they are manipulating. The simplest case is 3540 display or edit the data they are manipulating. The simplest case is
3356 editing an issue title. Including the expression:: 3541 editing an issue title. Including the expression::
3357 3542
3358 context/title/field 3543 context/title/field
3359 3544
3373 The request variable is packed with information about the current 3558 The request variable is packed with information about the current
3374 request. 3559 request.
3375 3560
3376 .. taken from ``roundup.cgi.templating.HTMLRequest`` docstring 3561 .. taken from ``roundup.cgi.templating.HTMLRequest`` docstring
3377 3562
3378 =========== ============================================================ 3563 .. table::
3379 Variable Holds 3564 :class: valign-top
3380 =========== ============================================================ 3565
3381 form the CGI form as a cgi.FieldStorage 3566 =========== ============================================================
3382 env the CGI environment variables 3567 Variable Holds
3383 base the base URL for this tracker 3568 =========== ============================================================
3384 user a HTMLUser instance for this user 3569 base the base URL for this tracker
3385 classname the current classname (possibly None) 3570 classname the current classname (possibly None)
3386 template the current template (suffix, also possibly None) 3571 env the CGI environment variables
3387 form the current CGI form variables in a FieldStorage 3572 form the current CGI form variables in a cgi.FieldStorage
3388 =========== ============================================================ 3573 template the current template (suffix, also possibly None)
3574 user a HTMLUser instance for this user
3575 =========== ============================================================
3389 3576
3390 **Index page specific variables (indexing arguments)** 3577 **Index page specific variables (indexing arguments)**
3391 3578
3392 =========== ============================================================ 3579 .. table::
3393 Variable Holds 3580 :class: valign-top
3394 =========== ============================================================ 3581
3395 columns dictionary of the columns to display in an index page 3582 =========== ============================================================
3396 show a convenience access to columns - request/show/colname will 3583 Variable Holds
3397 be true if the columns should be displayed, false otherwise 3584 =========== ============================================================
3398 sort index sort columns [(direction, column name)] 3585 columns dictionary of the columns to display in an index page
3399 group index grouping properties [(direction, column name)] 3586 filter properties to filter the index on
3400 filter properties to filter the index on 3587 filterspec values to filter the index on (property=value, eg
3401 filterspec values to filter the index on (property=value, eg 3588 ``priority=1`` or ``messages.author=42``
3402 ``priority=1`` or ``messages.author=42`` 3589 group index grouping properties [(direction, column name)]
3403 search_text text to perform a full-text search on for an index 3590 search_text text to perform a full-text search on for an index
3404 =========== ============================================================ 3591 show a convenience access to columns - request/show/colname will
3405 3592 be true if the columns should be displayed, false otherwise
3406 There are several methods available on the request variable: 3593 sort index sort columns [(direction, column name)]
3407 3594 =========== ============================================================
3408 =============== ======================================================== 3595
3409 Method Description 3596 Several methods are available on the request variable:
3410 =============== ======================================================== 3597
3411 description render a description of the request - handle for the 3598 .. table::
3412 page title 3599 :class: valign-top
3413 indexargs_form render the current index args as form elements 3600
3414 indexargs_url render the current index args as a URL 3601 =============== ========================================================
3415 base_javascript render some javascript that is used by other components 3602 Method Description
3416 of the templating 3603 =============== ========================================================
3417 batch run the current index args through a filter and return a 3604 base_javascript render some javascript used by other components
3418 list of items (see `hyperdb item wrapper`_, and 3605 of the templating
3419 `batching`_) 3606 batch run the current index args through a filter and return a
3420 =============== ======================================================== 3607 list of items (see `hyperdb item wrapper`_, and
3608 `batching`_)
3609 description render a description of the request - handle for the
3610 page title
3611 indexargs_form render the current index args as form elements
3612 indexargs_url render the current index args as a URL::
3613
3614 request.indexargs_url("url", {args})
3615
3616 If the value of an arg (in args dict) is None,
3617 the argument is excluded from the url. If you want
3618 an empty value use an empty string '' as the value.
3619 Use this in templates to conditionally
3620 include an arg if it is set to a value. E.G.
3621 {..., '@queryname': request.dispname or None, ...}
3622 will include @queryname in the url if there is a
3623 dispname otherwise the parameter will be omitted
3624 from the url.
3625 =============== ========================================================
3421 3626
3422 The form variable 3627 The form variable
3423 ::::::::::::::::: 3628 :::::::::::::::::
3424 3629
3425 The form variable is a bit special because it's actually a python 3630 The form variable is a bit special because it's actually a python
3432 or the python expression:: 3637 or the python expression::
3433 3638
3434 python:request.form['name'].value 3639 python:request.form['name'].value
3435 3640
3436 Note the "item" access used in the python case, and also note the 3641 Note the "item" access used in the python case, and also note the
3437 explicit "value" attribute we have to access. That's because the form 3642 explicit "value" attribute we have to access. That's because the
3438 variables are stored as MiniFieldStorages. If there's more than one 3643 form variables are stored as MiniFieldStorages. If there's more
3439 "name" value in the form, then the above will break since 3644 than one "name" value in the form, then the above will break
3440 ``request/form/name`` is actually a *list* of MiniFieldStorages. So it's 3645 since ``request/form/name`` is actually a *list* of
3441 best to know beforehand what you're dealing with. 3646 MiniFieldStorages. So it is best to know beforehand what you are
3647 dealing with.
3442 3648
3443 3649
3444 The db variable 3650 The db variable
3445 ~~~~~~~~~~~~~~~ 3651 ~~~~~~~~~~~~~~~
3446 3652
3451 you want access to the "user" class, for example, you would use:: 3657 you want access to the "user" class, for example, you would use::
3452 3658
3453 db/user 3659 db/user
3454 python:db.user 3660 python:db.user
3455 3661
3456 Also, the current id of the current user is available as 3662 Also, the id of the current user is available as
3457 ``db.getuid()``. This isn't so useful in templates (where you have 3663 ``db.getuid()``. This isn't as useful in templates (where you have
3458 ``request/user``), but it can be useful in detectors or interfaces. 3664 ``request/user``), but is useful in detectors or interfaces.
3459 3665
3460 The access results in a `hyperdb class wrapper`_. 3666 The access results in a `hyperdb class wrapper`_.
3461 3667
3462 3668
3463 The templates variable 3669 The templates variable
3467 class before 1.4.20. In later versions it is the instance of appropriate 3673 class before 1.4.20. In later versions it is the instance of appropriate
3468 template engine loader class. 3674 template engine loader class.
3469 3675
3470 This variable is used to access other templates in expressions and 3676 This variable is used to access other templates in expressions and
3471 template macros. It doesn't have any useful methods defined. The 3677 template macros. It doesn't have any useful methods defined. The
3472 templates can be accessed using the following path expression:: 3678 templates are accessed using the following path expression::
3473 3679
3474 templates/name 3680 templates/name
3475 3681
3476 or the python expression:: 3682 or the python expression::
3477 3683
3488 templates[name].macros[macro_name] 3694 templates[name].macros[macro_name]
3489 3695
3490 The repeat variable 3696 The repeat variable
3491 ~~~~~~~~~~~~~~~~~~~ 3697 ~~~~~~~~~~~~~~~~~~~
3492 3698
3493 The repeat variable holds an entry for each active iteration. That is, if 3699 The repeat variable holds an entry for each active iteration. If
3494 you have a ``tal:repeat="user db/users"`` command, then there will be a 3700 you have a ``tal:repeat="myusers db/users"`` command, then there
3495 repeat variable entry called "user". This may be accessed as either:: 3701 will be a repeat variable entry called "myusers". This is accessed
3496 3702 as either::
3497 repeat/user 3703
3498 python:repeat['user'] 3704 repeat/myusers
3499 3705 python:repeat['myusers']
3500 The "user" entry has a number of methods available for information: 3706
3501 3707 The "myusers" entry has nine methods available for information:
3502 =============== ========================================================= 3708
3503 Method Description 3709 .. table::
3504 =============== ========================================================= 3710 :class: valign-top
3505 first True if the current item is the first in the sequence. 3711
3506 last True if the current item is the last in the sequence. 3712 =============== =========================================================
3507 even True if the current item is an even item in the sequence. 3713 Method Description
3508 odd True if the current item is an odd item in the sequence. 3714 =============== =========================================================
3509 number Current position in the sequence, starting from 1. 3715 first True if the current item is the first in the sequence.
3510 letter Current position in the sequence as a letter, a through 3716 last True if the current item is the last in the sequence.
3511 z, then aa through zz, and so on. 3717 even True if the current item is an even item in the sequence.
3512 Letter Same as letter(), except uppercase. 3718 odd True if the current item is an odd item in the sequence.
3513 roman Current position in the sequence as lowercase roman 3719 number Current position in the sequence, starting from 1.
3514 numerals. 3720 letter Current position in the sequence as a letter, a through
3515 Roman Same as roman(), except uppercase. 3721 z, then aa through zz, and so on.
3516 =============== ========================================================= 3722 Letter Same as letter(), except uppercase.
3723 roman Current position in the sequence as lowercase roman
3724 numerals.
3725 Roman Same as roman(), except uppercase.
3726 =============== =========================================================
3727
3728 (Note: except for even, True above can be a truthy/falsy value not
3729 actually True/False. Also the first item in a sequence is 0,
3730 so it starts with even() = True when number() returns 1 as index
3731 is 0.)
3732
3733 It also has the following properties:
3734
3735 .. table::
3736 :class: valign-top
3737
3738 =============== =========================================================
3739 Properties Description
3740 =============== =========================================================
3741 end Truthy if the current item is the last in the sequence.
3742 index Current index in sequence starting at 0
3743 start Truthy if the current item is the first in the sequence.
3744 =============== =========================================================
3745
3746 For example, this will print a comma after each element except the
3747 last::
3748
3749 <span>
3750 <tal:x tal:repeat="field
3751 python:request.form['properties'].value.split(',')">
3752 <tal:x tal:replace="field"></tal:x>
3753 <tal:x tal:condition="python:not repeat['field'].last()"
3754 tal:content="string:,"></tal:x>
3755 </tal:x>
3756 </span>
3757
3758 The same can be done using a path expression::
3759
3760 <tal:x tal:condition="not: repeat/field/last" ...
3517 3761
3518 .. _templating utilities: 3762 .. _templating utilities:
3519 3763
3520 The utils variable 3764 The utils variable
3521 ~~~~~~~~~~~~~~~~~~ 3765 ~~~~~~~~~~~~~~~~~~
3522 3766
3523 This is implemented by the 3767 This is implemented by the
3524 ``roundup.cgi.templating.TemplatingUtils`` class, which may be extended 3768 ``roundup.cgi.templating.TemplatingUtils`` class. New methods can
3525 with additional methods by extensions_. 3769 be added to the variable by using extensions_.
3526 3770
3527 =============== ======================================================== 3771 -----
3528 Method Description 3772
3529 =============== ======================================================== 3773 .. list-table:: TemplatingUtils Methods
3530 Batch return a batch object using the supplied list 3774 :align: left
3531 url_quote quote some text as safe for a URL (ie. space, %, ...) 3775 :header-rows: 1
3532 html_quote quote some text as safe in HTML (ie. <, >, ...) 3776 :class: valign-top captionbelow booktabs
3533 html_calendar renders an HTML calendar used by the 3777
3534 ``_generic.calendar.html`` template (itself invoked by 3778 * - Method
3535 the popupCalendar DateHTMLProperty method 3779 - Description
3536 anti_csrf_nonce returns the random noncue generated for this session 3780 * - Batch
3537 =============== ======================================================== 3781 - return a batch object using the supplied list
3538 3782 * - anti_csrf_nonce
3783 - returns the random nonce generated for this session
3784 * - :meth:`expandfile <roundup.cgi.templating.TemplatingUtils.expandfile>`
3785 - load a file into a template and expand
3786 '%(tokenname)s' in the file using
3787 values from the supplied dictionary.
3788 * - :meth:`html_calendar <roundup.cgi.templating.TemplatingUtils.html_calendar>`
3789 - renders an HTML calendar used by the ``_generic.calendar.html``
3790 template (itself invoked by the popupCalendar DateHTMLProperty
3791 method
3792 * - :meth:`html_quote <roundup.cgi.templating.TemplatingUtils.html_quote>`
3793 - quote some text as safe in HTML (ie. <, >, ...)
3794 * - :meth:`readfile <roundup.cgi.templating.TemplatingUtils.readfile>`
3795 - read JavaScript or other content in an external file
3796 into the template.
3797 * - :meth:`set_http_response <roundup.cgi.templating.TemplatingUtils.set_http_response>`
3798 - set_http_response sets the HTTP response code for the request.
3799 * - :meth:`url_quote <roundup.cgi.templating.TemplatingUtils.url_quote>`
3800 - quote some text as safe for a URL (ie. space, %, ...)
3801 * - :meth:`embed_form_fields <roundup.cgi.templating.TemplatingUtils.embed_form_fields>`
3802 - Creates a hidden input for each of the client's form fields. It
3803 also embeds base64 encoded file contents into pre tags and
3804 processes that informtion back into a file input control.
3805
3806
3807 -----
3808
3809 Additional info can be obtained by starting ``python`` with the
3810 ``roundup`` subdirectory on your PYTHONPATH and using the Python help
3811 function like::
3812
3813 >>> from roundup.cgi.templating import TemplatingUtils
3814 >>> help(TemplatingUtils.readfile)
3815 Help on function readfile in module roundup.cgi.templating:
3816
3817 readfile(self, name, optional=False)
3818 Read an file in the template directory.
3819
3820 Used to inline file content into a template. If file
3821 is not found in template directory, reports an error
3822 to the user unless optional=True. Then it returns an
3823 empty string. Useful inlining JavaScript kept in an
3824 external file where you can use linters/minifiers and
3825
3826 (Note: ``>>>`` is the Python REPL prompt. Don't type the ``>>>``.)
3539 3827
3540 Batching 3828 Batching
3541 :::::::: 3829 ::::::::
3542 3830
3543 Use Batch to turn a list of items, or item ids of a given class, into a 3831 Use Batch to turn a list of items, or item ids of a given class, into a
3550 3838
3551 request/batch 3839 request/batch
3552 3840
3553 The parameters are: 3841 The parameters are:
3554 3842
3555 ========= ============================================================== 3843 .. table::
3556 Parameter Usage 3844 :class: valign-top
3557 ========= ============================================================== 3845
3558 sequence a list of HTMLItems 3846 ========= ==============================================================
3559 size how big to make the sequence. 3847 Parameter Usage
3560 start where to start (0-indexed) in the sequence. 3848 ========= ==============================================================
3561 end where to end (0-indexed) in the sequence. 3849 end where to end (0-indexed) in the sequence.
3562 orphan if the next batch would contain less items than this value, 3850 orphan if the next batch would contain less items than this value,
3563 then it is combined with this batch 3851 then it is combined with this batch
3564 overlap the number of items shared between adjacent batches 3852 overlap the number of items shared between adjacent batches
3565 ========= ============================================================== 3853 sequence a list of HTMLItems
3854 size how big to make the sequence.
3855 start where to start (0-indexed) in the sequence.
3856 ========= ==============================================================
3566 3857
3567 All of the parameters are assigned as attributes on the batch object. In 3858 All of the parameters are assigned as attributes on the batch object. In
3568 addition, it has several more attributes: 3859 addition, it has several more attributes:
3569 3860
3570 =============== ======================================================== 3861 .. table::
3571 Attribute Description 3862 :class: valign-top
3572 =============== ======================================================== 3863
3573 start indicates the start index of the batch. *Unlike 3864 =============== ========================================================
3574 the argument, is a 1-based index (I know, lame)* 3865 Attribute Description
3575 first indicates the start index of the batch *as a 0-based 3866 =============== ========================================================
3576 index* 3867 first indicates the start index of the batch *as a 0-based
3577 length the actual number of elements in the batch 3868 index*
3578 sequence_length the length of the original, unbatched, sequence. 3869 length the actual number of elements in the batch
3579 =============== ======================================================== 3870 start indicates the start index of the batch. *Unlike
3871 the argument, is a 1-based index (I know, lame)*
3872 sequence_length the length of the original, unbatched, sequence.
3873 =============== ========================================================
3580 3874
3581 And several methods: 3875 And several methods:
3582 3876
3583 =============== ======================================================== 3877 .. table::
3584 Method Description 3878 :class: valign-top
3585 =============== ======================================================== 3879
3586 previous returns a new Batch with the previous batch settings 3880 =============== ========================================================
3587 next returns a new Batch with the next batch settings 3881 Method Description
3588 propchanged detect if the named property changed on the current item 3882 =============== ========================================================
3589 when compared to the last item 3883 previous returns a new Batch with the previous batch settings
3590 =============== ======================================================== 3884 next returns a new Batch with the next batch settings
3885 propchanged detect if the named property changed on the current item
3886 when compared to the last item
3887 =============== ========================================================
3591 3888
3592 An example of batching:: 3889 An example of batching::
3593 3890
3594 <table class="otherinfo"> 3891 <table class="otherinfo">
3595 <tr><th colspan="4" class="header">Existing Keywords</th></tr> 3892 <tr><th colspan="4" class="header">Existing Keywords</th></tr>
3599 tal:repeat="keyword batch" tal:content="keyword/name"> 3896 tal:repeat="keyword batch" tal:content="keyword/name">
3600 keyword here</td> 3897 keyword here</td>
3601 </tr> 3898 </tr>
3602 </table> 3899 </table>
3603 3900
3604 ... which will produce a table with four columns containing the items of 3901 will produce a table with four columns containing the items of
3605 the "keyword" class (well, their "name" anyway). 3902 the "keyword" class (well, their "name" anyway).
3606 3903
3607 3904
3608 Translations 3905 Translations
3609 ~~~~~~~~~~~~ 3906 ~~~~~~~~~~~~
3612 create you'll need to add new locale files in the tracker home under a 3909 create you'll need to add new locale files in the tracker home under a
3613 ``locale`` directory. Use the `translation instructions in the 3910 ``locale`` directory. Use the `translation instructions in the
3614 developer's guide <developers.html#extracting-translatable-messages>`_ to 3911 developer's guide <developers.html#extracting-translatable-messages>`_ to
3615 create the locale files. 3912 create the locale files.
3616 3913
3914 Setting the Type of the Returned Data
3915 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3916
3917 Roundup processes a template and uses the name of the template to
3918 determine the Content-Type MIME header that is returned. For
3919 ``issue.index.html` it would return ``text/html``. Similarly a file
3920 named ``issue.atom.xml`` (an rss feed) would have a type
3921 of``application/xml``. A file named 'issue.json' would have type
3922 ``application/json``.
3923
3924 However as of Roundup 2.4.0 you can set the type of the file by
3925 calling::
3926
3927 request.client.setHeader('Content-Type', 'application/atom+xml')
3928
3929 from your template. For TAL based templates, something like this::
3930
3931 <tal:x tal:replace="python:request.client.setHeader(
3932 'Content-Type', 'application/atom+xml'
3933 )"/>
3934
3935 will set the ``Content-Type`` header. The header name is case sensitive,
3936 so use capital letters as shown. If you don't you end up with multiple
3937 Content-Type definitions returned to the browser.
3617 3938
3618 Displaying Properties 3939 Displaying Properties
3619 --------------------- 3940 ---------------------
3620 3941
3621 Properties appear in the user interface in three contexts: in indices, 3942 Properties appear in the user interface in three contexts: in indices,
3622 in editors, and as search arguments. For each type of property, there 3943 in editors, and as search arguments. For each type of property, there
3623 are several display possibilities. For example, in an index view, a 3944 are several display possibilities. For example, in an index view, a
3624 string property may just be printed as a plain string, but in an editor 3945 string property may just be printed as a plain string. In an editor
3625 view, that property may be displayed in an editable field. 3946 view, that property may be displayed in an editable field.
3626 3947
3627 3948
3628 Index Views 3949 Index Views
3629 ----------- 3950 -----------
3645 @filters=status,keyword& 3966 @filters=status,keyword&
3646 @columns=title,status,fixer 3967 @columns=title,status,fixer
3647 3968
3648 The index view is determined by two parts of the specifier: the layout 3969 The index view is determined by two parts of the specifier: the layout
3649 part and the filter part. The layout part consists of the query 3970 part and the filter part. The layout part consists of the query
3650 parameters that begin with colons, and it determines the way that the 3971 parameters that begin with the '@' character, and it determines
3651 properties of selected items are displayed. The filter part consists of 3972 the way that the properties of selected items are displayed. The
3652 all the other query parameters, and it determines the criteria by which 3973 filter part consists of all the other query parameters, and it
3653 items are selected for display. The filter part is interactively 3974 determines the criteria by which items are selected for
3654 manipulated with the form widgets displayed in the filter section. The 3975 display. The filter part is interactively manipulated with the
3655 layout part is interactively manipulated by clicking on the column 3976 form widgets displayed in the filter section. The layout part is
3656 headings in the table. 3977 interactively manipulated by clicking on the column headings in
3978 the table.
3657 3979
3658 The filter part selects the union of the sets of items with values 3980 The filter part selects the union of the sets of items with values
3659 matching any specified Link properties and the intersection of the sets 3981 matching any specified Link properties and the intersection of the sets
3660 of items with values matching any specified Multilink properties. 3982 of items with values matching any specified MultiLink properties.
3661 3983
3662 The example specifies an index of "issue" items. Only items with a 3984 The example specifies an index of "issue" items. Only items with a
3663 "status" of either "unread" or "in-progress" or "resolved" are 3985 "status" of either "unread", "in-progress" or "resolved" are
3664 displayed, and only items with "keyword" values including both "security" 3986 displayed, and only items with "keyword" values including both "security"
3665 and "ui" are displayed. The items are grouped by priority arranged in 3987 and "ui" are displayed. The items are grouped by priority arranged in
3666 ascending order and in descending order by status; and within 3988 ascending order and in descending order by status; and within
3667 groups, sorted by activity, arranged in descending order. The filter 3989 groups, sorted by activity, arranged in descending order. The filter
3668 section shows filters for the "status" and "keyword" properties, and the 3990 section shows filters for the "status" and "keyword" properties, and the
3669 table includes columns for the "title", "status", and "fixer" 3991 table includes columns for the "title", "status", and "fixer"
3670 properties. 3992 properties.
3671 3993
3672 ============ ============================================================= 3994 .. table::
3673 Argument Description 3995 :class: valign-top
3674 ============ ============================================================= 3996
3675 @sort sort by prop name, optionally preceeded with '-' to give 3997 ============ =============================================================
3676 descending or nothing for ascending sorting. Several 3998 Argument Description
3677 properties can be specified delimited with comma. 3999 ============ =============================================================
3678 Internally a search-page using several sort properties may 4000 @sort sort by prop name, optionally preceeded with '-' to give
3679 use @sort0, @sort1 etc. with option @sortdir0, @sortdir1 4001 descending or nothing for ascending sorting. Several
3680 etc. for the direction of sorting (a non-empty value of 4002 properties can be specified delimited with comma.
3681 sortdir0 specifies reverse order). 4003 Internally a search-page using several sort properties may
3682 @group group by prop name, optionally preceeded with '-' or to sort 4004 use @sort0, @sort1 etc. with option @sortdir0, @sortdir1
3683 in descending or nothing for ascending order. Several 4005 etc. for the direction of sorting (a non-empty value of
3684 properties can be specified delimited with comma. 4006 sortdir0 specifies reverse order).
3685 Internally a search-page using several grouping properties may 4007 @group group by prop name, optionally preceeded with '-' or to sort
3686 use @group0, @group1 etc. with option @groupdir0, @groupdir1 4008 in descending or nothing for ascending order. Several
3687 etc. for the direction of grouping (a non-empty value of 4009 properties can be specified delimited with comma.
3688 groupdir0 specifies reverse order). 4010 Internally a search-page using several grouping properties may
3689 @columns selects the columns that should be displayed. Default is 4011 use @group0, @group1 etc. with option @groupdir0, @groupdir1
3690 all. 4012 etc. for the direction of grouping (a non-empty value of
3691 @filter indicates which properties are being used in filtering. 4013 groupdir0 specifies reverse order).
3692 Default is none. 4014 @columns selects the columns that should be displayed. Default is
3693 propname selects the values the item properties given by propname must 4015 all.
3694 have (very basic search/filter). 4016 @filter indicates which properties are being used in filtering.
3695 @search_text if supplied, performs a full-text search (message bodies, 4017 Default is none.
3696 issue titles, etc) 4018 propname selects the values the item properties given by propname must
3697 ============ ============================================================= 4019 have (very basic search/filter).
4020 @search_text if supplied, performs a full-text search (message bodies,
4021 issue titles, etc)
4022 ============ =============================================================
3698 4023
3699 4024
3700 Searching Views 4025 Searching Views
3701 --------------- 4026 ---------------
3702 4027
3710 ``@action`` variable. The "search" action: 4035 ``@action`` variable. The "search" action:
3711 4036
3712 - sets up additional filtering, as well as performing indexed text 4037 - sets up additional filtering, as well as performing indexed text
3713 searching 4038 searching
3714 - sets the ``@filter`` variable correctly 4039 - sets the ``@filter`` variable correctly
3715 - saves the query off if ``@query_name`` is set. 4040 - saves the query to the user's query list if ``@query_name`` is set.
3716 4041
3717 The search page should lay out any fields that you wish to allow the 4042 The search page should lay out any fields that you wish to allow the
3718 user to search on. If your schema contains a large number of properties, 4043 user to search on. If your schema contains a large number of properties,
3719 you should be wary of making all of those properties available for 4044 you should be wary of making all of those properties available for
3720 searching, as this can cause confusion. If the additional properties are 4045 searching, as this can cause confusion. If the additional properties are
3723 more useful for the end user. 4048 more useful for the end user.
3724 4049
3725 If the search view does specify the "search" ``@action``, then it may also 4050 If the search view does specify the "search" ``@action``, then it may also
3726 provide an additional argument: 4051 provide an additional argument:
3727 4052
3728 ============ ============================================================= 4053 .. table::
3729 Argument Description 4054 :class: valign-top
3730 ============ ============================================================= 4055
3731 @query_name if supplied, the index parameters (including @search_text) 4056 ============ =============================================================
3732 will be saved off as a the query item and registered against 4057 Argument Description
3733 the user's queries property. Note that the *classic* template 4058 ============ =============================================================
3734 schema has this ability, but the *minimal* template schema 4059 @query_name if supplied, the index parameters (including @search_text)
3735 does not. 4060 will be saved as a the query item and registered against
3736 ============ ============================================================= 4061 the user's queries property. Note that the *classic* template
4062 schema has this ability, but the *minimal* template schema
4063 does not.
4064 ============ =============================================================
3737 4065
3738 4066
3739 Item Views 4067 Item Views
3740 ---------- 4068 ----------
3741 4069
3793 </tr> 4121 </tr>
3794 4122
3795 <tr> 4123 <tr>
3796 <th>Change Note</th> 4124 <th>Change Note</th>
3797 <td colspan="3"> 4125 <td colspan="3">
3798 <textarea name=":note" wrap="hard" rows="5" cols="60"></textarea> 4126 <textarea name="@note" wrap="hard" rows="5" cols="60"></textarea>
3799 </td> 4127 </td>
3800 </tr> 4128 </tr>
3801 4129
3802 <tr> 4130 <tr>
3803 <th>File</th> 4131 <th>File</th>
3804 <td colspan="3"><input type="file" name=":file" size="40"></td> 4132 <td colspan="3"><input type="file" name="@file" size="40"></td>
3805 </tr> 4133 </tr>
3806 4134
3807 <tr> 4135 <tr>
3808 <td>&nbsp;</td> 4136 <td>&nbsp;</td>
3809 <td colspan="3" tal:content="structure context/submit"> 4137 <td colspan="3" tal:content="structure context/submit">
3813 </table> 4141 </table>
3814 4142
3815 4143
3816 When a change is submitted, the system automatically generates a message 4144 When a change is submitted, the system automatically generates a message
3817 describing the changed properties. As shown in the example, the editor 4145 describing the changed properties. As shown in the example, the editor
3818 template can use the ":note" and ":file" fields, which are added to the 4146 template can use the "@note" and "@file" fields, which are added to the
3819 standard changenote message generated by Roundup. 4147 standard changenote message generated by Roundup.
3820 4148
3821 4149
3822 Form values 4150 Form values
3823 ::::::::::: 4151 :::::::::::
3824 4152
3825 We have a number of ways to pull properties out of the form in order to 4153 We have a number of ways to pull properties out of the form in order to
3826 meet the various needs of: 4154 meet the various needs of:
3827 4155
3828 1. editing the current item (perhaps an issue item) 4156 1. editing the current item (perhaps an issue item)
3829 2. editing information related to the current item (eg. messages or 4157 2. editing information related to the current item (e.g. messages or
3830 attached files) 4158 attached files)
3831 3. creating new information to be linked to the current item (eg. time 4159 3. creating new information to be linked to the current item (e.g. time
3832 spent on an issue) 4160 spent on an issue)
3833 4161
3834 In the following, ``<bracketed>`` values are variable, ":" may be one of 4162 In the following, ``<bracketed>`` values are variable, ":" may be one of
3835 ":" or "@", and other text ("required") is fixed. 4163 ":" or "@", and other text ("required") is fixed.
3836 4164
3844 4172
3845 ``<classname>-<N>:<propname>`` 4173 ``<classname>-<N>:<propname>``
3846 property on the Nth new item of classname (generally for creating new 4174 property on the Nth new item of classname (generally for creating new
3847 items to attach to the current item) 4175 items to attach to the current item)
3848 4176
3849 Once we have determined the "propname", we check to see if it is one of 4177 Once we have determined the "propname", check to see if it is one of
3850 the special form values: 4178 the special form values:
3851 4179
3852 ``@required`` 4180 ``@required``
3853 The named property values must be supplied or a ValueError will be 4181 The named property values must be supplied or a ValueError will be
3854 raised. 4182 raised.
3918 4246
3919 4247
3920 Defining new web actions 4248 Defining new web actions
3921 ------------------------ 4249 ------------------------
3922 4250
3923 You may define new actions to be triggered by the ``@action`` form variable. 4251 You may define new actions triggered by the ``@action`` form variable.
3924 These are added to the tracker ``extensions`` directory and registered 4252 These defined in the tracker's ``extensions`` directory and registered
3925 using ``instance.registerAction``. 4253 using ``instance.registerAction``.
3926 4254
3927 All the existing Actions are defined in ``roundup.cgi.actions``. 4255 All the pre-existing Actions are defined in ``roundup.cgi.actions``.
3928 4256
3929 Adding action classes takes three steps; first you `define the new 4257 Adding action classes takes three steps; first you `define the new
3930 action class`_, then you `register the action class`_ with the cgi 4258 action class`_, then you `register the action class`_ with the cgi
3931 interface so it may be triggered by the ``@action`` form variable. 4259 interface so it can be triggered by the ``@action`` form variable.
3932 Finally you `use the new action`_ in your HTML form. 4260 Finally you `use the new action`_ in your HTML form.
3933 4261
3934 See `setting up a "wizard" (or "druid") for controlled adding of 4262 See `setting up a "wizard" (or "druid") for controlled adding of
3935 issues 4263 issues
3936 <customizing.html#setting-up-a-wizard-or-druid-for-controlled-adding-of-issues>`_ for an example. 4264 <customizing.html#setting-up-a-wizard-or-druid-for-controlled-adding-of-issues>`_ for an example.
3948 def handle(self): 4276 def handle(self):
3949 ''' Perform some action. No return value is required. 4277 ''' Perform some action. No return value is required.
3950 ''' 4278 '''
3951 4279
3952 The *self.client* attribute is an instance of ``roundup.cgi.client.Client``. 4280 The *self.client* attribute is an instance of ``roundup.cgi.client.Client``.
3953 See the docstring of that class for details of what it can do. 4281 See the :class:`docstring of that class <roundup.cgi.client.Client>`
4282 for details of what it can do.
3954 4283
3955 The method will typically check the ``self.form`` variable's contents. 4284 The method will typically check the ``self.form`` variable's contents.
3956 It may then: 4285 It may then:
3957 4286
3958 - add information to ``self.client._ok_message`` 4287 - add information to ``self.client._ok_message``
3997 override the content type indicated to the user by calling ``setHeader``:: 4326 override the content type indicated to the user by calling ``setHeader``::
3998 4327
3999 self.client.setHeader('Content-Type', 'text/csv') 4328 self.client.setHeader('Content-Type', 'text/csv')
4000 4329
4001 This example indicates that the value sent back to the user is actually 4330 This example indicates that the value sent back to the user is actually
4002 comma-separated value content (eg. something to be loaded into a 4331 comma-separated value content (i.e. something to load into a
4003 spreadsheet or database). 4332 spreadsheet or database).
4333
4334 CSS for the web interface
4335 -------------------------
4336
4337 The web interface can be completely redesigned by the admin, However
4338 some parts of Roundup use classes or set attributes that can be
4339 selected by css to change the look of the element.
4340
4341 The ``datecopy.js`` module used to allow editing a date value with a
4342 text input assigns the ``mode_textdate`` class to the input when it is
4343 in text mode. The class is removed when it is not in text mode.
4004 4344
4005 4345
4006 8-bit character set support in Web interface 4346 8-bit character set support in Web interface
4007 -------------------------------------------- 4347 --------------------------------------------
4008 4348
4009 The web interface uses UTF-8 default. It may be overridden in both forms 4349 The web interface uses UTF-8 default. It may be overridden in
4010 and a browser cookie. 4350 both forms and a browser cookie. In general, the UTF-8 standard
4351 should work with all modern browsers. You shouldn't have to
4352 make any modifications from this section.
4011 4353
4012 - In forms, use the ``@charset`` variable. 4354 - In forms, use the ``@charset`` variable.
4013 - To use the cookie override, have the ``roundup_charset`` cookie set. 4355 - To use the cookie override, have the ``roundup_charset`` cookie set.
4014 4356
4015 In both cases, the value is a valid charset name (eg. ``utf-8`` or 4357 In both cases, the value is a valid charset name (eg. ``utf-8`` or
4016 ``kio8-r``). 4358 ``kio8-r``).
4017 4359
4018 Inside Roundup, all strings are stored and processed in utf-8. 4360 Inside Roundup, all strings are stored and processed in utf-8.
4019 Unfortunately, some older browsers do not work properly with 4361 Unfortunately, some older browsers do not work properly with
4020 utf-8-encoded pages (e.g. Netscape Navigator 4 displays wrong 4362 utf-8-encoded pages (e.g. Netscape Navigator 4 displays wrong
4021 characters in form fields). This version allows one to change 4363 characters in form fields). Roundup allows one to change
4022 the character set for http transfers. To do so, you may add 4364 the character set for http transfers. To do so, you may add
4023 the following code to your ``page.html`` template:: 4365 the following code to your ``page.html`` template::
4024 4366
4025 <tal:block define="uri string:${request/base}${request/env/PATH_INFO}"> 4367 <tal:block define="uri string:${request/base}${request/env/PATH_INFO}">
4026 <a tal:attributes="href python:request.indexargs_url(uri, 4368 <a tal:attributes="href python:request.indexargs_url(uri,
4027 {'@charset':'utf-8'})">utf-8</a> 4369 {'@charset':'utf-8'})">utf-8</a>
4040 /> 4382 />
4041 4383
4042 The charset is also sent in the http header. 4384 The charset is also sent in the http header.
4043 4385
4044 4386
4045
4046
4047
4048 Debugging Trackers 4387 Debugging Trackers
4049 ================== 4388 ==================
4050 4389
4051 There are three switches in tracker configs that turn on debugging in 4390 There are three switches in tracker configs that turn on debugging in
4052 Roundup: 4391 Roundup:

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