comparison doc/customizing.txt @ 1098:c5819344714c

more doc
author Richard Jones <richard@users.sourceforge.net>
date Tue, 10 Sep 2002 07:07:16 +0000
parents fa7df238e2d4
children f96deb4fb935
comparison
equal deleted inserted replaced
1097:98f3d41f41d9 1098:c5819344714c
1 =================== 1 ===================
2 Customising Roundup 2 Customising Roundup
3 =================== 3 ===================
4 4
5 :Version: $Revision: 1.25 $ 5 :Version: $Revision: 1.26 $
6 6
7 .. This document borrows from the ZopeBook section on ZPT. The original is at: 7 .. This document borrows from the ZopeBook section on ZPT. The original is at:
8 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx 8 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
9 9
10 .. contents:: 10 .. contents::
11 11
12 12
13 What You Can Do 13 What You Can Do
14 --------------- 14 ===============
15 15
16 Customisation of Roundup can take one of five forms: 16 Customisation of Roundup can take one of five forms:
17 17
18 1. `tracker configuration`_ file changes 18 1. `tracker configuration`_ file changes
19 2. database, or `tracker schema`_ changes 19 2. database, or `tracker schema`_ changes
26 may be done at any time, before or after tracker initialisation. Yes, this 26 may be done at any time, before or after tracker initialisation. Yes, this
27 includes adding or removing properties from classes. 27 includes adding or removing properties from classes.
28 28
29 29
30 Trackers in a Nutshell 30 Trackers in a Nutshell
31 ---------------------- 31 ======================
32 32
33 Trackers have the following structure: 33 Trackers have the following structure:
34 34
35 +-------------------+--------------------------------------------------------+ 35 =================== ========================================================
36 |config.py |Holds the basic `tracker configuration`_ | 36 Tracker File Description
37 +-------------------+--------------------------------------------------------+ 37 =================== ========================================================
38 |dbinit.py |Holds the `tracker schema`_ | 38 config.py Holds the basic `tracker configuration`_
39 +-------------------+--------------------------------------------------------+ 39 dbinit.py Holds the `tracker schema`_
40 |interfaces.py |Defines the Web and E-Mail interfaces for the tracker | 40 interfaces.py Defines the Web and E-Mail interfaces for the tracker
41 +-------------------+--------------------------------------------------------+ 41 select_db.py Selects the database back-end for the tracker
42 |select_db.py |Selects the database back-end for the tracker | 42 db/ Holds the tracker's database
43 +-------------------+--------------------------------------------------------+ 43 db/files/ Holds the tracker's upload files and messages
44 |db/ |Holds the tracker's database | 44 detectors/ Auditors and reactors for this tracker
45 +-------------------+--------------------------------------------------------+ 45 html/ Web interface templates, images and style sheets
46 |db/files/ |Holds the tracker's upload files and messages | 46 =================== ========================================================
47 +-------------------+--------------------------------------------------------+
48 |detectors/ |Auditors and reactors for this tracker |
49 +-------------------+--------------------------------------------------------+
50 |html/ |Web interface templates, images and style sheets |
51 +-------------------+--------------------------------------------------------+
52 47
53 Tracker Configuration 48 Tracker Configuration
54 --------------------- 49 =====================
55 50
56 The config.py located in your tracker home contains the basic 51 The config.py located in your tracker home contains the basic
57 configuration for the web and e-mail components of roundup's interfaces. This 52 configuration for the web and e-mail components of roundup's interfaces. This
58 file is a Python module. The configuration variables available are: 53 file is a Python module. The configuration variables available are:
59 54
181 # Examples: 176 # Examples:
182 MAIL_DEFAULT_CLASS = 'issue' # use "issue" class by default 177 MAIL_DEFAULT_CLASS = 'issue' # use "issue" class by default
183 #MAIL_DEFAULT_CLASS = '' # disable (or just comment the var out) 178 #MAIL_DEFAULT_CLASS = '' # disable (or just comment the var out)
184 179
185 Tracker Schema 180 Tracker Schema
186 -------------- 181 ==============
187 182
188 Note: if you modify the schema, you'll most likely need to edit the 183 Note: if you modify the schema, you'll most likely need to edit the
189 `web interface`_ HTML template files and `detectors`_ to reflect 184 `web interface`_ HTML template files and `detectors`_ to reflect
190 your changes. 185 your changes.
191 186
239 issue.setkey('title') 234 issue.setkey('title')
240 235
241 XXX security definitions 236 XXX security definitions
242 237
243 Classes and Properties - creating a new information store 238 Classes and Properties - creating a new information store
244 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 239 ---------------------------------------------------------
245 240
246 In the tracker above, we've defined 7 classes of information: 241 In the tracker above, we've defined 7 classes of information:
247 242
248 priority 243 priority
249 Defines the possible levels of urgency for issues. 244 Defines the possible levels of urgency for issues.
273 searching of issues by priority and status. By only requiring a link on the 268 searching of issues by priority and status. By only requiring a link on the
274 issue (which is stored as a single number) we reduce the chance that someone 269 issue (which is stored as a single number) we reduce the chance that someone
275 mis-types a priority or status - or simply makes a new one up. 270 mis-types a priority or status - or simply makes a new one up.
276 271
277 Class and Items 272 Class and Items
278 ::::::::::::::: 273 ~~~~~~~~~~~~~~~
279 274
280 A Class defines a particular class (or type) of data that will be stored in the 275 A Class defines a particular class (or type) of data that will be stored in the
281 database. A class comprises one or more properties, which given the information 276 database. A class comprises one or more properties, which given the information
282 about the class items. 277 about the class items.
283 The actual data entered into the database, using class.create() are called 278 The actual data entered into the database, using class.create() are called
284 items. They have a special immutable property called id. We sometimes refer to 279 items. They have a special immutable property called id. We sometimes refer to
285 this as the itemid. 280 this as the itemid.
286 281
287 Properties 282 Properties
288 :::::::::: 283 ~~~~~~~~~~
289 284
290 A Class is comprised of one or more properties of the following types: 285 A Class is comprised of one or more properties of the following types:
291 286
292 * String properties are for storing arbitrary-length strings. 287 * String properties are for storing arbitrary-length strings.
293 * Password properties are for storing encoded arbitrary-length strings. The 288 * Password properties are for storing encoded arbitrary-length strings. The
301 of the chosen item. 296 of the chosen item.
302 * A Multilink property refers to possibly many items in a specified class. 297 * A Multilink property refers to possibly many items in a specified class.
303 The value is a list of integers. 298 The value is a list of integers.
304 299
305 FileClass 300 FileClass
306 ::::::::: 301 ~~~~~~~~~
307 302
308 FileClasses save their "content" attribute off in a separate file from the rest 303 FileClasses save their "content" attribute off in a separate file from the rest
309 of the database. This reduces the number of large entries in the database, 304 of the database. This reduces the number of large entries in the database,
310 which generally makes databases more efficient, and also allows us to use 305 which generally makes databases more efficient, and also allows us to use
311 command-line tools to operate on the files. They are stored in the files sub- 306 command-line tools to operate on the files. They are stored in the files sub-
312 directory of the db directory in your tracker. 307 directory of the db directory in your tracker.
313 308
314 IssueClass 309 IssueClass
315 :::::::::: 310 ~~~~~~~~~~
316 311
317 IssueClasses automatically include the "messages", "files", "nosy", and 312 IssueClasses automatically include the "messages", "files", "nosy", and
318 "superseder" properties. 313 "superseder" properties.
319 The messages and files properties list the links to the messages and files 314 The messages and files properties list the links to the messages and files
320 related to the issue. The nosy property is a list of links to users who wish to 315 related to the issue. The nosy property is a list of links to users who wish to
329 was last edited (equivalently, these are the dates on the first and last 324 was last edited (equivalently, these are the dates on the first and last
330 records in the item's journal). The "creator" property holds a link to the user 325 records in the item's journal). The "creator" property holds a link to the user
331 that created the issue. 326 that created the issue.
332 327
333 setkey(property) 328 setkey(property)
334 :::::::::::::::: 329 ~~~~~~~~~~~~~~~~
335 330
336 Select a String property of the class to be the key property. The key property 331 Select a String property of the class to be the key property. The key property
337 muse be unique, and allows references to the items in the class by the content 332 muse be unique, and allows references to the items in the class by the content
338 of the key property. That is, we can refer to users by their username, e.g. 333 of the key property. That is, we can refer to users by their username, e.g.
339 let's say that there's an issue in roundup, issue 23. There's also a user, 334 let's say that there's an issue in roundup, issue 23. There's also a user,
347 roundup-admin set issue assignedto=richard 342 roundup-admin set issue assignedto=richard
348 343
349 Note, the same thing can be done in the web and e-mail interfaces. 344 Note, the same thing can be done in the web and e-mail interfaces.
350 345
351 create(information) 346 create(information)
352 ::::::::::::::::::: 347 ~~~~~~~~~~~~~~~~~~~
353 348
354 Create an item in the database. This is generally used to create items in the 349 Create an item in the database. This is generally used to create items in the
355 "definitional" classes like "priority" and "status". 350 "definitional" classes like "priority" and "status".
356 351
357 352
358 Examples of adding to your schema 353 Examples of adding to your schema
359 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 354 ---------------------------------
360 355
361 TODO 356 TODO
362 357
363 358
364 Detectors - adding behaviour to your tracker 359 Detectors - adding behaviour to your tracker
365 -------------------------------------------- 360 ============================================
366 .. _detectors: 361 .. _detectors:
367 362
368 The detectors in your tracker fire before (*auditors*) and after (*reactors*) 363 The detectors in your tracker fire before (*auditors*) and after (*reactors*)
369 changes to the contents of your database. They are Python modules that sit in 364 changes to the contents of your database. They are Python modules that sit in
370 your tracker's ``detectors`` directory. You will have some installed by 365 your tracker's ``detectors`` directory. You will have some installed by
397 392
398 XXX give the example here. 393 XXX give the example here.
399 394
400 395
401 Database Content 396 Database Content
402 ---------------- 397 ================
403 398
404 Note: if you modify the content of definitional classes, you'll most likely 399 Note: if you modify the content of definitional classes, you'll most likely
405 need to edit the tracker `detectors`_ to reflect your changes. 400 need to edit the tracker `detectors`_ to reflect your changes.
406 401
407 Customisation of the special "definitional" classes (eg. status, priority, 402 Customisation of the special "definitional" classes (eg. status, priority,
420 415
421 XXX example 416 XXX example
422 417
423 418
424 Web Interface 419 Web Interface
425 ------------- 420 =============
426 421
427 The web is provided by the roundup.cgi.client module and is used by 422 The web is provided by the roundup.cgi.client module and is used by
428 roundup.cgi, roundup-server and ZRoundup. 423 roundup.cgi, roundup-server and ZRoundup.
429 In all cases, we determine which tracker is being accessed 424 In all cases, we determine which tracker is being accessed
430 (the first part of the URL path inside the scope of the CGI handler) and pass 425 (the first part of the URL path inside the scope of the CGI handler) and pass
432 from roundup.cgi.client - which handles the rest of 427 from roundup.cgi.client - which handles the rest of
433 the access through its main() method. This means that you can do pretty much 428 the access through its main() method. This means that you can do pretty much
434 anything you want as a web interface to your tracker. 429 anything you want as a web interface to your tracker.
435 430
436 Repurcussions of changing the tracker schema 431 Repurcussions of changing the tracker schema
437 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 432 ---------------------------------------------
438 433
439 If you choose to change the `tracker schema`_ you will need to ensure the web 434 If you choose to change the `tracker schema`_ you will need to ensure the web
440 interface knows about it: 435 interface knows about it:
441 436
442 1. Index, item and search pages for the relevant classes may need to have 437 1. Index, item and search pages for the relevant classes may need to have
443 properties added or removed, 438 properties added or removed,
444 2. The "page" template may require links to be changed, as might the "home" 439 2. The "page" template may require links to be changed, as might the "home"
445 page's content arguments. 440 page's content arguments.
446 441
447 How requests are processed 442 How requests are processed
448 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 443 --------------------------
449 444
450 The basic processing of a web request proceeds as follows: 445 The basic processing of a web request proceeds as follows:
451 446
452 1. figure out who we are, defaulting to the "anonymous" user 447 1. figure out who we are, defaulting to the "anonymous" user
453 2. figure out what the request is for - we call this the "context" 448 2. figure out what the request is for - we call this the "context"
467 granted for the action to take place 462 granted for the action to take place
468 - NotFound (raised wherever it needs to be) 463 - NotFound (raised wherever it needs to be)
469 this exception percolates up to the CGI interface that called the client 464 this exception percolates up to the CGI interface that called the client
470 465
471 Determining web context 466 Determining web context
472 ~~~~~~~~~~~~~~~~~~~~~~~ 467 -----------------------
473 468
474 To determine the "context" of a request, we look at the URL and the special 469 To determine the "context" of a request, we look at the URL and the special
475 request variable ``:template``. The URL path after the tracker identifier 470 request variable ``:template``. The URL path after the tracker identifier
476 is examined. Typical URL paths look like: 471 is examined. Typical URL paths look like:
477 472
514 - only classname suplied: "index" 509 - only classname suplied: "index"
515 - full item designator supplied: "item" 510 - full item designator supplied: "item"
516 511
517 512
518 Performing actions in web requests 513 Performing actions in web requests
519 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 514 ----------------------------------
520 515
521 When a user requests a web page, they may optionally also request for an 516 When a user requests a web page, they may optionally also request for an
522 action to take place. As described in `how requests are processed`_, the 517 action to take place. As described in `how requests are processed`_, the
523 action is performed before the requested page is generated. Actions are 518 action is performed before the requested page is generated. Actions are
524 triggered by using a ``:action`` CGI variable, where the value is one of: 519 triggered by using a ``:action`` CGI variable, where the value is one of:
568 563
569 Each of the actions is implemented by a corresponding *actionAction* (where 564 Each of the actions is implemented by a corresponding *actionAction* (where
570 "action" is the name of the action) method on 565 "action" is the name of the action) method on
571 the roundup.cgi.Client class, which also happens to be in your tracker as 566 the roundup.cgi.Client class, which also happens to be in your tracker as
572 interfaces.Client. So if you need to define new actions, you may add them 567 interfaces.Client. So if you need to define new actions, you may add them
573 there (see `definining new web actions`_). 568 there (see `defining new web actions`_).
574 569
575 Each action also has a corresponding *actionPermission* (where 570 Each action also has a corresponding *actionPermission* (where
576 "action" is the name of the action) method which determines 571 "action" is the name of the action) method which determines
577 whether the action is permissible given the current user. The base permission 572 whether the action is permissible given the current user. The base permission
578 checks are: 573 checks are:
603 Determine whether the user has permission to search this class. 598 Determine whether the user has permission to search this class.
604 Base behaviour is to check the user can view this class. 599 Base behaviour is to check the user can view this class.
605 600
606 601
607 Default templates 602 Default templates
608 ~~~~~~~~~~~~~~~~~ 603 -----------------
609 604
610 Most customisation of the web view can be done by modifying the templates in 605 Most customisation of the web view can be done by modifying the templates in
611 the tracker **html** directory. There are several types of files in there: 606 the tracker **html** directory. There are several types of files in there:
612 607
613 page 608 page
632 a special page just for the user class that renders the registration page 627 a special page just for the user class that renders the registration page
633 style.css 628 style.css
634 a static file that is served up as-is 629 a static file that is served up as-is
635 630
636 Overall Look - "page" template 631 Overall Look - "page" template
637 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 632 ------------------------------
638 633
639 XXX 634 XXX
640 635
641 How the templates work 636 How the templates work
642 ~~~~~~~~~~~~~~~~~~~~~~ 637 ----------------------
643 638
644 Roundup's templates consist of special attributes on your template tags. These 639 Roundup's templates consist of special attributes on your template tags. These
645 attributes form the Template Attribute Language, or TAL. The commands are: 640 attributes form the Template Attribute Language, or TAL. The commands are:
646 641
647 642
759 variables are available, so ``python:item.status.checklist()`` would be 754 variables are available, so ``python:item.status.checklist()`` would be
760 equivalent to ``item/status/checklist``, assuming that ``checklist`` is 755 equivalent to ``item/status/checklist``, assuming that ``checklist`` is
761 a method. 756 a method.
762 757
763 Information available to templates 758 Information available to templates
764 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 759 ----------------------------------
765 760
766 The following variables are available to templates. 761 The following variables are available to templates.
767 762
768 .. taken from roundup.cgi.templating.RoundupPageTemplate docstring 763 .. taken from roundup.cgi.templating.RoundupPageTemplate docstring
769 764
789 XXX a special variable 784 XXX a special variable
790 *default* 785 *default*
791 XXX a special variable 786 XXX a special variable
792 787
793 The context variable 788 The context variable
794 :::::::::::::::::::: 789 ~~~~~~~~~~~~~~~~~~~~
795 790
796 The *context* variable is one of three things based on the current context 791 The *context* variable is one of three things based on the current context
797 (see `determining web context`_ for how we figure this out): 792 (see `determining web context`_ for how we figure this out):
798 793
799 1. if we're looking at a "home" page, then it's None 794 1. if we're looking at a "home" page, then it's None
810 a real, or true value in the third. Thus we can determine whether we're 805 a real, or true value in the third. Thus we can determine whether we're
811 looking at a real item from the hyperdb by testing "context/id". 806 looking at a real item from the hyperdb by testing "context/id".
812 807
813 808
814 The request variable 809 The request variable
815 :::::::::::::::::::: 810 ~~~~~~~~~~~~~~~~~~~~
816 811
817 The request variable is packed with information about the current request. 812 The request variable is packed with information about the current request.
818 813
819 .. taken from roundup.cgi.templating.HTMLRequest docstring 814 .. taken from roundup.cgi.templating.HTMLRequest docstring
820 815
836 =========== ================================================================ 831 =========== ================================================================
837 Variable Holds 832 Variable Holds
838 =========== ================================================================ 833 =========== ================================================================
839 columns dictionary of the columns to display in an index page 834 columns dictionary of the columns to display in an index page
840 show a convenience access to columns - request/show/colname will 835 show a convenience access to columns - request/show/colname will
841 be true if the columns should be displayed, false otherwise 836 be true if the columns should be displayed, false otherwise
842 sort index sort column (direction, column name) 837 sort index sort column (direction, column name)
843 group index grouping property (direction, column name) 838 group index grouping property (direction, column name)
844 filter properties to filter the index on 839 filter properties to filter the index on
845 filterspec values to filter the index on 840 filterspec values to filter the index on
846 search_text text to perform a full-text search on for an index 841 search_text text to perform a full-text search on for an index
847 =========== ================================================================ 842 =========== ================================================================
848 843
849 844
850 Displaying Properties 845 Displaying Properties
851 ~~~~~~~~~~~~~~~~~~~~~ 846 ---------------------
852 847
853 Properties appear in the user interface in three contexts: in indices, in 848 Properties appear in the user interface in three contexts: in indices, in
854 editors, and as search arguments. 849 editors, and as search arguments.
855 For each type of property, there are several display possibilities. 850 For each type of property, there are several display possibilities.
856 For example, in an index view, a string property may just be 851 For example, in an index view, a string property may just be
857 printed as a plain string, but in an editor view, that property may be 852 printed as a plain string, but in an editor view, that property may be
858 displayed in an editable field. 853 displayed in an editable field.
859 854
860 855
861 Index Views 856 Index Views
862 ~~~~~~~~~~~ 857 -----------
863 858
864 This is one of the class context views. It is also the default view for 859 This is one of the class context views. It is also the default view for
865 classes. The template used is "*classname*.index". 860 classes. The template used is "*classname*.index".
866 861
867 Index View Specifiers 862 Index View Specifiers
868 ::::::::::::::::::::: 863 ~~~~~~~~~~~~~~~~~~~~~
869 864
870 An index view specifier (URL fragment) looks like this (whitespace has been 865 An index view specifier (URL fragment) looks like this (whitespace has been
871 added for clarity):: 866 added for clarity)::
872 867
873 /issue?status=unread,in-progress,resolved& 868 /issue?status=unread,in-progress,resolved&
874 topic=security,ui& 869 topic=security,ui&
875 :group=+priority& 870 :group=+priority&
876 :sort=-activity& 871 :sort==activity&
877 :filters=status,topic& 872 :filters=status,topic&
878 :columns=title,status,fixer 873 :columns=title,status,fixer
879 874
880 The index view is determined by two parts of the specifier: the layout part and 875 The index view is determined by two parts of the specifier: the layout part and
881 the filter part. The layout part consists of the query parameters that begin 876 the filter part. The layout part consists of the query parameters that begin
897 by activity, arranged in descending order. The filter section shows filters for 892 by activity, arranged in descending order. The filter section shows filters for
898 the "status" and "topic" properties, and the table includes columns for the 893 the "status" and "topic" properties, and the table includes columns for the
899 "title", "status", and "fixer" properties. 894 "title", "status", and "fixer" properties.
900 895
901 Filtering of indexes 896 Filtering of indexes
902 :::::::::::::::::::: 897 ~~~~~~~~~~~~~~~~~~~~
903 898
904 TODO 899 TODO
905 900
906 Searching Views 901 Searching Views
907 ~~~~~~~~~~~~~~~ 902 ---------------
908 903
909 This is one of the class context views. The template used is typically 904 This is one of the class context views. The template used is typically
910 "*classname*.search". 905 "*classname*.search".
911 906
912 TODO 907 TODO
913 908
914 Item Views 909 Item Views
915 ~~~~~~~~~~ 910 ----------
916 911
917 The basic view of a hyperdb item is provided by the "*classname*.item" 912 The basic view of a hyperdb item is provided by the "*classname*.item"
918 template. It generally has three sections; an "editor", a "spool" and a 913 template. It generally has three sections; an "editor", a "spool" and a
919 "history" section. 914 "history" section.
920 915
921 916
922 917
923 Editor Section 918 Editor Section
924 :::::::::::::: 919 ~~~~~~~~~~~~~~
925 920
926 The editor section is used to manipulate the item - it may be a 921 The editor section is used to manipulate the item - it may be a
927 static display if the user doesn't have permission to edit the item. 922 static display if the user doesn't have permission to edit the item.
928 923
929 Here's an example of a basic editor template (this is the default "classic" 924 Here's an example of a basic editor template (this is the default "classic"
992 describing the changed properties. As shown in the example, the editor 987 describing the changed properties. As shown in the example, the editor
993 template can use the ":note" and ":file" fields, which are added to the 988 template can use the ":note" and ":file" fields, which are added to the
994 standard change note message generated by Roundup. 989 standard change note message generated by Roundup.
995 990
996 Spool Section 991 Spool Section
997 ::::::::::::: 992 ~~~~~~~~~~~~~
998 993
999 The spool section lists related information like the messages and files of 994 The spool section lists related information like the messages and files of
1000 an issue. 995 an issue.
1001 996
1002 TODO 997 TODO
1003 998
1004 999
1005 History Section 1000 History Section
1006 ::::::::::::::: 1001 ~~~~~~~~~~~~~~~
1007 1002
1008 The final section displayed is the history of the item - its database journal. 1003 The final section displayed is the history of the item - its database journal.
1009 This is generally generated with the template:: 1004 This is generally generated with the template::
1010 1005
1011 <tal:block tal:replace="structure context/history" /> 1006 <tal:block tal:replace="structure context/history" />
1019 a journal entry 1014 a journal entry
1020 </tal:block> 1015 </tal:block>
1021 1016
1022 *where each journal entry is an HTMLJournalEntry.* 1017 *where each journal entry is an HTMLJournalEntry.*
1023 1018
1019 Defining new web actions
1020 ------------------------
1021
1022 XXX
1023
1024 1024
1025 Access Controls 1025 Access Controls
1026 --------------- 1026 ===============
1027 1027
1028 A set of Permissions are built in to the security module by default: 1028 A set of Permissions are built in to the security module by default:
1029 1029
1030 - Edit (everything) 1030 - Edit (everything)
1031 - View (everything) 1031 - View (everything)
1065 1065
1066 You may use the ``roundup-admin`` "``security``" command to display the 1066 You may use the ``roundup-admin`` "``security``" command to display the
1067 current Role and Permission configuration in your tracker. 1067 current Role and Permission configuration in your tracker.
1068 1068
1069 Adding a new Permission 1069 Adding a new Permission
1070 ~~~~~~~~~~~~~~~~~~~~~~~ 1070 -----------------------
1071 1071
1072 When adding a new Permission, you will need to: 1072 When adding a new Permission, you will need to:
1073 1073
1074 1. add it to your tracker's dbinit so it is created 1074 1. add it to your tracker's dbinit so it is created
1075 2. enable it for the Roles that should have it (verify with 1075 2. enable it for the Roles that should have it (verify with
1078 4. add it to the appropriate xxxPermission methods on in your tracker 1078 4. add it to the appropriate xxxPermission methods on in your tracker
1079 interfaces module 1079 interfaces module
1080 1080
1081 1081
1082 1082
1083 ----------------- 1083 An example of adding a new field to a roundup schema
1084 ====================================================
1085
1086 Introduction
1087 ------------
1088
1089 To make the classic schema of roundup useful as a todo tracking system
1090 for a group of systems administrators, it needed an extra data field
1091 per issue: a category.
1092
1093 This would let sysads quickly list all todos in their particular
1094 area of interest without having to do complex queries, and without
1095 relying on the spelling capabilities of other sysads (a losing
1096 proposition at best).
1097
1098 Adding a field to the database
1099 ------------------------------
1100
1101 This is the easiest part of the change. The category would just be a plain
1102 string, nothing fancy. To change what is in the database you need to add
1103 some lines to the ``open()`` function in ``dbinit.py``::
1104
1105 category = Class(db, "category", name=String())
1106 category.setkey("name")
1107
1108 Here we are setting up a chunk of the database which we are calling
1109 "category". It contains a string, which we are refering to as "name" for
1110 lack of a more imaginative title. Then we are setting the key of this chunk
1111 of the database to be that "name". This is equivalent to an index for
1112 database types. This also means that there can only be one category with a
1113 given name.
1114
1115 Adding the above lines allows us to create categories, but they're not tied
1116 to the issues that we are going to be creating. It's just a list of categories
1117 off on its own, which isn't much use. We need to link it in with the issues.
1118 To do that, find the lines in the ``open()`` function in ``dbinit.py`` which
1119 set up the "issue" class, and then add a link to the category::
1120
1121 issue = IssueClass(db, "issue", ... , category=Multilink("category"), ... )
1122
1123 The Multilink() means that each issue can have many categories. If you were
1124 adding something with a more one to one relationship use Link() instead.
1125
1126 That is all you need to do to change the schema. The rest of the effort is
1127 fiddling around so you can actually use the new category.
1128
1129 Setting up security on the new objects
1130 --------------------------------------
1131
1132 By default only the admin user can look at and change objects. This doesn't
1133 suit us, as we want any user to be able to create new categories as
1134 required, and obviously everyone needs to be able to view the categories of
1135 issues for it to be useful.
1136
1137 We therefore need to change the security of the category objects. This is
1138 also done in the ``open()`` function of ``dbinit.py``.
1139
1140 There are currently two loops which set up permissions and then assign them
1141 to various roles. Simply add the new "category" to both lists::
1142
1143 # new permissions for this schema
1144 for cl in 'issue', 'file', 'msg', 'user', 'category':
1145 db.security.addPermission(name="Edit", klass=cl,
1146 description="User is allowed to edit "+cl)
1147 db.security.addPermission(name="View", klass=cl,
1148 description="User is allowed to access "+cl)
1149
1150 # Assign the access and edit permissions for issue, file and message
1151 # to regular users now
1152 for cl in 'issue', 'file', 'msg', 'category':
1153 p = db.security.getPermission('View', cl)
1154 db.security.addPermissionToRole('User', p)
1155 p = db.security.getPermission('Edit', cl)
1156 db.security.addPermissionToRole('User', p)
1157
1158 So you are in effect doing the following::
1159
1160 db.security.addPermission(name="Edit", klass='category',
1161 description="User is allowed to edit "+'category')
1162 db.security.addPermission(name="View", klass='category',
1163 description="User is allowed to access "+'category')
1164
1165 which is creating two permission types; that of editing and viewing
1166 "category" objects respectively. Then the following lines assign those new
1167 permissions to the "User" role, so that normal users can view and edit
1168 "category" objects::
1169
1170 p = db.security.getPermission('View', 'category')
1171 db.security.addPermissionToRole('User', p)
1172
1173 p = db.security.getPermission('Edit', 'category')
1174 db.security.addPermissionToRole('User', p)
1175
1176 This is all the work that needs to be done for the database. It will store
1177 categories, and let users view and edit them. Now on to the interface
1178 stuff.
1179
1180 Changing the web left hand frame
1181 --------------------------------
1182
1183 We need to give the users the ability to create new categories, and the
1184 place to put the link to this functionality is in the left hand function
1185 bar, under the "Issues" area. The file that defines how this area looks is
1186 ``html/page``, which is what we are going to be editing next.
1187
1188 If you look at this file you can see that it contains a lot of "classblock"
1189 sections which are chunks of HTML that will be included or excluded in the
1190 output depending on whether the condition in the classblock is met. Under
1191 the end of the classblock for issue is where we are going to add the
1192 category code::
1193
1194 <p class="classblock"
1195 tal:condition="python:request.user.hasPermission('View', 'category')">
1196 <b>Categories</b><br>
1197 <a tal:condition="python:request.user.hasPermission('Edit', 'category')"
1198 href="category?:template=item">New Category<br></a>
1199 </p>
1200
1201 The first two lines is the classblock definition, which sets up a condition
1202 that only users who have "View" permission to the "category" object will
1203 have this section included in their output. Next comes a plain "Categories"
1204 header in bold. Everyone who can view categories will get that.
1205
1206 Next comes the link to the editing area of categories. This link will only
1207 appear if the condition is matched: that condition being that the user has
1208 "Edit" permissions for the "category" objects. If they do have permission
1209 then they will get a link to another page which will let the user add new
1210 categories.
1211
1212 Note that if you have permission to view but not edit categories then all
1213 you will see is a "Categories" header with nothing underneath it. This is
1214 obviously not very good interface design, but will do for now. I just claim
1215 that it is so I can add more links in this section later on. However to fix
1216 the problem you could change the condition in the classblock statement, so
1217 that only users with "Edit" permission would see the "Categories" stuff.
1218
1219 Setting up a page to edit categories
1220 ------------------------------------
1221
1222 We defined code in the previous section which let users with the
1223 appropriate permissions see a link to a page which would let them edit
1224 conditions. Now we have to write that page.
1225
1226 The link was for the item template for the category object. This translates
1227 into the system looking for a file called ``category.item`` in the ``html``
1228 tracker directory. This is the file that we are going to write now.
1229
1230 First we add an id tag in a comment which doesn't affect the outcome
1231 of the code at all but is essential for managing the changes to this
1232 file. It is useful for debugging however, if you load a page in a
1233 browser and look at the page source, you can see which sections come
1234 from which files by looking for these comments::
1235
1236 <!-- dollarId: category.item,v 1.3 2002/05/22 00:32:34 me Exp dollar-->
1237
1238 Next we need to setup up a standard HTML form, which is the whole
1239 purpose of this file. We link to some handy javascript which sends the form
1240 through only once. This is to stop users hitting the send button
1241 multiple times when they are impatient and thus having the form sent
1242 multiple times::
1243
1244 <form method="POST" onSubmit="return submit_once()"
1245 enctype="multipart/form-data">
1246
1247 Next we define some code which sets up the minimum list of fields that we
1248 require the user to enter. There will be only one field, that of "name", so
1249 they user better put something in it otherwise the whole form is pointless::
1250
1251 <input type="hidden" name=":required" value="name">
1252
1253 To get everything to line up properly we will put everything in a table,
1254 and put a nice big header on it so the user has an idea what is happening::
1255
1256 <table class="form">
1257 <tr class="strong-header"><td colspan=2>Category</td></tr>
1258
1259 Next we need the actual field that the user is going to enter the new
1260 category. The "context.name.field(size=60)" bit tells roundup to generate a
1261 normal HTML field of size 60, and the contents of that field will be the
1262 "name" variable of the current context (which is "category"). The upshot of
1263 this is that when the user types something in to the form, a new category
1264 will be created with that name::
1265
1266 <tr>
1267 <td nowrap>Name</td>
1268 <td tal:content="structure python:context.name.field(size=60)">name</td>
1269 </tr>
1270
1271 Finally a submit button so that the user can submit the new category::
1272
1273 <tr>
1274 <td>&nbsp;</td>
1275 <td colspan=3 tal:content="structure context/submit">
1276 submit button will go here
1277 </td>
1278 </tr>
1279
1280 So putting it all together, and closing the table and form we get::
1281
1282 <!-- dollarId: category.item,v 1.3 2002/05/22 00:32:34 richard Exp dollar-->
1283
1284 <form method="POST" onSubmit="return submit_once()"
1285 enctype="multipart/form-data">
1286
1287 <input type="hidden" name=":required" value="name">
1288
1289 <table class="form">
1290 <tr class="strong-header"><td colspan=2>Category</td></tr>
1291
1292 <tr>
1293 <td nowrap>Name</td>
1294 <td tal:content="structure python:context.name.field(size=60)">name</td>
1295 </tr>
1296
1297 <tr>
1298 <td>&nbsp;</td>
1299 <td colspan=3 tal:content="structure context/submit">
1300 submit button will go here
1301 </td>
1302 </tr>
1303 </table>
1304 </form>
1305
1306 This is quite a lot to just ask the user one simple question, but
1307 there is a lot of setup for basically one line (the form line) to do
1308 its work. To add another field to "category" would involve one more line
1309 (well maybe a few extra to get the formatting correct).
1310
1311 Adding the category to the issue
1312 --------------------------------
1313
1314 We now have the ability to create issues to our hearts content, but
1315 that is pointless unless we can assign categories to issues. Just like
1316 the ``html/category.item`` file was used to define how to add a new
1317 category, the ``html/issue.item`` is used to define how a new issue is
1318 created.
1319
1320 Just like ``category.issue`` this file defines a form which has a table to lay
1321 things out. It doesn't matter where in the table we add new stuff,
1322 it is entirely up to your sense of aesthetics::
1323
1324 <th nowrap>Category</th>
1325 <td><span tal:replace="structure context/category/field" />
1326 <span tal:replace="structure python:db.category.classhelp('name',
1327 label='list', width=500)" />
1328 </td>
1329
1330 First we define a nice header so that the user knows what the next section
1331 is, then the middle line does what we are most interested in. This
1332 ``context/category/field`` gets replaced with a field which contains the
1333 category in the current context (the current context being the new issue).
1334
1335 The classhelp lines generate a link (labelled "list") to a popup window
1336 which contains the list of currently known categories.
1337
1338 Searching on categories
1339 -----------------------
1340
1341 We can add categories, and create issues with categories. The next obvious
1342 thing that we would like to be would be to search issues based on their
1343 category, so that any one working on the web server could look at all
1344 issues in the category "Web" for example.
1345
1346 If you look in the html/page file and look for the "Search Issues" you will
1347 see that it looks something like ``<a href="issue?:template=search">Search
1348 Issues</a>`` which shows us that when you click on "Search Issues" it will
1349 be looking for a ``issue.search`` file to display. So that is indeed the file
1350 that we are going to change.
1351
1352 If you look at this file it should be starting to seem familiar. It is a
1353 simple HTML form using a table to define structure. You can add the new
1354 category search code anywhere you like within that form::
1355
1356 <tr>
1357 <th>Category:</th>
1358 <td>
1359 <select name="category">
1360 <option value="">don't care</option>
1361 <option value="">------------</option>
1362 <option tal:repeat="s db/category/list" tal:attributes="value s/name"
1363 tal:content="s/name">category to filter on</option>
1364 </select>
1365 </td>
1366 <td><input type="checkbox" name=":columns" value="category" checked></td>
1367 <td><input type="radio" name=":sort" value="category"></td>
1368 <td><input type="radio" name=":group" value="category"></td>
1369 </tr>
1370
1371 Most of this is straightforward to anyone who knows HTML. It is just
1372 setting up a select list followed by a checkbox and a couple of radio
1373 buttons.
1374
1375 The ``tal:repeat`` part repeats the tag for every item in the "category"
1376 table and setting "s" to be each category in turn.
1377
1378 The ``tal:attributes`` part is setting up the ``value=`` part of the option tag
1379 to be the name part of "s" which is the current category in the loop.
1380
1381 The ``tal:content`` part is setting the contents of the option tag to be the
1382 name part of "s" again. For objects more complex than category, obviously
1383 you would put an id in the value, and the descriptive part in the content;
1384 but for category they are the same.
1385
1386 Adding category to the default view
1387 -----------------------------------
1388
1389 We can now add categories, add issues with categories, and search issues
1390 based on categories. This is everything that we need to do, however there
1391 is some more icing that we would like. I think the category of an issue is
1392 important enough that it should be displayed by default when listing all
1393 the issues.
1394
1395 Unfortunately, this is a bit less obvious than the previous steps. The code
1396 defining how the issues look is in ``html/issue.index``. This is a large table
1397 with a form down the bottom for redisplaying and so forth.
1398
1399 Firstly we need to add an appropriate header to the start of the table::
1400
1401 <th tal:condition="request/show/category">Category</th>
1402
1403 The condition part of this statement is so that if the user has selected
1404 not to see the Category column then they won't.
1405
1406 The rest of the table is a loop which will go through every issue that
1407 matches the display criteria. The loop variable is "i" - which means that
1408 every issue gets assigned to "i" in turn.
1409
1410 The new part of code to display the category will look like this::
1411
1412 <td tal:condition="request/show/category" tal:content="i/category"></td>
1413
1414 The condition is the same as above: only display the condition when the
1415 user hasn't asked for it to be hidden. The next part is to set the content
1416 of the cell to be the category part of "i" - the current issue.
1417
1418 Finally we have to edit ``html/page`` again. This time to tell it that when the
1419 user clicks on "Unnasigned Issues" or "All Issues" that the category should
1420 be displayed. If you scroll down the page file, you can see the links with
1421 lots of options. The option that we are interested in is the ``:columns=`` one
1422 which tells roundup which fields of the issue to display. Simply add
1423 "category" to that list and it all should work.
1424
1425
1426 -------------------
1084 1427
1085 Back to `Table of Contents`_ 1428 Back to `Table of Contents`_
1086 1429
1087 .. _`Table of Contents`: index.html 1430 .. _`Table of Contents`: index.html
1088 1431

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