diff --git a/mayan/apps/acls/__init__.py b/mayan/apps/acls/__init__.py index e69de29bb2..f6a961cd19 100644 --- a/mayan/apps/acls/__init__.py +++ b/mayan/apps/acls/__init__.py @@ -0,0 +1 @@ +from .classes import ModelPermission # NOQA diff --git a/mayan/apps/acls/api.py b/mayan/apps/acls/api.py deleted file mode 100644 index 314eaad0c2..0000000000 --- a/mayan/apps/acls/api.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import unicode_literals - -from django.contrib.contenttypes.models import ContentType - -_class_permissions = {} - - -def class_permissions(cls, permission_list): - """ - Associate a permissions list to a class - """ - stored_permissions = _class_permissions.setdefault(cls, []) - stored_permissions.extend(permission_list) - - -def get_class_permissions_for(obj): - """ - Return a list of permissions associated with a content type - """ - content_type = ContentType.objects.get_for_model(obj) - return _class_permissions.get(content_type.model_class(), []) - - -def get_classes(): - """ - Return a list of encapsulated classes that have been registered - """ - return _class_permissions.keys() diff --git a/mayan/apps/acls/classes.py b/mayan/apps/acls/classes.py index 38bec74a0d..f8eae62b71 100644 --- a/mayan/apps/acls/classes.py +++ b/mayan/apps/acls/classes.py @@ -1,138 +1,22 @@ -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import import logging -from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ObjectDoesNotExist -from django.db.models.base import ModelBase - -from common.models import AnonymousUserSingleton - logger = logging.getLogger(__name__) -_cache = {} - -def get_source_object(obj): - if isinstance(obj, EncapsulatedObject): - return obj.source_object - else: - return obj - - -class EncapsulatedObject(object): - source_object_name = 'source_object' +class ModelPermission(object): + _registry = {} @classmethod - def object_key(cls, app_label=None, model=None, pk=None): - if pk: - return '%s.%s.%s.%s' % (cls.__name__, app_label, model, pk) - else: - return '%s.%s.%s' % (cls.__name__, app_label, model) + def register(cls, model, permissions): + cls._registry.setdefault(model, []) + for permission in permissions: + cls._registry[model].append(permission.stored_permission.pk) @classmethod - def add_to_class(cls, name, value): - if hasattr(value, 'contribute_to_class'): - value.contribute_to_class(cls, name) - else: - setattr(cls, name, value) + def get_for_instance(cls, instance): + from permissions.models import StoredPermission - @classmethod - def set_source_object_name(cls, new_name): - cls.source_object_name = new_name - - # @classmethod - # def encapsulate_list(cls, source_object=None, app_label=None, model=None, pk=None): - - @classmethod - def encapsulate(cls, source_object): - source_object = AnonymousUserSingleton.objects.passthru_check(source_object) - content_type = ContentType.objects.get_for_model(source_object) - - if hasattr(source_object, 'pk'): - # Object - object_key = cls.object_key(content_type.app_label, content_type.model, source_object.pk) - else: - # Class - object_key = cls.object_key(content_type.app_label, content_type.model) - - try: - return _cache[object_key] - except KeyError: - encapsulated_object = cls(source_object) - _cache[object_key] = encapsulated_object - return encapsulated_object - - @classmethod - def get(cls, gid): - elements = gid.split('.') - if len(elements) == 3: - app_label, model, pk = elements[0], elements[1], elements[2] - elif len(elements) == 2: - app_label, model = elements[0], elements[1] - pk = None - - object_key = cls.object_key(*elements) - - try: - return _cache[object_key] - except KeyError: - try: - content_type = ContentType.objects.get(app_label=app_label, model=model) - except ContentType.DoesNotExist: - raise ObjectDoesNotExist('%s matching query does not exist.' % ContentType._meta.object_name) - else: - source_object_model_class = content_type.model_class() - if pk: - try: - source_object = content_type.get_object_for_this_type(pk=pk) - except source_object_model_class.DoesNotExist: - raise ObjectDoesNotExist('%s matching query does not exist.' % source_object_model_class._meta.object_name) - else: - source_object = source_object_model_class - - return cls.encapsulate(source_object) - - def __init__(self, source_object): - self.content_type = ContentType.objects.get_for_model(source_object) - self.ct_fullname = '%s.%s' % (self.content_type.app_label, self.content_type.model) - - if isinstance(source_object, ModelBase): - # Class - self.gid = '%s.%s' % (self.content_type.app_label, self.content_type.model) - else: - # Object - self.gid = '%s.%s.%s' % (self.content_type.app_label, self.content_type.model, source_object.pk) - - setattr(self, self.__class__.source_object_name, source_object) - - def __unicode__(self): - if isinstance(self.source_object, ModelBase): - return unicode(self.source_object._meta.verbose_name_plural) - elif self.ct_fullname == 'auth.user': - return '%s %s' % (self.source_object._meta.verbose_name, self.source_object.get_full_name()) - elif self.ct_fullname == 'common.anonymoususersingleton': - return unicode(self.source_object) - elif self.ct_fullname == 'acls.creatorsingleton': - return unicode(self.source_object) - else: - return '%s %s' % (self.source_object._meta.verbose_name, self.source_object) - - def __repr__(self): - return self.__unicode__() - - @property - def source_object(self): - return getattr(self, self.__class__.source_object_name, None) - - -class AccessHolder(EncapsulatedObject): - source_object_name = 'holder_object' - - -class AccessObject(EncapsulatedObject): - source_object_name = 'obj' - - -class AccessObjectClass(EncapsulatedObject): - source_object_name = 'cls' + pks = cls._registry.get(type(instance), ()) + return StoredPermission.objects.filter(pk__in=pks) diff --git a/mayan/apps/acls/managers.py b/mayan/apps/acls/managers.py index 05e0de623f..5867447011 100644 --- a/mayan/apps/acls/managers.py +++ b/mayan/apps/acls/managers.py @@ -13,8 +13,6 @@ from django.utils.translation import ugettext from common.models import AnonymousUserSingleton from permissions import Permission -from .classes import AccessHolder, get_source_object - logger = logging.getLogger(__name__) diff --git a/mayan/apps/acls/views.py b/mayan/apps/acls/views.py index 5508944f6d..3593e460d0 100644 --- a/mayan/apps/acls/views.py +++ b/mayan/apps/acls/views.py @@ -17,6 +17,7 @@ from common.views import ( from permissions import Permission, PermissionNamespace from permissions.models import StoredPermission +from .classes import ModelPermission from .models import AccessControlList from .permissions import permission_acl_edit, permission_acl_view @@ -137,7 +138,7 @@ class ACLPermissionsView(AssignRemoveView): def left_list(self): results = [] - for namespace, permissions in itertools.groupby(StoredPermission.objects.exclude(id__in=self.get_object().permissions.values_list('pk', flat=True)), lambda entry: entry.namespace): + for namespace, permissions in itertools.groupby(ModelPermission.get_for_instance(instance=self.get_object().content_object).exclude(id__in=self.get_object().permissions.values_list('pk', flat=True)), lambda entry: entry.namespace): permission_options = [(unicode(permission.pk), permission) for permission in permissions] results.append((PermissionNamespace.get(namespace), permission_options)) diff --git a/mayan/apps/checkouts/apps.py b/mayan/apps/checkouts/apps.py index e68085af77..10c25c429c 100644 --- a/mayan/apps/checkouts/apps.py +++ b/mayan/apps/checkouts/apps.py @@ -5,7 +5,7 @@ from datetime import timedelta from django.db.models.signals import pre_save from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from common import MayanAppConfig, menu_facet, menu_main, menu_sidebar from documents.models import Document, DocumentVersion from mayan.celery import app @@ -47,11 +47,13 @@ class CheckoutsApp(MayanAppConfig): }, }) - class_permissions(Document, [ - permission_document_checkout, - permission_document_checkin, - permission_document_checkin_override, - ]) + ModelPermission.register( + model=Document, permissions=( + permission_document_checkout, + permission_document_checkin, + permission_document_checkin_override, + ) + ) menu_facet.bind_links(links=[link_checkout_info], sources=[Document]) menu_main.bind_links(links=[link_checkout_list]) diff --git a/mayan/apps/document_comments/apps.py b/mayan/apps/document_comments/apps.py index 7009b61bf4..50d8b04884 100644 --- a/mayan/apps/document_comments/apps.py +++ b/mayan/apps/document_comments/apps.py @@ -4,7 +4,7 @@ from django.contrib.comments.models import Comment from django.contrib.contenttypes import generic from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from common import MayanAppConfig, menu_facet, menu_object, menu_sidebar from common.classes import ModelAttribute from common.utils import encapsulate @@ -44,10 +44,11 @@ class DocumentCommentsApp(MayanAppConfig): SourceColumn(source=Comment, label=_('User'), attribute=encapsulate(lambda x: x.user.get_full_name() if x.user.get_full_name() else x.user)) SourceColumn(source=Comment, label=_('Comment'), attribute='comment') - class_permissions(Document, [ - permission_comment_create, - permission_comment_delete, - permission_comment_view] + ModelPermission.register( + model=Document, permissions=( + permission_comment_create, permission_comment_delete, + permission_comment_view + ) ) menu_sidebar.bind_links(links=[link_comment_add], sources=['comments:comments_for_document', 'comments:comment_add', 'comments:comment_delete', 'comments:comment_multiple_delete']) diff --git a/mayan/apps/document_signatures/apps.py b/mayan/apps/document_signatures/apps.py index 8c7995387e..bd7bfbb94e 100644 --- a/mayan/apps/document_signatures/apps.py +++ b/mayan/apps/document_signatures/apps.py @@ -9,7 +9,7 @@ except ImportError: from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from common import MayanAppConfig, menu_facet, menu_sidebar from django_gpg.exceptions import GPGDecryptionError from django_gpg.runtime import gpg @@ -67,12 +67,12 @@ class DocumentSignaturesApp(MayanAppConfig): DocumentVersion.register_post_save_hook(1, document_version_post_save_hook) DocumentVersion.register_pre_open_hook(1, document_pre_open_hook) - class_permissions(Document, [ - permission_document_verify, - permission_signature_delete, - permission_signature_download, - permission_signature_upload, - ]) + ModelPermission.register( + model=Document, permissions=( + permission_document_verify, permission_signature_delete, + permission_signature_download, permission_signature_upload, + ) + ) menu_facet.bind_links(links=[link_document_verify], sources=[Document]) menu_sidebar.bind_links(links=[link_document_signature_upload, link_document_signature_download, link_document_signature_delete], sources=['signatures:document_verify', 'signatures:document_signature_upload', 'signatures:document_signature_download', 'signatures:document_signature_delete']) diff --git a/mayan/apps/documents/apps.py b/mayan/apps/documents/apps.py index a2cc9600ac..5644558815 100644 --- a/mayan/apps/documents/apps.py +++ b/mayan/apps/documents/apps.py @@ -4,7 +4,7 @@ from django.utils.translation import ugettext_lazy as _ from actstream import registry -from acls.api import class_permissions +from acls import ModelPermission from acls.links import link_acl_list from acls.permissions import permission_acl_edit, permission_acl_view from common import ( @@ -78,19 +78,18 @@ class DocumentsApp(MayanAppConfig): ModelAttribute(Document, label=_('Label'), name='label', type_name='field') - class_permissions(Document, [ - ]) - - class_permissions(Document, [ - permission_acl_edit, permission_acl_view, - permission_document_delete, permission_document_download, - permission_document_edit, permission_document_new_version, - permission_document_print, permission_document_properties_edit, - permission_document_version_revert, permission_document_view, - permission_events_view, permission_transformation_create, - permission_transformation_delete, permission_transformation_edit, - permission_transformation_view, - ]) + ModelPermission.register( + model=Document, permissions=( + permission_acl_edit, permission_acl_view, + permission_document_delete, permission_document_download, + permission_document_edit, permission_document_new_version, + permission_document_print, permission_document_properties_edit, + permission_document_version_revert, permission_document_view, + permission_events_view, permission_transformation_create, + permission_transformation_delete, permission_transformation_edit, + permission_transformation_view, + ) + ) menu_front_page.bind_links(links=[link_document_list_recent, link_document_list]) menu_setup.bind_links(links=[link_document_type_setup]) diff --git a/mayan/apps/folders/apps.py b/mayan/apps/folders/apps.py index 8bbb3ab337..5c48692889 100644 --- a/mayan/apps/folders/apps.py +++ b/mayan/apps/folders/apps.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from acls.links import link_acl_list from acls.permissions import permission_acl_edit, permission_acl_view from common import ( @@ -38,14 +38,18 @@ class FoldersApp(MayanAppConfig): APIEndPoint('folders') - class_permissions(Document, [ - permission_folder_add_document, permission_folder_remove_document - ]) + ModelPermission.register( + model=Document, permissions=( + permission_folder_add_document, permission_folder_remove_document + ) + ) - class_permissions(Folder, [ - permission_acl_edit, permission_acl_view, permission_folder_delete, - permission_folder_edit, permission_folder_view - ]) + ModelPermission.register( + model=Folder, permissions=( + permission_acl_edit, permission_acl_view, permission_folder_delete, + permission_folder_edit, permission_folder_view + ) + ) menu_facet.bind_links(links=[link_document_folder_list], sources=[Document]) menu_main.bind_links(links=[link_folder_list]) diff --git a/mayan/apps/linking/apps.py b/mayan/apps/linking/apps.py index aad16ceefa..5208dd0b0f 100644 --- a/mayan/apps/linking/apps.py +++ b/mayan/apps/linking/apps.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from acls.links import link_acl_list from acls.permissions import permission_acl_edit, permission_acl_view from common import ( @@ -34,11 +34,13 @@ class LinkingApp(MayanAppConfig): def ready(self): super(LinkingApp, self).ready() - class_permissions(SmartLink, [ - permission_acl_edit, permission_acl_view, - permission_smart_link_delete, permission_smart_link_edit, - permission_smart_link_view - ]) + ModelPermission.register( + model=SmartLink, permissions=( + permission_acl_edit, permission_acl_view, + permission_smart_link_delete, permission_smart_link_edit, + permission_smart_link_view + ) + ) menu_facet.bind_links(links=[link_smart_link_instances_for_document], sources=[Document]) menu_object.bind_links(links=[link_smart_link_condition_edit, link_smart_link_condition_delete], sources=[SmartLinkCondition]) diff --git a/mayan/apps/mailer/apps.py b/mayan/apps/mailer/apps.py index c370473f60..97818de778 100644 --- a/mayan/apps/mailer/apps.py +++ b/mayan/apps/mailer/apps.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from common import MayanAppConfig, menu_object from documents.models import Document @@ -19,8 +19,10 @@ class MailerApp(MayanAppConfig): def ready(self): super(MailerApp, self).ready() - class_permissions(Document, [ - permission_mailing_link, permission_mailing_send_document - ]) + ModelPermission.register( + model=Document, permissions=( + permission_mailing_link, permission_mailing_send_document + ) + ) menu_object.bind_links(links=[link_send_document_link, link_send_document], sources=[Document]) diff --git a/mayan/apps/metadata/apps.py b/mayan/apps/metadata/apps.py index 8c608cbf2a..69d7fd60af 100644 --- a/mayan/apps/metadata/apps.py +++ b/mayan/apps/metadata/apps.py @@ -5,7 +5,7 @@ import logging from django.db.models.signals import post_delete, post_save from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from common import ( MayanAppConfig, menu_facet, menu_multi_item, menu_object, menu_secondary, menu_setup, menu_sidebar, menu_tools @@ -60,10 +60,12 @@ class MetadataApp(MayanAppConfig): SourceColumn(source=Document, label=_('Metadata'), attribute=encapsulate(lambda document: get_metadata_string(document))) - class_permissions(Document, [ - permission_metadata_document_add, permission_metadata_document_edit, - permission_metadata_document_remove, permission_metadata_document_view, - ]) + ModelPermission.register( + model=Document, permissions=( + permission_metadata_document_add, permission_metadata_document_edit, + permission_metadata_document_remove, permission_metadata_document_view, + ) + ) document_search.add_model_field(field='metadata__metadata_type__name', label=_('Metadata type')) document_search.add_model_field(field='metadata__value', label=_('Metadata value')) diff --git a/mayan/apps/ocr/apps.py b/mayan/apps/ocr/apps.py index 0aac61c4b4..f1f21b641f 100644 --- a/mayan/apps/ocr/apps.py +++ b/mayan/apps/ocr/apps.py @@ -6,7 +6,7 @@ import sh from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from common import ( MayanAppConfig, menu_facet, menu_multi_item, menu_object, menu_secondary, menu_tools @@ -59,10 +59,10 @@ class OCRApp(MayanAppConfig): SourceColumn(source=DocumentVersionOCRError, label=_('Added'), attribute='datetime_submitted') SourceColumn(source=DocumentVersionOCRError, label=_('Result'), attribute='result') - class_permissions( - Document, [ + ModelPermission.register( + model=Document, permissions=( permission_ocr_document, permission_ocr_content_view - ] + ) ) document_search.add_model_field(field='versions__pages__ocr_content__content', label=_('Content')) diff --git a/mayan/apps/tags/apps.py b/mayan/apps/tags/apps.py index 7be18c81f4..a003dff06d 100644 --- a/mayan/apps/tags/apps.py +++ b/mayan/apps/tags/apps.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ -from acls.api import class_permissions +from acls import ModelPermission from acls.links import link_acl_list from acls.permissions import permission_acl_edit, permission_acl_view from common import ( @@ -38,19 +38,24 @@ class TagsApp(MayanAppConfig): APIEndPoint('tags') + ModelPermission.register( + model=Document, permissions=( + permission_tag_attach, permission_tag_remove, + ) + ) + + ModelPermission.register( + model=Tag, permissions=( + permission_acl_edit, permission_acl_view, permission_tag_delete, + permission_tag_edit, permission_tag_view, + ) + ) + SourceColumn(source=Document, label=_('Tags'), attribute=encapsulate(lambda document: widget_inline_tags(document))) SourceColumn(source=Tag, label=_('Preview'), attribute=encapsulate(lambda tag: widget_single_tag(tag))) SourceColumn(source=Tag, label=_('Tagged items'), attribute=encapsulate(lambda tag: tag.documents.count())) - class_permissions(Document, [ - permission_tag_attach, permission_tag_remove, - ]) - class_permissions(Tag, [ - permission_acl_edit, permission_acl_view, permission_tag_delete, - permission_tag_edit, permission_tag_view, - ]) - document_search.add_model_field(field='tags__label', label=_('Tags')) menu_facet.bind_links(links=[link_tag_document_list], sources=[Document])