source: main/waeup.kofa/trunk/src/waeup/kofa/permissions.py @ 12853

Last change on this file since 12853 was 12847, checked in by Henrik Bettermann, 10 years ago

Update security documentation.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.0 KB
Line 
1## $Id: permissions.py 12847 2015-04-03 17:45:48Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18import grok
19from zope.component import getUtilitiesFor
20from zope.interface import Interface
21from zope.securitypolicy.interfaces import IRole, IPrincipalRoleMap
22from waeup.kofa.interfaces import ILocalRolesAssignable
23
24class Public(grok.Permission):
25    """The Public or everyone-can-do-this-permission is being applied
26    to views/pages that are used by everyone.
27    """
28    grok.name('waeup.Public')
29
30class Anonymous(grok.Permission):
31    """The Anonymous permission is applied to
32    views/pages which are dedicated to anonymous users only.
33    Logged-in users can't access these views.
34    """
35    grok.name('waeup.Anonymous')
36
37class Authenticated(grok.Permission):
38    """The Authenticated permission is applied to pages
39    which can only be used by logged-in users and not by anonymous users.
40    """
41    grok.name('waeup.Authenticated')
42
43class ViewAcademics(grok.Permission):
44    """The ViewAcademics permission is applied to all
45    views of the Academic Section. Users with this permission can view but
46    not edit content in the Academic Section.
47    """
48    grok.name('waeup.viewAcademics')
49
50class ManageAcademics(grok.Permission):
51    """The ManageAcademics permission is applied to all edit/manage
52    pages in the Academic Section. Users who have this permission
53    can change/edit context objects.
54    """
55    grok.name('waeup.manageAcademics')
56
57class ManagePortal(grok.Permission):
58    """The ManagePortal permission is used for very few pages
59    (e.g. the DatacenterSettings page). Only PortalManagers have this
60    permission. It is furthermore used to control delete methods of container
61    pages in the Academic Section. The ManageAcademics permission,
62    described above, does enable users to edit content but not to
63    remove sub-containers, like faculties, departments or certificates.
64    Users must have the ManagePortal permission too to remove
65    entire containers.
66    """
67    grok.name('waeup.managePortal')
68
69class ManageUsers(grok.Permission):
70    """The ManageUsers permission is a real superuser permission
71    and therefore very 'dangerous'. It allows to add, remove or edit
72    user accounts. Editing a user account includes the option to assign
73    or remove roles. That means that a user with this permission can lock out
74    other users by either removing their account or by removing
75    permissions.
76    """
77    grok.name('waeup.manageUsers')
78
79class ShowStudents(grok.Permission):
80    """Users with this permission do not neccessarily see the 'Students' tab
81    but they can search for students at department, certificate or course
82    level. If they additionally have the ExportData permission they can
83    export the data as csv files.
84
85    Bursary or Department Officers don't have the ExportData
86    permission (see Roles section) and are only allowed to export bursary
87    or payments overview data respectively.
88    """
89    grok.name('waeup.showStudents')
90
91class ClearAllStudents(grok.Permission):
92    """The ClearAllStudents permission allows to clear all students
93    in a department at one sweep.
94    """
95    grok.name('waeup.clearAllStudents')
96
97class EditScores(grok.Permission):
98    """The EditScores permission allows to edit scores in course tickets.
99    """
100    grok.name('waeup.editScores')
101
102class TriggerTransition(grok.Permission):
103    """The TriggerTransition permission allows to trigger workflow transitions
104    of student and document objects.
105    """
106    grok.name('waeup.triggerTransition')
107
108class EditUser(grok.Permission):
109    """The EditUser permission is required for editing
110    single user accounts.
111    """
112    grok.name('waeup.editUser')
113
114class ManageDataCenter(grok.Permission):
115    """The ManageDataCenter permission allows to access all pages
116    in the Data Center and to upload files. It does not automatically
117    allow to process uploaded data files.
118    """
119    grok.name('waeup.manageDataCenter')
120
121class ImportData(grok.Permission):
122    """The ImportData permission allows to batch process (import) any kind of
123    portal data except for user data. The User Data processor
124    requires also the ManageUsers permission.
125    """
126    grok.name('waeup.importData')
127
128class ExportData(grok.Permission):
129    """The ExportData permission allows to export any kind of portal data.
130    """
131    grok.name('waeup.exportData')
132
133class ExportPaymentsOverview(grok.Permission):
134    grok.name('waeup.exportPaymentsOverview')
135
136class ExportBursaryData(grok.Permission):
137    grok.name('waeup.exportBursaryData')
138
139class ViewTranscript(grok.Permission):
140    grok.name('waeup.viewTranscript')
141
142class ManagePortalConfiguration(grok.Permission):
143    """The ManagePortalConfiguration permission allows to
144    edit global and sessional portal configuration data.
145    """
146    grok.name('waeup.managePortalConfiguration')
147
148class ManageACBatches(grok.Permission):
149    """The ManageACBatches permission allows to view and
150    manage accesscodes.
151    """
152    grok.name('waeup.manageACBatches')
153
154class PutBiometricDataPermission(grok.Permission):
155    """This permission allows to upload/change biometric data.
156    """
157    grok.name('waeup.putBiometricData')
158
159class GetBiometricDataPermission(grok.Permission):
160    """This permission allows to read biometric data.
161    """
162    grok.name('waeup.getBiometricData')
163
164
165# Local Roles
166
167class ApplicationsManager(grok.Role):
168    """The local ApplicationsManager role can be assigned at department level.
169    Local Applications Managers do not gain further permissions. This role is
170    meant for the assignment of dynamic roles only, see below.
171    """
172    grok.name('waeup.local.ApplicationsManager')
173    grok.title(u'Applications Manager')
174    grok.permissions('waeup.viewAcademics')
175
176class DepartmentManager(grok.Role):
177    """The local DepartmentManager role can be assigned at faculty or
178    department level. The role allows to edit all data within this container.
179    It does not automatically allow to remove sub-containers.
180
181    Department Managers (Dean of Faculty or Head of Department respectively)
182    can also list student data but not access student pages.
183    """
184    grok.name('waeup.local.DepartmentManager')
185    grok.title(u'Department Manager')
186    grok.permissions('waeup.manageAcademics',
187                     'waeup.showStudents',
188                     'waeup.exportData')
189
190class DepartmentOfficer(grok.Role):
191    """The local DepartmentOfficer role can be assigned at faculty or
192    department level. The role allows to list all student data within the
193    faculty/department the local role is assigned.
194
195    Department Managers (Dean of Faculty or Head of Department respectively)
196    can also list student data but not access student pages. They can
197    furthermore export payment overviews.
198    """
199    grok.name('waeup.local.DepartmentOfficer')
200    grok.title(u'Department Officer')
201    grok.permissions('waeup.showStudents',
202                     'waeup.viewAcademics',
203                     'waeup.exportPaymentsOverview')
204
205class ClearanceOfficer(grok.Role):
206    """The local ClearanceOfficer role can be assigned at faculty or
207    department level. The role allows to list or export all student
208    data within the faculty/department the local role is assigned.
209
210    Clearance Officers can furthermore clear all students or reject clearance
211    of all students in their faculty/department. They get the
212    StudentsClearanceOfficer role for this subset of students.
213    """
214    grok.name('waeup.local.ClearanceOfficer')
215    grok.title(u'Clearance Officer')
216    grok.permissions('waeup.showStudents',
217                     'waeup.viewAcademics',
218                     'waeup.exportData',
219                     'waeup.clearAllStudents')
220
221class LocalStudentsManager(grok.Role):
222    """The local LocalStudentsManager role can be assigned at faculty or
223    department level. The role allows to view all data and to view or export
224    all student data within the faculty/department the local role is assigned.
225
226    Local Students Managers can furthermore manage data of students
227    in their faculty/department. They get the StudentsManager role for
228    this subset of students.
229    """
230    grok.name('waeup.local.LocalStudentsManager')
231    grok.title(u'Students Manager')
232    grok.permissions('waeup.showStudents',
233                     'waeup.viewAcademics',
234                     'waeup.exportData')
235
236class LocalWorkflowManager(grok.Role):
237    """The local LocalWorkflowManager role can be assigned at faculty level.
238    The role allows to view all data and to list or export
239    all student data within the faculty the local role is assigned.
240
241    Local Workflow Managers can trigger transition of students in their
242    faculty/department. They get the WorkflowManager role for
243    this subset of students.
244    """
245    grok.name('waeup.local.LocalWorkflowManager')
246    grok.title(u'Student Workflow Manager')
247    grok.permissions('waeup.showStudents',
248                     'waeup.viewAcademics',
249                     'waeup.exportData')
250
251class UGClearanceOfficer(grok.Role):
252    """UG Clearance Officers are regular Clearance Officers with restricted
253    dynamic permission assignment. They can only access undergraduate
254    students.
255    """
256    grok.name('waeup.local.UGClearanceOfficer')
257    grok.title(u'UG Clearance Officer')
258    grok.permissions('waeup.showStudents',
259                     'waeup.viewAcademics',
260                     'waeup.exportData',
261                     'waeup.clearAllStudents')
262
263class PGClearanceOfficer(grok.Role):
264    """PG Clearance Officers are regular Clearance Officers with restricted
265    dynamic permission assignment. They can only access postgraduate
266    students.
267    """
268    grok.name('waeup.local.PGClearanceOfficer')
269    grok.title(u'PG Clearance Officer')
270    grok.permissions('waeup.showStudents',
271                     'waeup.viewAcademics',
272                     'waeup.exportData',
273                     'waeup.clearAllStudents')
274
275class CourseAdviser100(grok.Role):
276    """The local CourseAdviser100 role can be assigned at faculty,
277    department or certificate level. The role allows to view all data and
278    to list or export all student data within the faculty, department
279    or certificate the local role is assigned.
280
281    Local Course Advisers can validate or reject course lists of students
282    in ther faculty/department/certificate at level 100.
283    They get the StudentsCourseAdviser role for this subset of students.
284    """
285    grok.name('waeup.local.CourseAdviser100')
286    grok.title(u'Course Adviser 100L')
287    grok.permissions('waeup.showStudents',
288                     'waeup.viewAcademics',
289                     'waeup.exportData')
290
291class CourseAdviser200(grok.Role):
292    """Same as CourseAdviser100 but for level 200.
293    """
294    grok.name('waeup.local.CourseAdviser200')
295    grok.title(u'Course Adviser 200L')
296    grok.permissions('waeup.showStudents',
297                     'waeup.viewAcademics',
298                     'waeup.exportData')
299
300class CourseAdviser300(grok.Role):
301    """Same as CourseAdviser100 but for level 300.
302    """
303    grok.name('waeup.local.CourseAdviser300')
304    grok.title(u'Course Adviser 300L')
305    grok.permissions('waeup.showStudents',
306                     'waeup.viewAcademics',
307                     'waeup.exportData')
308
309class CourseAdviser400(grok.Role):
310    """Same as CourseAdviser100 but for level 400.
311    """
312    grok.name('waeup.local.CourseAdviser400')
313    grok.title(u'Course Adviser 400L')
314    grok.permissions('waeup.showStudents',
315                     'waeup.viewAcademics',
316                     'waeup.exportData')
317
318class CourseAdviser500(grok.Role):
319    """Same as CourseAdviser100 but for level 500.
320    """
321    grok.name('waeup.local.CourseAdviser500')
322    grok.title(u'Course Adviser 500L')
323    grok.permissions('waeup.showStudents',
324                     'waeup.viewAcademics',
325                     'waeup.exportData')
326
327class CourseAdviser600(grok.Role):
328    """Same as CourseAdviser100 but for level 600.
329    """
330    grok.name('waeup.local.CourseAdviser600')
331    grok.title(u'Course Adviser 600L')
332    grok.permissions('waeup.showStudents',
333                     'waeup.viewAcademics',
334                     'waeup.exportData')
335
336class CourseAdviser700(grok.Role):
337    """Same as CourseAdviser100 but for level 700.
338    """
339    grok.name('waeup.local.CourseAdviser700')
340    grok.title(u'Course Adviser 700L')
341    grok.permissions('waeup.showStudents',
342                     'waeup.viewAcademics',
343                     'waeup.exportData')
344
345class CourseAdviser800(grok.Role):
346    """Same as CourseAdviser100 but for level 800.
347    """
348    grok.name('waeup.local.CourseAdviser800')
349    grok.title(u'Course Adviser 800L')
350    grok.permissions('waeup.showStudents',
351                     'waeup.viewAcademics',
352                     'waeup.exportData')
353
354class Lecturer(grok.Role):
355    """The local Lecturer role can be assigned at course level.
356    The role allows to view all data and to list or export all student
357    ata within course the local role is assigned. Lecturers can't access
358    student data directly but they can edit the scores in course tickets.
359    """
360    grok.name('waeup.local.Lecturer')
361    grok.title(u'Lecturer')
362    grok.permissions('waeup.showStudents',
363                     'waeup.editScores',
364                     'waeup.viewAcademics',
365                     'waeup.exportData')
366
367class Owner(grok.Role):
368    """Each user 'owns' her/his user object and gains permission to edit
369    some of the user attributes.
370    """
371    grok.name('waeup.local.Owner')
372    grok.title(u'Owner')
373    grok.permissions('waeup.editUser')
374
375# Site Roles
376
377class AcademicsOfficer(grok.Role):
378    """An Academics Officer can view but not edit data in the
379    Academics Section.
380
381    This is the default role which is automatically assigned to all
382    officers of the portal. A user with this role can access all display pages
383    at faculty, department, course, certificate and certificate course level.
384    """
385    grok.name('waeup.AcademicsOfficer')
386    grok.title(u'Academics Officer (view only)')
387    grok.permissions('waeup.viewAcademics')
388
389class AcademicsManager(grok.Role):
390    """An Academics Manager can view and edit all data in the
391    Academics Section, i.e. access all manage pages
392    at faculty, department, course, certificate and certificate course level.
393    """
394    grok.name('waeup.AcademicsManager')
395    grok.title(u'Academics Manager')
396    title = u'Academics Manager'
397    grok.permissions('waeup.viewAcademics',
398                     'waeup.manageAcademics')
399
400class ACManager(grok.Role):
401    """This is the role for Access Code Managers.
402    An AC Manager can view and manage the Accesscodes Section, see
403    ManageACBatches permission above.
404    """
405    grok.name('waeup.ACManager')
406    grok.title(u'Access Code Manager')
407    grok.permissions('waeup.manageACBatches')
408
409class DataCenterManager(grok.Role):
410    """This single-permission role is dedicated to those users
411    who are charged with batch processing of portal data.
412    A Data Center Manager can access all pages in the Data Center,
413    see ManageDataCenter permission above.
414    """
415    grok.name('waeup.DataCenterManager')
416    grok.title(u'Datacenter Manager')
417    grok.permissions('waeup.manageDataCenter')
418
419class ImportManager(grok.Role):
420    """An Import Manager is a Data Center Manager who is also allowed
421    to batch process (import) data. All batch processors (importers) are
422    available except for the User Processor. This processor requires the
423    Users Manager role too. The ImportManager role includes the
424    DataCenterManager role but not vice versa.
425    """
426    grok.name('waeup.ImportManager')
427    grok.title(u'Import Manager')
428    grok.permissions('waeup.manageDataCenter',
429                     'waeup.importData')
430
431class ExportManager(grok.Role):
432    """An Export Manager is a Data Center Manager who is also allowed
433    to export all kind of portal data. The ExportManager role includes the
434    DataCenterManager role but not vice versa.
435    """
436    grok.name('waeup.ExportManager')
437    grok.title(u'Export Manager')
438    grok.permissions('waeup.manageDataCenter',
439                     'waeup.exportData')
440
441class BursaryOfficer(grok.Role):
442    """Bursary Officers can export bursary data. They can't access the
443    Data Center but see student data export buttons in the Academic Section.
444    """
445    grok.name('waeup.BursaryOfficer')
446    grok.title(u'Bursary Officer')
447    grok.permissions('waeup.showStudents',
448                     'waeup.viewAcademics',
449                     'waeup.exportBursaryData')
450
451class UsersManager(grok.Role):
452    """A Users Manager can add, remove or edit
453    user accounts, see ManageUsers permission for further information.
454    Be very careful with this role.
455    """
456    grok.name('waeup.UsersManager')
457    grok.title(u'Users Manager')
458    grok.permissions('waeup.manageUsers',
459                     'waeup.editUser')
460
461class WorkflowManager(grok.Role):
462    """The Workflow Manager can trigger workflow transitions
463    of student and document objects, see TriggerTransition permission
464    for further information.
465    """
466    grok.name('waeup.WorkflowManager')
467    grok.title(u'Workflow Manager')
468    grok.permissions('waeup.triggerTransition')
469
470class PortalManager(grok.Role):
471    """The PortalManager role is the maximum set of Kofa permissions
472    which are needed to manage the entire portal. This set must not
473    be customized. It is recommended to assign this role only
474    to a few certified Kofa administrators.
475    A less dangerous manager role is the CCOfficer role described below.
476    For the most tasks the CCOfficer role is sufficient.
477    """
478    grok.name('waeup.PortalManager')
479    grok.title(u'Portal Manager')
480    grok.permissions('waeup.managePortal',
481                     'waeup.manageUsers',
482                     'waeup.viewAcademics', 'waeup.manageAcademics',
483                     'waeup.manageACBatches',
484                     'waeup.manageDataCenter',
485                     'waeup.importData',
486                     'waeup.exportData',
487                     'waeup.viewTranscript',
488                     'waeup.viewDocuments', 'waeup.manageDocuments',
489                     'waeup.managePortalConfiguration', 'waeup.viewApplication',
490                     'waeup.manageApplication', 'waeup.handleApplication',
491                     'waeup.viewApplicantsTab', 'waeup.payApplicant',
492                     'waeup.viewApplicationStatistics',
493                     'waeup.viewStudent', 'waeup.manageStudent',
494                     'waeup.clearStudent', 'waeup.payStudent',
495                     'waeup.uploadStudentFile', 'waeup.showStudents',
496                     'waeup.clearAllStudents',
497                     'waeup.editScores',
498                     'waeup.triggerTransition',
499                     'waeup.viewStudentsContainer',
500                     'waeup.handleAccommodation',
501                     'waeup.viewHostels', 'waeup.manageHostels',
502                     'waeup.editUser',
503                     'waeup.loginAsStudent',
504                     'waeup.manageReports',
505                     'waeup.manageJobs',
506                     )
507
508class CCOfficer(grok.Role):
509    """The role of the Computer Center Officer is basically a copy
510    of the the PortalManager role. Some 'dangerous' permissions are excluded
511    by commenting them out (see source code). If officers need to gain more
512    access rights than defined in this role, do not hastily switch to the
513    PortalManager role but add further manager roles instead. Additional
514    roles could be: UsersManager, ACManager, ImportManager, WorkflowManager
515    or StudentImpersonator.
516
517    CCOfficer is a base class which means that this role is subject to
518    customization. It is not used in the ``waeup.kofa`` base package.
519    """
520    grok.baseclass()
521    grok.name('waeup.CCOfficer')
522    grok.title(u'Computer Center Officer')
523    grok.permissions(#'waeup.managePortal',
524                     #'waeup.manageUsers',
525                     'waeup.viewAcademics', 'waeup.manageAcademics',
526                     #'waeup.manageACBatches',
527                     'waeup.manageDataCenter',
528                     #'waeup.importData',
529                     'waeup.exportData',
530                     'waeup.viewTranscript',
531                     'waeup.viewDocuments', 'waeup.manageDocuments',
532                     'waeup.managePortalConfiguration', 'waeup.viewApplication',
533                     'waeup.manageApplication', 'waeup.handleApplication',
534                     'waeup.viewApplicantsTab', 'waeup.payApplicant',
535                     'waeup.viewApplicationStatistics',
536                     'waeup.viewStudent', 'waeup.manageStudent',
537                     'waeup.clearStudent', 'waeup.payStudent',
538                     'waeup.uploadStudentFile', 'waeup.showStudents',
539                     'waeup.clearAllStudents',
540                     'waeup.editScores',
541                     #'waeup.triggerTransition',
542                     'waeup.viewStudentsContainer',
543                     'waeup.handleAccommodation',
544                     'waeup.viewHostels', 'waeup.manageHostels',
545                     #'waeup.editUser',
546                     #'waeup.loginAsStudent',
547                     'waeup.manageReports',
548                     #'waeup.manageJobs',
549                     )
550
551def get_all_roles():
552    """Return a list of tuples ``<ROLE-NAME>, <ROLE>``.
553    """
554    return getUtilitiesFor(IRole)
555
556def get_waeup_roles(also_local=False):
557    """Get all Kofa roles.
558
559    Kofa roles are ordinary roles whose id by convention starts with
560    a ``waeup.`` prefix.
561
562    If `also_local` is ``True`` (``False`` by default), also local
563    roles are returned. Local Kofa roles are such whose id starts
564    with ``waeup.local.`` prefix (this is also a convention).
565
566    Returns a generator of the found roles.
567    """
568    for name, item in get_all_roles():
569        if not name.startswith('waeup.'):
570            # Ignore non-Kofa roles...
571            continue
572        if not also_local and name.startswith('waeup.local.'):
573            # Ignore local roles...
574            continue
575        yield item
576
577def get_waeup_role_names():
578    """Get the ids of all Kofa roles.
579
580    See :func:`get_waeup_roles` for what a 'KofaRole' is.
581
582    This function returns a sorted list of Kofa role names.
583    """
584    return sorted([x.id for x in get_waeup_roles()])
585
586class LocalRolesAssignable(grok.Adapter):
587    """Default implementation for `ILocalRolesAssignable`.
588
589    This adapter returns a list for dictionaries for objects for which
590    we want to know the roles assignable to them locally.
591
592    The returned dicts contain a ``name`` and a ``title`` entry which
593    give a role (``name``) and a description, for which kind of users
594    the permission is meant to be used (``title``).
595
596    Having this adapter registered we make sure, that for each normal
597    object we get a valid `ILocalRolesAssignable` adapter.
598
599    Objects that want to offer certain local roles, can do so by
600    setting a (preferably class-) attribute to a list of role ids.
601
602    You can also define different adapters for different contexts to
603    have different role lookup mechanisms become available. But in
604    normal cases it should be sufficient to use this basic adapter.
605    """
606    grok.context(Interface)
607    grok.provides(ILocalRolesAssignable)
608
609    _roles = []
610
611    def __init__(self, context):
612        self.context = context
613        role_ids = getattr(context, 'local_roles', self._roles)
614        self._roles = [(name, role) for name, role in get_all_roles()
615                       if name in role_ids]
616        return
617
618    def __call__(self):
619        """Get a list of dictionaries containing ``names`` (the roles to
620        assign) and ``titles`` (some description of the type of user
621        to assign each role to).
622        """
623        list_of_dict = [dict(
624                name=name,
625                title=role.title,
626                description=role.description)
627                for name, role in self._roles]
628        return sorted(list_of_dict, key=lambda x: x['name'])
629
630def get_all_users():
631    """Get a list of dictionaries.
632    """
633    users = sorted(grok.getSite()['users'].items(), key=lambda x: x[1].title)
634    for key, val in users:
635        yield(dict(name=key, val=val))
636
637def get_users_with_local_roles(context):
638    """Get a list of dicts representing the local roles set for `context`.
639
640    Each dict returns `user_name`, `user_title`, `local_role`,
641    `local_role_title`, and `setting` for each entry in the local
642    roles map of the `context` object.
643    """
644    try:
645        role_map = IPrincipalRoleMap(context)
646    except TypeError:
647        # no map no roles.
648        raise StopIteration
649    for local_role, user_name, setting in role_map.getPrincipalsAndRoles():
650        user = grok.getSite()['users'].get(user_name,None)
651        user_title = getattr(user, 'title', user_name)
652        local_role_title = getattr(
653            dict(get_all_roles()).get(local_role, None), 'title', None)
654        yield dict(user_name = user_name,
655                   user_title = user_title,
656                   local_role = local_role,
657                   local_role_title = local_role_title,
658                   setting = setting)
659
660def get_users_with_role(role, context):
661    """Get a list of dicts representing the usres who have been granted
662    a role for `context`.
663    """
664    try:
665        role_map = IPrincipalRoleMap(context)
666    except TypeError:
667        # no map no roles.
668        raise StopIteration
669    for user_name, setting in role_map.getPrincipalsForRole(role):
670        user = grok.getSite()['users'].get(user_name,None)
671        user_title = getattr(user, 'title', user_name)
672        user_email = getattr(user, 'email', None)
673        yield dict(user_name = user_name,
674                   user_title = user_title,
675                   user_email = user_email,
676                   setting = setting)
Note: See TracBrowser for help on using the repository browser.