diff --git a/apps/checkouts/__init__.py b/apps/checkouts/__init__.py index 1b3f2b740a..2ad1a215b6 100644 --- a/apps/checkouts/__init__.py +++ b/apps/checkouts/__init__.py @@ -11,7 +11,9 @@ from documents.permissions import PERMISSION_DOCUMENT_VIEW from acls.api import class_permissions from history.api import register_history_type -from .permissions import (PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE) +from .permissions import (PERMISSION_DOCUMENT_CHECKOUT, + PERMISSION_DOCUMENT_CHECKIN, PERMISSION_DOCUMENT_CHECKIN_OVERRIDE, + PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE) from .links import checkout_list, checkout_document, checkout_info, checkin_document from .models import DocumentCheckout from .tasks import task_check_expired_check_outs @@ -23,7 +25,7 @@ def initialize_document_checkout_extra_methods(): Document.add_to_class('check_in', lambda document, user=None: DocumentCheckout.objects.check_in_document(document, user)) Document.add_to_class('checkout_info', lambda document: DocumentCheckout.objects.document_checkout_info(document)) Document.add_to_class('checkout_state', lambda document: DocumentCheckout.objects.document_checkout_state(document)) - Document.add_to_class('is_new_versions_allowed', lambda document: DocumentCheckout.objects.is_document_new_versions_allowed(document)) + Document.add_to_class('is_new_versions_allowed', lambda document, user=None: DocumentCheckout.objects.is_document_new_versions_allowed(document, user)) register_top_menu(name='checkouts', link=checkout_list) register_links(Document, [checkout_info], menu_name='form_header') @@ -32,7 +34,8 @@ register_links(['checkout_info', 'checkout_document', 'checkin_document'], [chec class_permissions(Document, [ PERMISSION_DOCUMENT_CHECKOUT, PERMISSION_DOCUMENT_CHECKIN, - PERMISSION_DOCUMENT_CHECKIN_OVERRIDE + PERMISSION_DOCUMENT_CHECKIN_OVERRIDE, + PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE ]) CHECK_EXPIRED_CHECK_OUTS_INTERVAL=60 # Lowest check out expiration allowed @@ -42,5 +45,3 @@ register_history_type(HISTORY_DOCUMENT_CHECKED_OUT) register_history_type(HISTORY_DOCUMENT_CHECKED_IN) #TODO: forcefull check in -#TODO: add checkin out history -#TODO: limit restrictions to non checkout user and admins? diff --git a/apps/checkouts/managers.py b/apps/checkouts/managers.py index bd3d815a12..c1185651ef 100644 --- a/apps/checkouts/managers.py +++ b/apps/checkouts/managers.py @@ -4,13 +4,17 @@ import datetime import logging from django.db import models +from django.core.exceptions import PermissionDenied from documents.models import Document from history.api import create_history +from permissions.models import Permission +from acls.models import AccessEntry from .exceptions import DocumentNotCheckedOut from .literals import STATE_CHECKED_OUT, STATE_CHECKED_IN from .events import HISTORY_DOCUMENT_CHECKED_IN +from .permissions import PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE logger = logging.getLogger(__name__) @@ -56,8 +60,34 @@ class DocumentCheckoutManager(models.Manager): else: return STATE_CHECKED_IN - def is_document_new_versions_allowed(self, document): + def is_document_new_versions_allowed(self, document, user=None): try: - return not self.document_checkout_info(document).block_new_version + checkout_info = self.document_checkout_info(document) except DocumentNotCheckedOut: return True + else: + if not user: + return not checkout_info.block_new_version + else: + if user.is_staff or user.is_superuser: + # Allow anything to superusers and staff + return True + + if user == checkout_info.user_object: + # Allow anything to the user who checked out this document + True + else: + # If not original user check to see if user has global or this document's PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE permission + try: + Permission.objects.check_permissions(user, [PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE]) + except PermissionDenied: + try: + AccessEntry.objects.check_accesses([PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE], user, document) + except PermissionDenied: + # Last resort check if original user enabled restriction + return not checkout_info.block_new_version + else: + return True + else: + return True + diff --git a/apps/checkouts/permissions.py b/apps/checkouts/permissions.py index 2a24c9d47d..19430381b8 100644 --- a/apps/checkouts/permissions.py +++ b/apps/checkouts/permissions.py @@ -9,4 +9,5 @@ namespace = PermissionNamespace('checkouts', _(u'Document checkout')) PERMISSION_DOCUMENT_CHECKOUT = Permission.objects.register(namespace, 'checkout_document', _(u'Check out documents')) PERMISSION_DOCUMENT_CHECKIN = Permission.objects.register(namespace, 'checkin_document', _(u'Check in documents')) PERMISSION_DOCUMENT_CHECKIN_OVERRIDE = Permission.objects.register(namespace, 'checkin_document_override', _(u'Forcefully check in documents')) +PERMISSION_DOCUMENT_RESTRICTIONS_OVERRIDE = Permission.objects.register(namespace, 'checkout_restrictions_override', _(u'Allow overriding check out restrictions')) diff --git a/apps/documents/models.py b/apps/documents/models.py index d941c86c7d..eb94051902 100644 --- a/apps/documents/models.py +++ b/apps/documents/models.py @@ -170,9 +170,9 @@ class Document(models.Model): def size(self): return self.latest_version.size - def new_version(self, file, comment=None, version_update=None, release_level=None, serial=None): + def new_version(self, file, user=None, comment=None, version_update=None, release_level=None, serial=None): logger.debug('creating new document version') - if not self.is_new_versions_allowed(): + if not self.is_new_versions_allowed(user=user): raise NewDocumentVersionNotAllowed if version_update: diff --git a/apps/sources/models.py b/apps/sources/models.py index 0941abd00d..e659b4e60e 100644 --- a/apps/sources/models.py +++ b/apps/sources/models.py @@ -114,7 +114,7 @@ class BaseModel(models.Model): new_version_data = {} try: - new_version = document.new_version(file=file_object, **new_version_data) + new_version = document.new_version(file=file_object, user=user, **new_version_data) except Exception: # Don't leave the database in a broken state # document.delete() diff --git a/apps/sources/views.py b/apps/sources/views.py index c436e4daeb..0014d9b4cf 100644 --- a/apps/sources/views.py +++ b/apps/sources/views.py @@ -176,10 +176,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No return HttpResponseRedirect(request.get_full_path()) except NewDocumentVersionNotAllowed: - if not document.is_new_versions_allowed(): - messages.error(request, _(u'The check out options for document currently don\'t allow new version uploads.')) - else: - messages.error(request, _(u'This document currently don\'t allow new version uploads.')) + messages.error(request, _(u'New version uploads are not allowed for this document.')) except Exception, e: if settings.DEBUG: raise @@ -260,10 +257,7 @@ def upload_interactive(request, source_type=None, source_id=None, document_pk=No else: return HttpResponseRedirect(request.get_full_path()) except NewDocumentVersionNotAllowed: - if not document.is_new_versions_allowed: - messages.error(request, _(u'The check out options for document currently don\'t allow new version uploads.')) - else: - messages.error(request, _(u'This document currently don\'t allow new version uploads.')) + messages.error(request, _(u'New version uploads are not allowed for this document.')) except Exception, e: if settings.DEBUG: raise