comparison doc/customizing.txt @ 1100:f96deb4fb935

more docco
author Richard Jones <richard@users.sourceforge.net>
date Tue, 10 Sep 2002 12:42:46 +0000
parents c5819344714c
children a95428868bf4
comparison
equal deleted inserted replaced
1099:7362dc1f0226 1100:f96deb4fb935
1 =================== 1 ===================
2 Customising Roundup 2 Customising Roundup
3 =================== 3 ===================
4 4
5 :Version: $Revision: 1.26 $ 5 :Version: $Revision: 1.27 $
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::
388 **newissuecopy.py** 388 **newissuecopy.py**
389 This detector sends an email to a team address whenever a new issue is 389 This detector sends an email to a team address whenever a new issue is
390 created. The address is hard-coded into the detector, so edit it before you 390 created. The address is hard-coded into the detector, so edit it before you
391 use it (look for the text 'team@team.host') or you'll get email errors! 391 use it (look for the text 'team@team.host') or you'll get email errors!
392 392
393 XXX give the example here. 393 The detector code::
394
395 from roundup import roundupdb
396
397 def newissuecopy(db, cl, nodeid, oldvalues):
398 ''' Copy a message about new issues to a team address.
399 '''
400 # so use all the messages in the create
401 change_note = cl.generateCreateNote(nodeid)
402
403 # send a copy to the nosy list
404 for msgid in cl.get(nodeid, 'messages'):
405 try:
406 # note: last arg must be a list
407 cl.send_message(nodeid, msgid, change_note, ['team@team.host'])
408 except roundupdb.MessageSendError, message:
409 raise roundupdb.DetectorError, message
410
411 def init(db):
412 db.issue.react('create', newissuecopy)
394 413
395 414
396 Database Content 415 Database Content
397 ================ 416 ================
398 417
405 case though, so be careful to use the right one. 424 case though, so be careful to use the right one.
406 425
407 **Changing content before tracker initialisation** 426 **Changing content before tracker initialisation**
408 Edit the dbinit module in your tracker to alter the items created in using 427 Edit the dbinit module in your tracker to alter the items created in using
409 the create() methods. 428 the create() methods.
410
411 429
412 **Changing content after tracker initialisation** 430 **Changing content after tracker initialisation**
413 Use the roundup-admin interface's create, set and retire methods to add, 431 Use the roundup-admin interface's create, set and retire methods to add,
414 alter or remove items from the classes in question. 432 alter or remove items from the classes in question.
415 433
604 622
605 Most customisation of the web view can be done by modifying the templates in 623 Most customisation of the web view can be done by modifying the templates in
606 the tracker **html** directory. There are several types of files in there: 624 the tracker **html** directory. There are several types of files in there:
607 625
608 page 626 page
609 defines the overall look of your tracker. When you 627 This template defines the overall look of your tracker. When you
610 view an issue, it appears inside this template. When you view an index, it 628 view an issue, it appears inside this template. When you view an index, it
611 also appears inside this template. 629 also appears inside this template. It will have a ``tal:content`` or
630 ``tal:replace`` command with the expression ``structure content`` which
631 will show the issue, list of issues or whatever.
612 home 632 home
613 the default page displayed when no other page is indicated by the user 633 the default page displayed when no other page is indicated by the user
614 home.classlist 634 home.classlist
615 a special version of the default page that lists the classes in the tracker 635 a special version of the default page that lists the classes in the tracker
616 *classname*.item 636 *classname*.item
625 used to display a "class help" page where there is no *classname*.help 645 used to display a "class help" page where there is no *classname*.help
626 user.register 646 user.register
627 a special page just for the user class that renders the registration page 647 a special page just for the user class that renders the registration page
628 style.css 648 style.css
629 a static file that is served up as-is 649 a static file that is served up as-is
630
631 Overall Look - "page" template
632 ------------------------------
633
634 XXX
635 650
636 How the templates work 651 How the templates work
637 ---------------------- 652 ----------------------
638 653
639 Roundup's templates consist of special attributes on your template tags. These 654 Roundup's templates consist of special attributes on your template tags. These
779 *tracker* 794 *tracker*
780 The current tracker 795 The current tracker
781 *db* 796 *db*
782 The current database, through which db.config may be reached. 797 The current database, through which db.config may be reached.
783 *nothing* 798 *nothing*
784 XXX a special variable 799 This is a special variable - if an expression evaluates to this, then the
800 tag (in the case of a tal:replace), its contents (in the case of
801 tal:content) or some attributes (in the case of tal:attributes) will not
802 appear in the the output. So for example::
803
804 <span tal:attributes="class nothing">Hello, World!</span>
805
806 would result in::
807
808 <span>Hello, World!</span>
809
785 *default* 810 *default*
786 XXX a special variable 811 Also a special variable - if an expression evaluates to this, then the
812 existing HTML in the template will not be replaced or removed, it will
813 remain. So::
814
815 <span tal:replace="default">Hello, World!</span>
816
817 would result in::
818
819 <span>Hello, World!</span>
787 820
788 The context variable 821 The context variable
789 ~~~~~~~~~~~~~~~~~~~~ 822 ~~~~~~~~~~~~~~~~~~~~
790 823
791 The *context* variable is one of three things based on the current context 824 The *context* variable is one of three things based on the current context
1078 4. add it to the appropriate xxxPermission methods on in your tracker 1111 4. add it to the appropriate xxxPermission methods on in your tracker
1079 interfaces module 1112 interfaces module
1080 1113
1081 1114
1082 1115
1083 An example of adding a new field to a roundup schema 1116 Examples
1084 ==================================================== 1117 ========
1118
1119 Adding a new field to a roundup schema
1120 --------------------------------------
1121
1122 This example shows how to add a new constrained property (ie. a selection of
1123 distinct values) to your tracker.
1085 1124
1086 Introduction 1125 Introduction
1087 ------------ 1126 ~~~~~~~~~~~~
1088 1127
1089 To make the classic schema of roundup useful as a todo tracking system 1128 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 1129 for a group of systems administrators, it needed an extra data field
1091 per issue: a category. 1130 per issue: a category.
1092 1131
1094 area of interest without having to do complex queries, and without 1133 area of interest without having to do complex queries, and without
1095 relying on the spelling capabilities of other sysads (a losing 1134 relying on the spelling capabilities of other sysads (a losing
1096 proposition at best). 1135 proposition at best).
1097 1136
1098 Adding a field to the database 1137 Adding a field to the database
1099 ------------------------------ 1138 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1100 1139
1101 This is the easiest part of the change. The category would just be a plain 1140 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 1141 string, nothing fancy. To change what is in the database you need to add
1103 some lines to the ``open()`` function in ``dbinit.py``:: 1142 some lines to the ``open()`` function in ``dbinit.py``::
1104 1143
1125 1164
1126 That is all you need to do to change the schema. The rest of the effort is 1165 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. 1166 fiddling around so you can actually use the new category.
1128 1167
1129 Setting up security on the new objects 1168 Setting up security on the new objects
1130 -------------------------------------- 1169 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1131 1170
1132 By default only the admin user can look at and change objects. This doesn't 1171 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 1172 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 1173 required, and obviously everyone needs to be able to view the categories of
1135 issues for it to be useful. 1174 issues for it to be useful.
1176 This is all the work that needs to be done for the database. It will store 1215 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 1216 categories, and let users view and edit them. Now on to the interface
1178 stuff. 1217 stuff.
1179 1218
1180 Changing the web left hand frame 1219 Changing the web left hand frame
1181 -------------------------------- 1220 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1182 1221
1183 We need to give the users the ability to create new categories, and the 1222 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 1223 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 1224 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. 1225 ``html/page``, which is what we are going to be editing next.
1215 that it is so I can add more links in this section later on. However to fix 1254 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 1255 the problem you could change the condition in the classblock statement, so
1217 that only users with "Edit" permission would see the "Categories" stuff. 1256 that only users with "Edit" permission would see the "Categories" stuff.
1218 1257
1219 Setting up a page to edit categories 1258 Setting up a page to edit categories
1220 ------------------------------------ 1259 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1221 1260
1222 We defined code in the previous section which let users with the 1261 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 1262 appropriate permissions see a link to a page which would let them edit
1224 conditions. Now we have to write that page. 1263 conditions. Now we have to write that page.
1225 1264
1307 there is a lot of setup for basically one line (the form line) to do 1346 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 1347 its work. To add another field to "category" would involve one more line
1309 (well maybe a few extra to get the formatting correct). 1348 (well maybe a few extra to get the formatting correct).
1310 1349
1311 Adding the category to the issue 1350 Adding the category to the issue
1312 -------------------------------- 1351 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1313 1352
1314 We now have the ability to create issues to our hearts content, but 1353 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 1354 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 1355 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 1356 category, the ``html/issue.item`` is used to define how a new issue is
1334 1373
1335 The classhelp lines generate a link (labelled "list") to a popup window 1374 The classhelp lines generate a link (labelled "list") to a popup window
1336 which contains the list of currently known categories. 1375 which contains the list of currently known categories.
1337 1376
1338 Searching on categories 1377 Searching on categories
1339 ----------------------- 1378 ~~~~~~~~~~~~~~~~~~~~~~~
1340 1379
1341 We can add categories, and create issues with categories. The next obvious 1380 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 1381 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 1382 category, so that any one working on the web server could look at all
1344 issues in the category "Web" for example. 1383 issues in the category "Web" for example.
1382 name part of "s" again. For objects more complex than category, obviously 1421 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; 1422 you would put an id in the value, and the descriptive part in the content;
1384 but for category they are the same. 1423 but for category they are the same.
1385 1424
1386 Adding category to the default view 1425 Adding category to the default view
1387 ----------------------------------- 1426 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1388 1427
1389 We can now add categories, add issues with categories, and search issues 1428 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 1429 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 1430 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 1431 important enough that it should be displayed by default when listing all
1421 lots of options. The option that we are interested in is the ``:columns=`` one 1460 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 1461 which tells roundup which fields of the issue to display. Simply add
1423 "category" to that list and it all should work. 1462 "category" to that list and it all should work.
1424 1463
1425 1464
1465 Adding in state transition control
1466 ----------------------------------
1467
1468 Sometimes tracker admins want to control the states that users may move issues
1469 to.
1470
1471 1. add a Multilink property to the status class::
1472
1473 stat = Class(db, "status", ... , transitions=Multilink('status'), ...)
1474
1475 and then edit the statuses already created through the web using the
1476 generic class list / CSV editor.
1477
1478 2. add an auditor module ``checktransition.py`` in your tracker's
1479 ``detectors`` directory::
1480
1481 def checktransition(db, cl, nodeid, newvalues):
1482 ''' Check that the desired transition is valid for the "status"
1483 property.
1484 '''
1485 if not newvalues.has_key('status'):
1486 return
1487 current = cl.get(nodeid, 'status')
1488 new = newvalues['status']
1489 if new == current:
1490 return
1491 ok = db.status.get(current, 'transitions')
1492 if new not in ok:
1493 raise ValueError, 'Status not allowed to move from "%s" to "%s"'%(
1494 db.status.get(current, 'name'), db.status.get(new, 'name'))
1495
1496 def init(db):
1497 db.issue.audit('set', checktransition)
1498
1499 3. in the ``issue.item`` template, change the status editing bit from::
1500
1501 <th nowrap>Status</th>
1502 <td tal:content="structure context/status/menu">status</td>
1503
1504 to::
1505
1506 <th nowrap>Status</th>
1507 <td>
1508 <select tal:condition="context/id" name="status">
1509 <tal:block tal:define="ok context/status/transitions"
1510 tal:repeat="state db/status/list">
1511 <option tal:condition="python:state.id in ok"
1512 tal:attributes="value state/id;
1513 selected python:state.id == context.status.id"
1514 tal:content="state/name"></option>
1515 </tal:block>
1516 </select>
1517 <tal:block tal:condition="not:context/id"
1518 tal:replace="structure context/status/menu" />
1519 </td>
1520
1521 which displays only the allowed status to transition to.
1522
1523
1426 ------------------- 1524 -------------------
1427 1525
1428 Back to `Table of Contents`_ 1526 Back to `Table of Contents`_
1429 1527
1430 .. _`Table of Contents`: index.html 1528 .. _`Table of Contents`: index.html

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