diff --git a/mayan/apps/appearance/templates/appearance/generic_multiform_subtemplate.html b/mayan/apps/appearance/templates/appearance/generic_multiform_subtemplate.html
index 6bd10457bb..02cd08dcf8 100644
--- a/mayan/apps/appearance/templates/appearance/generic_multiform_subtemplate.html
+++ b/mayan/apps/appearance/templates/appearance/generic_multiform_subtemplate.html
@@ -1,9 +1,9 @@
{% load i18n %}
{% load static %}
-
diff --git a/mayan/apps/checkouts/views.py b/mayan/apps/checkouts/views.py
index aaefb668cb..39a5e76f70 100644
--- a/mayan/apps/checkouts/views.py
+++ b/mayan/apps/checkouts/views.py
@@ -33,7 +33,7 @@ class CheckoutListView(DocumentListView):
'title': _('Documents checked out'),
'hide_links': True,
'extra_columns': [
- {'name': _('Checkout user'), 'attribute': encapsulate(lambda document: get_object_name(document.checkout_info().user))},
+ {'name': _('User'), 'attribute': encapsulate(lambda document: get_object_name(document.checkout_info().user))},
{'name': _('Checkout time and date'), 'attribute': encapsulate(lambda document: document.checkout_info().checkout_datetime)},
{'name': _('Checkout expiration'), 'attribute': encapsulate(lambda document: document.checkout_info().expiration_datetime)},
],
diff --git a/mayan/apps/permissions/admin.py b/mayan/apps/permissions/admin.py
index 9d40c1820e..56aa392603 100644
--- a/mayan/apps/permissions/admin.py
+++ b/mayan/apps/permissions/admin.py
@@ -2,32 +2,13 @@ from __future__ import unicode_literals
from django.contrib import admin
-from .models import StoredPermission, PermissionHolder, Role, RoleMember
+from .models import StoredPermission, Role
-class PermissionHolderInline(admin.StackedInline):
- model = PermissionHolder
- extra = 1
- classes = ('collapse-open',)
- allow_add = True
-
-
-class PermissionAdmin(admin.ModelAdmin):
- inlines = [PermissionHolderInline]
+class StoredPermissionAdmin(admin.ModelAdmin):
list_display = ('namespace', 'name')
list_display_links = list_display
-class RoleMemberInline(admin.StackedInline):
- model = RoleMember
- extra = 1
- classes = ('collapse-open',)
- allow_add = True
-
-
-class RoleAdmin(admin.ModelAdmin):
- inlines = [RoleMemberInline]
-
-
-admin.site.register(StoredPermission, PermissionAdmin)
-admin.site.register(Role, RoleAdmin)
+admin.site.register(StoredPermission, StoredPermissionAdmin)
+admin.site.register(Role)
diff --git a/mayan/apps/permissions/classes.py b/mayan/apps/permissions/classes.py
index 4e43f642bf..dea83a4725 100644
--- a/mayan/apps/permissions/classes.py
+++ b/mayan/apps/permissions/classes.py
@@ -12,15 +12,29 @@ class Member(EncapsulatedObject):
class PermissionNamespace(object):
+ _registry = {}
+
+ @classmethod
+ def all(cls):
+ return cls._registry.values()
+
+ @classmethod
+ def get(cls, name):
+ return cls._registry[name]
+
def __init__(self, name, label):
self.name = name
self.label = label
+ self.permissions = []
+ self.__class__._registry[name] = self
def __unicode__(self):
return unicode(self.label)
def add_permission(self, name, label):
- return Permission(namespace=self, name=name, label=label)
+ permission = Permission(namespace=self, name=name, label=label)
+ self.permissions.append(permission)
+ return permission
class Permission(object):
diff --git a/mayan/apps/permissions/migrations/0002_auto_20150628_0533.py b/mayan/apps/permissions/migrations/0002_auto_20150628_0533.py
new file mode 100644
index 0000000000..66066026fa
--- /dev/null
+++ b/mayan/apps/permissions/migrations/0002_auto_20150628_0533.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('auth', '0001_initial'),
+ ('permissions', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='permissionholder',
+ name='holder_type',
+ ),
+ migrations.RemoveField(
+ model_name='permissionholder',
+ name='permission',
+ ),
+ migrations.DeleteModel(
+ name='PermissionHolder',
+ ),
+ migrations.RemoveField(
+ model_name='rolemember',
+ name='member_type',
+ ),
+ migrations.RemoveField(
+ model_name='rolemember',
+ name='role',
+ ),
+ migrations.DeleteModel(
+ name='RoleMember',
+ ),
+ migrations.AddField(
+ model_name='role',
+ name='groups',
+ field=models.ManyToManyField(related_name='roles', verbose_name='Groups', to='auth.Group'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='role',
+ name='permissions',
+ field=models.ManyToManyField(related_name='roles', verbose_name='Permissions', to='permissions.StoredPermission'),
+ preserve_default=True,
+ ),
+ ]
diff --git a/mayan/apps/permissions/models.py b/mayan/apps/permissions/models.py
index a723eecf45..18960ad9b8 100644
--- a/mayan/apps/permissions/models.py
+++ b/mayan/apps/permissions/models.py
@@ -2,7 +2,7 @@ from __future__ import unicode_literals
import logging
-from django.contrib.auth.models import User
+from django.contrib.auth.models import Group, User
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
@@ -12,7 +12,7 @@ from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _
-from common.models import AnonymousUserSingleton
+#from common.models import AnonymousUserSingleton
from .managers import RoleMemberManager, StoredPermissionManager
@@ -47,10 +47,12 @@ class StoredPermission(models.Model):
return unicode(getattr(self, 'volatile_permission', self.name))
def get_holders(self):
- return (holder.holder_object for holder in self.permissionholder_set.all())
+ return self.roles.all()
+ #return (holder.holder_object for holder in self.permissionholder_set.all())
def requester_has_this(self, actor):
- actor = AnonymousUserSingleton.objects.passthru_check(actor)
+ #actor = AnonymousUserSingleton.objects.passthru_check(actor)
+
logger.debug('actor: %s', actor)
if isinstance(actor, User):
if actor.is_superuser or actor.is_staff:
@@ -92,6 +94,7 @@ class StoredPermission(models.Model):
return True
+"""
@python_2_unicode_compatible
class PermissionHolder(models.Model):
permission = models.ForeignKey(StoredPermission, verbose_name=_('Permission'))
@@ -107,12 +110,14 @@ class PermissionHolder(models.Model):
def __str__(self):
return '%s: %s' % (self.holder_type, self.holder_object)
-
+"""
@python_2_unicode_compatible
class Role(models.Model):
name = models.CharField(max_length=64, unique=True)
label = models.CharField(max_length=64, unique=True, verbose_name=_('Label'))
+ permissions = models.ManyToManyField(StoredPermission, related_name='roles', verbose_name=_('Permissions'))
+ groups = models.ManyToManyField(Group, related_name='roles', verbose_name=_('Groups'))
class Meta:
ordering = ('label',)
@@ -125,6 +130,7 @@ class Role(models.Model):
def get_absolute_url(self):
return reverse('permissions:role_list')
+ """
def add_member(self, member):
member = AnonymousUserSingleton.objects.passthru_check(member)
role_member, created = RoleMember.objects.get_or_create(
@@ -143,8 +149,9 @@ class Role(models.Model):
def members(self, filter_dict=None):
filter_dict = filter_dict or {}
return (member.member_object for member in self.rolemember_set.filter(**filter_dict))
+ """
-
+ """
@python_2_unicode_compatible
class RoleMember(models.Model):
role = models.ForeignKey(Role, verbose_name=_('Role'))
@@ -168,3 +175,4 @@ class RoleMember(models.Model):
def __str__(self):
return unicode(self.member_object)
+ """
diff --git a/mayan/apps/permissions/urls.py b/mayan/apps/permissions/urls.py
index a067a8dbde..1370c19ec7 100644
--- a/mayan/apps/permissions/urls.py
+++ b/mayan/apps/permissions/urls.py
@@ -4,20 +4,18 @@ from django.conf.urls import patterns, url
from .api_views import APIRoleListView, APIRoleView
from .views import (
- RoleCreateView, RoleDeleteView, RoleEditView, SetupRoleMembersView
+ RoleCreateView, RoleDeleteView, RoleEditView, SetupRoleMembersView,
+ SetupRolePermissionsView
)
urlpatterns = patterns(
'permissions.views',
url(r'^role/list/$', 'role_list', name='role_list'),
url(r'^role/create/$', RoleCreateView.as_view(), name='role_create'),
- url(r'^role/(?P
\d+)/permissions/$', 'role_permissions', name='role_permissions'),
+ url(r'^role/(?P\d+)/permissions/$', SetupRolePermissionsView.as_view(), name='role_permissions'),
url(r'^role/(?P\d+)/edit/$', RoleEditView.as_view(), name='role_edit'),
url(r'^role/(?P\d+)/delete/$', RoleDeleteView.as_view(), name='role_delete'),
url(r'^role/(?P\d+)/members/$', SetupRoleMembersView.as_view(), name='role_members'),
-
- url(r'^permissions/multiple/grant/$', 'permission_grant', name='permission_multiple_grant'),
- url(r'^permissions/multiple/revoke/$', 'permission_revoke', name='permission_multiple_revoke'),
)
api_urls = patterns(
diff --git a/mayan/apps/permissions/views.py b/mayan/apps/permissions/views.py
index 9e14d01d45..2597b7dff8 100644
--- a/mayan/apps/permissions/views.py
+++ b/mayan/apps/permissions/views.py
@@ -5,6 +5,7 @@ from json import loads
import operator
from django.contrib import messages
+from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
@@ -21,9 +22,9 @@ from common.views import (
from common.utils import encapsulate
from common.widgets import two_state_template
-from .classes import Member, Permission
+from .classes import Member, Permission, PermissionNamespace
from .forms import RoleForm, RoleForm_view
-from .models import Role
+from .models import Role, StoredPermission
from .permissions import (
permission_permission_grant, permission_permission_revoke,
permission_role_view, permission_role_create, permission_role_delete,
@@ -51,34 +52,84 @@ class RoleEditView(SingleObjectEditView):
class SetupRoleMembersView(AssignRemoveView):
- grouped = True
+ grouped = False
def add(self, item):
- member = Member.get(item).source_object
- self.role.add_member(member)
+ group = get_object_or_404(Group, pk=item)
+ self.role.groups.add(group)
def dispatch(self, request, *args, **kwargs):
Permission.check_permissions(request.user, [permission_role_edit])
self.role = get_object_or_404(Role, pk=self.kwargs['role_id'])
- self.left_list_title = _('Non members of role: %s') % self.role
- self.right_list_title = _('Members of role: %s') % self.role
+ self.left_list_title = _('Available groups')
+ self.right_list_title = _('Member groups')
return super(SetupRoleMembersView, self).dispatch(request, *args, **kwargs)
def left_list(self):
- return get_non_role_members(self.role)
+ return [(unicode(group.pk), group.name) for group in set(Group.objects.all()) - set(self.role.groups.all())]
def right_list(self):
- return get_role_members(self.role)
+ return [(unicode(group.pk), group.name) for group in self.role.groups.all()]
def remove(self, item):
- member = Member.get(item).source_object
- self.role.remove_member(member)
+ group = get_object_or_404(Group, pk=item)
+ self.role.groups.remove(group)
def get_context_data(self, **kwargs):
data = super(SetupRoleMembersView, self).get_context_data(**kwargs)
data.update({
'object': self.role,
+ 'title': _('Group members of role: %s') % self.role
+ })
+
+ return data
+
+
+class SetupRolePermissionsView(AssignRemoveView):
+ grouped = True
+
+ @staticmethod
+ def as_choice_list(items):
+ return sorted([(item.pk, item) for item in items], key=lambda x: x[1])
+
+ def add(self, item):
+ permission = get_object_or_404(StoredPermission, pk=item)
+ self.role.permissions.add(permission)
+
+ def dispatch(self, request, *args, **kwargs):
+ Permission.check_permissions(request.user, [permission_permission_grant, permission_permission_revoke])
+ self.role = get_object_or_404(Role, pk=self.kwargs['pk'])
+ self.left_list_title = _('Available permissions')
+ self.right_list_title = _('Granted permissions')
+
+ return super(SetupRolePermissionsView, self).dispatch(request, *args, **kwargs)
+
+ def left_list(self):
+ results = []
+ for namespace, permissions in itertools.groupby(StoredPermission.objects.exclude(id__in=self.role.permissions.values_list('pk', flat=True)), lambda entry: entry.namespace):
+ permission_options = [(unicode(permission.pk), permission) for permission in permissions]
+ results.append((PermissionNamespace.get(namespace), permission_options))
+
+ return results
+
+ def right_list(self):
+ results = []
+ for namespace, permissions in itertools.groupby(self.role.permissions.all(), lambda entry: entry.namespace):
+ permission_options = [(unicode(permission.pk), permission) for permission in permissions]
+ results.append((PermissionNamespace.get(namespace), permission_options))
+
+ return results
+
+ def remove(self, item):
+ permission = get_object_or_404(StoredPermission, pk=item)
+ self.role.permissions.remove(permission)
+
+ def get_context_data(self, **kwargs):
+ data = super(SetupRolePermissionsView, self).get_context_data(**kwargs)
+ data.update({
+ 'object': self.role,
+ 'title': _('Permissions for role: %s') % self.role,
})
return data
@@ -123,123 +174,3 @@ def role_permissions(request, role_id):
'hide_link': True,
'hide_object': True,
}, context_instance=RequestContext(request))
-
-
-def permission_grant(request):
- Permission.check_permissions(request.user, [permission_permission_grant])
- items_property_list = loads(request.GET.get('items_property_list', []))
-
- next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
- previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
-
- items = []
- for item_properties in items_property_list:
- try:
- permission = Permission.get({'pk': item_properties['permission_id']})
- except Permission.DoesNotExist:
- raise Http404
-
- ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
- requester_model = ct.model_class()
- requester = get_object_or_404(requester_model, pk=item_properties['requester_id'])
- items.append({'requester': requester, 'permission': permission})
-
- sorted_items = sorted(items, key=operator.itemgetter('requester'))
- # Group items by requester
- groups = itertools.groupby(sorted_items, key=operator.itemgetter('requester'))
- grouped_items = [(grouper, [permission['permission'] for permission in group_data]) for grouper, group_data in groups]
-
- # Warning: trial and error black magic ahead
- title_suffix = _(' and ').join([_('%(permissions)s to %(requester)s') % {'permissions': ', '.join(['"%s"' % unicode(ps) for ps in p]), 'requester': unicode(r)} for r, p in grouped_items])
-
- if len(grouped_items) == 1 and len(grouped_items[0][1]) == 1:
- permissions_label = _('Permission')
- else:
- permissions_label = _('Permissions')
-
- if request.method == 'POST':
- for item in items:
- if item['permission'].grant_to(item['requester']):
- messages.success(request, _('Permission "%(permission)s" granted to: %(requester)s.') % {
- 'permission': item['permission'], 'requester': item['requester']})
- else:
- messages.warning(request, _('%(requester)s, already had the permission "%(permission)s" granted.') % {
- 'requester': item['requester'], 'permission': item['permission']})
-
- return HttpResponseRedirect(next)
-
- context = {
- 'previous': previous,
- 'next': next,
- }
-
- context['title'] = _('Are you sure you wish to grant the %(permissions_label)s %(title_suffix)s?') % {
- 'permissions_label': permissions_label,
- 'title_suffix': title_suffix,
- }
-
- if len(grouped_items) == 1:
- context['object'] = grouped_items[0][0]
-
- return render_to_response('appearance/generic_confirm.html', context,
- context_instance=RequestContext(request))
-
-
-def permission_revoke(request):
- Permission.check_permissions(request.user, [permission_permission_revoke])
- items_property_list = loads(request.GET.get('items_property_list', []))
-
- next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', None)))
- previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', None)))
-
- items = []
- for item_properties in items_property_list:
- try:
- permission = Permission.get({'pk': item_properties['permission_id']})
- except Permission.DoesNotExist:
- raise Http404
-
- ct = get_object_or_404(ContentType, app_label=item_properties['requester_app_label'], model=item_properties['requester_model'])
- requester_model = ct.model_class()
- requester = get_object_or_404(requester_model, pk=item_properties['requester_id'])
- items.append({'requester': requester, 'permission': permission})
-
- sorted_items = sorted(items, key=operator.itemgetter('requester'))
- # Group items by requester
- groups = itertools.groupby(sorted_items, key=operator.itemgetter('requester'))
- grouped_items = [(grouper, [permission['permission'] for permission in group_data]) for grouper, group_data in groups]
-
- # Warning: trial and error black magic ahead
- title_suffix = _(' and ').join([_('%(permissions)s to %(requester)s') % {'permissions': ', '.join(['"%s"' % unicode(ps) for ps in p]), 'requester': unicode(r)} for r, p in grouped_items])
-
- if len(grouped_items) == 1 and len(grouped_items[0][1]) == 1:
- permissions_label = _('permission')
- else:
- permissions_label = _('permissions')
-
- if request.method == 'POST':
- for item in items:
- if item['permission'].revoke_from(item['requester']):
- messages.success(request, _('Permission "%(permission)s" revoked from: %(requester)s.') % {
- 'permission': item['permission'], 'requester': item['requester']})
- else:
- messages.warning(request, _('%(requester)s, doesn\'t have the permission "%(permission)s" granted.') % {
- 'requester': item['requester'], 'permission': item['permission']})
-
- return HttpResponseRedirect(next)
-
- context = {
- 'previous': previous,
- 'next': next,
- }
-
- context['title'] = _('Are you sure you wish to revoke the %(permissions_label)s %(title_suffix)s?') % {
- 'permissions_label': permissions_label,
- 'title_suffix': title_suffix,
- }
-
- if len(grouped_items) == 1:
- context['object'] = grouped_items[0][0]
-
- return render_to_response('appearance/generic_confirm.html', context,
- context_instance=RequestContext(request))
diff --git a/mayan/apps/sources/views.py b/mayan/apps/sources/views.py
index 451d89980c..ed44517233 100644
--- a/mayan/apps/sources/views.py
+++ b/mayan/apps/sources/views.py
@@ -157,14 +157,15 @@ class UploadBaseView(MultiFormView):
'name': 'appearance/generic_multiform_subtemplate.html',
'context': {
'forms': context['forms'],
+ 'title': _('Document properties'),
}
},
{
'name': 'appearance/generic_list_subtemplate.html',
'context': {
- 'title': _('Files in staging path'),
- 'object_list': staging_filelist,
'hide_link': True,
+ 'object_list': staging_filelist,
+ 'title': _('Files in staging path'),
}
},
]
@@ -173,7 +174,8 @@ class UploadBaseView(MultiFormView):
'name': 'appearance/generic_multiform_subtemplate.html',
'context': {
'forms': context['forms'],
- 'is_multipart': True
+ 'is_multipart': True,
+ 'title': _('Document properties'),
},
})