Refactor checkouts app
Change "checkin" usage to "check_in".
Update URL parameters to the "_id" form.
Add support to checkout and check in multiple documents.
Optimize queries that used an ID list of documents for
filtering using values_list('pk', flat=True). These
queries now use .values('pk') as a subquery.
Add pre save hooks to block new document version uploads.
Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
@@ -225,6 +225,8 @@
|
|||||||
- Remove the permissions to grant or revoke a permission to a role.
|
- Remove the permissions to grant or revoke a permission to a role.
|
||||||
The instead the role edit permission is used.
|
The instead the role edit permission is used.
|
||||||
- Add a test mixin to generate random model primary keys.
|
- Add a test mixin to generate random model primary keys.
|
||||||
|
- Add support for checkout and check in multiple documents at
|
||||||
|
the same time.
|
||||||
|
|
||||||
3.1.9 (2018-11-01)
|
3.1.9 (2018-11-01)
|
||||||
==================
|
==================
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from mayan.apps.documents.permissions import permission_document_view
|
|||||||
|
|
||||||
from .models import DocumentCheckout
|
from .models import DocumentCheckout
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_document_checkin, permission_document_checkin_override,
|
permission_document_check_in, permission_document_check_in_override,
|
||||||
permission_document_checkout_detail_view
|
permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
from .serializers import (
|
from .serializers import (
|
||||||
@@ -78,12 +78,12 @@ class APICheckedoutDocumentView(generics.RetrieveDestroyAPIView):
|
|||||||
|
|
||||||
if document.checkout_info().user == request.user:
|
if document.checkout_info().user == request.user:
|
||||||
AccessControlList.objects.check_access(
|
AccessControlList.objects.check_access(
|
||||||
permissions=permission_document_checkin, user=request.user,
|
permissions=permission_document_check_in, user=request.user,
|
||||||
obj=document
|
obj=document
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
AccessControlList.objects.check_access(
|
AccessControlList.objects.check_access(
|
||||||
permissions=permission_document_checkin_override,
|
permissions=permission_document_check_in_override,
|
||||||
user=request.user, obj=document
|
user=request.user, obj=document
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
|
|
||||||
from mayan.apps.acls import ModelPermission
|
from mayan.apps.acls import ModelPermission
|
||||||
from mayan.apps.common import (
|
from mayan.apps.common import (
|
||||||
MayanAppConfig, menu_facet, menu_main, menu_sidebar
|
MayanAppConfig, menu_facet, menu_main, menu_multi_item, menu_sidebar
|
||||||
)
|
)
|
||||||
from mayan.apps.dashboards.dashboards import dashboard_main
|
from mayan.apps.dashboards.dashboards import dashboard_main
|
||||||
from mayan.apps.events import ModelEventType
|
from mayan.apps.events import ModelEventType
|
||||||
@@ -23,8 +23,9 @@ from .events import (
|
|||||||
)
|
)
|
||||||
from .handlers import handler_check_new_version_creation
|
from .handlers import handler_check_new_version_creation
|
||||||
from .links import (
|
from .links import (
|
||||||
link_checkin_document, link_checkout_document, link_checkout_info,
|
link_document_check_in, link_document_checkout, link_document_checkout_info,
|
||||||
link_checkout_list
|
link_document_checkout_list, link_document_multiple_check_in,
|
||||||
|
link_document_multiple_checkout
|
||||||
)
|
)
|
||||||
from .literals import CHECK_EXPIRED_CHECK_OUTS_INTERVAL
|
from .literals import CHECK_EXPIRED_CHECK_OUTS_INTERVAL
|
||||||
from .methods import (
|
from .methods import (
|
||||||
@@ -32,7 +33,7 @@ from .methods import (
|
|||||||
method_is_checked_out
|
method_is_checked_out
|
||||||
)
|
)
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_document_checkin, permission_document_checkin_override,
|
permission_document_check_in, permission_document_check_in_override,
|
||||||
permission_document_checkout, permission_document_checkout_detail_view
|
permission_document_checkout, permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
from .queues import * # NOQA
|
from .queues import * # NOQA
|
||||||
@@ -79,8 +80,8 @@ class CheckoutsApp(MayanAppConfig):
|
|||||||
ModelPermission.register(
|
ModelPermission.register(
|
||||||
model=Document, permissions=(
|
model=Document, permissions=(
|
||||||
permission_document_checkout,
|
permission_document_checkout,
|
||||||
permission_document_checkin,
|
permission_document_check_in,
|
||||||
permission_document_checkin_override,
|
permission_document_check_in_override,
|
||||||
permission_document_checkout_detail_view
|
permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -115,13 +116,18 @@ class CheckoutsApp(MayanAppConfig):
|
|||||||
widget=DashboardWidgetTotalCheckouts, order=-1
|
widget=DashboardWidgetTotalCheckouts, order=-1
|
||||||
)
|
)
|
||||||
|
|
||||||
menu_facet.bind_links(links=(link_checkout_info,), sources=(Document,))
|
menu_facet.bind_links(links=(link_document_checkout_info,), sources=(Document,))
|
||||||
menu_main.bind_links(links=(link_checkout_list,), position=98)
|
menu_main.bind_links(links=(link_document_checkout_list,), position=98)
|
||||||
|
menu_multi_item.bind_links(
|
||||||
|
links=(
|
||||||
|
link_document_multiple_check_in, link_document_multiple_checkout
|
||||||
|
), sources=(Document,)
|
||||||
|
)
|
||||||
menu_sidebar.bind_links(
|
menu_sidebar.bind_links(
|
||||||
links=(link_checkout_document, link_checkin_document),
|
links=(link_document_checkout, link_document_check_in),
|
||||||
sources=(
|
sources=(
|
||||||
'checkouts:checkout_info', 'checkouts:checkout_document',
|
'checkouts:document_checkout_info', 'checkouts:document_checkout',
|
||||||
'checkouts:checkin_document'
|
'checkouts:document_check_in'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from .permissions import permission_document_checkout_detail_view
|
|||||||
class DashboardWidgetTotalCheckouts(DashboardWidgetNumeric):
|
class DashboardWidgetTotalCheckouts(DashboardWidgetNumeric):
|
||||||
icon_class = icon_dashboard_checkouts
|
icon_class = icon_dashboard_checkouts
|
||||||
label = _('Checkedout documents')
|
label = _('Checkedout documents')
|
||||||
link = reverse_lazy(viewname='checkouts:checkout_list')
|
link = reverse_lazy(viewname='checkouts:document_checkout_list')
|
||||||
|
|
||||||
def render(self, request):
|
def render(self, request):
|
||||||
AccessControlList = apps.get_model(
|
AccessControlList = apps.get_model(
|
||||||
|
|||||||
13
mayan/apps/checkouts/hooks.py
Normal file
13
mayan/apps/checkouts/hooks.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
|
||||||
|
|
||||||
|
def hook_is_new_version_allowed(document_version):
|
||||||
|
NewVersionBlock = apps.get_model(
|
||||||
|
app_label='checkouts', model_name='NewVersionBlock'
|
||||||
|
)
|
||||||
|
|
||||||
|
NewVersionBlock.objects.new_versions_allowed(
|
||||||
|
document_version=document_version.document
|
||||||
|
)
|
||||||
@@ -8,8 +8,8 @@ from .icons import (
|
|||||||
icon_checkin_document, icon_checkout_document, icon_checkout_info
|
icon_checkin_document, icon_checkout_document, icon_checkout_info
|
||||||
)
|
)
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_document_checkin, permission_document_checkin_override,
|
permission_document_check_in, permission_document_checkout,
|
||||||
permission_document_checkout, permission_document_checkout_detail_view
|
permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -29,23 +29,32 @@ def is_not_checked_out(context):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
link_checkout_list = Link(
|
link_document_checkout_list = Link(
|
||||||
icon_class=icon_checkout_info, text=_('Checkouts'),
|
icon_class=icon_checkout_info, text=_('Checkouts'),
|
||||||
view='checkouts:checkout_list'
|
view='checkouts:document_checkout_list'
|
||||||
)
|
)
|
||||||
link_checkout_document = Link(
|
link_document_checkout = Link(
|
||||||
args='object.pk', condition=is_not_checked_out,
|
condition=is_not_checked_out, icon_class=icon_checkout_document,
|
||||||
icon_class=icon_checkout_document,
|
kwargs={'document_id': 'object.pk'},
|
||||||
permission=permission_document_checkout, text=_('Check out document'),
|
permission=permission_document_checkout, text=_('Check out document'),
|
||||||
view='checkouts:checkout_document',
|
view='checkouts:document_checkout',
|
||||||
)
|
)
|
||||||
link_checkin_document = Link(
|
link_document_multiple_checkout = Link(
|
||||||
args='object.pk', condition=is_checked_out,
|
icon_class=icon_checkout_document,
|
||||||
icon_class=icon_checkin_document, permission=permission_document_checkin,
|
permission=permission_document_checkout, text=_('Check out'),
|
||||||
text=_('Check in document'), view='checkouts:checkin_document',
|
view='checkouts:document_multiple_checkout',
|
||||||
)
|
)
|
||||||
link_checkout_info = Link(
|
link_document_check_in = Link(
|
||||||
args='resolved_object.pk', icon_class=icon_checkout_info,
|
condition=is_checked_out, icon_class=icon_checkin_document,
|
||||||
|
kwargs={'document_id': 'object.pk'}, permission=permission_document_check_in,
|
||||||
|
text=_('Check in document'), view='checkouts:document_check_in',
|
||||||
|
)
|
||||||
|
link_document_multiple_check_in = Link(
|
||||||
|
icon_class=icon_checkin_document, permission=permission_document_check_in,
|
||||||
|
text=_('Check in'), view='checkouts:document_multiple_check_in',
|
||||||
|
)
|
||||||
|
link_document_checkout_info = Link(
|
||||||
|
icon_class=icon_checkout_info, kwargs={'document_id': 'resolved_object.pk'},
|
||||||
permission=permission_document_checkout_detail_view,
|
permission=permission_document_checkout_detail_view,
|
||||||
text=_('Check in/out'), view='checkouts:checkout_info',
|
text=_('Check in/out'), view='checkouts:document_checkout_info',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,39 +2,45 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.apps import apps
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from mayan.apps.acls.models import AccessControlList
|
||||||
from mayan.apps.documents.models import Document
|
from mayan.apps.documents.models import Document
|
||||||
|
|
||||||
from .events import (
|
from .events import (
|
||||||
event_document_auto_check_in, event_document_check_in,
|
event_document_auto_check_in, event_document_check_in,
|
||||||
event_document_forceful_check_in
|
event_document_forceful_check_in
|
||||||
)
|
)
|
||||||
from .exceptions import DocumentNotCheckedOut
|
from .exceptions import DocumentNotCheckedOut, NewDocumentVersionNotAllowed
|
||||||
from .literals import STATE_CHECKED_IN, STATE_CHECKED_OUT
|
from .literals import STATE_CHECKED_IN, STATE_CHECKED_OUT
|
||||||
|
from .permissions import permission_document_check_in_override
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DocumentCheckoutManager(models.Manager):
|
class DocumentCheckoutManager(models.Manager):
|
||||||
def are_document_new_versions_allowed(self, document, user=None):
|
|
||||||
try:
|
|
||||||
checkout_info = self.document_checkout_info(document=document)
|
|
||||||
except DocumentNotCheckedOut:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return not checkout_info.block_new_version
|
|
||||||
|
|
||||||
def check_in_document(self, document, user=None):
|
def check_in_document(self, document, user=None):
|
||||||
try:
|
try:
|
||||||
document_checkout = self.model.objects.get(document=document)
|
document_checkout = self.model.objects.get(document=document)
|
||||||
except self.model.DoesNotExist:
|
except self.model.DoesNotExist:
|
||||||
raise DocumentNotCheckedOut
|
raise DocumentNotCheckedOut(
|
||||||
|
_('Document not checked out.')
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
|
with transaction.atomic():
|
||||||
if user:
|
if user:
|
||||||
if self.get_document_checkout_info(document=document).user != user:
|
if self.get_document_checkout_info(document=document).user != user:
|
||||||
|
try:
|
||||||
|
AccessControlList.objects.check_access(
|
||||||
|
obj=document, permission=permission_document_check_in_override,
|
||||||
|
user=user
|
||||||
|
)
|
||||||
|
except PermissionDenied:
|
||||||
|
return
|
||||||
|
else:
|
||||||
event_document_forceful_check_in.commit(
|
event_document_forceful_check_in.commit(
|
||||||
actor=user, target=document
|
actor=user, target=document
|
||||||
)
|
)
|
||||||
@@ -57,15 +63,10 @@ class DocumentCheckoutManager(models.Manager):
|
|||||||
|
|
||||||
def checked_out_documents(self):
|
def checked_out_documents(self):
|
||||||
return Document.objects.filter(
|
return Document.objects.filter(
|
||||||
pk__in=self.model.objects.all().values_list(
|
pk__in=self.model.objects.values('document__id')
|
||||||
'document__pk', flat=True
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_by_natural_key(self, document_natural_key):
|
def get_by_natural_key(self, document_natural_key):
|
||||||
Document = apps.get_model(
|
|
||||||
app_label='documents', model_name='Document'
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
document = Document.objects.get_by_natural_key(document_natural_key)
|
document = Document.objects.get_by_natural_key(document_natural_key)
|
||||||
except Document.DoesNotExist:
|
except Document.DoesNotExist:
|
||||||
@@ -87,15 +88,15 @@ class DocumentCheckoutManager(models.Manager):
|
|||||||
|
|
||||||
def get_expired_check_outs(self):
|
def get_expired_check_outs(self):
|
||||||
expired_list = Document.objects.filter(
|
expired_list = Document.objects.filter(
|
||||||
pk__in=self.model.objects.filter(
|
pk__in=self.filter(
|
||||||
expiration_datetime__lte=now()
|
expiration_datetime__lte=now()
|
||||||
).values_list('document__pk', flat=True)
|
).values('document__id')
|
||||||
)
|
)
|
||||||
logger.debug('expired_list: %s', expired_list)
|
logger.debug('expired_list: %s', expired_list)
|
||||||
return expired_list
|
return expired_list
|
||||||
|
|
||||||
def is_document_checked_out(self, document):
|
def is_document_checked_out(self, document):
|
||||||
if self.model.objects.filter(document=document):
|
if self.filter(document=document).exists():
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@@ -105,13 +106,7 @@ class NewVersionBlockManager(models.Manager):
|
|||||||
def block(self, document):
|
def block(self, document):
|
||||||
self.get_or_create(document=document)
|
self.get_or_create(document=document)
|
||||||
|
|
||||||
def is_blocked(self, document):
|
|
||||||
return self.filter(document=document).exists()
|
|
||||||
|
|
||||||
def get_by_natural_key(self, document_natural_key):
|
def get_by_natural_key(self, document_natural_key):
|
||||||
Document = apps.get_model(
|
|
||||||
app_label='documents', model_name='Document'
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
document = Document.objects.get_by_natural_key(document_natural_key)
|
document = Document.objects.get_by_natural_key(document_natural_key)
|
||||||
except Document.DoesNotExist:
|
except Document.DoesNotExist:
|
||||||
@@ -119,5 +114,12 @@ class NewVersionBlockManager(models.Manager):
|
|||||||
|
|
||||||
return self.get(document__pk=document.pk)
|
return self.get(document__pk=document.pk)
|
||||||
|
|
||||||
|
def is_blocked(self, document):
|
||||||
|
return self.filter(document=document).exists()
|
||||||
|
|
||||||
|
def new_versions_allowed(self, document):
|
||||||
|
if self.filter(document=document).exist():
|
||||||
|
raise NewDocumentVersionNotAllowed
|
||||||
|
|
||||||
def unblock(self, document):
|
def unblock(self, document):
|
||||||
self.filter(document=document).delete()
|
self.filter(document=document).delete()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import logging
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
@@ -68,13 +68,14 @@ class DocumentCheckout(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def delete(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
# TODO: enclose in transaction
|
with transaction.atomic():
|
||||||
NewVersionBlock.objects.unblock(self.document)
|
NewVersionBlock.objects.unblock(document=self.document)
|
||||||
super(DocumentCheckout, self).delete(*args, **kwargs)
|
super(DocumentCheckout, self).delete(*args, **kwargs)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse(
|
return reverse(
|
||||||
viewname='checkout:checkout_info', kwargs={'pk': self.document.pk}
|
viewname='checkout:checkout_info',
|
||||||
|
kwargs={'document_id': self.document.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
def natural_key(self):
|
def natural_key(self):
|
||||||
@@ -82,11 +83,13 @@ class DocumentCheckout(models.Model):
|
|||||||
natural_key.dependencies = ['documents.Document']
|
natural_key.dependencies = ['documents.Document']
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
# TODO: enclose in transaction
|
|
||||||
new_checkout = not self.pk
|
new_checkout = not self.pk
|
||||||
if not new_checkout or self.document.is_checked_out():
|
if not new_checkout or self.document.is_checked_out():
|
||||||
raise DocumentAlreadyCheckedOut
|
raise DocumentAlreadyCheckedOut(
|
||||||
|
_('Document already checked out.')
|
||||||
|
)
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
result = super(DocumentCheckout, self).save(*args, **kwargs)
|
result = super(DocumentCheckout, self).save(*args, **kwargs)
|
||||||
if new_checkout:
|
if new_checkout:
|
||||||
event_document_check_out.commit(
|
event_document_check_out.commit(
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ from mayan.apps.permissions import PermissionNamespace
|
|||||||
|
|
||||||
namespace = PermissionNamespace(label=_('Document checkout'), name='checkouts')
|
namespace = PermissionNamespace(label=_('Document checkout'), name='checkouts')
|
||||||
|
|
||||||
permission_document_checkin = namespace.add_permission(
|
permission_document_check_in = namespace.add_permission(
|
||||||
label=_('Check in documents'), name='checkin_document'
|
label=_('Check in documents'), name='checkin_document'
|
||||||
)
|
)
|
||||||
permission_document_checkin_override = namespace.add_permission(
|
permission_document_check_in_override = namespace.add_permission(
|
||||||
label=_('Forcefully check in documents'), name='checkin_document_override'
|
label=_('Forcefully check in documents'), name='checkin_document_override'
|
||||||
)
|
)
|
||||||
permission_document_checkout = namespace.add_permission(
|
permission_document_checkout = namespace.add_permission(
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ class NewDocumentCheckoutSerializer(serializers.ModelSerializer):
|
|||||||
document = Document.objects.get(pk=validated_data.pop('document_pk'))
|
document = Document.objects.get(pk=validated_data.pop('document_pk'))
|
||||||
|
|
||||||
AccessControlList.objects.check_access(
|
AccessControlList.objects.check_access(
|
||||||
permissions=permission_document_checkout,
|
obj=document, permissions=permission_document_checkout,
|
||||||
obj=document, user=self.context['request'].user
|
user=self.context['request'].user
|
||||||
)
|
)
|
||||||
|
|
||||||
validated_data['document'] = document
|
validated_data['document'] = document
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class DocumentCheckoutTestCase(DocumentTestMixin, BaseTestCase):
|
|||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
DocumentCheckout.objects.checkout_document(
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
document=self.document, expiration_datetime=expiration_datetime,
|
||||||
user=self.admin_user, block_new_version=True
|
user=self._test_case_user, block_new_version=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertTrue(self.document.is_checked_out())
|
self.assertTrue(self.document.is_checked_out())
|
||||||
@@ -33,29 +33,12 @@ class DocumentCheckoutTestCase(DocumentTestMixin, BaseTestCase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_version_creation_blocking(self):
|
|
||||||
expiration_datetime = now() + datetime.timedelta(days=1)
|
|
||||||
|
|
||||||
# Silence unrelated logging
|
|
||||||
logging.getLogger('mayan.apps.documents.models').setLevel(
|
|
||||||
level=logging.CRITICAL
|
|
||||||
)
|
|
||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
|
||||||
user=self.admin_user, block_new_version=True
|
|
||||||
)
|
|
||||||
|
|
||||||
with self.assertRaises(NewDocumentVersionNotAllowed):
|
|
||||||
with open(TEST_SMALL_DOCUMENT_PATH, mode='rb') as file_object:
|
|
||||||
self.document.new_version(file_object=file_object)
|
|
||||||
|
|
||||||
def test_checkin_in(self):
|
def test_checkin_in(self):
|
||||||
expiration_datetime = now() + datetime.timedelta(days=1)
|
expiration_datetime = now() + datetime.timedelta(days=1)
|
||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
DocumentCheckout.objects.checkout_document(
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
document=self.document, expiration_datetime=expiration_datetime,
|
||||||
user=self.admin_user, block_new_version=True
|
user=self._test_case_user, block_new_version=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.document.check_in()
|
self.document.check_in()
|
||||||
@@ -72,13 +55,13 @@ class DocumentCheckoutTestCase(DocumentTestMixin, BaseTestCase):
|
|||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
DocumentCheckout.objects.checkout_document(
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
document=self.document, expiration_datetime=expiration_datetime,
|
||||||
user=self.admin_user, block_new_version=True
|
user=self._test_case_user, block_new_version=True
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.assertRaises(DocumentAlreadyCheckedOut):
|
with self.assertRaises(DocumentAlreadyCheckedOut):
|
||||||
DocumentCheckout.objects.checkout_document(
|
DocumentCheckout.objects.checkout_document(
|
||||||
document=self.document,
|
document=self.document,
|
||||||
expiration_datetime=expiration_datetime, user=self.admin_user,
|
expiration_datetime=expiration_datetime, user=self._test_case_user,
|
||||||
block_new_version=True
|
block_new_version=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,7 +74,7 @@ class DocumentCheckoutTestCase(DocumentTestMixin, BaseTestCase):
|
|||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
DocumentCheckout.objects.checkout_document(
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
document=self.document, expiration_datetime=expiration_datetime,
|
||||||
user=self.admin_user, block_new_version=True
|
user=self._test_case_user, block_new_version=True
|
||||||
)
|
)
|
||||||
|
|
||||||
time.sleep(.11)
|
time.sleep(.11)
|
||||||
@@ -100,18 +83,6 @@ class DocumentCheckoutTestCase(DocumentTestMixin, BaseTestCase):
|
|||||||
|
|
||||||
self.assertFalse(self.document.is_checked_out())
|
self.assertFalse(self.document.is_checked_out())
|
||||||
|
|
||||||
def test_blocking_new_versions(self):
|
|
||||||
# Silence unrelated logging
|
|
||||||
logging.getLogger('mayan.apps.documents.models').setLevel(
|
|
||||||
level=logging.CRITICAL
|
|
||||||
)
|
|
||||||
|
|
||||||
NewVersionBlock.objects.block(document=self.document)
|
|
||||||
|
|
||||||
with self.assertRaises(NewDocumentVersionNotAllowed):
|
|
||||||
with open(TEST_SMALL_DOCUMENT_PATH, mode='rb') as file_object:
|
|
||||||
self.document.new_version(file_object=file_object)
|
|
||||||
|
|
||||||
|
|
||||||
class NewVersionBlockTestCase(DocumentTestMixin, BaseTestCase):
|
class NewVersionBlockTestCase(DocumentTestMixin, BaseTestCase):
|
||||||
def test_blocking(self):
|
def test_blocking(self):
|
||||||
@@ -141,3 +112,32 @@ class NewVersionBlockTestCase(DocumentTestMixin, BaseTestCase):
|
|||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
NewVersionBlock.objects.is_blocked(document=self.document)
|
NewVersionBlock.objects.is_blocked(document=self.document)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_blocking_new_versions(self):
|
||||||
|
# Silence unrelated logging
|
||||||
|
logging.getLogger('mayan.apps.documents.models').setLevel(
|
||||||
|
level=logging.CRITICAL
|
||||||
|
)
|
||||||
|
|
||||||
|
NewVersionBlock.objects.block(document=self.document)
|
||||||
|
|
||||||
|
with self.assertRaises(NewDocumentVersionNotAllowed):
|
||||||
|
with open(TEST_SMALL_DOCUMENT_PATH, mode='rb') as file_object:
|
||||||
|
self.document.new_version(file_object=file_object)
|
||||||
|
|
||||||
|
def test_version_creation_blocking(self):
|
||||||
|
expiration_datetime = now() + datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
# Silence unrelated logging
|
||||||
|
logging.getLogger('mayan.apps.documents.models').setLevel(
|
||||||
|
level=logging.CRITICAL
|
||||||
|
)
|
||||||
|
|
||||||
|
DocumentCheckout.objects.checkout_document(
|
||||||
|
document=self.document, expiration_datetime=expiration_datetime,
|
||||||
|
user=self._test_case_user, block_new_version=True
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaises(NewDocumentVersionNotAllowed):
|
||||||
|
with open(TEST_SMALL_DOCUMENT_PATH, mode='rb') as file_object:
|
||||||
|
self.document.new_version(file_object=file_object)
|
||||||
|
|||||||
@@ -8,62 +8,53 @@ from django.utils.timezone import now
|
|||||||
from mayan.apps.common.literals import TIME_DELTA_UNIT_DAYS
|
from mayan.apps.common.literals import TIME_DELTA_UNIT_DAYS
|
||||||
from mayan.apps.documents.tests import GenericDocumentViewTestCase
|
from mayan.apps.documents.tests import GenericDocumentViewTestCase
|
||||||
from mayan.apps.sources.links import link_upload_version
|
from mayan.apps.sources.links import link_upload_version
|
||||||
from mayan.apps.user_management.tests import (
|
|
||||||
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_USER_PASSWORD,
|
|
||||||
TEST_USER_USERNAME
|
|
||||||
)
|
|
||||||
|
|
||||||
from ..models import DocumentCheckout
|
from ..models import DocumentCheckout
|
||||||
from ..permissions import (
|
from ..permissions import (
|
||||||
permission_document_checkin, permission_document_checkin_override,
|
permission_document_check_in, permission_document_check_in_override,
|
||||||
permission_document_checkout, permission_document_checkout_detail_view
|
permission_document_checkout, permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
||||||
|
create_test_case_superuser = True
|
||||||
|
|
||||||
|
def _checkout_document(self):
|
||||||
|
expiration_datetime = now() + datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
DocumentCheckout.objects.checkout_document(
|
||||||
|
document=self.document, expiration_datetime=expiration_datetime,
|
||||||
|
user=self._test_case_user, block_new_version=True
|
||||||
|
)
|
||||||
|
self.assertTrue(self.document.is_checked_out())
|
||||||
|
|
||||||
def _request_document_check_in_view(self):
|
def _request_document_check_in_view(self):
|
||||||
return self.post(
|
return self.post(
|
||||||
viewname='checkouts:checkin_document',
|
viewname='checkouts:document_check_in',
|
||||||
kwargs={'document_pk': self.document.pk}
|
kwargs={'document_id': self.document.pk}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_checkin_document_view_no_permission(self):
|
def test_document_check_in_view_no_permission(self):
|
||||||
self.login_user()
|
self._checkout_document()
|
||||||
|
|
||||||
expiration_datetime = now() + datetime.timedelta(days=1)
|
|
||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
|
||||||
user=self.user, block_new_version=True
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertTrue(self.document.is_checked_out())
|
|
||||||
|
|
||||||
response = self._request_document_check_in_view()
|
response = self._request_document_check_in_view()
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEquals(response.status_code, 404)
|
||||||
|
|
||||||
self.assertTrue(self.document.is_checked_out())
|
self.assertTrue(self.document.is_checked_out())
|
||||||
|
|
||||||
def test_checkin_document_view_with_access(self):
|
def test_document_check_in_view_with_access(self):
|
||||||
self.login_user()
|
self._checkout_document()
|
||||||
|
|
||||||
expiration_datetime = now() + datetime.timedelta(days=1)
|
|
||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
|
||||||
user=self.user, block_new_version=True
|
|
||||||
)
|
|
||||||
self.assertTrue(self.document.is_checked_out())
|
|
||||||
|
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
obj=self.document, permission=permission_document_checkin
|
obj=self.document, permission=permission_document_check_in
|
||||||
)
|
)
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
obj=self.document,
|
obj=self.document,
|
||||||
permission=permission_document_checkout_detail_view
|
permission=permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self._request_document_check_in_view()
|
response = self._request_document_check_in_view()
|
||||||
self.assertEquals(response.status_code, 302)
|
self.assertEquals(response.status_code, 302)
|
||||||
|
|
||||||
self.assertFalse(self.document.is_checked_out())
|
self.assertFalse(self.document.is_checked_out())
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
DocumentCheckout.objects.is_document_checked_out(
|
DocumentCheckout.objects.is_document_checked_out(
|
||||||
@@ -73,8 +64,8 @@ class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
|||||||
|
|
||||||
def _request_document_checkout_view(self):
|
def _request_document_checkout_view(self):
|
||||||
return self.post(
|
return self.post(
|
||||||
viewname='checkouts:checkout_document',
|
viewname='checkouts:document_checkout',
|
||||||
kwargs={'document_pk': self.document.pk},
|
kwargs={'document_id': self.document.pk},
|
||||||
data={
|
data={
|
||||||
'expiration_datetime_0': 2,
|
'expiration_datetime_0': 2,
|
||||||
'expiration_datetime_1': TIME_DELTA_UNIT_DAYS,
|
'expiration_datetime_1': TIME_DELTA_UNIT_DAYS,
|
||||||
@@ -83,14 +74,11 @@ class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_checkout_document_view_no_permission(self):
|
def test_checkout_document_view_no_permission(self):
|
||||||
self.login_user()
|
|
||||||
|
|
||||||
response = self._request_document_checkout_view()
|
response = self._request_document_checkout_view()
|
||||||
self.assertEquals(response.status_code, 403)
|
self.assertEquals(response.status_code, 404)
|
||||||
self.assertFalse(self.document.is_checked_out())
|
self.assertFalse(self.document.is_checked_out())
|
||||||
|
|
||||||
def test_checkout_document_view_with_access(self):
|
def test_checkout_document_view_with_access(self):
|
||||||
self.login_user()
|
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
obj=self.document, permission=permission_document_checkout
|
obj=self.document, permission=permission_document_checkout
|
||||||
)
|
)
|
||||||
@@ -98,9 +86,9 @@ class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
|||||||
obj=self.document,
|
obj=self.document,
|
||||||
permission=permission_document_checkout_detail_view
|
permission=permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self._request_document_checkout_view()
|
response = self._request_document_checkout_view()
|
||||||
self.assertEquals(response.status_code, 302)
|
self.assertEquals(response.status_code, 302)
|
||||||
|
|
||||||
self.assertTrue(self.document.is_checked_out())
|
self.assertTrue(self.document.is_checked_out())
|
||||||
|
|
||||||
def test_document_new_version_after_checkout(self):
|
def test_document_new_version_after_checkout(self):
|
||||||
@@ -113,25 +101,15 @@ class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
|||||||
- Link to upload version view should not resolve
|
- Link to upload version view should not resolve
|
||||||
- Upload version view should reject request
|
- Upload version view should reject request
|
||||||
"""
|
"""
|
||||||
self.login(
|
self.login_superuser()
|
||||||
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
|
|
||||||
)
|
|
||||||
|
|
||||||
expiration_datetime = now() + datetime.timedelta(days=1)
|
self._checkout_document()
|
||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
|
||||||
user=self.admin_user, block_new_version=True
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertTrue(self.document.is_checked_out())
|
|
||||||
|
|
||||||
response = self.post(
|
response = self.post(
|
||||||
viewname='sources:upload_version',
|
viewname='sources:upload_version',
|
||||||
kwargs={'document_pk': self.document.pk},
|
kwargs={'document_id': self.document.pk},
|
||||||
follow=True
|
follow=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertContains(
|
self.assertContains(
|
||||||
response, text='blocked from uploading',
|
response, text='blocked from uploading',
|
||||||
status_code=200
|
status_code=200
|
||||||
@@ -139,7 +117,7 @@ class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
|||||||
|
|
||||||
response = self.get(
|
response = self.get(
|
||||||
viewname='documents:document_version_list',
|
viewname='documents:document_version_list',
|
||||||
kwargs={'document_pk': self.document.pk},
|
kwargs={'document_id': self.document.pk},
|
||||||
follow=True
|
follow=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -163,28 +141,22 @@ class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
|||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
DocumentCheckout.objects.checkout_document(
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
document=self.document, expiration_datetime=expiration_datetime,
|
||||||
user=self.admin_user, block_new_version=True
|
user=self._test_case_superuser, block_new_version=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertTrue(self.document.is_checked_out())
|
self.assertTrue(self.document.is_checked_out())
|
||||||
|
|
||||||
self.login(
|
self.grant_access(
|
||||||
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
obj=self.document, permission=permission_document_check_in
|
||||||
)
|
)
|
||||||
|
self.grant_access(
|
||||||
self.role.permissions.add(
|
obj=self.document, permission=permission_document_checkout
|
||||||
permission_document_checkin.stored_permission
|
|
||||||
)
|
)
|
||||||
self.role.permissions.add(
|
|
||||||
permission_document_checkout.stored_permission
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.post(
|
response = self.post(
|
||||||
viewname='checkouts:checkin_document',
|
viewname='checkouts:document_check_in',
|
||||||
kwargs={'document_pk': self.document.pk},
|
kwargs={'document_id': self.document.pk},
|
||||||
follow=True
|
follow=True
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertContains(
|
self.assertContains(
|
||||||
response, text='Insufficient permissions', status_code=403
|
response, text='Insufficient permissions', status_code=403
|
||||||
)
|
)
|
||||||
@@ -192,34 +164,20 @@ class DocumentCheckoutViewTestCase(GenericDocumentViewTestCase):
|
|||||||
self.assertTrue(self.document.is_checked_out())
|
self.assertTrue(self.document.is_checked_out())
|
||||||
|
|
||||||
def test_forcefull_check_in_document_view_with_permission(self):
|
def test_forcefull_check_in_document_view_with_permission(self):
|
||||||
expiration_datetime = now() + datetime.timedelta(days=1)
|
self._checkout_document()
|
||||||
|
|
||||||
DocumentCheckout.objects.checkout_document(
|
self.grant_access(
|
||||||
document=self.document, expiration_datetime=expiration_datetime,
|
obj=self.document, permission=permission_document_check_in
|
||||||
user=self.admin_user, block_new_version=True
|
|
||||||
)
|
)
|
||||||
|
self.grant_access(
|
||||||
self.assertTrue(self.document.is_checked_out())
|
obj=self.document, permission=permission_document_check_in_override
|
||||||
|
|
||||||
self.login(
|
|
||||||
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD
|
|
||||||
)
|
)
|
||||||
|
self.grant_access(
|
||||||
self.role.permissions.add(
|
obj=self.document, permission=permission_document_checkout_detail_view
|
||||||
permission_document_checkin.stored_permission
|
|
||||||
)
|
|
||||||
self.role.permissions.add(
|
|
||||||
permission_document_checkin.stored_permission
|
|
||||||
)
|
|
||||||
self.role.permissions.add(
|
|
||||||
permission_document_checkin_override.stored_permission
|
|
||||||
)
|
|
||||||
self.role.permissions.add(
|
|
||||||
permission_document_checkout_detail_view.stored_permission
|
|
||||||
)
|
)
|
||||||
response = self.post(
|
response = self.post(
|
||||||
viewname='checkouts:checkin_document',
|
viewname='checkouts:document_check_in',
|
||||||
kwargs={'document_pk': self.document.pk},
|
kwargs={'document_id': self.document.pk},
|
||||||
follow=True
|
follow=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,26 +4,34 @@ from django.conf.urls import url
|
|||||||
|
|
||||||
from .api_views import APICheckedoutDocumentListView, APICheckedoutDocumentView
|
from .api_views import APICheckedoutDocumentListView, APICheckedoutDocumentView
|
||||||
from .views import (
|
from .views import (
|
||||||
CheckoutDetailView, CheckoutDocumentView, CheckoutListView,
|
DocumentCheckinView, DocumentCheckoutView, DocumentCheckoutDetailView,
|
||||||
DocumentCheckinView
|
DocumentCheckoutListView
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(
|
url(
|
||||||
regex=r'^documents/$', name='checkout_list',
|
regex=r'^documents/$', name='document_checkout_list',
|
||||||
view=CheckoutListView.as_view()
|
view=DocumentCheckoutListView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
regex=r'^documents/(?P<document_pk>\d+)/check/out/$',
|
regex=r'^documents/(?P<document_id>\d+)/check_in/$',
|
||||||
name='checkout_document', view=CheckoutDocumentView.as_view()
|
name='document_check_in', view=DocumentCheckinView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
regex=r'^documents/(?P<document_pk>\d+)/check/in/$',
|
regex=r'^documents/multiple/check_in/$',
|
||||||
name='checkin_document', view=DocumentCheckinView.as_view()
|
name='document_multiple_check_in', view=DocumentCheckinView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
regex=r'^documents/(?P<document_pk>\d+)/check/info/$',
|
regex=r'^documents/(?P<document_id>\d+)/checkout/$',
|
||||||
name='checkout_info', view=CheckoutDetailView.as_view()
|
name='document_checkout', view=DocumentCheckoutView.as_view()
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
regex=r'^documents/multiple/checkout/$',
|
||||||
|
name='document_multiple_checkout', view=DocumentCheckoutView.as_view()
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
regex=r'^documents/(?P<document_id>\d+)/checkout/info/$',
|
||||||
|
name='document_checkout_info', view=DocumentCheckoutDetailView.as_view()
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -33,7 +41,7 @@ api_urls = [
|
|||||||
view=APICheckedoutDocumentListView.as_view()
|
view=APICheckedoutDocumentListView.as_view()
|
||||||
),
|
),
|
||||||
url(
|
url(
|
||||||
regex=r'^checkouts/(?P<document_pk>[0-9]+)/checkout_info/$',
|
regex=r'^checkouts/(?P<document_id>\d+)/checkout_info/$',
|
||||||
name='checkedout-document-view',
|
name='checkedout-document-view',
|
||||||
view=APICheckedoutDocumentView.as_view()
|
view=APICheckedoutDocumentView.as_view()
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,86 +1,145 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _, ungettext
|
||||||
|
|
||||||
from mayan.apps.acls.models import AccessControlList
|
from mayan.apps.acls.models import AccessControlList
|
||||||
from mayan.apps.common.generics import (
|
from mayan.apps.common.generics import (
|
||||||
ConfirmView, SingleObjectCreateView, SingleObjectDetailView
|
MultipleObjectConfirmActionView, MultipleObjectFormActionView,
|
||||||
|
SingleObjectDetailView
|
||||||
)
|
)
|
||||||
from mayan.apps.common.utils import encapsulate
|
from mayan.apps.common.utils import encapsulate
|
||||||
from mayan.apps.documents.models import Document
|
from mayan.apps.documents.models import Document
|
||||||
from mayan.apps.documents.views import DocumentListView
|
from mayan.apps.documents.views import DocumentListView
|
||||||
|
|
||||||
from .exceptions import DocumentAlreadyCheckedOut, DocumentNotCheckedOut
|
|
||||||
from .forms import DocumentCheckoutDefailForm, DocumentCheckoutForm
|
from .forms import DocumentCheckoutDefailForm, DocumentCheckoutForm
|
||||||
from .icons import icon_checkout_info
|
from .icons import icon_checkout_info
|
||||||
from .models import DocumentCheckout
|
from .models import DocumentCheckout
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_document_checkin, permission_document_checkin_override,
|
permission_document_check_in, permission_document_checkout,
|
||||||
permission_document_checkout, permission_document_checkout_detail_view
|
permission_document_checkout_detail_view
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CheckoutDocumentView(SingleObjectCreateView):
|
class DocumentCheckinView(MultipleObjectConfirmActionView):
|
||||||
form_class = DocumentCheckoutForm
|
error_message = 'Unable to check in document "%(instance)s". %(exception)s'
|
||||||
|
model = Document
|
||||||
|
object_permission = permission_document_check_in
|
||||||
|
pk_url_kwarg = 'document_id'
|
||||||
|
success_message = '%(count)d document checked in.'
|
||||||
|
success_message_plural = '%(count)d documents checked in.'
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def get_extra_context(self):
|
||||||
self.document = get_object_or_404(
|
queryset = self.get_object_list()
|
||||||
klass=Document, pk=self.kwargs['document_pk']
|
|
||||||
|
result = {
|
||||||
|
'title': ungettext(
|
||||||
|
singular='Check in %(count)d document',
|
||||||
|
plural='Check in %(count)d documents',
|
||||||
|
number=queryset.count()
|
||||||
|
) % {
|
||||||
|
'count': queryset.count(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if queryset.count() == 1:
|
||||||
|
result.update(
|
||||||
|
{
|
||||||
|
'object': queryset.first(),
|
||||||
|
'title': _(
|
||||||
|
'Check in document: %s'
|
||||||
|
) % queryset.first()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
AccessControlList.objects.check_access(
|
return result
|
||||||
obj=self.document, permissions=permission_document_checkout,
|
|
||||||
user=request.user
|
|
||||||
)
|
|
||||||
|
|
||||||
return super(
|
def get_post_object_action_url(self):
|
||||||
CheckoutDocumentView, self
|
if self.action_count == 1:
|
||||||
).dispatch(request, *args, **kwargs)
|
return reverse(
|
||||||
|
viewname='checkouts:document_checkout_info',
|
||||||
def form_valid(self, form):
|
kwargs={'document_id': self.action_id_list[0]}
|
||||||
try:
|
|
||||||
instance = form.save(commit=False)
|
|
||||||
instance.user = self.request.user
|
|
||||||
instance.document = self.document
|
|
||||||
instance.save()
|
|
||||||
except DocumentAlreadyCheckedOut:
|
|
||||||
messages.error(
|
|
||||||
request=self.request,
|
|
||||||
message=_('Document already checked out.')
|
|
||||||
)
|
|
||||||
except Exception as exception:
|
|
||||||
messages.error(
|
|
||||||
request=self.request,
|
|
||||||
message=_('Error trying to check out document; %s') % exception
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
messages.success(
|
super(DocumentCheckinView, self).get_post_action_redirect()
|
||||||
request=self.request,
|
|
||||||
message=_(
|
def object_action(self, form, instance):
|
||||||
'Document "%s" checked out successfully.'
|
DocumentCheckout.objects.check_in_document(
|
||||||
) % self.document
|
document=instance, user=self.request.user
|
||||||
)
|
)
|
||||||
|
|
||||||
return HttpResponseRedirect(redirect_to=self.get_success_url())
|
|
||||||
|
class DocumentCheckoutView(MultipleObjectFormActionView):
|
||||||
|
error_message = 'Unable to checkout document "%(instance)s". %(exception)s'
|
||||||
|
form_class = DocumentCheckoutForm
|
||||||
|
model = Document
|
||||||
|
object_permission = permission_document_checkout
|
||||||
|
pk_url_kwarg = 'document_id'
|
||||||
|
success_message = '%(count)d document checked out.'
|
||||||
|
success_message_plural = '%(count)d documents checked out.'
|
||||||
|
|
||||||
|
def get_extra_context(self):
|
||||||
|
queryset = self.get_object_list()
|
||||||
|
|
||||||
|
result = {
|
||||||
|
'title': ungettext(
|
||||||
|
singular='Checkout %(count)d document',
|
||||||
|
plural='Checkout %(count)d documents',
|
||||||
|
number=queryset.count()
|
||||||
|
) % {
|
||||||
|
'count': queryset.count(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if queryset.count() == 1:
|
||||||
|
result.update(
|
||||||
|
{
|
||||||
|
'object': queryset.first(),
|
||||||
|
'title': _(
|
||||||
|
'Check out document: %s'
|
||||||
|
) % queryset.first()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_post_object_action_url(self):
|
||||||
|
if self.action_count == 1:
|
||||||
|
return reverse(
|
||||||
|
viewname='checkouts:document_checkout_info',
|
||||||
|
kwargs={'document_id': self.action_id_list[0]}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
super(DocumentCheckoutView, self).get_post_action_redirect()
|
||||||
|
|
||||||
|
def object_action(self, form, instance):
|
||||||
|
DocumentCheckout.objects.checkout_document(
|
||||||
|
block_new_version=form.cleaned_data['block_new_version'],
|
||||||
|
document=instance,
|
||||||
|
expiration_datetime=form.cleaned_data['expiration_datetime'],
|
||||||
|
user=self.request.user,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentCheckoutDetailView(SingleObjectDetailView):
|
||||||
|
form_class = DocumentCheckoutDefailForm
|
||||||
|
model = Document
|
||||||
|
object_permission = permission_document_checkout_detail_view
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
return {
|
return {
|
||||||
'object': self.document,
|
'object': self.get_object(),
|
||||||
'title': _('Check out document: %s') % self.document
|
'title': _(
|
||||||
|
'Check out details for document: %s'
|
||||||
|
) % self.get_object()
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_post_action_redirect(self):
|
def get_object(self):
|
||||||
return reverse(
|
return get_object_or_404(klass=Document, pk=self.kwargs['document_id'])
|
||||||
viewname='checkouts:checkout_info',
|
|
||||||
kwargs={'document_pk': self.document.pk}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class CheckoutListView(DocumentListView):
|
class DocumentCheckoutListView(DocumentListView):
|
||||||
def get_document_queryset(self):
|
def get_document_queryset(self):
|
||||||
return AccessControlList.objects.restrict_queryset(
|
return AccessControlList.objects.restrict_queryset(
|
||||||
permission=permission_document_checkout_detail_view,
|
permission=permission_document_checkout_detail_view,
|
||||||
@@ -89,7 +148,7 @@ class CheckoutListView(DocumentListView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
context = super(CheckoutListView, self).get_extra_context()
|
context = super(DocumentCheckoutListView, self).get_extra_context()
|
||||||
context.update(
|
context.update(
|
||||||
{
|
{
|
||||||
'extra_columns': (
|
'extra_columns': (
|
||||||
@@ -123,81 +182,3 @@ class CheckoutListView(DocumentListView):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class CheckoutDetailView(SingleObjectDetailView):
|
|
||||||
form_class = DocumentCheckoutDefailForm
|
|
||||||
model = Document
|
|
||||||
object_permission = permission_document_checkout_detail_view
|
|
||||||
|
|
||||||
def get_extra_context(self):
|
|
||||||
return {
|
|
||||||
'object': self.get_object(),
|
|
||||||
'title': _(
|
|
||||||
'Check out details for document: %s'
|
|
||||||
) % self.get_object()
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return get_object_or_404(klass=Document, pk=self.kwargs['document_pk'])
|
|
||||||
|
|
||||||
|
|
||||||
class DocumentCheckinView(ConfirmView):
|
|
||||||
def get_extra_context(self):
|
|
||||||
document = self.get_object()
|
|
||||||
|
|
||||||
context = {
|
|
||||||
'object': document,
|
|
||||||
}
|
|
||||||
|
|
||||||
if document.get_checkout_info().user != self.request.user:
|
|
||||||
context['title'] = _(
|
|
||||||
'You didn\'t originally checked out this document. '
|
|
||||||
'Forcefully check in the document: %s?'
|
|
||||||
) % document
|
|
||||||
else:
|
|
||||||
context['title'] = _('Check in the document: %s?') % document
|
|
||||||
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_object(self):
|
|
||||||
return get_object_or_404(klass=Document, pk=self.kwargs['document_pk'])
|
|
||||||
|
|
||||||
def get_post_action_redirect(self):
|
|
||||||
return reverse(
|
|
||||||
viewname='checkouts:checkout_info',
|
|
||||||
kwargs={'document_pk': self.get_object().pk}
|
|
||||||
)
|
|
||||||
|
|
||||||
def view_action(self):
|
|
||||||
document = self.get_object()
|
|
||||||
|
|
||||||
if document.get_checkout_info().user == self.request.user:
|
|
||||||
AccessControlList.objects.check_access(
|
|
||||||
obj=document, permissions=permission_document_checkin,
|
|
||||||
user=self.request.user
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
AccessControlList.objects.check_access(
|
|
||||||
obj=document, permissions=permission_document_checkin_override,
|
|
||||||
user=self.request.user
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
document.check_in(user=self.request.user)
|
|
||||||
except DocumentNotCheckedOut:
|
|
||||||
messages.error(
|
|
||||||
request=self.request, message=_(
|
|
||||||
'Document has not been checked out.'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
except Exception as exception:
|
|
||||||
messages.error(
|
|
||||||
request=self.request,
|
|
||||||
message=_('Error trying to check in document; %s') % exception
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
messages.success(
|
|
||||||
request=self.request,
|
|
||||||
message=_('Document "%s" checked in successfully.') % document
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user