[wiki:WikiStart Back] = Permissions = [wiki:permissions#Abstract Abstract][[BR]] [wiki:permissions#Usergroups Usergroups][[BR]] [wiki:permissions#Views Views][[BR]] == Abstract == With the permission system of roundup you can handle almost all situations without any problems. It gives you enough freedom to model even complex rules which fits your needs. It is extensible so you can write your own functions to check things which would not be handled without this functions. But when I was working on FaSt setting up a fairly complex permission system I was missing some concepts which makes my life more easy. As you see in the [wiki:WikiStart#Background background info] the internal tracker and its issues are accessed by multiple persons or to be more precise: groups of people. Because of privacy we need to guarantee that issues and its attributes can only be accessed by users how are permitted to. In general there are three groups of people who are involved while working on an issue. The groups and its members can vary on each issue. Groups can be temporarily created just for fixing a single issue: * Internals of Intevation * Customers * Partner-Developers. For each issue in the tracker we define which group should be handles as partner, internal or customer So a member of one of those groups should be able to access the issue. Depending on the group he is member of the user will get a different view on the issue which provides him with more or less information on the issue. This brings us to the concept of usergroups and views. == Usergroups == Roundup does not know usergroups. Roundup has a role based permission system in which you can model something like usergroups but this isn't flexible enough to deal with the requirements mentioned above. There are two problems which are addressed by usergroups: '''1. How to enforce that only permitted people can access the issue?'''[[BR]] This is quite easy. We add three extra attributes to the issue class which links to the new introduced class "usergroup". This way you can define three groups for each issue as you can see below. [[Image(http://www.irlaender.de/projects/fast/usergroups.png, 450, align=center)]][[BR]] ''(Picture: Three groups for each issue )'' Now we need to write a custom function to check if the user how request the issue is a member in one of the thress groups (customer, partner, internal). This can be done in ''schemy.py''. We create a new permission and add our own check function to this permission: {{{ def view_issue(db, userid, itemid): return issue_check_group(db, userid, itemid) or is_issue_creator(db, userid, itemid) def issue_check_group(db, userid, itemid): '''Checks if the user is member of either the customers, partners or internals group of the issue''' if itemid == '': return False i_groups = [] i_groups.append(db.issue.get(itemid, 'group_customer')) i_groups.append(db.issue.get(itemid, 'group_partner')) i_groups.append(db.issue.get(itemid, 'group_internal')) groups = db.usergroup.filter(None, {'member': userid}) for id in groups: if id in i_groups: return True return False vi = db.security.addPermission(name='View', description='Partner is allowed to view only some attributes of the issue', klass='issue', properties = (...), check=view_issue) db.security.addPermissionToRole('Partner', vi, 'issue') }}} This will do the trick that only members of one of the three groups will be ables to view the issue. '''2. How do we enforce that the user will get permissions depending on the group he is member of?'''[[BR]] Well, we simply do not assign roles to users but to usergroups. This way users inherit the role (and it permissions) from the usergroup the user is member of. We can now move users between the usergroups, and do not need to take care of assigning the right roles to the user. We only need to assign the roles one time to the usergroup. This make permission handling much more easy. These permissions lead us to the term ''views'' == Views == Users will get a different view on the tracker and its classes depending on which group they are member of. E.g customers can not see timelogs, or internal communication. "Managers" can create workpackages etc. 90% of these permissions can be modeled within the role based systen of roundup, and it is actually done. You can define roles and regulate the permission down to the single attributes of a class. '''FaSt''' has for predefined roles which enforce these permissions. Ordered by its power: 1. Internal 2. Partners 3. Customers 4. (Manager) But we want also be able to define which messages (change notes) in an issue can be viewed by the users. We want messages which are public and viewable to all involved people. We want messages which can only be viewed my partners and internals and there should be messages only available for internals. Because messages in roundup are all of type msg the rolebased permission system can not handle this without further modifications. Rather than creating new messages classes we introduce a new attribute on the messages called "view". There are three views available. One view per role. You can set the view of a message to: 1. Internal. Only internal can view this message 2. Internal, Partner. Partners and can view this message 3. Internal, Partner, Customer. All users can see the message Below can can see a screenshot with an selection field to setup the view of the message which will be created: [[Image(http://www.irlaender.de/projects/fast/setup_view.png, 450, align=center)]][[BR]] ''(Picture: Setup view )'' This will result in a message list as shown below. The is what an internal user will see if the looks at the message list of an issue. Public messages are not intended. Messages which are also viewable by partners are indented 25pix and coloured blue. Internal messages are indented 50pix and coloured green. This way you can easily see which messages are visible to whom at one glance. [[Image(http://www.irlaender.de/projects/fast/view_message_list.png, 450, align=center)]][[BR]] ''(Picture: Messages are coloured and indented )'' Views also work on attached files. This means users get only presented files they are allowed to see. As same as for the usergroups this behaviour is enforced by a custom check method in a Permission: {{{ def check_permission(db, userid, view_id): allowed_views = [] groups = db.usergroup.filter(None, {'member': userid}) for g in groups: allowed_views.extend(db.usergroup.get(g, 'show_msg')) if view_id in allowed_views: return True return False def view_msg(db, userid, itemid): '''Checks if the user is allowed to see the msg. Returns False if the user is not permitted to see it else True''' view_id = db.msg.get(itemid, 'view') return check_permission(db, userid, view_id) }}} Each usergroup has a list of "views" which define which type of messages can be viewed by the members of the group. Now we check if the "view" assigned to the messages is among the allowed_views of the group the user is member of. '''Nosy messages'''[[BR]] Of course views also affect the nosy messages. Before sending the nosymessage we need to check if the user is allowed to see the message at all. So we make sure that only people you are allowed to the see message will receive a nosy message.