Complete multiple check in/out support
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
This commit is contained in:
@@ -11,6 +11,7 @@ from mayan.apps.common.menus import (
|
||||
)
|
||||
from mayan.apps.dashboards.dashboards import dashboard_main
|
||||
from mayan.apps.events.classes import ModelEventType
|
||||
from mayan.apps.navigation.classes import SourceColumn
|
||||
|
||||
from .dashboard_widgets import DashboardWidgetTotalCheckouts
|
||||
from .events import (
|
||||
@@ -46,6 +47,8 @@ class CheckoutsApp(MayanAppConfig):
|
||||
def ready(self):
|
||||
super(CheckoutsApp, self).ready()
|
||||
|
||||
CheckedOutDocument = self.get_model(model_name='CheckedOutDocument')
|
||||
DocumentCheckout = self.get_model(model_name='DocumentCheckout')
|
||||
Document = apps.get_model(
|
||||
app_label='documents', model_name='Document'
|
||||
)
|
||||
@@ -79,6 +82,22 @@ class CheckoutsApp(MayanAppConfig):
|
||||
permission_document_check_out_detail_view
|
||||
)
|
||||
)
|
||||
ModelPermission.register_inheritance(
|
||||
model=DocumentCheckout, related='document'
|
||||
)
|
||||
|
||||
SourceColumn(
|
||||
attribute='get_user_display', include_label=True, order=99,
|
||||
source=CheckedOutDocument
|
||||
)
|
||||
SourceColumn(
|
||||
attribute='get_checkout_datetime', include_label=True, order=99,
|
||||
source=CheckedOutDocument
|
||||
)
|
||||
SourceColumn(
|
||||
attribute='get_checkout_expiration', include_label=True, order=99,
|
||||
source=CheckedOutDocument
|
||||
)
|
||||
|
||||
dashboard_main.add_widget(
|
||||
widget=DashboardWidgetTotalCheckouts, order=-1
|
||||
@@ -91,9 +110,19 @@ class CheckoutsApp(MayanAppConfig):
|
||||
menu_multi_item.bind_links(
|
||||
links=(
|
||||
link_check_in_document_multiple,
|
||||
link_check_out_document_multiple
|
||||
), sources=(CheckedOutDocument,)
|
||||
)
|
||||
menu_multi_item.bind_links(
|
||||
links=(
|
||||
link_check_in_document_multiple,
|
||||
link_check_out_document_multiple,
|
||||
), sources=(Document,)
|
||||
)
|
||||
menu_multi_item.unbind_links(
|
||||
links=(
|
||||
link_check_out_document_multiple,
|
||||
), sources=(CheckedOutDocument,)
|
||||
)
|
||||
menu_secondary.bind_links(
|
||||
links=(link_check_out_document, link_check_in_document),
|
||||
sources=(
|
||||
|
||||
@@ -6,6 +6,7 @@ from django.apps import apps
|
||||
from django.db import models, transaction
|
||||
from django.utils.timezone import now
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.documents.models import Document
|
||||
|
||||
from .events import (
|
||||
@@ -14,10 +15,53 @@ from .events import (
|
||||
)
|
||||
from .exceptions import DocumentNotCheckedOut
|
||||
from .literals import STATE_CHECKED_OUT, STATE_CHECKED_IN
|
||||
from .permissions import (
|
||||
permission_document_check_in, permission_document_check_in_override
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DocumentCheckoutBusinessLogicManager(models.Manager):
|
||||
def check_in_document(self, document, user=None):
|
||||
queryset = document._meta.default_manager.filter(pk=document.pk)
|
||||
return self.check_in_documents(queryset=queryset, user=user)
|
||||
|
||||
def check_in_documents(self, queryset, user=None):
|
||||
if user:
|
||||
user_document_checkouts = AccessControlList.objects.restrict_queryset(
|
||||
permission=permission_document_check_in,
|
||||
queryset=self.filter(user_id=user.pk, document__in=queryset),
|
||||
user=user
|
||||
)
|
||||
|
||||
others_document_checkouts = AccessControlList.objects.restrict_queryset(
|
||||
permission=permission_document_check_in_override,
|
||||
queryset=self.exclude(user_id=user.pk, document__in=queryset),
|
||||
user=user
|
||||
)
|
||||
|
||||
with transaction.atomic():
|
||||
if user:
|
||||
for checkout in user_document_checkouts:
|
||||
event_document_check_in.commit(
|
||||
actor=user, target=checkout.document
|
||||
)
|
||||
checkout.delete()
|
||||
|
||||
for checkout in others_document_checkouts:
|
||||
event_document_forceful_check_in.commit(
|
||||
actor=user, target=checkout.document
|
||||
)
|
||||
checkout.delete()
|
||||
else:
|
||||
for checkout in self.filter(document__in=queryset):
|
||||
event_document_auto_check_in.commit(
|
||||
target=checkout.document
|
||||
)
|
||||
checkout.delete()
|
||||
|
||||
|
||||
class DocumentCheckoutManager(models.Manager):
|
||||
def are_document_new_versions_allowed(self, document, user=None):
|
||||
try:
|
||||
@@ -27,25 +71,6 @@ class DocumentCheckoutManager(models.Manager):
|
||||
else:
|
||||
return not check_out_info.block_new_version
|
||||
|
||||
def check_in_document(self, document, user=None):
|
||||
try:
|
||||
document_check_out = self.model.objects.get(document=document)
|
||||
except self.model.DoesNotExist:
|
||||
raise DocumentNotCheckedOut
|
||||
else:
|
||||
with transaction.atomic():
|
||||
if user:
|
||||
if self.get_check_out_info(document=document).user != user:
|
||||
event_document_forceful_check_in.commit(
|
||||
actor=user, target=document
|
||||
)
|
||||
else:
|
||||
event_document_check_in.commit(actor=user, target=document)
|
||||
else:
|
||||
event_document_auto_check_in.commit(target=document)
|
||||
|
||||
document_check_out.delete()
|
||||
|
||||
def check_in_expired_check_outs(self):
|
||||
for document in self.expired_check_outs():
|
||||
document.check_in()
|
||||
@@ -57,7 +82,11 @@ class DocumentCheckoutManager(models.Manager):
|
||||
)
|
||||
|
||||
def checked_out_documents(self):
|
||||
return Document.objects.filter(
|
||||
CheckedOutDocument = apps.get_model(
|
||||
app_label='checkouts', model_name='CheckedOutDocument'
|
||||
)
|
||||
|
||||
return CheckedOutDocument.objects.filter(
|
||||
pk__in=self.model.objects.values('document__id')
|
||||
)
|
||||
|
||||
@@ -74,7 +103,11 @@ class DocumentCheckoutManager(models.Manager):
|
||||
return STATE_CHECKED_IN
|
||||
|
||||
def expired_check_outs(self):
|
||||
expired_list = Document.objects.filter(
|
||||
CheckedOutDocument = apps.get_model(
|
||||
app_label='checkouts', model_name='CheckedOutDocument'
|
||||
)
|
||||
|
||||
expired_list = CheckedOutDocument.objects.filter(
|
||||
pk__in=self.model.objects.filter(
|
||||
expiration_datetime__lte=now()
|
||||
).values_list('document__pk', flat=True)
|
||||
@@ -83,9 +116,6 @@ class DocumentCheckoutManager(models.Manager):
|
||||
return expired_list
|
||||
|
||||
def get_by_natural_key(self, document_natural_key):
|
||||
Document = apps.get_model(
|
||||
app_label='documents', model_name='Document'
|
||||
)
|
||||
try:
|
||||
document = Document.objects.get_by_natural_key(document_natural_key)
|
||||
except Document.DoesNotExist:
|
||||
|
||||
@@ -8,7 +8,7 @@ def method_check_in(self, user=None):
|
||||
app_label='checkouts', model_name='DocumentCheckout'
|
||||
)
|
||||
|
||||
return DocumentCheckout.objects.check_in_document(
|
||||
return DocumentCheckout.business_logic.check_in_document(
|
||||
document=self, user=user
|
||||
)
|
||||
|
||||
|
||||
@@ -14,7 +14,10 @@ from mayan.apps.documents.models import Document
|
||||
|
||||
from .events import event_document_check_out
|
||||
from .exceptions import DocumentAlreadyCheckedOut
|
||||
from .managers import DocumentCheckoutManager, NewVersionBlockManager
|
||||
from .managers import (
|
||||
DocumentCheckoutBusinessLogicManager, DocumentCheckoutManager,
|
||||
NewVersionBlockManager
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -49,6 +52,7 @@ class DocumentCheckout(models.Model):
|
||||
)
|
||||
|
||||
objects = DocumentCheckoutManager()
|
||||
business_logic = DocumentCheckoutBusinessLogicManager()
|
||||
|
||||
class Meta:
|
||||
ordering = ('pk',)
|
||||
@@ -81,13 +85,13 @@ class DocumentCheckout(models.Model):
|
||||
natural_key.dependencies = ['documents.Document']
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
new_checkout = not self.pk
|
||||
if not new_checkout or self.document.is_checked_out():
|
||||
is_new = not self.pk
|
||||
if not is_new or self.document.is_checked_out():
|
||||
raise DocumentAlreadyCheckedOut
|
||||
|
||||
with transaction.atomic():
|
||||
result = super(DocumentCheckout, self).save(*args, **kwargs)
|
||||
if new_checkout:
|
||||
if is_new:
|
||||
event_document_check_out.commit(
|
||||
actor=self.user, target=self.document
|
||||
)
|
||||
@@ -119,3 +123,24 @@ class NewVersionBlock(models.Model):
|
||||
def natural_key(self):
|
||||
return self.document.natural_key()
|
||||
natural_key.dependencies = ['documents.Document']
|
||||
|
||||
|
||||
class CheckedOutDocument(Document):
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
def get_user_display(self):
|
||||
check_out_info = self.get_check_out_info()
|
||||
return check_out_info.user.get_full_name() or check_out_info.user
|
||||
|
||||
get_user_display.short_description = _('User')
|
||||
|
||||
def get_checkout_datetime(self):
|
||||
return self.get_check_out_info().checkout_datetime
|
||||
|
||||
get_checkout_datetime.short_description = _('Checkout time and date')
|
||||
|
||||
def get_checkout_expiration(self):
|
||||
return self.get_check_out_info().expiration_datetime
|
||||
|
||||
get_checkout_expiration.short_description = _('Checkout expiration')
|
||||
|
||||
@@ -5,6 +5,7 @@ import datetime
|
||||
from django.utils.timezone import now
|
||||
|
||||
from mayan.apps.common.literals import TIME_DELTA_UNIT_DAYS
|
||||
from mayan.apps.common.tests.utils import as_id_list
|
||||
|
||||
from ..models import DocumentCheckout
|
||||
|
||||
@@ -12,7 +13,10 @@ from ..models import DocumentCheckout
|
||||
class DocumentCheckoutTestMixin(object):
|
||||
_test_document_check_out_seconds = 0.1
|
||||
|
||||
def _check_out_test_document(self, user=None):
|
||||
def _check_out_test_document(self, document=None, user=None):
|
||||
if not document:
|
||||
document = self.test_document
|
||||
|
||||
if not user:
|
||||
user = self._test_case_user
|
||||
|
||||
@@ -21,7 +25,7 @@ class DocumentCheckoutTestMixin(object):
|
||||
)
|
||||
|
||||
self.test_check_out = DocumentCheckout.objects.check_out_document(
|
||||
block_new_version=True, document=self.test_document,
|
||||
block_new_version=True, document=document,
|
||||
expiration_datetime=self._check_out_expiration_datetime,
|
||||
user=user
|
||||
)
|
||||
@@ -42,6 +46,13 @@ class DocumentCheckoutViewTestMixin(object):
|
||||
}
|
||||
)
|
||||
|
||||
def _request_test_document_multiple_check_in_post_view(self):
|
||||
return self.post(
|
||||
viewname='checkouts:check_in_document_multiple', data={
|
||||
'id_list': as_id_list(items=self.test_documents)
|
||||
}
|
||||
)
|
||||
|
||||
def _request_test_document_check_out_view(self):
|
||||
return self.post(
|
||||
viewname='checkouts:check_out_document', kwargs={
|
||||
@@ -53,6 +64,16 @@ class DocumentCheckoutViewTestMixin(object):
|
||||
}
|
||||
)
|
||||
|
||||
def _request_test_document_multiple_check_out_post_view(self):
|
||||
return self.post(
|
||||
viewname='checkouts:check_out_document_multiple', data={
|
||||
'block_new_version': True,
|
||||
'expiration_datetime_0': TIME_DELTA_UNIT_DAYS,
|
||||
'expiration_datetime_1': 2,
|
||||
'id_list': as_id_list(items=self.test_documents)
|
||||
}
|
||||
)
|
||||
|
||||
def _request_test_document_check_out_detail_view(self):
|
||||
return self.get(
|
||||
viewname='checkouts:check_out_info', kwargs={
|
||||
|
||||
@@ -7,8 +7,7 @@ from mayan.apps.documents.tests import GenericDocumentTestCase, DocumentTestMixi
|
||||
from mayan.apps.documents.tests.literals import TEST_SMALL_DOCUMENT_PATH
|
||||
|
||||
from ..exceptions import (
|
||||
DocumentAlreadyCheckedOut, DocumentNotCheckedOut,
|
||||
NewDocumentVersionNotAllowed
|
||||
DocumentAlreadyCheckedOut, NewDocumentVersionNotAllowed
|
||||
)
|
||||
from ..models import DocumentCheckout, NewVersionBlock
|
||||
|
||||
@@ -49,10 +48,6 @@ class DocumentCheckoutTestCase(DocumentCheckoutTestMixin, GenericDocumentTestCas
|
||||
block_new_version=True
|
||||
)
|
||||
|
||||
def test_checkin_without_checkout(self):
|
||||
with self.assertRaises(DocumentNotCheckedOut):
|
||||
self.test_document.check_in()
|
||||
|
||||
def test_auto_check_in(self):
|
||||
self._check_out_test_document()
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from mayan.apps.common.literals import TIME_DELTA_UNIT_DAYS
|
||||
from mayan.apps.documents.permissions import permission_document_view
|
||||
from mayan.apps.documents.tests import GenericDocumentViewTestCase
|
||||
from mayan.apps.sources.links import link_document_version_upload
|
||||
@@ -23,8 +22,8 @@ class DocumentCheckoutViewTestCase(
|
||||
self._check_out_test_document()
|
||||
|
||||
response = self._request_test_document_check_in_get_view()
|
||||
self.assertContains(
|
||||
response=response, text=self.test_document.label, status_code=200
|
||||
self.assertNotContains(
|
||||
response=response, text=self.test_document.label, status_code=404
|
||||
)
|
||||
|
||||
self.assertTrue(self.test_document.is_checked_out())
|
||||
@@ -68,6 +67,86 @@ class DocumentCheckoutViewTestCase(
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_multiple_check_in_post_view_no_permission(self):
|
||||
# Upload second document
|
||||
self.upload_document()
|
||||
|
||||
self._check_out_test_document(document=self.test_documents[0])
|
||||
self._check_out_test_document(document=self.test_documents[1])
|
||||
|
||||
response = self._request_test_document_multiple_check_in_post_view()
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
self.assertTrue(self.test_documents[0].is_checked_out())
|
||||
self.assertTrue(self.test_documents[1].is_checked_out())
|
||||
self.assertTrue(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[0]
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[1]
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_multiple_check_in_post_view_with_document_0_access(self):
|
||||
# Upload second document
|
||||
self.upload_document()
|
||||
|
||||
self._check_out_test_document(document=self.test_documents[0])
|
||||
self._check_out_test_document(document=self.test_documents[1])
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_documents[0], permission=permission_document_check_in
|
||||
)
|
||||
|
||||
response = self._request_test_document_multiple_check_in_post_view()
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
self.assertFalse(self.test_documents[0].is_checked_out())
|
||||
self.assertTrue(self.test_documents[1].is_checked_out())
|
||||
self.assertFalse(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[0]
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[1]
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_multiple_check_in_post_view_with_access(self):
|
||||
# Upload second document
|
||||
self.upload_document()
|
||||
|
||||
self._check_out_test_document(document=self.test_documents[0])
|
||||
self._check_out_test_document(document=self.test_documents[1])
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_documents[0], permission=permission_document_check_in
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_documents[1], permission=permission_document_check_in
|
||||
)
|
||||
|
||||
response = self._request_test_document_multiple_check_in_post_view()
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
self.assertFalse(self.test_documents[0].is_checked_out())
|
||||
self.assertFalse(self.test_documents[1].is_checked_out())
|
||||
self.assertFalse(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[0]
|
||||
)
|
||||
)
|
||||
self.assertFalse(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[1]
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_check_out_view_no_permission(self):
|
||||
response = self._request_test_document_check_out_view()
|
||||
self.assertEqual(response.status_code, 404)
|
||||
@@ -88,6 +167,102 @@ class DocumentCheckoutViewTestCase(
|
||||
|
||||
self.assertTrue(self.test_document.is_checked_out())
|
||||
|
||||
def test_document_multiple_check_out_post_view_no_permission(self):
|
||||
# Upload second document
|
||||
self.upload_document()
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_documents[0],
|
||||
permission=permission_document_check_out_detail_view
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_documents[1],
|
||||
permission=permission_document_check_out_detail_view
|
||||
)
|
||||
|
||||
response = self._request_test_document_multiple_check_out_post_view()
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
self.assertFalse(self.test_documents[0].is_checked_out())
|
||||
self.assertFalse(self.test_documents[1].is_checked_out())
|
||||
self.assertFalse(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[0]
|
||||
)
|
||||
)
|
||||
self.assertFalse(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[1]
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_multiple_check_out_post_view_with_document_0_access(self):
|
||||
# Upload second document
|
||||
self.upload_document()
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_documents[0], permission=permission_document_check_out
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_documents[0],
|
||||
permission=permission_document_check_out_detail_view
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_documents[1],
|
||||
permission=permission_document_check_out_detail_view
|
||||
)
|
||||
|
||||
response = self._request_test_document_multiple_check_out_post_view()
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
self.assertTrue(self.test_documents[0].is_checked_out())
|
||||
self.assertFalse(self.test_documents[1].is_checked_out())
|
||||
self.assertTrue(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[0]
|
||||
)
|
||||
)
|
||||
self.assertFalse(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[1]
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_multiple_check_out_post_view_with_access(self):
|
||||
# Upload second document
|
||||
self.upload_document()
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_documents[0], permission=permission_document_check_out
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_documents[1], permission=permission_document_check_out
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_documents[0],
|
||||
permission=permission_document_check_out_detail_view
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_documents[1],
|
||||
permission=permission_document_check_out_detail_view
|
||||
)
|
||||
|
||||
response = self._request_test_document_multiple_check_out_post_view()
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
self.assertTrue(self.test_documents[0].is_checked_out())
|
||||
self.assertTrue(self.test_documents[1].is_checked_out())
|
||||
self.assertTrue(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[0]
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
DocumentCheckout.objects.is_checked_out(
|
||||
document=self.test_documents[1]
|
||||
)
|
||||
)
|
||||
|
||||
def test_document_check_out_detail_view_no_permission(self):
|
||||
self._check_out_test_document()
|
||||
|
||||
@@ -177,45 +352,39 @@ class DocumentCheckoutViewTestCase(
|
||||
|
||||
self.assertEqual(resolved_link, None)
|
||||
|
||||
def test_document_forcefull_check_in_view_no_permission(self):
|
||||
def test_document_check_in_forcefull_view_no_permission(self):
|
||||
# Gitlab issue #237
|
||||
# Forcefully checking in a document by a user without adequate
|
||||
# permissions throws out an error
|
||||
|
||||
self._create_test_case_superuser()
|
||||
self._check_out_test_document(user=self._test_case_superuser)
|
||||
self._create_test_user()
|
||||
self._check_out_test_document(user=self.test_user)
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_document, permission=permission_document_check_in
|
||||
)
|
||||
|
||||
response = self.post(
|
||||
viewname='checkouts:check_in_document', kwargs={
|
||||
'pk': self.test_document.pk
|
||||
}
|
||||
)
|
||||
self.assertContains(
|
||||
response=response, text='Insufficient permissions', status_code=403
|
||||
)
|
||||
|
||||
self.assertTrue(self.test_document.is_checked_out())
|
||||
|
||||
def test_document_forcefull_check_in_view_with_permission(self):
|
||||
self._create_test_case_superuser()
|
||||
self._check_out_test_document(user=self._test_case_superuser)
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_document, permission=permission_document_check_in
|
||||
)
|
||||
self.grant_access(
|
||||
obj=self.test_document, permission=permission_document_check_in_override
|
||||
)
|
||||
|
||||
response = self.post(
|
||||
viewname='checkouts:check_in_document', kwargs={
|
||||
'pk': self.test_document.pk
|
||||
}
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(self.test_document.is_checked_out())
|
||||
|
||||
def test_document_check_in_forcefull_view_with_access(self):
|
||||
self._create_test_user()
|
||||
self._check_out_test_document(user=self.test_user)
|
||||
|
||||
self.grant_access(
|
||||
obj=self.test_document,
|
||||
permission=permission_document_check_in_override
|
||||
)
|
||||
|
||||
response = self.post(
|
||||
viewname='checkouts:check_in_document', kwargs={
|
||||
'pk': self.test_document.pk
|
||||
}
|
||||
)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertFalse(self.test_document.is_checked_out())
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
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.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _, ungettext
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.common.generics import (
|
||||
ConfirmView, MultipleObjectConfirmActionView, MultipleObjectFormActionView,
|
||||
SingleObjectCreateView, SingleObjectDetailView
|
||||
MultipleObjectConfirmActionView, MultipleObjectFormActionView,
|
||||
SingleObjectDetailView
|
||||
)
|
||||
from mayan.apps.common.utils import encapsulate
|
||||
from mayan.apps.documents.models import Document
|
||||
from mayan.apps.documents.views import DocumentListView
|
||||
|
||||
from .exceptions import DocumentAlreadyCheckedOut, DocumentNotCheckedOut
|
||||
from .forms import DocumentCheckoutForm, DocumentCheckoutDefailForm
|
||||
from .icons import icon_check_out_info
|
||||
from .models import DocumentCheckout
|
||||
@@ -25,69 +20,9 @@ from .permissions import (
|
||||
)
|
||||
|
||||
|
||||
"""
|
||||
class DocumentCheckinView(ConfirmView):
|
||||
def get_extra_context(self):
|
||||
document = self.get_object()
|
||||
|
||||
context = {
|
||||
'object': document,
|
||||
}
|
||||
|
||||
if document.get_check_out_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['pk'])
|
||||
|
||||
def get_post_action_redirect(self):
|
||||
return reverse(
|
||||
viewname='checkouts:check_out_info', kwargs={
|
||||
'pk': self.get_object().pk
|
||||
}
|
||||
)
|
||||
|
||||
def view_action(self):
|
||||
document = self.get_object()
|
||||
|
||||
if document.get_check_out_info().user == self.request.user:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document, permissions=(permission_document_check_in,),
|
||||
user=self.request.user
|
||||
)
|
||||
else:
|
||||
AccessControlList.objects.check_access(
|
||||
obj=document,
|
||||
permissions=(permission_document_check_in_override,),
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
try:
|
||||
document.check_in(user=self.request.user)
|
||||
except DocumentNotCheckedOut:
|
||||
messages.error(
|
||||
message=_('Document has not been checked out.'),
|
||||
request=self.request
|
||||
)
|
||||
else:
|
||||
messages.success(
|
||||
message=_(
|
||||
'Document "%s" checked in successfully.'
|
||||
) % document, request=self.request
|
||||
)
|
||||
"""
|
||||
|
||||
class DocumentCheckinView(MultipleObjectConfirmActionView):
|
||||
error_message = 'Unable to check in document "%(instance)s". %(exception)s'
|
||||
model = Document
|
||||
object_permission = permission_document_check_in
|
||||
pk_url_kwarg = 'pk'
|
||||
success_message_singular = '%(count)d document checked in.'
|
||||
success_message_plural = '%(count)d documents checked in.'
|
||||
@@ -126,63 +61,30 @@ class DocumentCheckinView(MultipleObjectConfirmActionView):
|
||||
else:
|
||||
super(DocumentCheckinView, self).get_post_action_redirect()
|
||||
|
||||
def get_source_queryset(self):
|
||||
# object_permission is None to disable restricting queryset mixin
|
||||
# and restrict the queryset ourselves from two permissions
|
||||
|
||||
source_queryset = super(DocumentCheckinView, self).get_source_queryset()
|
||||
|
||||
check_in_queryset = AccessControlList.objects.restrict_queryset(
|
||||
permission=permission_document_check_in, queryset=source_queryset,
|
||||
user=self.request.user
|
||||
)
|
||||
|
||||
check_in_override_queryset = AccessControlList.objects.restrict_queryset(
|
||||
permission=permission_document_check_in_override,
|
||||
queryset=source_queryset, user=self.request.user
|
||||
)
|
||||
|
||||
return check_in_queryset | check_in_override_queryset
|
||||
|
||||
def object_action(self, form, instance):
|
||||
DocumentCheckout.objects.check_in_document(
|
||||
DocumentCheckout.business_logic.check_in_document(
|
||||
document=instance, user=self.request.user
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
class CheckoutDocumentView(SingleObjectCreateView):
|
||||
form_class = DocumentCheckoutForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.document = get_object_or_404(klass=Document, pk=self.kwargs['pk'])
|
||||
|
||||
AccessControlList.objects.check_access(
|
||||
obj=self.document, permissions=(permission_document_check_out,),
|
||||
user=request.user
|
||||
)
|
||||
|
||||
return super(
|
||||
CheckoutDocumentView, self
|
||||
).dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
try:
|
||||
instance = form.save(commit=False)
|
||||
instance.user = self.request.user
|
||||
instance.document = self.document
|
||||
instance.save()
|
||||
except DocumentAlreadyCheckedOut:
|
||||
messages.error(
|
||||
message=_('Document already checked out.'),
|
||||
request=self.request
|
||||
)
|
||||
else:
|
||||
messages.success(
|
||||
message=_(
|
||||
'Document "%s" checked out successfully.'
|
||||
) % self.document, request=self.request
|
||||
)
|
||||
|
||||
return HttpResponseRedirect(redirect_to=self.get_success_url())
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.document,
|
||||
'title': _('Check out document: %s') % self.document
|
||||
}
|
||||
|
||||
def get_post_action_redirect(self):
|
||||
return reverse(
|
||||
viewname='checkouts:check_out_info', kwargs={
|
||||
'pk': self.document.pk
|
||||
}
|
||||
)
|
||||
"""
|
||||
class DocumentCheckoutView(MultipleObjectFormActionView):
|
||||
error_message = 'Unable to checkout document "%(instance)s". %(exception)s'
|
||||
form_class = DocumentCheckoutForm
|
||||
@@ -261,26 +163,6 @@ class DocumentCheckoutListView(DocumentListView):
|
||||
context = super(DocumentCheckoutListView, self).get_extra_context()
|
||||
context.update(
|
||||
{
|
||||
'extra_columns': (
|
||||
{
|
||||
'name': _('User'),
|
||||
'attribute': encapsulate(
|
||||
lambda document: document.get_check_out_info().user.get_full_name() or document.get_check_out_info().user
|
||||
)
|
||||
},
|
||||
{
|
||||
'name': _('Checkout time and date'),
|
||||
'attribute': encapsulate(
|
||||
lambda document: document.get_check_out_info().checkout_datetime
|
||||
)
|
||||
},
|
||||
{
|
||||
'name': _('Checkout expiration'),
|
||||
'attribute': encapsulate(
|
||||
lambda document: document.get_check_out_info().expiration_datetime
|
||||
)
|
||||
},
|
||||
),
|
||||
'no_results_icon': icon_check_out_info,
|
||||
'no_results_text': _(
|
||||
'Checking out a document, blocks certain operations '
|
||||
|
||||
Reference in New Issue
Block a user