Update signature API to support uploads
Signed-off-by: Roberto Rosario <roberto.rosario@mayan-edms.com>
This commit is contained in:
+1
-2
@@ -110,8 +110,7 @@
|
|||||||
own module.
|
own module.
|
||||||
- Update label and icon of the document sign form
|
- Update label and icon of the document sign form
|
||||||
Label updated from "Save" to "Sign".
|
Label updated from "Save" to "Sign".
|
||||||
- Add list, create, detail and edit API views for
|
- Document signatures API views.
|
||||||
detached and embedded signatures.
|
|
||||||
|
|
||||||
3.2.9 (2019-11-03)
|
3.2.9 (2019-11-03)
|
||||||
==================
|
==================
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from mayan.apps.acls.models import AccessControlList
|
from mayan.apps.acls.models import AccessControlList
|
||||||
from mayan.apps.documents.models import Document
|
from mayan.apps.documents.models import Document
|
||||||
from mayan.apps.rest_api import generics
|
from mayan.apps.rest_api import generics
|
||||||
@@ -11,13 +14,153 @@ from .permissions import (
|
|||||||
permission_document_version_sign_detached,
|
permission_document_version_sign_detached,
|
||||||
permission_document_version_sign_embedded,
|
permission_document_version_sign_embedded,
|
||||||
permission_document_version_signature_delete,
|
permission_document_version_signature_delete,
|
||||||
|
permission_document_version_signature_upload,
|
||||||
permission_document_version_signature_view
|
permission_document_version_signature_view
|
||||||
)
|
)
|
||||||
from .serializers import (
|
from .serializers import (
|
||||||
DetachedSignatureSerializer, EmbeddedSignatureSerializer
|
DetachedSignatureSerializer, EmbeddedSignatureSerializer,
|
||||||
|
SignDetachedSerializer, SignEmbeddedSerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class APIDocumentSignDetachedView(generics.GenericAPIView):
|
||||||
|
"""
|
||||||
|
post: Sign a document version with a detached signature.
|
||||||
|
"""
|
||||||
|
serializer_class = SignDetachedSerializer
|
||||||
|
|
||||||
|
def get_document(self):
|
||||||
|
return get_object_or_404(
|
||||||
|
klass=self.get_document_queryset(), pk=self.kwargs['document_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_document_queryset(self):
|
||||||
|
if self.request.method == 'POST':
|
||||||
|
permission = permission_document_version_sign_detached
|
||||||
|
|
||||||
|
return AccessControlList.objects.restrict_queryset(
|
||||||
|
permission=permission, queryset=Document.objects.all(),
|
||||||
|
user=self.request.user
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_document_version(self):
|
||||||
|
return get_object_or_404(
|
||||||
|
klass=self.get_document_version_queryset(),
|
||||||
|
pk=self.kwargs['document_version_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_document_version_queryset(self):
|
||||||
|
return self.get_document().versions.all()
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return DetachedSignature.objects.filter(
|
||||||
|
document_version=self.get_document_version()
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
if not self.request:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return super(
|
||||||
|
APIDocumentSignDetachedView, self
|
||||||
|
).get_serializer(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_serializer_context(self):
|
||||||
|
"""
|
||||||
|
Extra context provided to the serializer class.
|
||||||
|
"""
|
||||||
|
context = super(
|
||||||
|
APIDocumentSignDetachedView, self
|
||||||
|
).get_serializer_context()
|
||||||
|
|
||||||
|
if self.kwargs:
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
'document_version': self.get_document_version(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
serializer.sign(
|
||||||
|
key_id=request.data['key_id'],
|
||||||
|
passphrase=request.data['passphrase']
|
||||||
|
)
|
||||||
|
return Response(status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class APIDocumentSignEmbeddedView(generics.GenericAPIView):
|
||||||
|
"""
|
||||||
|
post: Sign a document version with an embedded signature.
|
||||||
|
"""
|
||||||
|
serializer_class = SignEmbeddedSerializer
|
||||||
|
|
||||||
|
def get_document(self):
|
||||||
|
return get_object_or_404(
|
||||||
|
klass=self.get_document_queryset(), pk=self.kwargs['document_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_document_queryset(self):
|
||||||
|
if self.request.method == 'POST':
|
||||||
|
permission = permission_document_version_sign_embedded
|
||||||
|
|
||||||
|
return AccessControlList.objects.restrict_queryset(
|
||||||
|
permission=permission, queryset=Document.objects.all(),
|
||||||
|
user=self.request.user
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_document_version(self):
|
||||||
|
return get_object_or_404(
|
||||||
|
klass=self.get_document_version_queryset(),
|
||||||
|
pk=self.kwargs['document_version_id']
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_document_version_queryset(self):
|
||||||
|
return self.get_document().versions.all()
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return DetachedSignature.objects.filter(
|
||||||
|
document_version=self.get_document_version()
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
if not self.request:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return super(
|
||||||
|
APIDocumentSignEmbeddedView, self
|
||||||
|
).get_serializer(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_serializer_context(self):
|
||||||
|
"""
|
||||||
|
Extra context provided to the serializer class.
|
||||||
|
"""
|
||||||
|
context = super(
|
||||||
|
APIDocumentSignEmbeddedView, self
|
||||||
|
).get_serializer_context()
|
||||||
|
|
||||||
|
if self.kwargs:
|
||||||
|
context.update(
|
||||||
|
{
|
||||||
|
'document_version': self.get_document_version(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
serializer.sign(
|
||||||
|
key_id=request.data['key_id'],
|
||||||
|
passphrase=request.data['passphrase']
|
||||||
|
)
|
||||||
|
return Response(status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
class APIDocumentDetachedSignatureListView(generics.ListCreateAPIView):
|
class APIDocumentDetachedSignatureListView(generics.ListCreateAPIView):
|
||||||
"""
|
"""
|
||||||
get: Returns a list of all the detached signatures of a document version.
|
get: Returns a list of all the detached signatures of a document version.
|
||||||
@@ -34,7 +177,7 @@ class APIDocumentDetachedSignatureListView(generics.ListCreateAPIView):
|
|||||||
if self.request.method == 'GET':
|
if self.request.method == 'GET':
|
||||||
permission = permission_document_version_signature_view
|
permission = permission_document_version_signature_view
|
||||||
elif self.request.method == 'POST':
|
elif self.request.method == 'POST':
|
||||||
permission = permission_document_version_sign_detached
|
permission = permission_document_version_signature_upload
|
||||||
|
|
||||||
return AccessControlList.objects.restrict_queryset(
|
return AccessControlList.objects.restrict_queryset(
|
||||||
permission=permission, queryset=Document.objects.all(),
|
permission=permission, queryset=Document.objects.all(),
|
||||||
@@ -135,10 +278,9 @@ class APIDocumentDetachedSignatureView(generics.RetrieveDestroyAPIView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class APIDocumentEmbeddedSignatureListView(generics.ListCreateAPIView):
|
class APIDocumentEmbeddedSignatureListView(generics.ListAPIView):
|
||||||
"""
|
"""
|
||||||
get: Returns a list of all the embedded signatures of a document version.
|
get: Returns a list of all the embedded signatures of a document version.
|
||||||
post: Create an embedded signature for a document version.
|
|
||||||
"""
|
"""
|
||||||
serializer_class = EmbeddedSignatureSerializer
|
serializer_class = EmbeddedSignatureSerializer
|
||||||
|
|
||||||
@@ -150,8 +292,6 @@ class APIDocumentEmbeddedSignatureListView(generics.ListCreateAPIView):
|
|||||||
def get_document_queryset(self):
|
def get_document_queryset(self):
|
||||||
if self.request.method == 'GET':
|
if self.request.method == 'GET':
|
||||||
permission = permission_document_version_signature_view
|
permission = permission_document_version_signature_view
|
||||||
elif self.request.method == 'POST':
|
|
||||||
permission = permission_document_version_sign_embedded
|
|
||||||
|
|
||||||
return AccessControlList.objects.restrict_queryset(
|
return AccessControlList.objects.restrict_queryset(
|
||||||
permission=permission, queryset=Document.objects.all(),
|
permission=permission, queryset=Document.objects.all(),
|
||||||
|
|||||||
@@ -43,7 +43,10 @@ class SignatureBaseModel(models.Model):
|
|||||||
date = models.DateField(
|
date = models.DateField(
|
||||||
blank=True, editable=False, null=True, verbose_name=_('Date signed')
|
blank=True, editable=False, null=True, verbose_name=_('Date signed')
|
||||||
)
|
)
|
||||||
key_id = models.CharField(max_length=40, verbose_name=_('Key ID'))
|
key_id = models.CharField(
|
||||||
|
help_text=_('ID of the key that will be used to sign the document.'),
|
||||||
|
max_length=40, verbose_name=_('Key ID')
|
||||||
|
)
|
||||||
# With proper key
|
# With proper key
|
||||||
signature_id = models.CharField(
|
signature_id = models.CharField(
|
||||||
blank=True, editable=False, null=True, max_length=64,
|
blank=True, editable=False, null=True, max_length=64,
|
||||||
@@ -128,7 +131,9 @@ class EmbeddedSignature(SignatureBaseModel):
|
|||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
class DetachedSignature(SignatureBaseModel):
|
class DetachedSignature(SignatureBaseModel):
|
||||||
signature_file = models.FileField(
|
signature_file = models.FileField(
|
||||||
blank=True, null=True, storage=storage_detachedsignature,
|
blank=True, help_text=_(
|
||||||
|
'Signature file previously generated.'
|
||||||
|
), null=True, storage=storage_detachedsignature,
|
||||||
upload_to=upload_to, verbose_name=_('Signature file')
|
upload_to=upload_to, verbose_name=_('Signature file')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
||||||
@@ -11,7 +13,7 @@ from mayan.apps.rest_api.relations import MultiKwargHyperlinkedIdentityField
|
|||||||
from .models import DetachedSignature, EmbeddedSignature
|
from .models import DetachedSignature, EmbeddedSignature
|
||||||
|
|
||||||
|
|
||||||
class DetachedSignatureSerializer(serializers.HyperlinkedModelSerializer):
|
class BaseSignatureSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
document_version_url = MultiKwargHyperlinkedIdentityField(
|
document_version_url = MultiKwargHyperlinkedIdentityField(
|
||||||
view_kwargs=(
|
view_kwargs=(
|
||||||
{
|
{
|
||||||
@@ -26,6 +28,18 @@ class DetachedSignatureSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
view_name='rest_api:documentversion-detail'
|
view_name='rest_api:documentversion-detail'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSignSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
passphrase = serializers.CharField(
|
||||||
|
help_text=_(
|
||||||
|
'The passphrase to unlock the key and allow it to be used to '
|
||||||
|
'sign the document version.'
|
||||||
|
),
|
||||||
|
required=False, write_only=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DetachedSignatureSerializer(BaseSignatureSerializer):
|
||||||
url = MultiKwargHyperlinkedIdentityField(
|
url = MultiKwargHyperlinkedIdentityField(
|
||||||
view_kwargs=(
|
view_kwargs=(
|
||||||
{
|
{
|
||||||
@@ -43,38 +57,22 @@ class DetachedSignatureSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
),
|
),
|
||||||
view_name='rest_api:detachedsignature-detail'
|
view_name='rest_api:detachedsignature-detail'
|
||||||
)
|
)
|
||||||
passphrase = serializers.CharField(required=False, write_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
extra_kwargs = {
|
||||||
|
'signature_file': {'write_only': True},
|
||||||
|
}
|
||||||
fields = (
|
fields = (
|
||||||
'date', 'document_version_url', 'key_id', 'signature_id',
|
'date', 'document_version_url', 'key_id', 'signature_file',
|
||||||
'passphrase', 'public_key_fingerprint', 'url'
|
'signature_id', 'public_key_fingerprint', 'url'
|
||||||
)
|
)
|
||||||
model = DetachedSignature
|
model = DetachedSignature
|
||||||
|
read_only_fields = ('key_id',)
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
key_id = validated_data.pop('key_id')
|
validated_data['document_version'] = self.context['document_version']
|
||||||
passphrase = validated_data.pop('passphrase', None)
|
return super(DetachedSignatureSerializer, self).create(
|
||||||
|
validated_data=validated_data
|
||||||
key_queryset = AccessControlList.objects.restrict_queryset(
|
|
||||||
permission=permission_key_sign, queryset=Key.objects.all(),
|
|
||||||
user=self.context['request'].user
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
key = key_queryset.get(fingerprint__endswith=key_id)
|
|
||||||
except Key.DoesNotExist:
|
|
||||||
raise ValidationError(
|
|
||||||
{
|
|
||||||
'key_id': [
|
|
||||||
'Key "{}" not found.'.format(key_id)
|
|
||||||
]
|
|
||||||
}, code='invalid'
|
|
||||||
)
|
|
||||||
|
|
||||||
return DetachedSignature.objects.sign_document_version(
|
|
||||||
document_version=self.context['document_version'], key=key,
|
|
||||||
passphrase=passphrase, user=self.context['request'].user
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -145,3 +143,65 @@ class EmbeddedSignatureSerializer(serializers.HyperlinkedModelSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return signature
|
return signature
|
||||||
|
|
||||||
|
|
||||||
|
class SignDetachedSerializer(BaseSignatureSerializer, BaseSignSerializer):
|
||||||
|
class Meta:
|
||||||
|
fields = (
|
||||||
|
'date', 'document_version_url', 'key_id', 'signature_id',
|
||||||
|
'passphrase', 'public_key_fingerprint', 'url'
|
||||||
|
)
|
||||||
|
model = DetachedSignature
|
||||||
|
|
||||||
|
def sign(self, key_id, passphrase):
|
||||||
|
key_queryset = AccessControlList.objects.restrict_queryset(
|
||||||
|
permission=permission_key_sign, queryset=Key.objects.all(),
|
||||||
|
user=self.context['request'].user
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
key = key_queryset.get(fingerprint__endswith=key_id)
|
||||||
|
except Key.DoesNotExist:
|
||||||
|
raise ValidationError(
|
||||||
|
{
|
||||||
|
'key_id': [
|
||||||
|
'Key "{}" not found.'.format(key_id)
|
||||||
|
]
|
||||||
|
}, code='invalid'
|
||||||
|
)
|
||||||
|
|
||||||
|
return DetachedSignature.objects.sign_document_version(
|
||||||
|
document_version=self.context['document_version'], key=key,
|
||||||
|
passphrase=passphrase, user=self.context['request'].user
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SignEmbeddedSerializer(SignDetachedSerializer):
|
||||||
|
class Meta:
|
||||||
|
fields = (
|
||||||
|
'date', 'document_version_url', 'key_id', 'signature_id',
|
||||||
|
'passphrase', 'public_key_fingerprint', 'url'
|
||||||
|
)
|
||||||
|
model = EmbeddedSignature
|
||||||
|
|
||||||
|
def sign(self, key_id, passphrase):
|
||||||
|
key_queryset = AccessControlList.objects.restrict_queryset(
|
||||||
|
permission=permission_key_sign, queryset=Key.objects.all(),
|
||||||
|
user=self.context['request'].user
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
key = key_queryset.get(fingerprint__endswith=key_id)
|
||||||
|
except Key.DoesNotExist:
|
||||||
|
raise ValidationError(
|
||||||
|
{
|
||||||
|
'key_id': [
|
||||||
|
'Key "{}" not found.'.format(key_id)
|
||||||
|
]
|
||||||
|
}, code='invalid'
|
||||||
|
)
|
||||||
|
|
||||||
|
return EmbeddedSignature.objects.sign_document_version(
|
||||||
|
document_version=self.context['document_version'], key=key,
|
||||||
|
passphrase=passphrase, user=self.context['request'].user
|
||||||
|
)
|
||||||
|
|||||||
@@ -12,16 +12,14 @@ from .literals import TEST_KEY_FILE_PATH, TEST_SIGNATURE_FILE_PATH
|
|||||||
|
|
||||||
class DetachedSignatureAPIViewTestMixin(object):
|
class DetachedSignatureAPIViewTestMixin(object):
|
||||||
def _request_test_document_signature_detached_create_view(self):
|
def _request_test_document_signature_detached_create_view(self):
|
||||||
return self.post(
|
with open(TEST_SIGNATURE_FILE_PATH, mode='rb') as file_object:
|
||||||
viewname='rest_api:document-version-signature-detached-list',
|
return self.post(
|
||||||
kwargs={
|
viewname='rest_api:document-version-signature-detached-list',
|
||||||
'document_id': self.test_document.pk,
|
kwargs={
|
||||||
'document_version_id': self.test_document_version.pk
|
'document_id': self.test_document.pk,
|
||||||
}, data={
|
'document_version_id': self.test_document_version.pk
|
||||||
'key_id': self.test_key_private.key_id,
|
}, data={'signature_file': file_object}
|
||||||
'passphrase': TEST_KEY_PRIVATE_PASSPHRASE
|
)
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def _request_test_document_signature_detached_delete_view(self):
|
def _request_test_document_signature_detached_delete_view(self):
|
||||||
return self.delete(
|
return self.delete(
|
||||||
@@ -52,6 +50,18 @@ class DetachedSignatureAPIViewTestMixin(object):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _request_test_document_signature_detached_sign_view(self):
|
||||||
|
return self.post(
|
||||||
|
viewname='rest_api:document-version-signature-detached-sign',
|
||||||
|
kwargs={
|
||||||
|
'document_id': self.test_document.pk,
|
||||||
|
'document_version_id': self.test_document_version.pk
|
||||||
|
}, data={
|
||||||
|
'key_id': self.test_key_private.key_id,
|
||||||
|
'passphrase': TEST_KEY_PRIVATE_PASSPHRASE
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DetachedSignatureViewTestMixin(object):
|
class DetachedSignatureViewTestMixin(object):
|
||||||
def _request_test_document_version_signature_download_view(self):
|
def _request_test_document_version_signature_download_view(self):
|
||||||
@@ -70,18 +80,6 @@ class DetachedSignatureViewTestMixin(object):
|
|||||||
|
|
||||||
|
|
||||||
class EmbeddedSignatureAPIViewTestMixin(object):
|
class EmbeddedSignatureAPIViewTestMixin(object):
|
||||||
def _request_test_document_signature_embedded_create_view(self):
|
|
||||||
return self.post(
|
|
||||||
viewname='rest_api:document-version-signature-embedded-list',
|
|
||||||
kwargs={
|
|
||||||
'document_id': self.test_document.pk,
|
|
||||||
'document_version_id': self.test_document_version.pk
|
|
||||||
}, data={
|
|
||||||
'key_id': self.test_key_private.key_id,
|
|
||||||
'passphrase': TEST_KEY_PRIVATE_PASSPHRASE
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def _request_test_document_signature_embedded_detail_view(self):
|
def _request_test_document_signature_embedded_detail_view(self):
|
||||||
return self.get(
|
return self.get(
|
||||||
viewname='rest_api:embeddedsignature-detail',
|
viewname='rest_api:embeddedsignature-detail',
|
||||||
@@ -101,6 +99,18 @@ class EmbeddedSignatureAPIViewTestMixin(object):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _request_test_document_signature_embedded_sign_view(self):
|
||||||
|
return self.post(
|
||||||
|
viewname='rest_api:document-version-signature-embedded-sign',
|
||||||
|
kwargs={
|
||||||
|
'document_id': self.test_document.pk,
|
||||||
|
'document_version_id': self.test_document_version.pk
|
||||||
|
}, data={
|
||||||
|
'key_id': self.test_key_private.key_id,
|
||||||
|
'passphrase': TEST_KEY_PRIVATE_PASSPHRASE
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SignatureTestMixin(object):
|
class SignatureTestMixin(object):
|
||||||
def _create_test_detached_signature(self):
|
def _create_test_detached_signature(self):
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ from ..permissions import (
|
|||||||
permission_document_version_sign_detached,
|
permission_document_version_sign_detached,
|
||||||
permission_document_version_sign_embedded,
|
permission_document_version_sign_embedded,
|
||||||
permission_document_version_signature_delete,
|
permission_document_version_signature_delete,
|
||||||
permission_document_version_signature_view
|
permission_document_version_signature_view,
|
||||||
|
permission_document_version_signature_upload
|
||||||
)
|
)
|
||||||
|
|
||||||
from .literals import TEST_KEY_PUBLIC_ID, TEST_SIGNED_DOCUMENT_PATH
|
from .literals import TEST_KEY_PUBLIC_ID, TEST_SIGNED_DOCUMENT_PATH
|
||||||
@@ -27,6 +28,39 @@ class DetachedSignatureDocumentAPIViewTestCase(
|
|||||||
):
|
):
|
||||||
auto_upload_document = False
|
auto_upload_document = False
|
||||||
|
|
||||||
|
def test_document_signature_detached_create_view_no_permission(self):
|
||||||
|
self.upload_document()
|
||||||
|
self._create_test_key_private()
|
||||||
|
|
||||||
|
signatures = self.test_document.latest_version.signatures.count()
|
||||||
|
|
||||||
|
response = self._request_test_document_signature_detached_create_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.test_document.latest_version.signatures.count(),
|
||||||
|
signatures
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_document_signature_detached_create_view_with_access(self):
|
||||||
|
self.upload_document()
|
||||||
|
self._create_test_key_private()
|
||||||
|
|
||||||
|
signatures = self.test_document.latest_version.signatures.count()
|
||||||
|
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_document,
|
||||||
|
permission=permission_document_version_signature_upload
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_test_document_signature_detached_create_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.test_document.latest_version.signatures.count(),
|
||||||
|
signatures + 1
|
||||||
|
)
|
||||||
|
|
||||||
def test_document_signature_detached_delete_no_permission(self):
|
def test_document_signature_detached_delete_no_permission(self):
|
||||||
self.upload_document()
|
self.upload_document()
|
||||||
self._create_test_detached_signature()
|
self._create_test_detached_signature()
|
||||||
@@ -83,81 +117,6 @@ class DetachedSignatureDocumentAPIViewTestCase(
|
|||||||
response.data['key_id'], TEST_KEY_PUBLIC_ID
|
response.data['key_id'], TEST_KEY_PUBLIC_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_signature_detached_create_view_no_permission(self):
|
|
||||||
self.upload_document()
|
|
||||||
self._create_test_key_private()
|
|
||||||
|
|
||||||
signatures = self.test_document.latest_version.signatures.count()
|
|
||||||
|
|
||||||
response = self._request_test_document_signature_detached_create_view()
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
self.test_document.latest_version.signatures.count(),
|
|
||||||
signatures
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_document_signature_detached_create_view_with_document_access(self):
|
|
||||||
self.upload_document()
|
|
||||||
self._create_test_key_private()
|
|
||||||
|
|
||||||
signatures = self.test_document.latest_version.signatures.count()
|
|
||||||
|
|
||||||
self.grant_access(
|
|
||||||
obj=self.test_document,
|
|
||||||
permission=permission_document_version_sign_detached
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self._request_test_document_signature_detached_create_view()
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
self.test_document.latest_version.signatures.count(),
|
|
||||||
signatures
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_document_signature_detached_create_view_with_key_access(self):
|
|
||||||
self.upload_document()
|
|
||||||
self._create_test_key_private()
|
|
||||||
|
|
||||||
signatures = self.test_document.latest_version.signatures.count()
|
|
||||||
|
|
||||||
self.grant_access(
|
|
||||||
obj=self.test_key_private,
|
|
||||||
permission=permission_key_sign
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self._request_test_document_signature_detached_create_view()
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
self.test_document.latest_version.signatures.count(),
|
|
||||||
signatures
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_document_signature_detached_create_view_with_full_access(self):
|
|
||||||
self.upload_document()
|
|
||||||
self._create_test_key_private()
|
|
||||||
|
|
||||||
signatures = self.test_document.latest_version.signatures.count()
|
|
||||||
|
|
||||||
self.grant_access(
|
|
||||||
obj=self.test_document,
|
|
||||||
permission=permission_document_version_sign_detached
|
|
||||||
)
|
|
||||||
self.grant_access(
|
|
||||||
obj=self.test_key_private,
|
|
||||||
permission=permission_key_sign
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self._request_test_document_signature_detached_create_view()
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
self.test_document.latest_version.signatures.count(),
|
|
||||||
signatures + 1
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_document_signature_detached_list_view_no_permission(self):
|
def test_document_signature_detached_list_view_no_permission(self):
|
||||||
self.upload_document()
|
self.upload_document()
|
||||||
self._create_test_detached_signature()
|
self._create_test_detached_signature()
|
||||||
@@ -180,20 +139,14 @@ class DetachedSignatureDocumentAPIViewTestCase(
|
|||||||
response.data['results'][0]['key_id'], TEST_KEY_PUBLIC_ID
|
response.data['results'][0]['key_id'], TEST_KEY_PUBLIC_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
|
##
|
||||||
class EmbeddedSignatureDocumentAPIViewTestCase(
|
def test_document_signature_detached_sign_view_with_no_permission(self):
|
||||||
DocumentTestMixin, EmbeddedSignatureAPIViewTestMixin,
|
|
||||||
KeyTestMixin, BaseAPITestCase
|
|
||||||
):
|
|
||||||
auto_upload_document = False
|
|
||||||
|
|
||||||
def test_document_signature_embedded_create_view_no_permission(self):
|
|
||||||
self.upload_document()
|
self.upload_document()
|
||||||
self._create_test_key_private()
|
self._create_test_key_private()
|
||||||
|
|
||||||
signatures = self.test_document.latest_version.signatures.count()
|
signatures = self.test_document.latest_version.signatures.count()
|
||||||
|
|
||||||
response = self._request_test_document_signature_embedded_create_view()
|
response = self._request_test_document_signature_detached_sign_view()
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -201,7 +154,7 @@ class EmbeddedSignatureDocumentAPIViewTestCase(
|
|||||||
signatures
|
signatures
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_signature_embedded_create_view_with_document_access(self):
|
def test_document_signature_detached_sign_view_with_document_access(self):
|
||||||
self.upload_document()
|
self.upload_document()
|
||||||
self._create_test_key_private()
|
self._create_test_key_private()
|
||||||
|
|
||||||
@@ -209,10 +162,10 @@ class EmbeddedSignatureDocumentAPIViewTestCase(
|
|||||||
|
|
||||||
self.grant_access(
|
self.grant_access(
|
||||||
obj=self.test_document,
|
obj=self.test_document,
|
||||||
permission=permission_document_version_sign_embedded
|
permission=permission_document_version_sign_detached
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self._request_test_document_signature_embedded_create_view()
|
response = self._request_test_document_signature_detached_sign_view()
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -220,7 +173,7 @@ class EmbeddedSignatureDocumentAPIViewTestCase(
|
|||||||
signatures
|
signatures
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_signature_embedded_create_view_with_key_access(self):
|
def test_document_signature_detached_sign_view_with_key_access(self):
|
||||||
self.upload_document()
|
self.upload_document()
|
||||||
self._create_test_key_private()
|
self._create_test_key_private()
|
||||||
|
|
||||||
@@ -231,7 +184,7 @@ class EmbeddedSignatureDocumentAPIViewTestCase(
|
|||||||
permission=permission_key_sign
|
permission=permission_key_sign
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self._request_test_document_signature_embedded_create_view()
|
response = self._request_test_document_signature_detached_sign_view()
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -239,7 +192,89 @@ class EmbeddedSignatureDocumentAPIViewTestCase(
|
|||||||
signatures
|
signatures
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_document_signature_embedded_create_view_with_full_access(self):
|
def test_document_signature_detached_sign_view_with_full_access(self):
|
||||||
|
self.upload_document()
|
||||||
|
self._create_test_key_private()
|
||||||
|
|
||||||
|
signatures = self.test_document.latest_version.signatures.count()
|
||||||
|
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_document,
|
||||||
|
permission=permission_document_version_sign_detached
|
||||||
|
)
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_key_private,
|
||||||
|
permission=permission_key_sign
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_test_document_signature_detached_sign_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.test_document.latest_version.signatures.count(),
|
||||||
|
signatures + 1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class EmbeddedSignatureDocumentAPIViewTestCase(
|
||||||
|
DocumentTestMixin, EmbeddedSignatureAPIViewTestMixin,
|
||||||
|
KeyTestMixin, BaseAPITestCase
|
||||||
|
):
|
||||||
|
auto_upload_document = False
|
||||||
|
|
||||||
|
def test_document_signature_embedded_sign_view_with_no_permission(self):
|
||||||
|
self.upload_document()
|
||||||
|
self._create_test_key_private()
|
||||||
|
|
||||||
|
signatures = self.test_document.latest_version.signatures.count()
|
||||||
|
|
||||||
|
response = self._request_test_document_signature_embedded_sign_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.test_document.latest_version.signatures.count(),
|
||||||
|
signatures
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_document_signature_embedded_sign_view_with_document_access(self):
|
||||||
|
self.upload_document()
|
||||||
|
self._create_test_key_private()
|
||||||
|
|
||||||
|
signatures = self.test_document.latest_version.signatures.count()
|
||||||
|
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_document,
|
||||||
|
permission=permission_document_version_sign_embedded
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_test_document_signature_embedded_sign_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.test_document.latest_version.signatures.count(),
|
||||||
|
signatures
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_document_signature_embedded_sign_view_with_key_access(self):
|
||||||
|
self.upload_document()
|
||||||
|
self._create_test_key_private()
|
||||||
|
|
||||||
|
signatures = self.test_document.latest_version.signatures.count()
|
||||||
|
|
||||||
|
self.grant_access(
|
||||||
|
obj=self.test_key_private,
|
||||||
|
permission=permission_key_sign
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self._request_test_document_signature_embedded_sign_view()
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.test_document.latest_version.signatures.count(),
|
||||||
|
signatures
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_document_signature_embedded_sign_view_with_full_access(self):
|
||||||
self.upload_document()
|
self.upload_document()
|
||||||
self._create_test_key_private()
|
self._create_test_key_private()
|
||||||
|
|
||||||
@@ -254,8 +289,8 @@ class EmbeddedSignatureDocumentAPIViewTestCase(
|
|||||||
permission=permission_key_sign
|
permission=permission_key_sign
|
||||||
)
|
)
|
||||||
|
|
||||||
response = self._request_test_document_signature_embedded_create_view()
|
response = self._request_test_document_signature_embedded_sign_view()
|
||||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.test_document.latest_version.signatures.count(),
|
self.test_document.latest_version.signatures.count(),
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ from __future__ import unicode_literals
|
|||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from .api_views import (
|
from .api_views import (
|
||||||
APIDocumentDetachedSignatureListView, APIDocumentDetachedSignatureView,
|
APIDocumentSignDetachedView, APIDocumentDetachedSignatureListView,
|
||||||
APIDocumentEmbeddedSignatureListView, APIDocumentEmbeddedSignatureView
|
APIDocumentDetachedSignatureView, APIDocumentEmbeddedSignatureListView,
|
||||||
|
APIDocumentEmbeddedSignatureView, APIDocumentSignEmbeddedView
|
||||||
)
|
)
|
||||||
|
|
||||||
from .views import (
|
from .views import (
|
||||||
@@ -64,6 +65,11 @@ api_urls = [
|
|||||||
view=APIDocumentDetachedSignatureListView.as_view(),
|
view=APIDocumentDetachedSignatureListView.as_view(),
|
||||||
name='document-version-signature-detached-list'
|
name='document-version-signature-detached-list'
|
||||||
),
|
),
|
||||||
|
url(
|
||||||
|
regex=r'^documents/(?P<document_id>[0-9]+)/versions/(?P<document_version_id>[0-9]+)/signatures/detached/sign/$',
|
||||||
|
view=APIDocumentSignDetachedView.as_view(),
|
||||||
|
name='document-version-signature-detached-sign'
|
||||||
|
),
|
||||||
url(
|
url(
|
||||||
regex=r'^documents/(?P<document_id>[0-9]+)/versions/(?P<document_version_id>[0-9]+)/signatures/detached/(?P<detached_signature_id>[0-9]+)/$',
|
regex=r'^documents/(?P<document_id>[0-9]+)/versions/(?P<document_version_id>[0-9]+)/signatures/detached/(?P<detached_signature_id>[0-9]+)/$',
|
||||||
view=APIDocumentDetachedSignatureView.as_view(),
|
view=APIDocumentDetachedSignatureView.as_view(),
|
||||||
@@ -74,6 +80,11 @@ api_urls = [
|
|||||||
view=APIDocumentEmbeddedSignatureListView.as_view(),
|
view=APIDocumentEmbeddedSignatureListView.as_view(),
|
||||||
name='document-version-signature-embedded-list'
|
name='document-version-signature-embedded-list'
|
||||||
),
|
),
|
||||||
|
url(
|
||||||
|
regex=r'^documents/(?P<document_id>[0-9]+)/versions/(?P<document_version_id>[0-9]+)/signatures/embedded/sign/$',
|
||||||
|
view=APIDocumentSignEmbeddedView.as_view(),
|
||||||
|
name='document-version-signature-embedded-sign'
|
||||||
|
),
|
||||||
url(
|
url(
|
||||||
regex=r'^documents/(?P<document_id>[0-9]+)/versions/(?P<document_version_id>[0-9]+)/signatures/embedded/(?P<embedded_signature_id>[0-9]+)/$',
|
regex=r'^documents/(?P<document_id>[0-9]+)/versions/(?P<document_version_id>[0-9]+)/signatures/embedded/(?P<embedded_signature_id>[0-9]+)/$',
|
||||||
view=APIDocumentEmbeddedSignatureView.as_view(),
|
view=APIDocumentEmbeddedSignatureView.as_view(),
|
||||||
|
|||||||
Reference in New Issue
Block a user