Mercurial > p > roundup > code
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 ``<``. 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. ``<``). 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> </td> | 4136 <td> </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: |
