Skip to content

Commit

Permalink
Merge pull request #1427 from open-zaak/feature/1424-force-change
Browse files Browse the repository at this point in the history
Feature/1424 force change
  • Loading branch information
annashamray committed Aug 14, 2023
2 parents cd06259 + 2a085ad commit e7a65e7
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 11 deletions.
8 changes: 8 additions & 0 deletions src/openzaak/components/documenten/api/scopes.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,11 @@
* to unlock documents without lock key
""",
)

SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN = Scope(
"documenten.geforceerd-bijwerken",
description="""
**Allows**:
* changes meta data of all documents including "definitief" ones
""",
)
28 changes: 27 additions & 1 deletion src/openzaak/components/documenten/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
from ..query.django import InformatieobjectRelatedQuerySet
from ..utils import PrivateMediaStorageWithCMIS
from .fields import OnlyRemoteOrFKOrURLField
from .scopes import SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN
from .utils import create_filename, merge_files
from .validators import (
InformatieObjectUniqueValidator,
Expand Down Expand Up @@ -655,11 +656,36 @@ def validate(self, attrs):
_("Lock id must be provided"), code="missing-lock-id"
)

# update
if lock != self.instance.canonical.lock:
raise serializers.ValidationError(
_("Lock id is not correct"), code="incorrect-lock-id"
)

# for CMIS just use this instance
request = self.context["request"]
latest_version = (
self.instance
if settings.CMIS_ENABLED
else self.instance.canonical.latest_version
)
if (
not request.jwt_auth.has_auth(
scopes=SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN,
informatieobjecttype=request.build_absolute_uri(
self.instance.informatieobjecttype.get_absolute_api_url()
),
vertrouwelijkheidaanduiding=self.instance.vertrouwelijkheidaanduiding,
init_component=self.Meta.model._meta.app_label,
)
and latest_version.status == Statussen.definitief
):
raise serializers.ValidationError(
_(
"Het bijwerken van Informatieobjecten met status `definitief` is niet toegestaan"
),
code="modify-status-definitief",
)

return valid_attrs


Expand Down
6 changes: 4 additions & 2 deletions src/openzaak/components/documenten/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
SCOPE_DOCUMENTEN_ALLES_LEZEN,
SCOPE_DOCUMENTEN_ALLES_VERWIJDEREN,
SCOPE_DOCUMENTEN_BIJWERKEN,
SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN,
SCOPE_DOCUMENTEN_GEFORCEERD_UNLOCK,
SCOPE_DOCUMENTEN_LOCK,
)
Expand Down Expand Up @@ -200,8 +201,9 @@ class EnkelvoudigInformatieObjectViewSet(
"retrieve": SCOPE_DOCUMENTEN_ALLES_LEZEN,
"create": SCOPE_DOCUMENTEN_AANMAKEN,
"destroy": SCOPE_DOCUMENTEN_ALLES_VERWIJDEREN,
"update": SCOPE_DOCUMENTEN_BIJWERKEN,
"partial_update": SCOPE_DOCUMENTEN_BIJWERKEN,
"update": SCOPE_DOCUMENTEN_BIJWERKEN | SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN,
"partial_update": SCOPE_DOCUMENTEN_BIJWERKEN
| SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN,
"download": SCOPE_DOCUMENTEN_ALLES_LEZEN,
"lock": SCOPE_DOCUMENTEN_LOCK,
"unlock": SCOPE_DOCUMENTEN_LOCK | SCOPE_DOCUMENTEN_GEFORCEERD_UNLOCK,
Expand Down
10 changes: 5 additions & 5 deletions src/openzaak/components/documenten/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ paths:
- enkelvoudiginformatieobjecten
security:
- JWT-Claims:
- documenten.bijwerken
- (documenten.bijwerken | documenten.geforceerd-bijwerken)
patch:
operationId: enkelvoudiginformatieobject_partial_update
summary: Werk een (ENKELVOUDIG) INFORMATIEOBJECT deels bij.
Expand Down Expand Up @@ -703,7 +703,7 @@ paths:
- enkelvoudiginformatieobjecten
security:
- JWT-Claims:
- documenten.bijwerken
- (documenten.bijwerken | documenten.geforceerd-bijwerken)
delete:
operationId: enkelvoudiginformatieobject_delete
summary: Verwijder een (ENKELVOUDIG) INFORMATIEOBJECT.
Expand Down Expand Up @@ -2719,9 +2719,9 @@ components:
readOnly: true
lock:
title: Lock
description: Lock id generated if the large file is created and should be
used while updating the document. Documents with base64 encoded files
are created without lock
description: Het gegenereerde lock ID voor grote bestandsuploads wat gebruikt
moet worden bij document updates. Documenten met base64-encoded bestandsdata
worden zonder lock aangemaakt.
type: string
readOnly: true
minLength: 1
Expand Down
6 changes: 3 additions & 3 deletions src/openzaak/components/documenten/swagger2.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@
"security": [
{
"JWT-Claims": [
"documenten.bijwerken"
"(documenten.bijwerken | documenten.geforceerd-bijwerken)"
]
}
]
Expand Down Expand Up @@ -895,7 +895,7 @@
"security": [
{
"JWT-Claims": [
"documenten.bijwerken"
"(documenten.bijwerken | documenten.geforceerd-bijwerken)"
]
}
]
Expand Down Expand Up @@ -3081,7 +3081,7 @@
},
"lock": {
"title": "Lock",
"description": "Lock id generated if the large file is created and should be used while updating the document. Documents with base64 encoded files are created without lock",
"description": "Het gegenereerde lock ID voor grote bestandsuploads wat gebruikt moet worden bij document updates. Documenten met base64-encoded bestandsdata worden zonder lock aangemaakt.",
"type": "string",
"readOnly": true,
"minLength": 1
Expand Down
115 changes: 115 additions & 0 deletions src/openzaak/components/documenten/tests/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
from base64 import b64encode
from copy import deepcopy

from django.contrib.sites.models import Site
from django.test import override_settings, tag

import requests_mock
from privates.test import temp_private_root
from rest_framework import status
from rest_framework.test import APITestCase
from vng_api_common.constants import ComponentTypes, VertrouwelijkheidsAanduiding
from vng_api_common.tests import get_validation_errors, reverse, reverse_lazy
from vng_api_common.validators import IsImmutableValidator
from zgw_consumers.constants import APITypes
Expand All @@ -18,6 +20,12 @@
from openzaak.components.catalogi.tests.factories import InformatieObjectTypeFactory
from openzaak.tests.utils import JWTAuthMixin

from ..api.scopes import (
SCOPE_DOCUMENTEN_ALLES_LEZEN,
SCOPE_DOCUMENTEN_BIJWERKEN,
SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN,
SCOPE_DOCUMENTEN_LOCK,
)
from ..constants import OndertekeningSoorten, Statussen
from .factories import EnkelvoudigInformatieObjectFactory

Expand Down Expand Up @@ -289,6 +297,113 @@ def test_status_set_ontvangstdatum_is_set_later(self):
self.assertEqual(error["code"], "invalid_for_received")


class UpdateStatusDefinitiefTests(JWTAuthMixin, APITestCase):
max_vertrouwelijkheidaanduiding = VertrouwelijkheidsAanduiding.zeer_geheim
component = ComponentTypes.drc

@classmethod
def setUpTestData(cls):
cls.informatieobjecttype = InformatieObjectTypeFactory.create(concept=False)
site = Site.objects.get_current()
site.domain = "testserver"
site.save()
super().setUpTestData()

def test_update_definitief_status_fail(self):
self.autorisatie.scopes = [
SCOPE_DOCUMENTEN_ALLES_LEZEN,
SCOPE_DOCUMENTEN_BIJWERKEN,
SCOPE_DOCUMENTEN_LOCK,
]
self.autorisatie.save()
eio = EnkelvoudigInformatieObjectFactory.create(
informatieobjecttype=self.informatieobjecttype, status=Statussen.definitief
)
eio_url = reverse(eio)

eio_response = self.client.get(eio_url)
eio_data = eio_response.data

lock = self.client.post(f"{eio_url}/lock").data["lock"]
eio_data.update(
{"inhoud": b64encode(b"aaaaa"), "bestandsomvang": 5, "lock": lock,}
)
for i in ["integriteit", "ondertekening"]:
eio_data.pop(i)

response = self.client.put(eio_url, eio_data)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
error = get_validation_errors(response, "nonFieldErrors")
self.assertEqual(error["code"], "modify-status-definitief")

def test_patch_definitief_status_fail(self):
self.autorisatie.scopes = [
SCOPE_DOCUMENTEN_ALLES_LEZEN,
SCOPE_DOCUMENTEN_BIJWERKEN,
SCOPE_DOCUMENTEN_LOCK,
]
self.autorisatie.save()
eio = EnkelvoudigInformatieObjectFactory.create(
informatieobjecttype=self.informatieobjecttype, status=Statussen.definitief
)
eio_url = reverse(eio)
lock = self.client.post(f"{eio_url}/lock").data["lock"]

response = self.client.patch(
eio_url, {"lock": lock, "beschrijving": "updated",}
)

self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
error = get_validation_errors(response, "nonFieldErrors")
self.assertEqual(error["code"], "modify-status-definitief")

def test_update_definitief_status_force(self):
self.autorisatie.scopes = [
SCOPE_DOCUMENTEN_ALLES_LEZEN,
SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN,
SCOPE_DOCUMENTEN_LOCK,
]
self.autorisatie.save()
eio = EnkelvoudigInformatieObjectFactory.create(
informatieobjecttype=self.informatieobjecttype, status=Statussen.definitief
)
eio_url = reverse(eio)

eio_response = self.client.get(eio_url)
eio_data = eio_response.data

lock = self.client.post(f"{eio_url}/lock").data["lock"]
eio_data.update(
{"inhoud": b64encode(b"aaaaa"), "bestandsomvang": 5, "lock": lock,}
)
for i in ["integriteit", "ondertekening"]:
eio_data.pop(i)

response = self.client.put(eio_url, eio_data)

self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_patch_definitief_status_force(self):
self.autorisatie.scopes = [
SCOPE_DOCUMENTEN_ALLES_LEZEN,
SCOPE_DOCUMENTEN_GEFORCEERD_BIJWERKEN,
SCOPE_DOCUMENTEN_LOCK,
]
self.autorisatie.save()
eio = EnkelvoudigInformatieObjectFactory.create(
informatieobjecttype=self.informatieobjecttype, status=Statussen.definitief
)
eio_url = reverse(eio)
lock = self.client.post(f"{eio_url}/lock").data["lock"]

response = self.client.patch(
eio_url, {"lock": lock, "beschrijving": "updated",}
)

self.assertEqual(response.status_code, status.HTTP_200_OK)


@tag("oio")
class FilterValidationTests(JWTAuthMixin, APITestCase):
"""
Expand Down

0 comments on commit e7a65e7

Please sign in to comment.