Backport ACL computation improvements
Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
10
HISTORY.rst
10
HISTORY.rst
@@ -212,6 +212,16 @@
|
||||
* Add new app to handle all dependencies.
|
||||
* Remove the licenses.py module and replace
|
||||
it with a dependencies.py module.
|
||||
* Backport ACL computation improvements.
|
||||
* Remove model permission proxy models.
|
||||
* Remove related access control argument. This is
|
||||
now handled by the related field registration.
|
||||
* Allow nested access control checking.
|
||||
* check_access's permissions argument must now be
|
||||
an interable.
|
||||
* Remove permissions_related from links.
|
||||
* Remove mayan_permission_attribute_check from
|
||||
API permission.
|
||||
|
||||
3.1.11 (2019-04-XX)
|
||||
===================
|
||||
|
||||
@@ -245,6 +245,16 @@ Other changes
|
||||
* Add new app to handle all dependencies.
|
||||
* Remove the licenses.py module and replace
|
||||
it with a dependencies.py module.
|
||||
* Backport ACL computation improvements.
|
||||
* Remove model permission proxy models.
|
||||
* Remove related access control argument. This is
|
||||
now handled by the related field registration.
|
||||
* Allow nested access control checking.
|
||||
* check_access's permissions argument must now be
|
||||
an interable.
|
||||
* Remove permissions_related from links.
|
||||
* Remove mayan_permission_attribute_check from
|
||||
API permission.
|
||||
|
||||
Removals
|
||||
--------
|
||||
|
||||
@@ -35,8 +35,8 @@ class APIObjectACLListView(generics.ListCreateAPIView):
|
||||
permission_required = permission_acl_edit
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=content_object
|
||||
obj=content_object, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return content_object
|
||||
@@ -94,8 +94,8 @@ class APIObjectACLView(generics.RetrieveDestroyAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=content_object
|
||||
obj=content_object, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return content_object
|
||||
@@ -130,7 +130,8 @@ class APIObjectACLPermissionListView(generics.ListCreateAPIView):
|
||||
permission = permission_acl_edit
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=content_object, permissions=permission, user=self.request.user
|
||||
obj=content_object, permissions=(permission,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return content_object
|
||||
@@ -191,7 +192,8 @@ class APIObjectACLPermissionView(generics.RetrieveDestroyAPIView):
|
||||
permission = permission_acl_edit
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=content_object, permissions=permission, user=self.request.user
|
||||
obj=content_object, permissions=(permission,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return content_object
|
||||
|
||||
@@ -10,6 +10,7 @@ from mayan.apps.events.links import (
|
||||
)
|
||||
from mayan.apps.navigation.classes import SourceColumn
|
||||
|
||||
from .classes import ModelPermission
|
||||
from .events import event_acl_created, event_acl_edited
|
||||
from .links import link_acl_create, link_acl_delete, link_acl_permissions
|
||||
|
||||
@@ -33,6 +34,10 @@ class ACLsApp(MayanAppConfig):
|
||||
model=AccessControlList
|
||||
)
|
||||
|
||||
ModelPermission.register_inheritance(
|
||||
model=AccessControlList, related='content_object',
|
||||
)
|
||||
|
||||
SourceColumn(
|
||||
attribute='role', is_sortable=True, source=AccessControlList,
|
||||
)
|
||||
|
||||
@@ -8,8 +8,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ModelPermission(object):
|
||||
_functions = {}
|
||||
_inheritances = {}
|
||||
_proxies = {}
|
||||
_registry = {}
|
||||
|
||||
@classmethod
|
||||
@@ -63,24 +63,23 @@ class ModelPermission(object):
|
||||
if class_permissions:
|
||||
permissions.extend(class_permissions)
|
||||
|
||||
proxy = cls._proxies.get(type(instance))
|
||||
|
||||
if proxy:
|
||||
permissions.extend(cls._registry.get(proxy))
|
||||
|
||||
pks = [
|
||||
permission.stored_permission.pk for permission in set(permissions)
|
||||
]
|
||||
return StoredPermission.objects.filter(pk__in=pks)
|
||||
|
||||
@classmethod
|
||||
def register_proxy(cls, source, model):
|
||||
cls._proxies[model] = source
|
||||
|
||||
@classmethod
|
||||
def register_inheritance(cls, model, related):
|
||||
cls._inheritances[model] = related
|
||||
def get_function(cls, model):
|
||||
return cls._functions[model]
|
||||
|
||||
@classmethod
|
||||
def get_inheritance(cls, model):
|
||||
return cls._inheritances[model]
|
||||
|
||||
@classmethod
|
||||
def register_function(cls, model, function):
|
||||
cls._functions[model] = function
|
||||
|
||||
@classmethod
|
||||
def register_inheritance(cls, model, related):
|
||||
cls._inheritances[model] = related
|
||||
|
||||
@@ -29,23 +29,22 @@ def get_kwargs_factory(variable_name):
|
||||
return get_kwargs
|
||||
|
||||
|
||||
link_acl_delete = Link(
|
||||
args='resolved_object.pk', icon_class=icon_acl_delete,
|
||||
permissions=(permission_acl_edit,), permissions_related='content_object',
|
||||
tags='dangerous', text=_('Delete'), view='acls:acl_delete',
|
||||
)
|
||||
link_acl_list = Link(
|
||||
icon_class=icon_acl_list, kwargs=get_kwargs_factory('resolved_object'),
|
||||
permissions=(permission_acl_view,), text=_('ACLs'), view='acls:acl_list'
|
||||
)
|
||||
link_acl_create = Link(
|
||||
icon_class=icon_acl_new, kwargs=get_kwargs_factory('resolved_object'),
|
||||
permissions=(permission_acl_edit,), text=_('New ACL'),
|
||||
view='acls:acl_create'
|
||||
)
|
||||
link_acl_delete = Link(
|
||||
args='resolved_object.pk', icon_class=icon_acl_delete,
|
||||
permissions=(permission_acl_edit,), tags='dangerous', text=_('Delete'),
|
||||
view='acls:acl_delete'
|
||||
)
|
||||
link_acl_list = Link(
|
||||
icon_class=icon_acl_list, kwargs=get_kwargs_factory('resolved_object'),
|
||||
permissions=(permission_acl_view,), text=_('ACLs'), view='acls:acl_list'
|
||||
)
|
||||
link_acl_permissions = Link(
|
||||
args='resolved_object.pk', icon_class=icon_acl_permissions,
|
||||
permissions=(permission_acl_edit,),
|
||||
permissions_related='content_object', text=_('Permissions'),
|
||||
view='acls:acl_permissions',
|
||||
text=_('Permissions'), view='acls:acl_permissions'
|
||||
)
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from functools import reduce
|
||||
import logging
|
||||
import operator
|
||||
import warnings
|
||||
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.db.models import CharField, Value as V, Q
|
||||
from django.db.models.functions import Concat
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.translation import ugettext
|
||||
|
||||
from mayan.apps.common.utils import (
|
||||
resolve_attribute, return_attrib, return_related
|
||||
get_related_field, resolve_attribute, return_related
|
||||
)
|
||||
from mayan.apps.common.warnings import InterfaceWarning
|
||||
from mayan.apps.permissions import Permission
|
||||
from mayan.apps.permissions.models import StoredPermission
|
||||
|
||||
@@ -26,170 +32,235 @@ class AccessControlListManager(models.Manager):
|
||||
Implement a 3 tier permission system, involving a permissions, an actor
|
||||
and an object
|
||||
"""
|
||||
def check_access(self, permissions, user, obj, related=None):
|
||||
if user.is_superuser or user.is_staff:
|
||||
logger.debug(
|
||||
'Permissions "%s" on "%s" granted to user "%s" as superuser '
|
||||
'or staff', permissions, obj, user
|
||||
def _get_acl_filters(self, queryset, stored_permission, user, related_field_name=None):
|
||||
"""
|
||||
This method does the bulk of the work. It generates filters for the
|
||||
AccessControlList model to determine if there are ACL entries for the
|
||||
members of the queryset's model provided.
|
||||
"""
|
||||
# Determine which of the cases we need to address
|
||||
# 1: No related field
|
||||
# 2: Related field
|
||||
# 3: Related field that is Generic Foreign Key
|
||||
# 4: No related field, but has an inherited related field, solved by
|
||||
# recursion, branches to #2 or #3.
|
||||
# 5: Inherited field of a related field
|
||||
# -- Not addressed yet --
|
||||
# 6: Inherited field of a related field that is Generic Foreign Key
|
||||
# 7: Has a related function
|
||||
result = []
|
||||
|
||||
if related_field_name:
|
||||
related_field = get_related_field(
|
||||
model=queryset.model, related_field_name=related_field_name
|
||||
)
|
||||
return True
|
||||
|
||||
try:
|
||||
return Permission.check_permissions(
|
||||
permissions=permissions, user=user
|
||||
if isinstance(related_field, GenericForeignKey):
|
||||
# Case 3: Generic Foreign Key, multiple ContentTypes + object
|
||||
# id combinations
|
||||
content_type_object_id_queryset = queryset.annotate(
|
||||
ct_fk_combination=Concat(
|
||||
related_field.ct_field, V('-'), related_field.fk_field,
|
||||
output_field=CharField()
|
||||
)
|
||||
except PermissionDenied:
|
||||
try:
|
||||
stored_permissions = [
|
||||
permission.stored_permission for permission in permissions
|
||||
]
|
||||
except TypeError:
|
||||
# Not a list of permissions, just one
|
||||
stored_permissions = (permissions.stored_permission,)
|
||||
).values('ct_fk_combination')
|
||||
|
||||
if related:
|
||||
obj = return_attrib(obj, related)
|
||||
|
||||
try:
|
||||
parent_accessor = ModelPermission.get_inheritance(
|
||||
model=obj._meta.model
|
||||
acl_filter = self.annotate(
|
||||
ct_fk_combination=Concat(
|
||||
'content_type', V('-'), 'object_id', output_field=CharField()
|
||||
)
|
||||
except AttributeError:
|
||||
# AttributeError means non model objects: ie Statistics
|
||||
# These can't have ACLs so we raise PermissionDenied
|
||||
).filter(
|
||||
permissions=stored_permission, role__groups__user=user,
|
||||
ct_fk_combination__in=content_type_object_id_queryset
|
||||
).values('object_id')
|
||||
|
||||
# Force object to text to avoid UnicodeDecodeError
|
||||
raise PermissionDenied(
|
||||
ugettext('Insufficient access for: %s') % force_text(obj)
|
||||
field_lookup = 'object_id__in'
|
||||
|
||||
result.append(Q(**{field_lookup: acl_filter}))
|
||||
else:
|
||||
# Case 2: Related field of a single type, single ContentType,
|
||||
# multiple object id
|
||||
content_type = ContentType.objects.get_for_model(
|
||||
model=related_field.related_model
|
||||
)
|
||||
field_lookup = '{}_id__in'.format(related_field_name)
|
||||
acl_filter = self.filter(
|
||||
content_type=content_type, permissions=stored_permission,
|
||||
role__groups__user=user
|
||||
).values('object_id')
|
||||
# Don't add empty filters otherwise the default AND operator
|
||||
# of the Q object will return an empty queryset when reduced
|
||||
# and filter out objects that should be in the final queryset.
|
||||
if acl_filter:
|
||||
result.append(Q(**{field_lookup: acl_filter}))
|
||||
|
||||
# Case 5: Related field, has an inherited related field itself
|
||||
# Bubble up permssion check
|
||||
# TODO: Add relationship support: OR or AND
|
||||
# TODO: OR for document pages, version, doc, and types
|
||||
# TODO: AND for new cabinet levels ACLs
|
||||
try:
|
||||
related_field_model_related_fields = (
|
||||
ModelPermission.get_inheritance(
|
||||
model=related_field.related_model
|
||||
),
|
||||
)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
return self.check_access(
|
||||
obj=getattr(obj, parent_accessor),
|
||||
permissions=permissions, user=user
|
||||
relation_result = []
|
||||
for related_field_model_related_field_name in related_field_model_related_fields:
|
||||
related_field_name = '{}__{}'.format(related_field_name, related_field_model_related_field_name)
|
||||
related_field_inherited_acl_queries = self._get_acl_filters(
|
||||
queryset=queryset, stored_permission=stored_permission,
|
||||
user=user, related_field_name=related_field_name
|
||||
)
|
||||
except AttributeError:
|
||||
# Has no such attribute, try it as a related field
|
||||
if related_field_inherited_acl_queries:
|
||||
relation_result.append(reduce(operator.and_, related_field_inherited_acl_queries))
|
||||
|
||||
if relation_result:
|
||||
result.append(reduce(operator.or_, relation_result))
|
||||
else:
|
||||
# Case 1: Original model, single ContentType, multiple object id
|
||||
content_type = ContentType.objects.get_for_model(model=queryset.model)
|
||||
field_lookup = 'id__in'
|
||||
acl_filter = self.filter(
|
||||
content_type=content_type, permissions=stored_permission,
|
||||
role__groups__user=user
|
||||
).values('object_id')
|
||||
result.append(Q(**{field_lookup: acl_filter}))
|
||||
|
||||
# Case 4: Original model, has an inherited related field
|
||||
try:
|
||||
return self.check_access(
|
||||
obj=return_related(
|
||||
instance=obj, related_field=parent_accessor
|
||||
), permissions=permissions, user=user
|
||||
related_fields = (
|
||||
ModelPermission.get_inheritance(
|
||||
model=queryset.model
|
||||
),
|
||||
)
|
||||
except PermissionDenied:
|
||||
pass
|
||||
except PermissionDenied:
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
relation_result = []
|
||||
|
||||
user_roles = []
|
||||
for group in user.groups.all():
|
||||
for role in group.roles.all():
|
||||
if set(stored_permissions).intersection(set(self.get_inherited_permissions(role=role, obj=obj))):
|
||||
logger.debug(
|
||||
'Permissions "%s" on "%s" granted to user "%s" through role "%s" via inherited ACL',
|
||||
permissions, obj, user, role
|
||||
for related_field_name in related_fields:
|
||||
inherited_acl_queries = self._get_acl_filters(
|
||||
queryset=queryset, stored_permission=stored_permission,
|
||||
related_field_name=related_field_name, user=user
|
||||
)
|
||||
return True
|
||||
if inherited_acl_queries:
|
||||
relation_result.append(reduce(operator.and_, inherited_acl_queries))
|
||||
|
||||
user_roles.append(role)
|
||||
|
||||
if not self.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk, permissions__in=stored_permissions, role__in=user_roles).exists():
|
||||
logger.debug(
|
||||
'Permissions "%s" on "%s" denied for user "%s"',
|
||||
permissions, obj, user
|
||||
)
|
||||
raise PermissionDenied(
|
||||
ugettext('Insufficient access for: %s') % force_text(obj)
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
'Permissions "%s" on "%s" granted to user "%s" through roles "%s" by direct ACL',
|
||||
permissions, obj, user, user_roles
|
||||
)
|
||||
|
||||
def filter_by_access(self, permission, user, queryset):
|
||||
if user.is_superuser or user.is_staff:
|
||||
logger.debug(
|
||||
'Unfiltered queryset returned to user "%s" as superuser or staff',
|
||||
user
|
||||
)
|
||||
return queryset
|
||||
if relation_result:
|
||||
result.append(reduce(operator.or_, relation_result))
|
||||
|
||||
# Case 7: Has a function
|
||||
try:
|
||||
Permission.check_permissions(
|
||||
permissions=(permission,), user=user
|
||||
)
|
||||
except PermissionDenied:
|
||||
user_roles = []
|
||||
for group in user.groups.all():
|
||||
for role in group.roles.all():
|
||||
user_roles.append(role)
|
||||
|
||||
try:
|
||||
parent_accessor = ModelPermission.get_inheritance(
|
||||
field_query_function = ModelPermission.get_function(
|
||||
model=queryset.model
|
||||
)
|
||||
except KeyError:
|
||||
parent_acl_query = Q()
|
||||
else:
|
||||
instance = queryset.first()
|
||||
if instance:
|
||||
parent_object = return_related(
|
||||
instance=instance, related_field=parent_accessor
|
||||
)
|
||||
|
||||
try:
|
||||
# Try to see if parent_object is a function
|
||||
parent_object()
|
||||
except TypeError:
|
||||
# Is not a function, try it as a field
|
||||
parent_content_type = ContentType.objects.get_for_model(
|
||||
parent_object
|
||||
)
|
||||
parent_queryset = self.filter(
|
||||
content_type=parent_content_type, role__in=user_roles,
|
||||
permissions=permission.stored_permission
|
||||
)
|
||||
parent_acl_query = Q(
|
||||
**{
|
||||
'{}__pk__in'.format(
|
||||
parent_accessor
|
||||
): parent_queryset.values_list(
|
||||
'object_id', flat=True
|
||||
)
|
||||
}
|
||||
)
|
||||
else:
|
||||
# Is a function. Can't perform Q object filtering.
|
||||
# Perform iterative filtering.
|
||||
result = []
|
||||
for entry in queryset:
|
||||
try:
|
||||
self.check_access(permissions=permission, user=user, obj=entry)
|
||||
except PermissionDenied:
|
||||
pass
|
||||
else:
|
||||
result.append(entry.pk)
|
||||
function_results = field_query_function()
|
||||
|
||||
return queryset.filter(pk__in=result)
|
||||
else:
|
||||
parent_acl_query = Q()
|
||||
# Filter by the model's content type
|
||||
content_type = ContentType.objects.get_for_model(
|
||||
model=queryset.model
|
||||
)
|
||||
acl_filter = self.filter(
|
||||
content_type=content_type, permissions=stored_permission,
|
||||
role__groups__user=user
|
||||
).values('object_id')
|
||||
# Obtain an queryset of filtered, authorized model instances
|
||||
acl_queryset = queryset.model._meta.default_manager.filter(
|
||||
id__in=acl_filter
|
||||
).filter(**function_results['acl_filter'])
|
||||
|
||||
# Directly granted access
|
||||
content_type = ContentType.objects.get_for_model(queryset.model)
|
||||
acl_query = Q(pk__in=self.filter(
|
||||
content_type=content_type, role__in=user_roles,
|
||||
permissions=permission.stored_permission
|
||||
).values_list('object_id', flat=True))
|
||||
logger.debug(
|
||||
'Filtered queryset returned to user "%s" based on roles "%s"',
|
||||
user, user_roles
|
||||
if 'acl_values' in function_results:
|
||||
acl_queryset = acl_queryset.values(
|
||||
*function_results['acl_values']
|
||||
)
|
||||
|
||||
return queryset.filter(parent_acl_query | acl_query)
|
||||
# Get the final query using the filtered queryset as the
|
||||
# reference
|
||||
result.append(
|
||||
Q(**{function_results['field_lookup']: acl_queryset})
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
def check_access(self, obj, permissions, user, related=None):
|
||||
"""
|
||||
The `related` argument is ignored.
|
||||
"""
|
||||
if related:
|
||||
warnings.warn(
|
||||
'Passing the argument `related` to check_access() is '
|
||||
'deprecated. Use the ModelPermission\'s class '
|
||||
'.register_inheritance() class method to register the access '
|
||||
'relationship between two models. The registered relationship '
|
||||
'will be automatically used by check_access().',
|
||||
InterfaceWarning
|
||||
)
|
||||
|
||||
meta = getattr(obj, '_meta', None)
|
||||
|
||||
if not meta:
|
||||
logger.debug(
|
||||
ugettext(
|
||||
'Object "%s" is not a model and cannot be checked for '
|
||||
'access.'
|
||||
) % force_text(obj)
|
||||
)
|
||||
return True
|
||||
else:
|
||||
source_queryset = obj._meta.default_manager.all()
|
||||
|
||||
restricted_queryset = obj._meta.default_manager.none()
|
||||
for permission in permissions:
|
||||
# Default relationship betweens permissions is OR
|
||||
# TODO: Add support for AND relationship
|
||||
restricted_queryset = restricted_queryset | self.restrict_queryset(
|
||||
permission=permission, queryset=source_queryset, user=user
|
||||
)
|
||||
|
||||
if restricted_queryset.filter(pk=obj.pk).exists():
|
||||
return True
|
||||
else:
|
||||
raise PermissionDenied(
|
||||
ugettext(message='Insufficient access for: %s') % force_text(
|
||||
s=obj
|
||||
)
|
||||
)
|
||||
|
||||
def filter_by_access(self, permission, user, queryset):
|
||||
return self.restrict_queryset(
|
||||
permission=permission, queryset=queryset, user=user
|
||||
)
|
||||
|
||||
def restrict_queryset(self, permission, queryset, user):
|
||||
# Check directly granted permission via a role
|
||||
try:
|
||||
Permission.check_user_permissions(
|
||||
permissions=(permission,), user=user
|
||||
)
|
||||
except PermissionDenied:
|
||||
acl_filters = self._get_acl_filters(
|
||||
queryset=queryset,
|
||||
stored_permission=permission.stored_permission, user=user
|
||||
)
|
||||
|
||||
final_query = None
|
||||
for acl_filter in acl_filters:
|
||||
if final_query is None:
|
||||
final_query = acl_filter
|
||||
else:
|
||||
final_query = final_query | acl_filter
|
||||
|
||||
return queryset.filter(final_query)
|
||||
else:
|
||||
# User has direct permission assignment via a role, is superuser or
|
||||
# is staff. Return the entire queryset.
|
||||
return queryset
|
||||
|
||||
def get_inherited_permissions(self, obj, role):
|
||||
|
||||
@@ -44,7 +44,7 @@ class ACLCreateView(SingleObjectCreateView):
|
||||
raise Http404
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.content_object, permissions=permission_acl_edit,
|
||||
obj=self.content_object, permissions=(permission_acl_edit,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ class ACLDeleteView(SingleObjectDeleteView):
|
||||
acl = get_object_or_404(klass=AccessControlList, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=acl.content_object, permissions=permission_acl_edit,
|
||||
obj=acl.content_object, permissions=(permission_acl_edit,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -126,7 +126,7 @@ class ACLListView(SingleObjectListView):
|
||||
raise Http404
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.content_object, permissions=permission_acl_view,
|
||||
obj=self.content_object, permissions=(permission_acl_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ class GrantAccessAction(WorkflowAction):
|
||||
|
||||
try:
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_acl_edit, user=request.user, obj=obj
|
||||
obj=obj, permissions=(permission_acl_edit,), user=request.user
|
||||
)
|
||||
except Exception as exception:
|
||||
raise ValidationError(exception)
|
||||
|
||||
@@ -35,8 +35,8 @@ class APIDocumentCabinetListView(generics.ListAPIView):
|
||||
def get_queryset(self):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
queryset = document.get_cabinets()
|
||||
@@ -189,8 +189,8 @@ class APICabinetDocumentView(generics.RetrieveDestroyAPIView):
|
||||
instance = self.get_object()
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=self.request.user,
|
||||
obj=instance
|
||||
obj=instance, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
serializer = self.get_serializer(instance)
|
||||
|
||||
@@ -73,8 +73,16 @@ class CabinetsApp(MayanAppConfig):
|
||||
permission_cabinet_remove_document
|
||||
)
|
||||
)
|
||||
ModelPermission.register_inheritance(
|
||||
model=Cabinet, related='get_root',
|
||||
|
||||
def get_root_filter():
|
||||
return {
|
||||
'acl_filter': {'level': 0},
|
||||
'acl_values': ('tree_id',),
|
||||
'field_lookup': 'tree_id__in'
|
||||
}
|
||||
|
||||
ModelPermission.register_function(
|
||||
model=Cabinet, function=get_root_filter
|
||||
)
|
||||
|
||||
SourceColumn(
|
||||
|
||||
@@ -63,7 +63,7 @@ class CabinetChildAddView(SingleObjectCreateView):
|
||||
cabinet = super(CabinetChildAddView, self).get_object(*args, **kwargs)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=cabinet.get_root(), permissions=permission_cabinet_edit,
|
||||
obj=cabinet.get_root(), permissions=(permission_cabinet_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -142,7 +142,7 @@ class CabinetDetailView(DocumentListView):
|
||||
permission_object = cabinet.get_root()
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=permission_object, permissions=permission_cabinet_view,
|
||||
obj=permission_object, permissions=(permission_cabinet_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -193,7 +193,7 @@ class DocumentCabinetListView(CabinetListView):
|
||||
self.document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document, permissions=permission_document_view,
|
||||
obj=self.document, permissions=(permission_document_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -288,7 +288,7 @@ class DocumentAddToCabinetView(MultipleObjectFormActionView):
|
||||
|
||||
for cabinet in form.cleaned_data['cabinets']:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=cabinet, permissions=permission_cabinet_add_document,
|
||||
obj=cabinet, permissions=(permission_cabinet_add_document,),
|
||||
user=self.request.user
|
||||
)
|
||||
if cabinet in cabinet_membership:
|
||||
@@ -376,7 +376,7 @@ class DocumentRemoveFromCabinetView(MultipleObjectFormActionView):
|
||||
|
||||
for cabinet in form.cleaned_data['cabinets']:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=cabinet, permissions=permission_cabinet_remove_document,
|
||||
obj=cabinet, permissions=(permission_cabinet_remove_document,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -79,12 +79,13 @@ class APICheckedoutDocumentView(generics.RetrieveDestroyAPIView):
|
||||
|
||||
if document.checkout_info().user == request.user:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_check_in,
|
||||
obj=document, permissions=(permission_document_check_in,),
|
||||
user=request.user
|
||||
)
|
||||
else:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_check_in_override,
|
||||
obj=document,
|
||||
permissions=(permission_document_check_in_override,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class NewDocumentCheckoutSerializer(serializers.ModelSerializer):
|
||||
document = Document.objects.get(pk=validated_data.pop('document_pk'))
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_check_out,
|
||||
obj=document, permissions=(permission_document_check_out,),
|
||||
user=self.context['request'].user
|
||||
)
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class CheckoutDocumentView(SingleObjectCreateView):
|
||||
self.document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document, permissions=permission_document_check_out,
|
||||
obj=self.document, permissions=(permission_document_check_out,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -168,13 +168,13 @@ class DocumentCheckinView(ConfirmView):
|
||||
|
||||
if document.get_check_out_info().user == self.request.user:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_check_in,
|
||||
obj=document, permissions=(permission_document_check_in,),
|
||||
user=self.request.user
|
||||
)
|
||||
else:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document,
|
||||
permissions=permission_document_check_in_override,
|
||||
permissions=(permission_document_check_in_override,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -286,8 +286,8 @@ class ObjectListPermissionFilterMixin(object):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if self.access_object_retrieve_method and self.object_permission:
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(self.object_permission,), user=request.user,
|
||||
obj=getattr(self, self.access_object_retrieve_method)()
|
||||
obj=getattr(self, self.access_object_retrieve_method)(),
|
||||
permissions=(self.object_permission,), user=request.user
|
||||
)
|
||||
return super(ObjectListPermissionFilterMixin, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
@@ -296,7 +296,8 @@ class ObjectListPermissionFilterMixin(object):
|
||||
|
||||
if not self.access_object_retrieve_method and self.object_permission:
|
||||
return AccessControlList.objects.filter_by_access(
|
||||
self.object_permission, self.request.user, queryset=queryset
|
||||
queryset=queryset, permission=self.object_permission,
|
||||
user=self.request.user
|
||||
)
|
||||
else:
|
||||
return queryset
|
||||
@@ -327,9 +328,10 @@ class ObjectPermissionCheckMixin(object):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if self.object_permission:
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=self.object_permission, user=request.user,
|
||||
obj=self.get_permission_object(),
|
||||
related=getattr(self, 'object_permission_related', None)
|
||||
permissions=(self.object_permission,),
|
||||
related=getattr(self, 'object_permission_related', None),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -427,7 +429,7 @@ class ViewPermissionCheckMixin(object):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if self.view_permission:
|
||||
Permission.check_permissions(
|
||||
Permission.check_user_permissions(
|
||||
permissions=(self.view_permission,), user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -33,6 +33,26 @@ def encapsulate(function):
|
||||
return lambda: function
|
||||
|
||||
|
||||
def get_related_field(model, related_field_name):
|
||||
try:
|
||||
local_field_name, remaining_field_path = related_field_name.split(
|
||||
LOOKUP_SEP, 1
|
||||
)
|
||||
except ValueError:
|
||||
local_field_name = related_field_name
|
||||
remaining_field_path = None
|
||||
|
||||
related_field = model._meta.get_field(local_field_name)
|
||||
|
||||
if remaining_field_path:
|
||||
return get_related_field(
|
||||
model=related_field.related_model,
|
||||
related_field_name=remaining_field_path
|
||||
)
|
||||
|
||||
return related_field
|
||||
|
||||
|
||||
def introspect_attribute(attribute_name, obj):
|
||||
"""
|
||||
Resolve the attribute of model. Supports nested reference using dotted
|
||||
|
||||
@@ -145,7 +145,7 @@ class ObjectErrorLogEntryListClearView(ConfirmView):
|
||||
class ObjectErrorLogEntryListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_object(), permissions=permission_error_log_view,
|
||||
obj=self.get_object(), permissions=(permission_error_log_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -5,3 +5,9 @@ class DatabaseWarning(UserWarning):
|
||||
"""
|
||||
Warning when using unsupported database backends
|
||||
"""
|
||||
|
||||
|
||||
class InterfaceWarning(UserWarning):
|
||||
"""
|
||||
Warning when using obsolete internal interfaces
|
||||
"""
|
||||
|
||||
@@ -45,7 +45,7 @@ class TransformationCreateView(SingleObjectCreateView):
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.content_object,
|
||||
permissions=permission_transformation_create, user=request.user
|
||||
permissions=(permission_transformation_create,), user=request.user
|
||||
)
|
||||
|
||||
return super(TransformationCreateView, self).dispatch(
|
||||
@@ -96,7 +96,7 @@ class TransformationDeleteView(SingleObjectDeleteView):
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.transformation.content_object,
|
||||
permissions=permission_transformation_delete, user=request.user
|
||||
permissions=(permission_transformation_delete,), user=request.user
|
||||
)
|
||||
|
||||
return super(TransformationDeleteView, self).dispatch(
|
||||
@@ -145,7 +145,7 @@ class TransformationEditView(SingleObjectEditView):
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.transformation.content_object,
|
||||
permissions=permission_transformation_edit, user=request.user
|
||||
permissions=(permission_transformation_edit,), user=request.user
|
||||
)
|
||||
|
||||
return super(TransformationEditView, self).dispatch(
|
||||
@@ -202,7 +202,7 @@ class TransformationListView(SingleObjectListView):
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.content_object,
|
||||
permissions=permission_transformation_view, user=request.user
|
||||
permissions=(permission_transformation_view,), user=request.user
|
||||
)
|
||||
|
||||
return super(TransformationListView, self).dispatch(
|
||||
|
||||
@@ -30,7 +30,7 @@ class APICommentListView(generics.ListCreateAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_required,
|
||||
obj=document, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -85,7 +85,7 @@ class APICommentView(generics.RetrieveDestroyAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_required,
|
||||
obj=document, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class DocumentCommentCreateView(SingleObjectCreateView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_document(), permissions=permission_comment_create,
|
||||
obj=self.get_document(), permissions=(permission_comment_create,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -67,7 +67,7 @@ class DocumentCommentDeleteView(SingleObjectDeleteView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_object().document,
|
||||
permissions=permission_comment_delete, user=request.user
|
||||
permissions=(permission_comment_delete,), user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -120,7 +120,7 @@ class DocumentCommentListView(SingleObjectListView):
|
||||
|
||||
def get_object_list(self):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_document(), permissions=permission_comment_view,
|
||||
obj=self.get_document(), permissions=(permission_comment_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class APIIndexNodeInstanceDocumentListView(generics.ListAPIView):
|
||||
)
|
||||
AccessControlList.objects.check_access(
|
||||
obj=index_node_instance.index,
|
||||
permissions=permission_document_indexing_view,
|
||||
permissions=(permission_document_indexing_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -113,7 +113,7 @@ class APIDocumentIndexListView(generics.ListAPIView):
|
||||
def get_queryset(self):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_view,
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ class TemplateNodeCreateView(SingleObjectCreateView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_parent_node().index,
|
||||
permissions=permission_document_indexing_edit, user=request.user
|
||||
permissions=(permission_document_indexing_edit,), user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -311,7 +311,7 @@ class IndexInstanceNodeView(DocumentListView):
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.index_instance_node.index(),
|
||||
permissions=permission_document_indexing_instance_view,
|
||||
permissions=(permission_document_indexing_instance_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -378,7 +378,7 @@ class DocumentIndexNodeListView(SingleObjectListView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_document(), permissions=permission_document_view,
|
||||
obj=self.get_document(), permissions=(permission_document_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ class DocumentSignaturesApp(MayanAppConfig):
|
||||
app_label='django_gpg', model_name='Key'
|
||||
)
|
||||
|
||||
DetachedSignature = self.get_model(model_name='DetachedSignature')
|
||||
EmbeddedSignature = self.get_model(model_name='EmbeddedSignature')
|
||||
|
||||
SignatureBaseModel = self.get_model(model_name='SignatureBaseModel')
|
||||
@@ -86,6 +87,12 @@ class DocumentSignaturesApp(MayanAppConfig):
|
||||
permission_document_version_signature_upload,
|
||||
)
|
||||
)
|
||||
ModelPermission.register_inheritance(
|
||||
model=SignatureBaseModel, related='document_version'
|
||||
)
|
||||
ModelPermission.register_inheritance(
|
||||
model=DetachedSignature, related='document_version'
|
||||
)
|
||||
|
||||
SourceColumn(
|
||||
source=SignatureBaseModel, label=_('Date'), attribute='date'
|
||||
|
||||
@@ -42,47 +42,44 @@ link_document_version_signature_delete = Link(
|
||||
args='resolved_object.pk', condition=is_detached_signature,
|
||||
icon_class_path='mayan.apps.document_signatures.icons.icon_document_version_signature_delete',
|
||||
permissions=(permission_document_version_signature_delete,),
|
||||
permissions_related='document_version.document', tags='dangerous',
|
||||
text=_('Delete'), view='signatures:document_version_signature_delete',
|
||||
tags='dangerous', text=_('Delete'),
|
||||
view='signatures:document_version_signature_delete',
|
||||
)
|
||||
link_document_version_signature_details = Link(
|
||||
args='resolved_object.pk',
|
||||
icon_class_path='mayan.apps.document_signatures.icons.icon_document_version_signature_details',
|
||||
permissions=(permission_document_version_signature_view,),
|
||||
permissions_related='document_version.document', text=_('Details'),
|
||||
view='signatures:document_version_signature_details',
|
||||
text=_('Details'), view='signatures:document_version_signature_details',
|
||||
)
|
||||
link_document_version_signature_list = Link(
|
||||
args='resolved_object.pk',
|
||||
icon_class_path='mayan.apps.document_signatures.icons.icon_document_version_signature_list',
|
||||
permissions=(permission_document_version_signature_view,),
|
||||
permissions_related='document', text=_('Signatures'),
|
||||
view='signatures:document_version_signature_list',
|
||||
text=_('Signatures'), view='signatures:document_version_signature_list'
|
||||
)
|
||||
link_document_version_signature_download = Link(
|
||||
args='resolved_object.pk', condition=is_detached_signature,
|
||||
permissions=(permission_document_version_signature_download,),
|
||||
permissions_related='document_version.document', text=_('Download'),
|
||||
view='signatures:document_version_signature_download',
|
||||
text=_('Download'), view='signatures:document_version_signature_download'
|
||||
)
|
||||
link_document_version_signature_upload = Link(
|
||||
args='resolved_object.pk',
|
||||
icon_class_path='mayan.apps.document_signatures.icons.icon_document_version_signature_upload',
|
||||
permissions=(permission_document_version_signature_upload,),
|
||||
permissions_related='document', text=_('Upload signature'),
|
||||
view='signatures:document_version_signature_upload',
|
||||
text=_('Upload signature'),
|
||||
view='signatures:document_version_signature_upload'
|
||||
)
|
||||
link_document_version_signature_detached_create = Link(
|
||||
args='resolved_object.pk',
|
||||
icon_class_path='mayan.apps.document_signatures.icons.icon_document_version_signature_detached_create',
|
||||
permissions=(permission_document_version_sign_detached,),
|
||||
permissions_related='document', text=_('Sign detached'),
|
||||
view='signatures:document_version_signature_detached_create',
|
||||
text=_('Sign detached'),
|
||||
view='signatures:document_version_signature_detached_create'
|
||||
)
|
||||
link_document_version_signature_embedded_create = Link(
|
||||
args='resolved_object.pk',
|
||||
icon_class_path='mayan.apps.document_signatures.icons.icon_document_version_signature_embedded_create',
|
||||
permissions=(permission_document_version_sign_embedded,),
|
||||
permissions_related='document', text=_('Sign embedded'),
|
||||
view='signatures:document_version_signature_embedded_create',
|
||||
text=_('Sign embedded'),
|
||||
view='signatures:document_version_signature_embedded_create'
|
||||
)
|
||||
|
||||
@@ -54,7 +54,7 @@ class DocumentVersionDetachedSignatureCreateView(FormView):
|
||||
passphrase = form.cleaned_data['passphrase'] or None
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=key, permissions=permission_key_sign, user=self.request.user
|
||||
obj=key, permissions=(permission_key_sign,), user=self.request.user
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -109,7 +109,7 @@ class DocumentVersionDetachedSignatureCreateView(FormView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_document_version().document,
|
||||
permissions=permission_document_version_sign_detached,
|
||||
permissions=(permission_document_version_sign_detached,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -146,7 +146,7 @@ class DocumentVersionEmbeddedSignatureCreateView(FormView):
|
||||
passphrase = form.cleaned_data['passphrase'] or None
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=key, permissions=permission_key_sign, user=self.request.user
|
||||
obj=key, permissions=(permission_key_sign,), user=self.request.user
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -206,7 +206,7 @@ class DocumentVersionEmbeddedSignatureCreateView(FormView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_document_version().document,
|
||||
permissions=permission_document_version_sign_embedded,
|
||||
permissions=(permission_document_version_sign_embedded,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -283,8 +283,9 @@ class DocumentVersionSignatureDownloadView(SingleObjectDownloadView):
|
||||
class DocumentVersionSignatureListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_version_signature_view,
|
||||
user=request.user, obj=self.get_document_version()
|
||||
obj=self.get_document_version(),
|
||||
permissions=(permission_document_version_signature_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -345,7 +346,7 @@ class DocumentVersionSignatureUploadView(SingleObjectCreateView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_document_version(),
|
||||
permissions=permission_document_version_signature_upload,
|
||||
permissions=(permission_document_version_signature_upload,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ class APIDocumentTypeWorkflowListView(generics.ListAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_type_view, user=self.request.user,
|
||||
obj=document_type
|
||||
obj=document_type, permissions=(permission_document_type_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document_type
|
||||
@@ -105,8 +105,8 @@ class APIWorkflowDocumentTypeList(generics.ListCreateAPIView):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=workflow
|
||||
obj=workflow, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return workflow
|
||||
@@ -158,8 +158,8 @@ class APIWorkflowDocumentTypeView(generics.RetrieveDestroyAPIView):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=workflow
|
||||
obj=workflow, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return workflow
|
||||
@@ -261,8 +261,8 @@ class APIWorkflowStateListView(generics.ListCreateAPIView):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=workflow
|
||||
obj=workflow, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return workflow
|
||||
@@ -304,8 +304,8 @@ class APIWorkflowStateView(generics.RetrieveUpdateDestroyAPIView):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=workflow
|
||||
obj=workflow, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return workflow
|
||||
@@ -357,8 +357,8 @@ class APIWorkflowTransitionListView(generics.ListCreateAPIView):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=workflow
|
||||
obj=workflow, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return workflow
|
||||
@@ -411,8 +411,8 @@ class APIWorkflowTransitionView(generics.RetrieveUpdateDestroyAPIView):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=workflow
|
||||
obj=workflow, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return workflow
|
||||
@@ -435,8 +435,8 @@ class APIWorkflowInstanceListView(generics.ListAPIView):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_workflow_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document
|
||||
@@ -460,8 +460,8 @@ class APIWorkflowInstanceView(generics.RetrieveAPIView):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_workflow_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document
|
||||
@@ -488,9 +488,10 @@ class APIWorkflowInstanceLogEntryListView(generics.ListCreateAPIView):
|
||||
Failing that, check for ACLs for any of the workflow's transitions.
|
||||
Failing that, then raise PermissionDenied
|
||||
"""
|
||||
# TODO: Improvement above
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_workflow_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document
|
||||
|
||||
@@ -417,8 +417,9 @@ class WorkflowInstance(models.Model):
|
||||
all transition options.
|
||||
"""
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_transition,
|
||||
user=_user, obj=self.workflow
|
||||
obj=self.workflow,
|
||||
permissions=(permission_workflow_transition,),
|
||||
user=_user
|
||||
)
|
||||
except PermissionDenied:
|
||||
"""
|
||||
@@ -427,7 +428,8 @@ class WorkflowInstance(models.Model):
|
||||
"""
|
||||
queryset = AccessControlList.objects.filter_by_access(
|
||||
permission=permission_workflow_transition,
|
||||
user=_user, queryset=queryset
|
||||
queryset=queryset,
|
||||
user=_user
|
||||
)
|
||||
return queryset
|
||||
else:
|
||||
|
||||
@@ -23,8 +23,8 @@ __all__ = (
|
||||
class DocumentWorkflowInstanceListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=request.user,
|
||||
obj=self.get_document()
|
||||
obj=self.get_document(), permissions=(permission_workflow_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -58,8 +58,8 @@ class DocumentWorkflowInstanceListView(SingleObjectListView):
|
||||
class WorkflowInstanceDetailView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=request.user,
|
||||
obj=self.get_workflow_instance().document
|
||||
obj=self.get_workflow_instance().document,
|
||||
permissions=(permission_workflow_view,), user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
|
||||
@@ -27,8 +27,8 @@ class WorkflowDocumentListView(DocumentListView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=request.user,
|
||||
obj=self.workflow
|
||||
obj=self.workflow, permissions=(permission_workflow_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -111,8 +111,8 @@ class WorkflowStateDocumentListView(DocumentListView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=self.request.user,
|
||||
obj=workflow_state.workflow
|
||||
obj=workflow_state.workflow,
|
||||
permissions=(permission_workflow_view,), user=self.request.user
|
||||
)
|
||||
|
||||
return workflow_state
|
||||
@@ -121,8 +121,8 @@ class WorkflowStateDocumentListView(DocumentListView):
|
||||
class WorkflowStateListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=request.user,
|
||||
obj=self.get_workflow()
|
||||
obj=self.get_workflow(), permissions=(permission_workflow_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
|
||||
@@ -345,7 +345,7 @@ class SetupWorkflowStateCreateView(SingleObjectCreateView):
|
||||
def get_workflow(self):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission_workflow_edit,), obj=workflow,
|
||||
obj=workflow, permissions=(permission_workflow_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
return workflow
|
||||
@@ -380,7 +380,7 @@ class SetupWorkflowStateDeleteView(SingleObjectDeleteView):
|
||||
def get_workflow(self):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission_workflow_edit,), obj=workflow,
|
||||
obj=workflow, permissions=(permission_workflow_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
return workflow
|
||||
@@ -410,8 +410,8 @@ class SetupWorkflowStateListView(SingleObjectListView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_view, user=request.user,
|
||||
obj=self.get_workflow()
|
||||
obj=self.get_workflow(), permissions=(permission_workflow_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -492,7 +492,7 @@ class SetupWorkflowTransitionCreateView(SingleObjectCreateView):
|
||||
def get_workflow(self):
|
||||
workflow = get_object_or_404(klass=Workflow, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission_workflow_edit,), obj=workflow,
|
||||
obj=workflow, permissions=(permission_workflow_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
return workflow
|
||||
@@ -580,8 +580,9 @@ class SetupWorkflowTransitionTriggerEventListView(FormView):
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_workflow_edit,
|
||||
user=self.request.user, obj=self.get_object().workflow
|
||||
obj=self.get_object().workflow,
|
||||
permissions=(permission_workflow_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
EventType.refresh()
|
||||
|
||||
@@ -16,7 +16,7 @@ from mayan.apps.rest_api.permissions import MayanPermission
|
||||
|
||||
from .literals import DOCUMENT_IMAGE_TASK_TIMEOUT
|
||||
from .models import (
|
||||
Document, DocumentType, RecentDocument
|
||||
DeletedDocument, Document, DocumentType, RecentDocument
|
||||
)
|
||||
from .permissions import (
|
||||
permission_document_create, permission_document_delete,
|
||||
@@ -42,14 +42,14 @@ from .tasks import task_generate_document_page_image
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class APIDeletedDocumentListView(generics.ListAPIView):
|
||||
class APITrashedDocumentListView(generics.ListAPIView):
|
||||
"""
|
||||
Returns a list of all the trashed documents.
|
||||
"""
|
||||
filter_backends = (MayanObjectPermissionsFilter,)
|
||||
mayan_object_permissions = {'GET': (permission_document_view,)}
|
||||
permission_classes = (MayanPermission,)
|
||||
queryset = Document.trash.all()
|
||||
queryset = DeletedDocument.objects.all()
|
||||
serializer_class = DeletedDocumentSerializer
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class APIDeletedDocumentView(generics.RetrieveDestroyAPIView):
|
||||
'GET': (permission_document_view,)
|
||||
}
|
||||
permission_classes = (MayanPermission,)
|
||||
queryset = Document.trash.all()
|
||||
queryset = DeletedDocument.objects.all()
|
||||
serializer_class = DeletedDocumentSerializer
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class APIDeletedDocumentRestoreView(generics.GenericAPIView):
|
||||
'POST': (permission_document_restore,)
|
||||
}
|
||||
permission_classes = (MayanPermission,)
|
||||
queryset = Document.trash.all()
|
||||
queryset = DeletedDocument.objects.all()
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
return None
|
||||
@@ -143,8 +143,8 @@ class APIDocumentListView(generics.ListCreateAPIView):
|
||||
|
||||
def perform_create(self, serializer):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission_document_create,), user=self.request.user,
|
||||
obj=serializer.validated_data['document_type']
|
||||
obj=serializer.validated_data['document_type'],
|
||||
permissions=(permission_document_create,), user=self.request.user
|
||||
)
|
||||
serializer.save(_user=self.request.user)
|
||||
|
||||
@@ -164,7 +164,8 @@ class APIDocumentPageImageView(generics.RetrieveAPIView):
|
||||
document = get_object_or_404(Document.passthrough, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permission_required, self.request.user, document
|
||||
obj=document, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
return document
|
||||
|
||||
@@ -231,7 +232,8 @@ class APIDocumentPageView(generics.RetrieveUpdateAPIView):
|
||||
document = get_object_or_404(Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permission_required, self.request.user, document
|
||||
obj=document, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
return document
|
||||
|
||||
@@ -309,8 +311,8 @@ class APIDocumentTypeDocumentListView(generics.ListAPIView):
|
||||
def get_queryset(self):
|
||||
document_type = get_object_or_404(DocumentType, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_type_view, user=self.request.user,
|
||||
obj=document_type
|
||||
obj=document_type, permissions=(permission_document_type_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document_type.documents.all()
|
||||
@@ -326,8 +328,8 @@ class APIDocumentVersionDownloadView(DownloadMixin, generics.RetrieveAPIView):
|
||||
document = get_object_or_404(Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission_document_download,), user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_document_download,),
|
||||
user=self.request.user
|
||||
)
|
||||
return document
|
||||
|
||||
@@ -420,7 +422,8 @@ class APIDocumentVersionPageListView(generics.ListAPIView):
|
||||
document = get_object_or_404(Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permission_document_view, self.request.user, document
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
return document
|
||||
|
||||
@@ -442,7 +445,6 @@ class APIDocumentVersionsListView(generics.ListCreateAPIView):
|
||||
mayan_object_permissions = {
|
||||
'GET': (permission_document_version_view,),
|
||||
}
|
||||
mayan_permission_attribute_check = 'document'
|
||||
permission_classes = (MayanPermission,)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
@@ -471,8 +473,8 @@ class APIDocumentVersionsListView(generics.ListCreateAPIView):
|
||||
document = get_object_or_404(Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission_document_new_version,),
|
||||
user=self.request.user, obj=document
|
||||
obj=document, permissions=(permission_document_new_version,),
|
||||
user=self.request.user,
|
||||
)
|
||||
serializer.save(document=document, _user=self.request.user)
|
||||
|
||||
@@ -497,7 +499,8 @@ class APIDocumentVersionView(generics.RetrieveUpdateDestroyAPIView):
|
||||
document = get_object_or_404(Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permission_required, self.request.user, document
|
||||
obj=document, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
return document
|
||||
|
||||
|
||||
@@ -220,10 +220,6 @@ class DocumentsApp(MayanAppConfig):
|
||||
)
|
||||
)
|
||||
|
||||
ModelPermission.register_proxy(
|
||||
source=Document, model=DocumentType,
|
||||
)
|
||||
|
||||
ModelPermission.register_inheritance(
|
||||
model=Document, related='document_type',
|
||||
)
|
||||
|
||||
@@ -53,13 +53,13 @@ def task_clear_image_cache():
|
||||
|
||||
|
||||
@app.task(ignore_result=True)
|
||||
def task_delete_document(deleted_document_id):
|
||||
def task_delete_document(trashed_document_id):
|
||||
DeletedDocument = apps.get_model(
|
||||
app_label='documents', model_name='DeletedDocument'
|
||||
)
|
||||
|
||||
logger.debug(msg='Executing')
|
||||
deleted_document = DeletedDocument.objects.get(pk=deleted_document_id)
|
||||
deleted_document = DeletedDocument.objects.get(pk=trashed_document_id)
|
||||
deleted_document.delete()
|
||||
logger.debug(msg='Finshed')
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from ..permissions import (
|
||||
from .base import GenericDocumentViewTestCase
|
||||
|
||||
|
||||
class DeletedDocumentTestCase(GenericDocumentViewTestCase):
|
||||
class TrashedDocumentTestCase(GenericDocumentViewTestCase):
|
||||
def _request_document_restore_view(self):
|
||||
return self.post(
|
||||
viewname='documents:document_restore', kwargs={
|
||||
@@ -22,7 +22,7 @@ class DeletedDocumentTestCase(GenericDocumentViewTestCase):
|
||||
self.assertEqual(Document.objects.count(), 0)
|
||||
|
||||
response = self._request_document_restore_view()
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
self.assertEqual(DeletedDocument.objects.count(), 1)
|
||||
self.assertEqual(Document.objects.count(), 0)
|
||||
@@ -50,7 +50,7 @@ class DeletedDocumentTestCase(GenericDocumentViewTestCase):
|
||||
|
||||
def test_document_trash_no_permissions(self):
|
||||
response = self._request_document_trash_view()
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
self.assertEqual(DeletedDocument.objects.count(), 0)
|
||||
self.assertEqual(Document.objects.count(), 1)
|
||||
@@ -79,7 +79,7 @@ class DeletedDocumentTestCase(GenericDocumentViewTestCase):
|
||||
self.assertEqual(DeletedDocument.objects.count(), 1)
|
||||
|
||||
response = self._request_document_delete_view()
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
self.assertEqual(Document.objects.count(), 0)
|
||||
self.assertEqual(DeletedDocument.objects.count(), 1)
|
||||
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
||||
from django.conf.urls import url
|
||||
|
||||
from .api_views import (
|
||||
APIDeletedDocumentListView, APIDeletedDocumentRestoreView,
|
||||
APITrashedDocumentListView, APIDeletedDocumentRestoreView,
|
||||
APIDeletedDocumentView, APIDocumentDownloadView, APIDocumentView,
|
||||
APIDocumentListView, APIDocumentVersionDownloadView,
|
||||
APIDocumentPageImageView, APIDocumentPageView,
|
||||
@@ -13,31 +13,33 @@ from .api_views import (
|
||||
APIRecentDocumentListView
|
||||
)
|
||||
from .views import (
|
||||
ClearImageCacheView, DeletedDocumentDeleteView,
|
||||
DeletedDocumentDeleteManyView, DeletedDocumentListView,
|
||||
DocumentDocumentTypeEditView, DocumentDownloadFormView,
|
||||
ClearImageCacheView, DocumentDocumentTypeEditView, DocumentDownloadFormView,
|
||||
DocumentDownloadView, DocumentDuplicatesListView, DocumentEditView,
|
||||
DocumentListView, DocumentPageListView, DocumentPageNavigationFirst,
|
||||
DocumentPageNavigationLast, DocumentPageNavigationNext,
|
||||
DocumentPageNavigationPrevious, DocumentPageRotateLeftView,
|
||||
DocumentPageRotateRightView, DocumentPageView, DocumentPageViewResetView,
|
||||
DocumentPageZoomInView, DocumentPageZoomOutView, DocumentPreviewView,
|
||||
DocumentPrint, DocumentRestoreView, DocumentRestoreManyView,
|
||||
DocumentTransformationsClearView, DocumentTransformationsCloneView,
|
||||
DocumentTrashView, DocumentTrashManyView, DocumentTypeCreateView,
|
||||
DocumentPrint, DocumentTransformationsClearView,
|
||||
DocumentTransformationsCloneView, DocumentTypeCreateView,
|
||||
DocumentTypeDeleteView, DocumentTypeDocumentListView,
|
||||
DocumentTypeFilenameCreateView, DocumentTypeFilenameDeleteView,
|
||||
DocumentTypeFilenameEditView, DocumentTypeFilenameListView,
|
||||
DocumentTypeListView, DocumentTypeEditView, DocumentUpdatePageCountView,
|
||||
DocumentVersionDownloadFormView, DocumentVersionDownloadView,
|
||||
DocumentVersionListView, DocumentVersionRevertView, DocumentVersionView,
|
||||
DocumentView, DuplicatedDocumentListView, EmptyTrashCanView,
|
||||
DocumentView, DuplicatedDocumentListView,
|
||||
RecentAccessDocumentListView, RecentAddedDocumentListView,
|
||||
ScanDuplicatedDocuments
|
||||
)
|
||||
from .views.favorite_document_views import (
|
||||
FavoriteAddView, FavoriteDocumentListView, FavoriteRemoveView
|
||||
)
|
||||
from .views.trashed_document_views import (
|
||||
DocumentTrashView, EmptyTrashCanView, TrashedDocumentDeleteView,
|
||||
TrashedDocumentListView, TrashedDocumentRestoreView
|
||||
)
|
||||
|
||||
|
||||
urlpatterns_favorite_documents = [
|
||||
url(
|
||||
@@ -62,6 +64,42 @@ urlpatterns_favorite_documents = [
|
||||
view=FavoriteRemoveView.as_view(),
|
||||
name='document_multiple_remove_from_favorites'
|
||||
),
|
||||
url(
|
||||
regex=r'^trash_can/empty/$', view=EmptyTrashCanView.as_view(),
|
||||
name='trash_can_empty'
|
||||
),
|
||||
]
|
||||
|
||||
urlpatterns_trashed_documents = [
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/trash/$', view=DocumentTrashView.as_view(),
|
||||
name='document_trash'
|
||||
),
|
||||
url(
|
||||
regex=r'^multiple/trash/$', view=DocumentTrashView.as_view(),
|
||||
name='document_multiple_trash'
|
||||
),
|
||||
url(
|
||||
regex=r'^list/deleted/$', view=TrashedDocumentListView.as_view(),
|
||||
name='document_list_deleted'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/restore/$',
|
||||
view=TrashedDocumentRestoreView.as_view(), name='document_restore'
|
||||
),
|
||||
url(
|
||||
regex=r'^multiple/restore/$', view=TrashedDocumentRestoreView.as_view(),
|
||||
name='document_multiple_restore'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/delete/$',
|
||||
view=TrashedDocumentDeleteView.as_view(), name='document_delete'
|
||||
),
|
||||
url(
|
||||
regex=r'^multiple/delete/$',
|
||||
view=TrashedDocumentDeleteView.as_view(),
|
||||
name='document_multiple_delete'
|
||||
),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
@@ -78,10 +116,6 @@ urlpatterns = [
|
||||
view=RecentAddedDocumentListView.as_view(),
|
||||
name='document_list_recent_added'
|
||||
),
|
||||
url(
|
||||
regex=r'^list/deleted/$', view=DeletedDocumentListView.as_view(),
|
||||
name='document_list_deleted'
|
||||
),
|
||||
url(
|
||||
regex=r'^list/duplicated/$',
|
||||
view=DuplicatedDocumentListView.as_view(),
|
||||
@@ -100,23 +134,6 @@ urlpatterns = [
|
||||
view=DocumentDuplicatesListView.as_view(),
|
||||
name='document_duplicates_list'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/restore/$', view=DocumentRestoreView.as_view(),
|
||||
name='document_restore'
|
||||
),
|
||||
url(
|
||||
regex=r'^multiple/restore/$', view=DocumentRestoreManyView.as_view(),
|
||||
name='document_multiple_restore'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/delete/$',
|
||||
view=DeletedDocumentDeleteView.as_view(), name='document_delete'
|
||||
),
|
||||
url(
|
||||
regex=r'^multiple/delete/$',
|
||||
view=DeletedDocumentDeleteManyView.as_view(),
|
||||
name='document_multiple_delete'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/type/$',
|
||||
view=DocumentDocumentTypeEditView.as_view(),
|
||||
@@ -126,14 +143,6 @@ urlpatterns = [
|
||||
regex=r'^multiple/type/$', view=DocumentDocumentTypeEditView.as_view(),
|
||||
name='document_multiple_document_type_edit'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/trash/$', view=DocumentTrashView.as_view(),
|
||||
name='document_trash'
|
||||
),
|
||||
url(
|
||||
regex=r'^multiple/trash/$', view=DocumentTrashManyView.as_view(),
|
||||
name='document_multiple_trash'
|
||||
),
|
||||
url(
|
||||
regex=r'^(?P<pk>\d+)/edit/$', view=DocumentEditView.as_view(),
|
||||
name='document_edit'
|
||||
@@ -218,11 +227,6 @@ urlpatterns = [
|
||||
regex=r'^cache/clear/$', view=ClearImageCacheView.as_view(),
|
||||
name='document_clear_image_cache'
|
||||
),
|
||||
url(
|
||||
regex=r'^trash_can/empty/$', view=EmptyTrashCanView.as_view(),
|
||||
name='trash_can_empty'
|
||||
),
|
||||
|
||||
url(
|
||||
regex=r'^page/(?P<pk>\d+)/$', view=DocumentPageView.as_view(),
|
||||
name='document_page_view'
|
||||
@@ -323,7 +327,7 @@ urlpatterns = [
|
||||
),
|
||||
]
|
||||
urlpatterns.extend(urlpatterns_favorite_documents)
|
||||
|
||||
urlpatterns.extend(urlpatterns_trashed_documents)
|
||||
|
||||
api_urls = [
|
||||
url(
|
||||
@@ -384,7 +388,7 @@ api_urls = [
|
||||
),
|
||||
url(
|
||||
regex=r'^trashed_documents/$',
|
||||
view=APIDeletedDocumentListView.as_view(), name='trasheddocument-list'
|
||||
view=APITrashedDocumentListView.as_view(), name='trasheddocument-list'
|
||||
),
|
||||
url(
|
||||
regex=r'^trashed_documents/(?P<pk>[0-9]+)/$',
|
||||
|
||||
@@ -38,8 +38,8 @@ logger = logging.getLogger(__name__)
|
||||
class DocumentPageListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=self.request.user,
|
||||
obj=self.get_document()
|
||||
obj=self.get_document(), permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -66,8 +66,8 @@ class DocumentPageNavigationBase(RedirectView):
|
||||
document_page = self.get_object()
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=request.user,
|
||||
obj=document_page.document
|
||||
obj=document_page.document,
|
||||
permissions=(permission_document_view,), user=request.user
|
||||
)
|
||||
|
||||
return super(DocumentPageNavigationBase, self).dispatch(
|
||||
@@ -170,8 +170,8 @@ class DocumentPageView(SimpleView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=request.user,
|
||||
obj=self.get_object().document
|
||||
obj=self.get_object().document,
|
||||
permissions=(permission_document_view,), user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -214,11 +214,11 @@ class DocumentPageViewResetView(RedirectView):
|
||||
|
||||
class DocumentPageInteractiveTransformation(RedirectView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
object = self.get_object()
|
||||
obj = self.get_object()
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=request.user,
|
||||
obj=object
|
||||
obj=obj, permissions=(permission_document_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(DocumentPageInteractiveTransformation, self).dispatch(
|
||||
|
||||
@@ -138,8 +138,9 @@ class DocumentTypeFilenameCreateView(SingleObjectCreateView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_type_edit, user=request.user,
|
||||
obj=self.get_document_type()
|
||||
obj=self.get_document_type(),
|
||||
permissions=(permission_document_type_edit,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(DocumentTypeFilenameCreateView, self).dispatch(
|
||||
|
||||
@@ -32,8 +32,9 @@ logger = logging.getLogger(__name__)
|
||||
class DocumentVersionListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_version_view, user=request.user,
|
||||
obj=self.get_document()
|
||||
obj=self.get_document(),
|
||||
permissions=(permission_document_version_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
self.get_document().add_as_recent_document_for_user(request.user)
|
||||
|
||||
@@ -318,8 +318,8 @@ class DocumentDownloadView(SingleObjectDownloadView):
|
||||
class DocumentDuplicatesListView(DocumentListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=self.request.user,
|
||||
obj=self.get_document()
|
||||
obj=self.get_document(), permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -582,8 +582,8 @@ class DocumentTransformationsCloneView(FormView):
|
||||
instance = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_transformation_edit,
|
||||
user=self.request.user, obj=instance
|
||||
obj=instance, permissions=(permission_transformation_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
instance.add_as_recent_document_for_user(self.request.user)
|
||||
@@ -597,8 +597,8 @@ class DocumentPrint(FormView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_print, user=self.request.user,
|
||||
obj=instance
|
||||
obj=instance, permissions=(permission_document_print,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
instance.add_as_recent_document_for_user(self.request.user)
|
||||
|
||||
@@ -3,13 +3,13 @@ from __future__ import absolute_import, unicode_literals
|
||||
import logging
|
||||
|
||||
from django.contrib import messages
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _, ungettext
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.common.generics import ConfirmView
|
||||
from mayan.apps.common.mixins import MultipleInstanceActionMixin
|
||||
from mayan.apps.common.generics import (
|
||||
ConfirmView, MultipleObjectConfirmActionView
|
||||
)
|
||||
|
||||
from ..icons import icon_document_list_deleted
|
||||
from ..models import DeletedDocument, Document
|
||||
@@ -23,64 +23,100 @@ from ..tasks import task_delete_document
|
||||
from .document_views import DocumentListView
|
||||
|
||||
__all__ = (
|
||||
'DeletedDocumentDeleteView', 'DeletedDocumentDeleteManyView',
|
||||
'DeletedDocumentListView', 'DocumentRestoreView', 'DocumentRestoreManyView',
|
||||
'DocumentTrashView', 'DocumentTrashManyView', 'EmptyTrashCanView'
|
||||
'DocumentTrashView', 'EmptyTrashCanView', 'TrashedDocumentDeleteView',
|
||||
'TrashedDocumentListView', 'TrashedDocumentRestoreView'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DeletedDocumentDeleteView(ConfirmView):
|
||||
extra_context = {
|
||||
'title': _('Delete the selected document?')
|
||||
class DocumentTrashView(MultipleObjectConfirmActionView):
|
||||
model = Document
|
||||
object_permission = permission_document_trash
|
||||
pk_url_kwarg = 'pk'
|
||||
success_message_singular = _(
|
||||
'%(count)d document moved to the trash.'
|
||||
)
|
||||
success_message_plural = _(
|
||||
'%(count)d documents moved to the trash.'
|
||||
)
|
||||
|
||||
def get_extra_context(self):
|
||||
queryset = self.get_object_list()
|
||||
|
||||
result = {
|
||||
'title': ungettext(
|
||||
single='Move the selected document to the trash?',
|
||||
plural='Move the selected documents to the trash?',
|
||||
number=queryset.count()
|
||||
)
|
||||
}
|
||||
|
||||
def object_action(self, instance):
|
||||
source_document = get_object_or_404(
|
||||
klass=Document.passthrough, pk=instance.pk
|
||||
)
|
||||
return result
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_delete, user=self.request.user,
|
||||
obj=source_document
|
||||
)
|
||||
def object_action(self, form, instance):
|
||||
instance.delete()
|
||||
|
||||
task_delete_document.apply_async(
|
||||
kwargs={'deleted_document_id': instance.pk}
|
||||
|
||||
class EmptyTrashCanView(ConfirmView):
|
||||
extra_context = {
|
||||
'title': _('Empty trash?')
|
||||
}
|
||||
view_permission = permission_empty_trash
|
||||
action_cancel_redirect = post_action_redirect = reverse_lazy(
|
||||
'documents:document_list_deleted'
|
||||
)
|
||||
|
||||
def view_action(self):
|
||||
instance = get_object_or_404(
|
||||
klass=DeletedDocument, pk=self.kwargs['pk']
|
||||
)
|
||||
self.object_action(instance=instance)
|
||||
messages.success(
|
||||
self.request, _('Document: %(document)s deleted.') % {
|
||||
'document': instance
|
||||
}
|
||||
for deleted_document in DeletedDocument.objects.all():
|
||||
task_delete_document.apply_async(
|
||||
kwargs={'trashed_document_id': deleted_document.pk}
|
||||
)
|
||||
|
||||
messages.success(self.request, _('Trash emptied successfully'))
|
||||
|
||||
class DeletedDocumentDeleteManyView(MultipleInstanceActionMixin, DeletedDocumentDeleteView):
|
||||
extra_context = {
|
||||
'title': _('Delete the selected documents?')
|
||||
}
|
||||
|
||||
class TrashedDocumentDeleteView(MultipleObjectConfirmActionView):
|
||||
model = DeletedDocument
|
||||
success_message = '%(count)d document deleted.'
|
||||
success_message_plural = '%(count)d documents deleted.'
|
||||
object_permission = permission_document_delete
|
||||
pk_url_kwarg = 'pk'
|
||||
success_message_singular = _(
|
||||
'%(count)d trashed document deleted.'
|
||||
)
|
||||
success_message_plural = _(
|
||||
'%(count)d trashed documents deleted.'
|
||||
)
|
||||
|
||||
def get_extra_context(self):
|
||||
queryset = self.get_object_list()
|
||||
|
||||
result = {
|
||||
'title': ungettext(
|
||||
single='Delete the selected trashed document?',
|
||||
plural='Delete the selected trashed documents?',
|
||||
number=queryset.count()
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
def object_action(self, form, instance):
|
||||
task_delete_document.apply_async(
|
||||
kwargs={'trashed_document_id': instance.pk}
|
||||
)
|
||||
|
||||
|
||||
class DeletedDocumentListView(DocumentListView):
|
||||
class TrashedDocumentListView(DocumentListView):
|
||||
object_permission = None
|
||||
|
||||
def get_document_queryset(self):
|
||||
return AccessControlList.objects.filter_by_access(
|
||||
permission_document_view, self.request.user,
|
||||
queryset=DeletedDocument.trash.all()
|
||||
permission=permission_document_view,
|
||||
queryset=DeletedDocument.trash.all(),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
def get_extra_context(self):
|
||||
context = super(DeletedDocumentListView, self).get_extra_context()
|
||||
context = super(TrashedDocumentListView, self).get_extra_context()
|
||||
context.update(
|
||||
{
|
||||
'hide_link': True,
|
||||
@@ -99,103 +135,29 @@ class DeletedDocumentListView(DocumentListView):
|
||||
return context
|
||||
|
||||
|
||||
class DocumentRestoreView(ConfirmView):
|
||||
extra_context = {
|
||||
'title': _('Restore the selected document?')
|
||||
}
|
||||
|
||||
def object_action(self, instance):
|
||||
source_document = get_object_or_404(
|
||||
klass=Document.passthrough, pk=instance.pk
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_restore, user=self.request.user,
|
||||
obj=source_document
|
||||
)
|
||||
|
||||
instance.restore()
|
||||
|
||||
def view_action(self):
|
||||
instance = get_object_or_404(
|
||||
klass=DeletedDocument, pk=self.kwargs['pk']
|
||||
)
|
||||
|
||||
self.object_action(instance=instance)
|
||||
|
||||
messages.success(
|
||||
self.request, _('Document: %(document)s restored.') % {
|
||||
'document': instance
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class DocumentRestoreManyView(MultipleInstanceActionMixin, DocumentRestoreView):
|
||||
extra_context = {
|
||||
'title': _('Restore the selected documents?')
|
||||
}
|
||||
class TrashedDocumentRestoreView(MultipleObjectConfirmActionView):
|
||||
model = DeletedDocument
|
||||
success_message = '%(count)d document restored.'
|
||||
success_message_plural = '%(count)d documents restored.'
|
||||
|
||||
|
||||
class DocumentTrashView(ConfirmView):
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.get_object(),
|
||||
'title': _('Move "%s" to the trash?') % self.get_object()
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
return get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
def get_post_action_redirect(self):
|
||||
return reverse('documents:document_list_recent_access')
|
||||
|
||||
def object_action(self, instance):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_trash, user=self.request.user,
|
||||
obj=instance
|
||||
object_permission = permission_document_restore
|
||||
pk_url_kwarg = 'pk'
|
||||
success_message_singular = _(
|
||||
'%(count)d trashed document restored.'
|
||||
)
|
||||
|
||||
instance.delete()
|
||||
|
||||
def view_action(self):
|
||||
instance = self.get_object()
|
||||
|
||||
self.object_action(instance=instance)
|
||||
|
||||
messages.success(
|
||||
self.request, _('Document: %(document)s moved to trash successfully.') % {
|
||||
'document': instance
|
||||
}
|
||||
success_message_plural = _(
|
||||
'%(count)d trashed documents restored.'
|
||||
)
|
||||
|
||||
|
||||
class DocumentTrashManyView(MultipleInstanceActionMixin, DocumentTrashView):
|
||||
model = Document
|
||||
success_message = '%(count)d document moved to the trash.'
|
||||
success_message_plural = '%(count)d documents moved to the trash.'
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'title': _('Move the selected documents to the trash?')
|
||||
queryset = self.get_object_list()
|
||||
|
||||
result = {
|
||||
'title': ungettext(
|
||||
single='Restore the selected trashed document?',
|
||||
plural='Restore the selected trashed documents?',
|
||||
number=queryset.count()
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
class EmptyTrashCanView(ConfirmView):
|
||||
extra_context = {
|
||||
'title': _('Empty trash?')
|
||||
}
|
||||
view_permission = permission_empty_trash
|
||||
action_cancel_redirect = post_action_redirect = reverse_lazy(
|
||||
'documents:document_list_deleted'
|
||||
)
|
||||
|
||||
def view_action(self):
|
||||
for deleted_document in DeletedDocument.objects.all():
|
||||
task_delete_document.apply_async(
|
||||
kwargs={'deleted_document_id': deleted_document.pk}
|
||||
)
|
||||
|
||||
messages.success(self.request, _('Trash emptied successfully'))
|
||||
def object_action(self, form, instance):
|
||||
instance.restore()
|
||||
|
||||
@@ -42,8 +42,8 @@ class APIObjectEventListView(generics.ListAPIView):
|
||||
obj = self.get_object()
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_events_view, user=self.request.user,
|
||||
obj=obj
|
||||
obj=obj, permissions=(permission_events_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return any_stream(obj)
|
||||
|
||||
@@ -113,8 +113,9 @@ class EventType(object):
|
||||
if result.target:
|
||||
try:
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_events_view,
|
||||
user=user, obj=result.target
|
||||
obj=result.target,
|
||||
permissions=(permission_events_view,),
|
||||
user=user
|
||||
)
|
||||
except PermissionDenied:
|
||||
pass
|
||||
@@ -139,8 +140,9 @@ class EventType(object):
|
||||
if relationship.exists():
|
||||
try:
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_events_view,
|
||||
user=user, obj=result.target
|
||||
obj=result.target,
|
||||
permissions=(permission_events_view,),
|
||||
user=user
|
||||
)
|
||||
except PermissionDenied:
|
||||
pass
|
||||
@@ -161,8 +163,9 @@ class EventType(object):
|
||||
if relationship.exists():
|
||||
try:
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_events_view,
|
||||
user=user, obj=result.action_object
|
||||
obj=result.action_object,
|
||||
permissions=(permission_events_view,),
|
||||
user=user
|
||||
)
|
||||
except PermissionDenied:
|
||||
pass
|
||||
@@ -191,7 +194,6 @@ class ModelEventType(object):
|
||||
Class to allow matching a model to a specific set of events.
|
||||
"""
|
||||
_inheritances = {}
|
||||
_proxies = {}
|
||||
_registry = {}
|
||||
|
||||
@classmethod
|
||||
@@ -211,11 +213,6 @@ class ModelEventType(object):
|
||||
if class_events:
|
||||
events.extend(class_events)
|
||||
|
||||
proxy = cls._proxies.get(type(instance))
|
||||
|
||||
if proxy:
|
||||
events.extend(cls._registry.get(proxy))
|
||||
|
||||
pks = [
|
||||
event.id for event in set(events)
|
||||
]
|
||||
@@ -237,7 +234,3 @@ class ModelEventType(object):
|
||||
@classmethod
|
||||
def register_inheritance(cls, model, related):
|
||||
cls._inheritances[model] = related
|
||||
|
||||
@classmethod
|
||||
def register_proxy(cls, source, model):
|
||||
cls._proxies[model] = source
|
||||
|
||||
@@ -234,7 +234,7 @@ class ObjectEventTypeSubscriptionListView(FormView):
|
||||
raise Http404
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=content_object, permissions=permission_events_view,
|
||||
obj=content_object, permissions=(permission_events_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ class APIResolvedSmartLinkDocumentListView(generics.ListAPIView):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_view,
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -48,7 +48,7 @@ class APIResolvedSmartLinkDocumentListView(generics.ListAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=smart_link, permissions=permission_smart_link_view,
|
||||
obj=smart_link, permissions=(permission_smart_link_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -91,7 +91,7 @@ class APIResolvedSmartLinkView(generics.RetrieveAPIView):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_view,
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -128,7 +128,7 @@ class APIResolvedSmartLinkListView(generics.ListAPIView):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=permission_document_view,
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -187,7 +187,7 @@ class APISmartLinkConditionListView(generics.ListCreateAPIView):
|
||||
smart_link = get_object_or_404(klass=SmartLink, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=smart_link, permissions=permission_required,
|
||||
obj=smart_link, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -230,7 +230,7 @@ class APISmartLinkConditionView(generics.RetrieveUpdateDestroyAPIView):
|
||||
smart_link = get_object_or_404(klass=SmartLink, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=smart_link, permissions=permission_required,
|
||||
obj=smart_link, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -88,12 +88,12 @@ class ResolvedSmartLinkView(DocumentListView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document, permissions=permission_document_view,
|
||||
obj=self.document, permissions=(permission_document_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.smart_link, permissions=permission_smart_link_view,
|
||||
obj=self.smart_link, permissions=(permission_smart_link_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -109,8 +109,9 @@ class ResolvedSmartLinkView(DocumentListView):
|
||||
|
||||
try:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.smart_link, permissions=permission_smart_link_edit,
|
||||
user=self.request.user,
|
||||
obj=self.smart_link,
|
||||
permissions=(permission_smart_link_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
except PermissionDenied:
|
||||
pass
|
||||
@@ -205,7 +206,7 @@ class DocumentSmartLinkListView(SmartLinkListView):
|
||||
self.document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document, permissions=permission_document_view,
|
||||
obj=self.document, permissions=(permission_document_view,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -319,7 +320,8 @@ class SmartLinkConditionCreateView(SingleObjectCreateView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_smart_link(), permissions=permission_smart_link_edit,
|
||||
obj=self.get_smart_link(),
|
||||
permissions=(permission_smart_link_edit,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -359,7 +361,7 @@ class SmartLinkConditionEditView(SingleObjectEditView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_object().smart_link,
|
||||
permissions=permission_smart_link_edit, user=request.user
|
||||
permissions=(permission_smart_link_edit,), user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
@@ -388,7 +390,7 @@ class SmartLinkConditionDeleteView(SingleObjectDeleteView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.get_object().smart_link,
|
||||
permissions=permission_smart_link_edit, user=request.user
|
||||
permissions=(permission_smart_link_edit,), user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
|
||||
@@ -85,8 +85,8 @@ class MailDocumentView(MultipleObjectFormActionView):
|
||||
|
||||
def object_action(self, form, instance):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_user_mailer_use, user=self.request.user,
|
||||
obj=form.cleaned_data['user_mailer']
|
||||
obj=form.cleaned_data['user_mailer'],
|
||||
permissions=(permission_user_mailer_use,), user=self.request.user
|
||||
)
|
||||
|
||||
task_send_document.apply_async(
|
||||
@@ -261,8 +261,8 @@ class UserMailerTestView(FormView):
|
||||
def get_object(self):
|
||||
user_mailer = get_object_or_404(klass=UserMailer, pk=self.kwargs['pk'])
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_user_mailer_use, user=self.request.user,
|
||||
obj=user_mailer
|
||||
obj=user_mailer, permissions=(permission_user_mailer_use,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return user_mailer
|
||||
|
||||
@@ -43,8 +43,8 @@ class APIDocumentMetadataListView(generics.ListCreateAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document
|
||||
@@ -103,8 +103,8 @@ class APIDocumentMetadataView(generics.RetrieveUpdateDestroyAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document
|
||||
@@ -175,8 +175,8 @@ class APIDocumentTypeMetadataTypeListView(generics.ListCreateAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document_type
|
||||
obj=document_type, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document_type
|
||||
@@ -232,8 +232,8 @@ class APIDocumentTypeMetadataTypeView(generics.RetrieveUpdateDestroyAPIView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_required, user=self.request.user,
|
||||
obj=document_type
|
||||
obj=document_type, permissions=(permission_required,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document_type
|
||||
|
||||
@@ -397,8 +397,9 @@ class DocumentMetadataEditView(MultipleObjectFormActionView):
|
||||
class DocumentMetadataListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_metadata_document_view,
|
||||
user=self.request.user, obj=self.get_document()
|
||||
obj=self.get_document(),
|
||||
permissions=(permission_metadata_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return super(DocumentMetadataListView, self).dispatch(
|
||||
@@ -725,8 +726,8 @@ class SetupDocumentTypeMetadataTypes(FormView):
|
||||
obj = get_object_or_404(klass=self.model, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission_metadata_type_edit,),
|
||||
user=self.request.user, obj=obj
|
||||
obj=obj, permissions=(permission_metadata_type_edit,),
|
||||
user=self.request.user
|
||||
)
|
||||
return obj
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class Link(object):
|
||||
conditional_disable=None, description=None, html_data=None,
|
||||
html_extra_classes=None, icon_class=None, icon_class_path=None,
|
||||
keep_query=False, kwargs=None, name=None, permissions=None,
|
||||
permissions_related=None, remove_from_query=None, tags=None, url=None
|
||||
remove_from_query=None, tags=None, url=None
|
||||
):
|
||||
self.args = args or []
|
||||
self.badge_text = badge_text
|
||||
@@ -62,7 +62,6 @@ class Link(object):
|
||||
self.kwargs = kwargs or {}
|
||||
self.name = name
|
||||
self.permissions = permissions or []
|
||||
self.permissions_related = permissions_related
|
||||
self.remove_from_query = remove_from_query or []
|
||||
self.tags = tags
|
||||
self.text = text
|
||||
@@ -117,13 +116,13 @@ class Link(object):
|
||||
try:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=resolved_object, permissions=self.permissions,
|
||||
related=self.permissions_related, user=request.user
|
||||
user=request.user
|
||||
)
|
||||
except PermissionDenied:
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
Permission.check_permissions(
|
||||
Permission.check_user_permissions(
|
||||
permissions=self.permissions, user=request.user
|
||||
)
|
||||
except PermissionDenied:
|
||||
@@ -567,7 +566,7 @@ class SourceColumn(object):
|
||||
except KeyError:
|
||||
try:
|
||||
# Might be a subclass, try its root class
|
||||
result.extend(cls._registry[source.__class__.__mro__[-2]])
|
||||
result = cls._registry[source.__class__.__mro__[-2]]
|
||||
except KeyError:
|
||||
try:
|
||||
# Might be an inherited class insance, try its source class
|
||||
|
||||
@@ -27,7 +27,7 @@ def get_cascade_condition(app_label, model_name, object_permission, view_permiss
|
||||
|
||||
if view_permission:
|
||||
try:
|
||||
Permission.check_permissions(
|
||||
Permission.check_user_permissions(
|
||||
permissions=(view_permission,), user=context.request.user
|
||||
)
|
||||
except PermissionDenied:
|
||||
|
||||
@@ -73,7 +73,8 @@ class Permission(object):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def check_permissions(cls, permissions, user):
|
||||
def check_user_permissions(cls, permissions, user):
|
||||
# TODO: Remove list check. Add permissions arguments will be lists.
|
||||
try:
|
||||
for permission in permissions:
|
||||
if permission.stored_permission.user_has_this(user=user):
|
||||
|
||||
@@ -26,7 +26,7 @@ class PermissionTestCase(GroupTestMixin, PermissionTestMixin, RoleTestMixin, Use
|
||||
|
||||
def test_no_permissions(self):
|
||||
with self.assertRaises(PermissionDenied):
|
||||
Permission.check_permissions(
|
||||
Permission.check_user_permissions(
|
||||
permissions=(self.test_permission,), user=self.test_user
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ class PermissionTestCase(GroupTestMixin, PermissionTestMixin, RoleTestMixin, Use
|
||||
self.test_role.groups.add(self.test_group)
|
||||
|
||||
try:
|
||||
Permission.check_permissions(
|
||||
Permission.check_user_permissions(
|
||||
permissions=(self.test_permission,), user=self.test_user
|
||||
)
|
||||
except PermissionDenied:
|
||||
|
||||
@@ -12,14 +12,14 @@ from mayan.apps.permissions import Permission
|
||||
|
||||
class MayanPermission(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
required_permission = getattr(
|
||||
required_permissions = getattr(
|
||||
view, 'mayan_view_permissions', {}
|
||||
).get(request.method, None)
|
||||
|
||||
if required_permission:
|
||||
if required_permissions:
|
||||
try:
|
||||
Permission.check_permissions(
|
||||
permissions=required_permission, user=request.user
|
||||
Permission.check_user_permissions(
|
||||
permissions=required_permissions, user=request.user
|
||||
)
|
||||
except PermissionDenied:
|
||||
return False
|
||||
@@ -29,22 +29,15 @@ class MayanPermission(BasePermission):
|
||||
return True
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
required_permission = getattr(
|
||||
required_permissions = getattr(
|
||||
view, 'mayan_object_permissions', {}
|
||||
).get(request.method, None)
|
||||
|
||||
if required_permission:
|
||||
if required_permissions:
|
||||
try:
|
||||
if hasattr(view, 'mayan_permission_attribute_check'):
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=required_permission,
|
||||
user=request.user, obj=obj,
|
||||
related=view.mayan_permission_attribute_check
|
||||
)
|
||||
else:
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=required_permission, user=request.user,
|
||||
obj=obj
|
||||
obj=obj, permissions=required_permissions,
|
||||
user=request.user
|
||||
)
|
||||
except PermissionDenied:
|
||||
return False
|
||||
|
||||
@@ -248,7 +248,7 @@ class StagingFolderViewTestCase(GenericViewTestCase):
|
||||
}
|
||||
)
|
||||
|
||||
def test_staging_folder_delete_no_permission(self):
|
||||
def test_staging_file_delete_no_permission(self):
|
||||
staging_folder = StagingFolderSource.objects.create(
|
||||
label=TEST_SOURCE_LABEL,
|
||||
folder_path=self.temporary_directory,
|
||||
@@ -263,11 +263,11 @@ class StagingFolderViewTestCase(GenericViewTestCase):
|
||||
response = self._request_staging_file_delete_view(
|
||||
staging_folder=staging_folder, staging_file=staging_file
|
||||
)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
self.assertEqual(len(list(staging_folder.get_files())), 1)
|
||||
|
||||
def test_staging_folder_delete_with_permission(self):
|
||||
def test_staging_file_delete_with_permission(self):
|
||||
self.grant_permission(permission=permission_staging_file_delete)
|
||||
|
||||
staging_folder = StagingFolderSource.objects.create(
|
||||
|
||||
@@ -14,12 +14,13 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.checkouts.models import NewVersionBlock
|
||||
from mayan.apps.common.menus import menu_facet
|
||||
from mayan.apps.common.models import SharedUploadedFile
|
||||
from mayan.apps.common.generics import (
|
||||
ConfirmView, MultiFormView, SingleObjectCreateView,
|
||||
SingleObjectDeleteView, SingleObjectEditView, SingleObjectListView
|
||||
)
|
||||
from mayan.apps.common.menus import menu_facet
|
||||
from mayan.apps.common.mixins import ExternalObjectMixin
|
||||
from mayan.apps.common.models import SharedUploadedFile
|
||||
from mayan.apps.documents.models import DocumentType, Document
|
||||
from mayan.apps.documents.permissions import (
|
||||
permission_document_create, permission_document_new_version
|
||||
@@ -205,7 +206,7 @@ class UploadInteractiveView(UploadBaseView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document_type, permissions=permission_document_create,
|
||||
obj=self.document_type, permissions=(permission_document_create,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
@@ -386,7 +387,7 @@ class UploadInteractiveVersionView(UploadBaseView):
|
||||
)
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document, permissions=permission_document_new_version,
|
||||
obj=self.document, permissions=(permission_document_new_version,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -474,28 +475,22 @@ class UploadInteractiveVersionView(UploadBaseView):
|
||||
return context
|
||||
|
||||
|
||||
class StagingFileDeleteView(SingleObjectDeleteView):
|
||||
object_permission = permission_staging_file_delete
|
||||
object_permission_related = 'staging_folder'
|
||||
class StagingFileDeleteView(ExternalObjectMixin, SingleObjectDeleteView):
|
||||
external_object_class = StagingFolderSource
|
||||
external_object_permission = permission_staging_file_delete
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.get_object(),
|
||||
'object': self.object,
|
||||
'object_name': _('Staging file'),
|
||||
'source': self.get_source(),
|
||||
'title': _('Delete staging file "%s"?') % self.object,
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
source = self.get_source()
|
||||
return source.get_file(
|
||||
return self.external_object.get_file(
|
||||
encoded_filename=self.kwargs['encoded_filename']
|
||||
)
|
||||
|
||||
def get_source(self):
|
||||
return get_object_or_404(
|
||||
klass=StagingFolderSource, pk=self.kwargs['pk']
|
||||
)
|
||||
|
||||
|
||||
# Setup views
|
||||
class SetupSourceCheckView(ConfirmView):
|
||||
|
||||
@@ -89,7 +89,7 @@ class APITagDocumentListView(generics.ListAPIView):
|
||||
tag = get_object_or_404(klass=Tag, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_tag_view, user=self.request.user, obj=tag
|
||||
obj=tag, permissions=(permission_tag_view,), user=self.request.user
|
||||
)
|
||||
|
||||
return tag.documents.all()
|
||||
@@ -113,8 +113,8 @@ class APIDocumentTagListView(generics.ListCreateAPIView):
|
||||
document = self.get_document()
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
return document.attached_tags().all()
|
||||
@@ -165,8 +165,8 @@ class APIDocumentTagView(generics.RetrieveDestroyAPIView):
|
||||
document = get_object_or_404(klass=Document, pk=self.kwargs['document_pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=permission_document_view, user=self.request.user,
|
||||
obj=document
|
||||
obj=document, permissions=(permission_document_view,),
|
||||
user=self.request.user
|
||||
)
|
||||
return document
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ class NewDocumentTagSerializer(serializers.Serializer):
|
||||
|
||||
try:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=tag, permissions=permission_tag_attach,
|
||||
obj=tag, permissions=(permission_tag_attach,),
|
||||
user=self.context['request'].user
|
||||
)
|
||||
except PermissionDenied:
|
||||
|
||||
@@ -100,7 +100,7 @@ class TagAttachActionView(MultipleObjectFormActionView):
|
||||
|
||||
for tag in form.cleaned_data['tags']:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=tag, permissions=permission_tag_attach,
|
||||
obj=tag, permissions=(permission_tag_attach,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
@@ -251,7 +251,7 @@ class DocumentTagListView(TagListView):
|
||||
self.document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document, permissions=permission_document_view,
|
||||
obj=self.document, permissions=(permission_document_view,),
|
||||
user=request.user,
|
||||
)
|
||||
|
||||
@@ -348,7 +348,7 @@ class TagRemoveActionView(MultipleObjectFormActionView):
|
||||
|
||||
for tag in form.cleaned_data['tags']:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=tag, permissions=permission_tag_remove,
|
||||
obj=tag, permissions=(permission_tag_remove,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
@@ -149,8 +149,7 @@ class APIUserGroupList(generics.ListCreateAPIView):
|
||||
user = get_object_or_404(klass=get_user_model(), pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
permissions=(permission,), user=self.request.user,
|
||||
obj=user
|
||||
obj=user, permissions=(permission,), user=self.request.user
|
||||
)
|
||||
return user
|
||||
|
||||
|
||||
Reference in New Issue
Block a user