22Customising Roundup
33===================
44
5- :Version: $Revision: 1.159 $
5+ :Version: $Revision: 1.160 $
66
77.. This document borrows from the ZopeBook section on ZPT. The original is at:
88 http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
@@ -290,13 +290,13 @@ Note: if you modify the schema, you'll most likely need to edit the
290290 your changes.
291291
292292A tracker schema defines what data is stored in the tracker's database.
293- Schemas are defined using Python code in the ``dbinit .py`` module of your
293+ Schemas are defined using Python code in the ``schema .py`` module of your
294294tracker.
295295
296- The ``dbinit .py`` module
296+ The ``schema .py`` module
297297------------------------
298298
299- The ``dbinit .py`` module contains two functions:
299+ The ``schema .py`` module contains two functions:
300300
301301**open**
302302 This function defines what your tracker looks like on the inside, the
@@ -702,7 +702,7 @@ tracker is initialised. The actual method of doing so is completely
702702different in each case though, so be careful to use the right one.
703703
704704**Changing content before tracker initialisation**
705- Edit the dbinit module in your tracker to alter the items created in
705+ Edit the schema module in your tracker to alter the items created in
706706 using the ``create()`` methods.
707707
708708**Changing content after tracker initialisation**
@@ -723,11 +723,12 @@ Security / Access Controls
723723
724724A set of Permissions is built into the security module by default:
725725
726+ - Create (everything)
726727- Edit (everything)
727728- View (everything)
728729
729- Every Class you define in your tracker's schema also gets an Edit and View
730- Permission of its own.
730+ Every Class you define in your tracker's schema also gets an Create, Edit
731+ and View Permission of its own.
731732
732733The default interfaces define:
733734
@@ -739,47 +740,108 @@ The default interfaces define:
739740
740741These are hooked into the default Roles:
741742
742- - Admin (Edit everything , View everything, Web Roles)
743- - User (Web Access, Email Access)
744- - Anonymous (Web Registration, Email Registration)
743+ - Admin (Create, Edit , View and everything; Web Roles)
744+ - User (Web Access; Email Access)
745+ - Anonymous (Web Registration; Email Registration)
745746
746747And finally, the "admin" user gets the "Admin" Role, and the "anonymous"
747- user gets "Anonymous" assigned when the database is initialised on
748- installation. The two default schemas then define:
748+ user gets "Anonymous" assigned when the tracker is installed.
749749
750- - Edit issue, View issue (both)
751- - Edit file, View file (both)
752- - Edit msg, View msg (both)
753- - Edit support, View support (extended only)
750+ For the "User" Role, the "classic" tracker defines:
754751
755- and assign those Permissions to the "User" Role. Put together, these
756- settings appear in the ``open()`` function of the tracker ``dbinit.py``
757- (the following is taken from the "minimal" template's ``dbinit.py``)::
752+ - Create, Edit and View issue, file, msg, query, keyword
753+ - View priority, status
754+ - View user
755+ - Edit their own record
758756
757+ And the "Anonymous" Role is defined as:
758+
759+ - Create user (for registration)
760+ - View issue, file, msg, query, keyword, priority, status
761+
762+ Put together, these settings appear in the tracker's ``schema.py`` file::
763+
764+ #
765+ # TRACKER SECURITY SETTINGS
759766 #
760- # SECURITY SETTINGS
767+ # See the configuration and customisation document for information
768+ # about security setup.
769+
770+ #
771+ # REGULAR USERS
761772 #
762- # and give the regular users access to the web and email interface
773+ # Give the regular users access to the web and email interface
763774 p = db.security.getPermission('Web Access')
764775 db.security.addPermissionToRole('User', p)
765776 p = db.security.getPermission('Email Access')
766777 db.security.addPermissionToRole('User', p)
767778
779+ # Assign the access and edit Permissions for issue, file and message
780+ # to regular users now
781+ for cl in 'issue', 'file', 'msg', 'query', 'keyword':
782+ p = db.security.getPermission('View', cl)
783+ db.security.addPermissionToRole('User', p)
784+ p = db.security.getPermission('Edit', cl)
785+ db.security.addPermissionToRole('User', p)
786+ p = db.security.getPermission('Create', cl)
787+ db.security.addPermissionToRole('User', p)
788+ for cl in 'priority', 'status':
789+ p = db.security.getPermission('View', cl)
790+ db.security.addPermissionToRole('User', p)
791+
768792 # May users view other user information? Comment these lines out
769793 # if you don't want them to
770794 p = db.security.getPermission('View', 'user')
771795 db.security.addPermissionToRole('User', p)
772796
773- # Assign the appropriate permissions to the anonymous user's
774- # Anonymous role. Choices here are:
775- # - Allow anonymous users to register through the web
776- p = db.security.getPermission('Web Registration')
797+ # Users should be able to edit their own details. Note that this
798+ # permission is limited to only the situation where the Viewed or
799+ # Edited item is their own.
800+ def own_record(db, userid, itemid):
801+ '''Determine whether the userid matches the item being accessed.'''
802+ return userid == itemid
803+ p = db.security.addPermission(name='View', klass='user', check=own_record,
804+ description="User is allowed to view their own user details")
805+ p = db.security.addPermission(name='Edit', klass='user', check=own_record,
806+ description="User is allowed to edit their own user details")
807+ db.security.addPermissionToRole('User', p)
808+
809+ #
810+ # ANONYMOUS USER PERMISSIONS
811+ #
812+ # Let anonymous users access the web interface. Note that almost all
813+ # trackers will need this Permission. The only situation where it's not
814+ # required is in a tracker that uses an HTTP Basic Authenticated front-end.
815+ p = db.security.getPermission('Web Access')
816+ db.security.addPermissionToRole('Anonymous', p)
817+
818+ # Let anonymous users access the email interface (note that this implies
819+ # that they will be registered automatically, hence they will need the
820+ # "Create" user Permission below)
821+ p = db.security.getPermission('Email Access')
777822 db.security.addPermissionToRole('Anonymous', p)
778- # - Allow anonymous (new) users to register through the email
779- # gateway
780- p = db.security.getPermission('Email Registration')
823+
824+ # Assign the appropriate permissions to the anonymous user's Anonymous
825+ # Role. Choices here are:
826+ # - Allow anonymous users to register
827+ p = db.security.getPermission('Create', 'user')
781828 db.security.addPermissionToRole('Anonymous', p)
782829
830+ # Allow anonymous users access to view issues (and the related, linked
831+ # information)
832+ for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status':
833+ p = db.security.getPermission('View', cl)
834+ db.security.addPermissionToRole('Anonymous', p)
835+
836+ # [OPTIONAL]
837+ # Allow anonymous users access to create or edit "issue" items (and the
838+ # related file and message items)
839+ #for cl in 'issue', 'file', 'msg':
840+ # p = db.security.getPermission('Create', cl)
841+ # db.security.addPermissionToRole('Anonymous', p)
842+ # p = db.security.getPermission('Edit', cl)
843+ # db.security.addPermissionToRole('Anonymous', p)
844+
783845
784846New User Roles
785847--------------
@@ -806,7 +868,7 @@ Adding a new Permission
806868
807869When adding a new Permission, you will need to:
808870
809- 1. add it to your tracker's dbinit so it is created, using
871+ 1. add it to your tracker's ``schema.py`` so it is created, using
810872 ``security.addPermission``, for example::
811873
812874 self.security.addPermission(name="View", klass='frozzle',
@@ -819,6 +881,18 @@ When adding a new Permission, you will need to:
8198814. add it to the appropriate xxxPermission methods on in your tracker
820882 interfaces module
821883
884+ The ``addPermission`` method takes a couple of optional parameters:
885+
886+ **properties**
887+ A sequence of property names that are the only properties to apply the
888+ new Permission to (eg. ``... klass='user', properties=('name',
889+ 'email') ...``)
890+ **code**
891+ A function to be execute which returns boolean determining whether the
892+ Permission is allowed. The function has the signature ``check(db, userid,
893+ itemid)`` where ``db`` is a handle on the open database, ``userid`` is
894+ the user attempting access and ``itemid`` is the specific item being
895+ accessed.
822896
823897Example Scenarios
824898~~~~~~~~~~~~~~~~~
@@ -1061,6 +1135,8 @@ Each action class also has a ``*permission*`` method which determines whether
10611135the action is permissible given the current user. The base permission checks
10621136are:
10631137
1138+ XXX REVIEW for Permissions changes
1139+
10641140**login**
10651141 Determine whether the user has permission to log in. Base behaviour is
10661142 to check the user has "Web Access".
@@ -1070,14 +1146,12 @@ are:
10701146 Determine whether the user has permission to register. Base behaviour
10711147 is to check the user has the "Web Registration" Permission.
10721148**edit**
1073- Determine whether the user has permission to edit this item. Base
1074- behaviour is to check whether the user can edit this class. If we're
1149+ Determine whether the user has permission to edit this item. If we're
10751150 editing the "user" class, users are allowed to edit their own details -
10761151 unless they try to edit the "roles" property, which requires the
10771152 special Permission "Web Roles".
10781153**new**
1079- Determine whether the user has permission to create (or edit) this
1080- item. Base behaviour is to check the user can edit this class. No
1154+ Determine whether the user has permission to create this item. No
10811155 additional property checks are made. Additionally, new user items may
10821156 be created if the user has the "Web Registration" Permission.
10831157**editCSV**
@@ -1164,11 +1238,11 @@ None of the above (ie. just a simple form value)
11641238
11651239 For a Link('klass') property, the form value is a
11661240 single key for 'klass', where the key field is
1167- specified in dbinit .py.
1241+ specified in schema .py.
11681242
11691243 For a Multilink('klass') property, the form value is a
11701244 comma-separated list of keys for 'klass', where the
1171- key field is specified in dbinit .py.
1245+ key field is specified in schema .py.
11721246
11731247 Note that for simple-form-variables specifiying Link
11741248 and Multilink properties, the linked-to class must
@@ -2510,7 +2584,7 @@ Adding a field to the database
25102584
25112585This is the easiest part of the change. The category would just be a
25122586plain string, nothing fancy. To change what is in the database you need
2513- to add some lines to the ``open()`` function in ``dbinit .py``. Under the
2587+ to add some lines to the ``open()`` function in ``schema .py``. Under the
25142588comment::
25152589
25162590 # add any additional database schema configuration here
@@ -2533,7 +2607,7 @@ Adding the above lines allows us to create categories, but they're not
25332607tied to the issues that we are going to be creating. It's just a list of
25342608categories off on its own, which isn't much use. We need to link it in
25352609with the issues. To do that, find the lines in the ``open()`` function
2536- in ``dbinit .py`` which set up the "issue" class, and then add a link to
2610+ in ``schema .py`` which set up the "issue" class, and then add a link to
25372611the category::
25382612
25392613 issue = IssueClass(db, "issue", ... ,
@@ -2552,7 +2626,7 @@ Populating the new category class
25522626
25532627If you haven't initialised the database with the roundup-admin
25542628"initialise" command, then you can add the following to the tracker
2555- ``dbinit .py`` in the ``init()`` function under the comment::
2629+ ``schema .py`` in the ``init()`` function under the comment::
25562630
25572631 # add any additional database create steps here - but only if you
25582632 # haven't initialised the database with the admin "initialise" command
@@ -2591,7 +2665,7 @@ as required, and obviously everyone needs to be able to view the
25912665categories of issues for it to be useful.
25922666
25932667We therefore need to change the security of the category objects. This
2594- is also done in the ``open()`` function of ``dbinit .py``.
2668+ is also done in the ``open()`` function of ``schema .py``.
25952669
25962670There are currently two loops which set up permissions and then assign
25972671them to various roles. Simply add the new "category" to both lists::
@@ -2908,7 +2982,7 @@ Adding a time log to your issues
29082982We want to log the dates and amount of time spent working on issues, and
29092983be able to give a summary of the total time spent on a particular issue.
29102984
2911- 1. Add a new class to your tracker ``dbinit .py``::
2985+ 1. Add a new class to your tracker ``schema .py``::
29122986
29132987 # storage for time logging
29142988 timelog = Class(db, "timelog", period=Interval())
@@ -2917,7 +2991,7 @@ be able to give a summary of the total time spent on a particular issue.
29172991 creation through the standard property "creation".
29182992
291929932. Link to the new class from your issue class (again, in
2920- ``dbinit .py``)::
2994+ ``schema .py``)::
29212995
29222996 issue = IssueClass(db, "issue",
29232997 assignedto=Link("user"), topic=Multilink("keyword"),
@@ -3012,7 +3086,7 @@ a customer support issue class to a tracker.
30123086 this is obvious, but sometimes it's better to actually sit down for a
30133087 while and think about the schema you're going to implement.
30143088
3015- 2. Add the new issue class to your tracker's ``dbinit .py`` - in this
3089+ 2. Add the new issue class to your tracker's ``schema .py`` - in this
30163090 example, we're adding a "system support" class. Just after the "issue"
30173091 class definition in the "open" function, add::
30183092
@@ -3460,7 +3534,7 @@ they can't be resolved until another issue (the blocker) they rely on is
34603534resolved. To achieve this:
34613535
346235361. Create a new property on the issue Class,
3463- ``blockers=Multilink("issue")``. Edit your tracker's dbinit .py file.
3537+ ``blockers=Multilink("issue")``. Edit your tracker's schema .py file.
34643538 Where the "issue" class is defined, something like::
34653539
34663540 issue = IssueClass(db, "issue",
@@ -3616,7 +3690,7 @@ a list of topics for which he wants to be put on the nosy list. Adding
36163690a ``Multilink`` of ``keyword`` seem to fullfill this (note that within
36173691the code topics are called ``keywords``.) As such, all what has to be
36183692done is to add a new field to the definition of ``user`` within the
3619- file ``dbinit .py``. We will call this new field ``nosy_keywords``, and
3693+ file ``schema .py``. We will call this new field ``nosy_keywords``, and
36203694the updated definition of user will be::
36213695
36223696 user = Class(db, "user",
@@ -3764,7 +3838,7 @@ Changes to Security and Permissions
37643838Restricting the list of users that are assignable to a task
37653839~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37663840
3767- 1. In your tracker's "dbinit .py" , create a new Role, say "Developer"::
3841+ 1. In your tracker's ``schema .py`` , create a new Role, say "Developer"::
37683842
37693843 db.security.addRole(name='Developer', description='A developer')
37703844
@@ -3829,7 +3903,7 @@ Own" on issues (regular users have "Edit".) We back up the permissions with
38293903an auditor.
38303904
38313905First up, we create the new Role and Permission structure in
3832- ``dbinit .py``::
3906+ ``schema .py``::
38333907
38343908 # New users not approved by the admin
38353909 db.security.addRole(name='Provisional User',
0 commit comments