from __future__ import absolute_import import logging from django.contrib import messages from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.core.urlresolvers import reverse from django.http import HttpResponseRedirect, Http404 from django.shortcuts import render_to_response, get_object_or_404 from django.template import RequestContext from django.utils.http import urlencode from django.utils.simplejson import loads from django.utils.translation import ugettext_lazy as _ from common.utils import encapsulate from common.widgets import two_state_template from permissions.models import Permission from .api import get_class_permissions_for from .classes import (AccessHolder, AccessObject, AccessObjectClass, ClassAccessHolder) from .forms import HolderSelectionForm, ClassHolderSelectionForm from .models import AccessEntry, DefaultAccessEntry from .permissions import (ACLS_EDIT_ACL, ACLS_VIEW_ACL, ACLS_CLASS_EDIT_ACL, ACLS_CLASS_VIEW_ACL) from .widgets import object_w_content_type_icon logger = logging.getLogger(__name__) def _permission_titles(permission_list): return u', '.join([unicode(permission) for permission in permission_list]) def acl_list_for(request, obj, extra_context=None): try: Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) except PermissionDenied: AccessEntry.objects.check_access(ACLS_VIEW_ACL, request.user, obj) logger.debug('obj: %s' % obj) context = { 'object_list': AccessEntry.objects.get_holders_for(obj), 'title': _(u'access control lists for: %s' % obj), 'extra_columns': [ {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object, db_only=True)))}, ], 'hide_object': True, 'access_object': AccessObject.encapsulate(obj), 'object': obj, 'navigation_object_list': [ {'object': 'object'}, {'object': 'access_object'} ], } if extra_context: context.update(extra_context) return render_to_response('generic_list.html', context, context_instance=RequestContext(request)) def acl_list(request, app_label, model_name, object_id): ct = get_object_or_404(ContentType, app_label=app_label, model=model_name) obj = get_object_or_404(ct.get_object_for_this_type, pk=object_id) return acl_list_for(request, obj) def acl_detail(request, access_object_gid, holder_object_gid): try: holder = AccessHolder.get(gid=holder_object_gid) access_object = AccessObject.get(gid=access_object_gid) except ObjectDoesNotExist: raise Http404 # return acl_detail_for(request, holder.source_object, access_object.source_object) return acl_detail_for(request, holder, access_object) def acl_detail_for(request, actor, obj): try: Permission.objects.check_permissions(request.user, [ACLS_VIEW_ACL]) except PermissionDenied: AccessEntry.objects.check_accesses([ACLS_VIEW_ACL], actor, obj) permission_list = get_class_permissions_for(obj.source_object) # TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { 'name': u'generic_list_subtemplate.html', 'context': { 'title': _(u'permissions available to: %(actor)s for %(obj)s' % { 'actor': actor, 'obj': obj } ), 'object_list': permission_list, 'extra_columns': [ {'name': _(u'namespace'), 'attribute': 'namespace'}, {'name': _(u'label'), 'attribute': 'label'}, { 'name': _(u'has permission'), 'attribute': encapsulate(lambda permission: two_state_template(AccessEntry.objects.has_access(permission, actor, obj, db_only=True))) }, ], 'hide_object': True, } }, ] context = { 'object': obj.source_object, 'subtemplates_list': subtemplates_list, 'multi_select_as_buttons': True, 'multi_select_item_properties': { 'permission_pk': lambda x: x.pk, 'holder_gid': lambda x: actor.gid, 'object_gid': lambda x: obj.gid, }, 'access_object': obj, 'navigation_object_list': [ {'object': 'object'}, {'object': 'access_object'} ], } return render_to_response( 'generic_detail.html', context, context_instance=RequestContext(request) ) def acl_grant(request): items_property_list = loads(request.GET.get('items_property_list', [])) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) items = {} title_suffix = [] navigation_object = None navigation_object_count = 0 for item_properties in items_property_list: try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object = AccessObject.get(gid=item_properties['object_gid']) except ObjectDoesNotExist: raise Http404 try: Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) except PermissionDenied: try: AccessEntry.objects.check_access(ACLS_EDIT_ACL, request.user, access_object) except PermissionDenied: raise else: items.setdefault(requester, {}) items[requester].setdefault(access_object, []) items[requester][access_object].append(permission) navigation_object = access_object navigation_object_count += 1 else: items.setdefault(requester, {}) items[requester].setdefault(access_object, []) items[requester][access_object].append(permission) navigation_object = access_object navigation_object_count += 1 for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' to %s') % requester) if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to grant the permission %(title_suffix)s?') else: title_prefix = _(u'Are you sure you wish to grant the permissions %(title_suffix)s?') if request.method == 'POST': for requester, object_permissions in items.items(): for obj, permissions in object_permissions.items(): for permission in permissions: if AccessEntry.objects.grant(permission, requester.source_object, obj.source_object): messages.success(request, _(u'Permission "%(permission)s" granted to %(actor)s for %(object)s.') % { 'permission': permission, 'actor': requester, 'object': obj }) else: messages.warning(request, _(u'%(actor)s, already had the permission "%(permission)s" granted for %(object)s.') % { 'actor': requester, 'permission': permission, 'object': obj, }) return HttpResponseRedirect(next) context = { 'delete_view': True, 'previous': previous, 'next': next, 'form_icon': u'key_add.png', } context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: context['object'] = navigation_object.source_object return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) def acl_revoke(request): items_property_list = loads(request.GET.get('items_property_list', [])) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) items = {} title_suffix = [] navigation_object = None navigation_object_count = 0 for item_properties in items_property_list: try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object = AccessObject.get(gid=item_properties['object_gid']) except ObjectDoesNotExist: raise Http404 try: Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) except PermissionDenied: try: AccessEntry.objects.check_access(ACLS_EDIT_ACL, request.user, access_object) except PermissionDenied: raise else: items.setdefault(requester, {}) items[requester].setdefault(access_object, []) items[requester][access_object].append(permission) navigation_object = access_object navigation_object_count += 1 else: items.setdefault(requester, {}) items[requester].setdefault(access_object, []) items[requester][access_object].append(permission) navigation_object = access_object navigation_object_count += 1 for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' from %s') % requester) if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to revoke the permission %(title_suffix)s?') else: title_prefix = _(u'Are you sure you wish to revoke the permissions %(title_suffix)s?') if request.method == 'POST': for requester, object_permissions in items.items(): for obj, permissions in object_permissions.items(): for permission in permissions: if AccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): messages.success(request, _(u'Permission "%(permission)s" revoked of %(actor)s for %(object)s.') % { 'permission': permission, 'actor': requester, 'object': obj }) else: messages.warning(request, _(u'%(actor)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { 'actor': requester, 'permission': permission, 'object': obj, }) return HttpResponseRedirect(next) context = { 'delete_view': True, 'previous': previous, 'next': next, 'form_icon': u'key_delete.png', } context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: context['object'] = navigation_object.source_object return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) def acl_new_holder_for(request, obj, extra_context=None, navigation_object=None): try: Permission.objects.check_permissions(request.user, [ACLS_EDIT_ACL]) except PermissionDenied: AccessEntry.objects.check_access(ACLS_EDIT_ACL, request.user, obj) if request.method == 'POST': form = HolderSelectionForm(request.POST) if form.is_valid(): try: access_object = AccessObject.encapsulate(obj) access_holder = AccessHolder.get(form.cleaned_data['holder_gid']) query_string = {u'navigation_object': navigation_object} return HttpResponseRedirect( u'%s?%s' % ( reverse('acl_detail', args=[access_object.gid, access_holder.gid]), urlencode(query_string) ) ) except ObjectDoesNotExist: raise Http404 else: form = HolderSelectionForm() context = { 'form': form, 'title': _(u'add new holder for: %s') % obj, 'submit_label': _(u'Select'), 'submit_icon_famfam': 'tick', 'object': obj, 'access_object': AccessObject.encapsulate(obj), 'navigation_object_list': [ {'object': 'object'}, {'object': 'access_object'}, ], } if extra_context: context.update(extra_context) return render_to_response('generic_form.html', context, context_instance=RequestContext(request)) def acl_holder_new(request, access_object_gid): try: access_object = AccessObject.get(gid=access_object_gid) except ObjectDoesNotExist: raise Http404 return acl_new_holder_for(request, access_object.source_object) # , extra_context={'access_object': access_object}) # Setup views def acl_setup_valid_classes(request): Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL]) context = { 'object_list': DefaultAccessEntry.get_classes(), 'title': _(u'classes'), 'extra_columns': [ {'name': _(u'class'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, ], 'hide_object': True, } return render_to_response('generic_list.html', context, context_instance=RequestContext(request)) def acl_class_acl_list(request, access_object_class_gid): logger.debug('access_object_class_gid: %s' % access_object_class_gid) Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL]) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) logger.debug('access_object_class: %s' % access_object_class) context = { 'object_list': DefaultAccessEntry.objects.get_holders_for(access_object_class.source_object), 'title': _(u'default access control lists for class: %s') % access_object_class, 'extra_columns': [ {'name': _(u'holder'), 'attribute': encapsulate(lambda x: object_w_content_type_icon(x.source_object))}, {'name': _(u'permissions'), 'attribute': encapsulate(lambda x: _permission_titles(DefaultAccessEntry.objects.get_holder_permissions_for(access_object_class.source_object, x.source_object)))}, ], 'hide_object': True, 'access_object_class': access_object_class, 'object': access_object_class, } return render_to_response('generic_list.html', context, context_instance=RequestContext(request)) def acl_class_acl_detail(request, access_object_class_gid, holder_object_gid): Permission.objects.check_permissions(request.user, [ACLS_CLASS_VIEW_ACL]) try: actor = AccessHolder.get(gid=holder_object_gid) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) except ObjectDoesNotExist: raise Http404 permission_list = get_class_permissions_for(access_object_class.content_type.model_class()) # TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware) subtemplates_list = [ { 'name': u'generic_list_subtemplate.html', 'context': { 'title': _(u'permissions available to: %(actor)s for class %(class)s' % { 'actor': actor, 'class': access_object_class } ), 'object_list': permission_list, 'extra_columns': [ {'name': _(u'namespace'), 'attribute': 'namespace'}, {'name': _(u'label'), 'attribute': 'label'}, { 'name': _(u'has permission'), 'attribute': encapsulate(lambda x: two_state_template(DefaultAccessEntry.objects.has_access(x, actor.source_object, access_object_class.source_object))) }, ], 'hide_object': True, } }, ] return render_to_response('generic_detail.html', { 'object': access_object_class, 'subtemplates_list': subtemplates_list, 'multi_select_as_buttons': True, 'multi_select_item_properties': { 'permission_pk': lambda x: x.pk, 'holder_gid': lambda x: actor.gid, 'access_object_class_gid': lambda x: access_object_class.gid, }, }, context_instance=RequestContext(request)) def acl_class_new_holder_for(request, access_object_class_gid): Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) access_object_class = AccessObjectClass.get(gid=access_object_class_gid) if request.method == 'POST': form = ClassHolderSelectionForm(request.POST) if form.is_valid(): try: access_holder = ClassAccessHolder.get(form.cleaned_data['holder_gid']) return HttpResponseRedirect(reverse('acl_class_acl_detail', args=[access_object_class.gid, access_holder.gid])) except ObjectDoesNotExist: raise Http404 else: form = ClassHolderSelectionForm(current_holders=DefaultAccessEntry.objects.get_holders_for(access_object_class)) context = { 'form': form, 'title': _(u'add new holder for class: %s') % unicode(access_object_class), 'object': access_object_class, 'submit_label': _(u'Select'), 'submit_icon_famfam': 'tick' } return render_to_response('generic_form.html', context, context_instance=RequestContext(request)) def acl_class_multiple_grant(request): Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) items = {} title_suffix = [] navigation_object = None navigation_object_count = 0 for item_properties in items_property_list: try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object_class = AccessObjectClass.get(gid=item_properties['access_object_class_gid']) except ObjectDoesNotExist: raise Http404 items.setdefault(requester, {}) items[requester].setdefault(access_object_class, []) items[requester][access_object_class].append(permission) navigation_object = access_object_class navigation_object_count += 1 for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' to %s') % requester) if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to grant the permission %(title_suffix)s?') else: title_prefix = _(u'Are you sure you wish to grant the permissions %(title_suffix)s?') if request.method == 'POST': for requester, object_permissions in items.items(): for obj, permissions in object_permissions.items(): for permission in permissions: if DefaultAccessEntry.objects.grant(permission, requester.source_object, obj.source_object): messages.success(request, _(u'Permission "%(permission)s" granted to %(actor)s for %(object)s.') % { 'permission': permission, 'actor': requester, 'object': obj }) else: messages.warning(request, _(u'%(actor)s, already had the permission "%(permission)s" granted for %(object)s.') % { 'actor': requester, 'permission': permission, 'object': obj, }) return HttpResponseRedirect(next) context = { 'delete_view': True, 'previous': previous, 'next': next, 'form_icon': u'key_add.png', } context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: context['object'] = navigation_object return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request)) def acl_class_multiple_revoke(request): Permission.objects.check_permissions(request.user, [ACLS_CLASS_EDIT_ACL]) items_property_list = loads(request.GET.get('items_property_list', [])) next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', '/'))) previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', '/'))) items = {} title_suffix = [] navigation_object = None navigation_object_count = 0 for item_properties in items_property_list: try: permission = Permission.objects.get({'pk': item_properties['permission_pk']}) except Permission.DoesNotExist: raise Http404 try: requester = AccessHolder.get(gid=item_properties['holder_gid']) access_object_class = AccessObjectClass.get(gid=item_properties['access_object_class_gid']) except ObjectDoesNotExist: raise Http404 items.setdefault(requester, {}) items[requester].setdefault(access_object_class, []) items[requester][access_object_class].append(permission) navigation_object = access_object_class navigation_object_count += 1 for requester, obj_ps in items.items(): for obj, ps in obj_ps.items(): title_suffix.append(_(u', ').join([u'"%s"' % unicode(p) for p in ps])) title_suffix.append(_(u' for %s') % obj) title_suffix.append(_(u' from %s') % requester) if len(items_property_list) == 1: title_prefix = _(u'Are you sure you wish to revoke the permission %(title_suffix)s?') else: title_prefix = _(u'Are you sure you wish to revoke the permissions %(title_suffix)s?') if request.method == 'POST': for requester, object_permissions in items.items(): for obj, permissions in object_permissions.items(): for permission in permissions: if DefaultAccessEntry.objects.revoke(permission, requester.source_object, obj.source_object): messages.success(request, _(u'Permission "%(permission)s" revoked of %(actor)s for %(object)s.') % { 'permission': permission, 'actor': requester, 'object': obj }) else: messages.warning(request, _(u'%(actor)s, didn\'t had the permission "%(permission)s" for %(object)s.') % { 'actor': requester, 'permission': permission, 'object': obj, }) return HttpResponseRedirect(next) context = { 'delete_view': True, 'previous': previous, 'next': next, 'form_icon': u'key_delete.png', } context['title'] = title_prefix % { 'title_suffix': u''.join(title_suffix), } logger.debug('navigation_object_count: %d' % navigation_object_count) logger.debug('navigation_object: %s' % navigation_object) if navigation_object_count == 1: context['object'] = navigation_object return render_to_response('generic_confirm.html', context, context_instance=RequestContext(request))