source: enpraxis.educommons/branches/educommons-imsintegration/enpraxis/educommons/browser/sharing.py @ 146

Revision 146, 15.9 KB checked in by jon, 4 years ago (diff)

Adding branch for ims integration

Line 
1from zope.component import getUtilitiesFor, queryUtility, getMultiAdapter
2
3from Products.Five.browser import BrowserView
4from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
5
6from Acquisition import aq_inner, aq_parent, aq_base
7from AccessControl import Unauthorized
8from zExceptions import Forbidden
9
10from Products.CMFCore.utils import getToolByName
11from Products.CMFCore import permissions
12from Products.CMFPlone import PloneMessageFactory as _
13
14from plone.memoize.instance import memoize, clearafter
15
16from plone.app.workflow.interfaces import ISharingPageRole
17
18from enpraxis.educommons.browser.interfaces import IeduCommonsSharingPageRole
19
20AUTH_GROUP = 'AuthenticatedUsers'
21STICKY = (AUTH_GROUP,)
22
23class SharingView(BrowserView):
24   
25    # Actions
26    template = ViewPageTemplateFile('sharing.pt')
27   
28    def __call__(self):
29        """Perform the update and redirect if necessary, or render the page
30        """
31       
32        postback = True
33       
34        form = self.request.form
35        submitted = form.get('form.submitted', False)
36   
37        save_button = form.get('form.button.Save', None) is not None
38        cancel_button = form.get('form.button.Cancel', None) is not None
39   
40        if submitted and not cancel_button:
41
42            if not self.request.get('REQUEST_METHOD','GET') == 'POST':
43                raise Forbidden
44           
45            # Update the acquire-roles setting
46            inherit = bool(form.get('inherit', False))
47            self.update_inherit(inherit)
48
49            # Update settings for users and groups
50            entries = form.get('entries', [])
51            roles = [r['id'] for r in self.roles()]
52            settings = []
53            for entry in entries:
54                settings.append(
55                    dict(id = entry['id'],
56                         type = entry['type'],
57                         roles = [r for r in roles if entry.get('role_%s' % r, False)]))
58            if settings:
59                self.update_role_settings(settings)
60           
61        # Other buttons return to the sharing page
62        if cancel_button:
63            postback = False
64       
65        if postback:
66            return self.template()
67        else:
68            context_state = self.context.restrictedTraverse("@@plone_context_state")
69            url = context_state.view_url()
70            self.request.response.redirect(url)
71           
72    # View
73   
74    @memoize
75    def roles(self):
76        """Get a list of roles that can be managed.
77       
78        Returns a list of dics with keys:
79       
80            - id
81            - title
82        """
83        context = aq_inner(self.context)
84        portal_membership = getToolByName(context, 'portal_membership')
85       
86        pairs = []
87
88        #check to see if OpenOCW installed
89        portal_setup = self.aq_parent.portal_setup
90        if 'openOCW-final' in portal_setup.getImportStepRegistry().listSteps():
91            #user default sharing page roles
92            for name, utility in getUtilitiesFor(ISharingPageRole):
93                permission = utility.required_permission
94                if permission is None or portal_membership.checkPermission(permission, context):
95                    pairs.append(dict(id = name, title = utility.title))
96        else:
97            #use eduCommons sharing page roles
98            for name, utility in getUtilitiesFor(IeduCommonsSharingPageRole):
99                permission = utility.required_permission
100                if permission is None or portal_membership.checkPermission(permission, context):
101                    pairs.append(dict(id = name, title = utility.title))
102
103        pairs.sort(lambda x, y: cmp(x['id'], y['id']))
104        return pairs
105       
106    @memoize
107    def role_settings(self):
108        """Get current settings for users and groups for which settings have been made.
109       
110        Returns a list of dicts with keys:
111       
112         - id
113         - title
114         - type (one of 'group' or 'user')
115         - roles
116         
117        'roles' is a dict of settings, with keys of role ids as returned by
118        roles(), and values True if the role is explicitly set, False
119        if the role is explicitly disabled and None if the role is inherited.
120        """
121       
122        existing_settings = self.existing_role_settings()
123        user_results = self.user_search_results()
124        group_results = self.group_search_results()
125
126        return existing_settings + user_results + group_results
127       
128    def inherited(self, context=None):
129        """Return True if local roles are inherited here.
130        """
131        if context is None:
132            context = self.context
133        if getattr(aq_base(context), '__ac_local_roles_block__', None):
134            return False
135        return True
136       
137    # helper functions
138   
139    @memoize
140    def existing_role_settings(self):
141        """Get current settings for users and groups that have already got
142        at least one of the managed local roles.
143
144        Returns a list of dicts as per role_settings()
145        """
146        context = aq_inner(self.context)
147       
148        portal_membership = getToolByName(aq_inner(self.context), 'portal_membership')
149        portal_groups = getToolByName(aq_inner(self.context), 'portal_groups')
150        portal = getToolByName(aq_inner(self.context), 'portal_url').getPortalObject()
151        acl_users = getattr(portal, 'acl_users')
152       
153        info = []
154       
155        # This logic is adapted from computeRoleMap.py
156       
157        local_roles = acl_users.getLocalRolesForDisplay(context)
158        acquired_roles = self._inherited_roles()
159        available_roles = [r['id'] for r in self.roles()]
160
161        # first process acquired roles
162        items = {}
163        for name, roles, rtype, rid in acquired_roles:
164            items[rid] = dict(id       = rid,
165                              name     = name,
166                              type     = rtype,
167                              sitewide = [],
168                              acquired = roles,
169                              local    = [],)
170                               
171        # second process local roles
172        for name, roles, rtype, rid in local_roles:
173            if items.has_key(rid):
174                items[rid]['local'] = roles
175            else:
176                items[rid] = dict(id       = rid,
177                                  name     = name,
178                                  type     = rtype,
179                                  sitewide = [],
180                                  acquired = [],
181                                  local    = roles,)
182
183        # Make sure we always get the authenticated users virtual group
184        if AUTH_GROUP not in items:
185            items[AUTH_GROUP] = dict(id = AUTH_GROUP,
186                                     name = _(u'Logged-in users'),
187                                     type  = 'group',
188                                     sitewide = [],
189                                     acquired = [],
190                                     local = [],)
191
192        # Sort the list: first the authenticated users virtual group, then
193        # all other groups and then all users, alphabetically
194
195        dec_users = [( a['id'] not in STICKY,
196                       a['type'],
197                       a['name'],
198                       a) for a in items.values()]
199        dec_users.sort()
200       
201        # Add the items to the info dict, assigning full name if possible.
202        # Also, recut roles in the format specified in the docstring
203       
204        for d in dec_users:
205            item = d[-1]
206            name = item['name']
207            rid = item['id']
208            global_roles = set()
209           
210            if item['type'] == 'user':
211                member = acl_users.getUserById(rid)
212                if member is not None:
213                    name = member.getProperty('fullname') or member.getId() or name
214                    global_roles = set(member.getRoles())
215            elif item['type'] == 'group':
216                g = portal_groups.getGroupById(rid)
217                name = g.getGroupTitleOrName()
218                global_roles = set(g.getRoles())
219               
220                # This isn't a proper group, so it needs special treatment :(
221                if rid == AUTH_GROUP:
222                    name = _(u'Logged-in users')
223           
224            info_item = dict(id    = item['id'],
225                             type  = item['type'],
226                             title = name,
227                             roles = {})
228                             
229            # Record role settings
230            have_roles = False
231            for r in available_roles:
232                if r in global_roles:
233                    info_item['roles'][r] = 'global'
234                elif r in item['acquired']:
235                    info_item['roles'][r] = 'acquired'
236                    have_roles = True # we want to show acquired roles
237                elif r in item['local']:
238                    info_item['roles'][r] = True
239                    have_roles = True # at least one role is set
240                else:
241                    info_item['roles'][r] = False
242                   
243            if have_roles or rid in STICKY:
244                info.append(info_item)
245           
246        return info
247       
248    def user_search_results(self):
249        """Return search results for a query to add new users
250       
251        Returns a list of dicts, as per role_settings()
252        """
253        context = aq_inner(self.context)
254        acl_users = getToolByName(context, 'acl_users')
255       
256        search_term = self.request.form.get('search_term', None)
257        if not search_term:
258            return []
259           
260        existing_users = set([u['id'] for u in self.existing_role_settings()
261                                if u['type'] == 'user'])
262        empty_roles = dict([(r['id'], False) for r in self.roles()])
263        info = []
264       
265        hunter = getMultiAdapter((context, self.request), name='pas_search')
266        for userinfo in hunter.searchUsers(fullname=search_term):
267            userid = userinfo['userid']
268            if userid not in existing_users:
269                user = acl_users.getUserById(userid)
270                roles = empty_roles.copy()
271                for r in user.getRoles():
272                    if r in roles:
273                        roles[r] = 'global'
274                info.append(dict(id    = userid,
275                                 title = user.getProperty('fullname') or user.getId() or userid,
276                                 type  = 'user',
277                                 roles = roles))
278        return info
279       
280    def group_search_results(self):
281        """Return search results for a query to add new groups
282       
283        Returns a list of dicts, as per role_settings()
284        """
285        context = aq_inner(self.context)
286        portal_groups = getToolByName(context, 'portal_groups')
287       
288        search_term = self.request.form.get('search_term', None)
289        if not search_term:
290            return []
291           
292        existing_groups = set([g['id'] for g in self.existing_role_settings()
293                                if g['type'] == 'group'])
294        empty_roles = dict([(r['id'], False) for r in self.roles()])
295        info = []
296       
297        hunter = getMultiAdapter((context, self.request), name='pas_search')
298        for groupinfo in hunter.searchGroups(id=search_term):
299            groupid = groupinfo['groupid']
300            if groupid not in existing_groups:
301                group = portal_groups.getGroupById(groupid)
302                roles = empty_roles.copy()
303                for r in group.getRoles():
304                    if r in roles:
305                        roles[r] = 'global'               
306                info.append(dict(id    = groupid,
307                                 title = group.getGroupTitleOrName(),
308                                 type  = 'group',
309                                 roles = roles))
310        return info
311       
312    def _inherited_roles(self):
313        """Returns a tuple with the acquired local roles."""
314        context = aq_inner(self.context)
315       
316        if not self.inherited(context):
317            return []
318       
319        portal = getToolByName(context, 'portal_url').getPortalObject()
320        result = []
321        cont = True
322        if portal != context:
323            parent = aq_parent(context)
324            while cont:
325                if not getattr(parent, 'acl_users', False):
326                    break
327                userroles = parent.acl_users._getLocalRolesForDisplay(parent)
328                for user, roles, role_type, name in userroles:
329                    # Find user in result
330                    found = 0
331                    for user2, roles2, type2, name2 in result:
332                        if user2 == user:
333                            # Check which roles must be added to roles2
334                            for role in roles:
335                                if not role in roles2:
336                                    roles2.append(role)
337                            found = 1
338                            break
339                    if found == 0:
340                        # Add it to result and make sure roles is a list so
341                        # we may append and not overwrite the loop variable
342                        result.append([user, list(roles), role_type, name])
343                if parent == portal:
344                    cont = False
345                elif not self.inherited(parent):
346                    # Role acquired check here
347                    cont = False
348                else:
349                    parent = aq_parent(parent)
350
351        # Tuplize all inner roles
352        for pos in range(len(result)-1,-1,-1):
353            result[pos][1] = tuple(result[pos][1])
354            result[pos] = tuple(result[pos])
355
356        return tuple(result)
357       
358    def update_inherit(self, status=True):
359        """Enable or disable local role acquisition on the context.
360        """
361        context = aq_inner(self.context)
362        portal_membership = getToolByName(context, 'portal_membership')
363       
364        if not portal_membership.checkPermission(permissions.ModifyPortalContent, context):
365            raise Unauthorized
366
367        if not status:
368            context.__ac_local_roles_block__ = True
369        else:
370            if getattr(aq_base(context), '__ac_local_roles_block__', None):
371                context.__ac_local_roles_block__ = None
372
373        context.reindexObjectSecurity()
374       
375    @clearafter
376    def update_role_settings(self, new_settings):
377        """Update local role settings and reindex object security if necessary.
378       
379        new_settings is a list of dicts with keys id, for the user/group id;
380        type, being either 'user' or 'group'; and roles, containing the list
381        of role ids that are set.
382        """
383       
384        reindex = False
385        context = aq_inner(self.context)
386           
387        managed_roles = frozenset([r['id'] for r in self.roles()])
388        member_ids_to_clear = []
389        for s in new_settings:
390            user_id = s['id']
391           
392            existing_roles = frozenset(context.get_local_roles_for_userid(userid=user_id))
393            selected_roles = frozenset(s['roles'])
394           
395            # We will remove those roles that we are managing and which set
396            # on the context, but which were not selected
397            to_remove = (managed_roles & existing_roles) - selected_roles
398           
399            # Leaving us with the selected roles, less any roles that we
400            # want to remove
401            new_roles = (selected_roles | existing_roles) - to_remove
402           
403            # take away roles that we are managing, that were not selected
404            # and which were part of the existing roles
405           
406            if new_roles:
407                context.manage_setLocalRoles(user_id, list(new_roles))
408                reindex = True
409            elif existing_roles:
410                member_ids_to_clear.append(user_id)
411               
412        if member_ids_to_clear:
413            context.manage_delLocalRoles(userids=member_ids_to_clear)
414            reindex = True
415       
416        if reindex:
417            self.context.reindexObjectSecurity()
Note: See TracBrowser for help on using the repository browser.