Skip to content

Commit 5f2a658

Browse files
author
Anna Manko
committed
Added document of document validations.
1 parent 4c8b616 commit 5f2a658

20 files changed

Lines changed: 1412 additions & 230 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ __pycache__/
88
# Distribution / packaging
99
.Python
1010
env/
11+
.venv/
1112
build/
1213
develop-eggs/
1314
dist/
@@ -60,3 +61,5 @@ bin/
6061

6162
cover/
6263
output.html
64+
65+
.vscode/

docker-compose.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,4 @@ services:
1818
image: "couchdb:1.6"
1919
environment:
2020
COUCHDB_USER: op
21-
COUCHDB_PASSWORD: op
22-
ports:
23-
- "5984:5984"
21+
COUCHDB_PASSWORD: op

src/openprocurement/tender/belowthreshold/tests/base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@
100100
"format": "application/pdf"
101101
}
102102

103+
test_tender_full_document_data = {
104+
"hash": "md5:00000000000000000000000000000000",
105+
"author": "tender_owner",
106+
"format": "application/msword",
107+
"title": "tender_document.doc",
108+
"documentOf": "tender",
109+
"datePublished": "2020-04-23T14:31:34.217330+03:00",
110+
"dateModified": "2020-04-23T14:31:34.217368+03:00",
111+
"id": uuid4().hex
112+
}
113+
103114
if SANDBOX_MODE:
104115
test_tender_data["procurementMethodDetails"] = "quick, accelerator=1440"
105116
test_features_tender_data = test_tender_data.copy()

src/openprocurement/tender/belowthreshold/tests/contract.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ def setUp(self):
175175
class TenderContractDocumentResourceTest(TenderContentWebTest, TenderContractDocumentResourceTestMixin):
176176
initial_status = "active.qualification"
177177
initial_bids = test_bids
178-
178+
docservice = True
179+
179180
def setUp(self):
180181
super(TenderContractDocumentResourceTest, self).setUp()
181182
# Create award
@@ -218,6 +219,7 @@ class Tender2LotContractDocumentResourceTest(TenderContentWebTest):
218219
initial_status = "active.qualification"
219220
initial_bids = test_bids
220221
initial_lots = 2 * test_lots
222+
docservice = True
221223

222224
def setUp(self):
223225
super(Tender2LotContractDocumentResourceTest, self).setUp()

src/openprocurement/tender/belowthreshold/tests/contract_blanks.py

Lines changed: 1092 additions & 156 deletions
Large diffs are not rendered by default.

src/openprocurement/tender/belowthreshold/views/contract_document.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
from openprocurement.api.validation import validate_file_update, validate_file_upload, validate_patch_document_data
1212

1313
from openprocurement.tender.core.utils import save_tender, optendersresource, apply_patch
14-
from openprocurement.tender.core.validation import validate_role_for_contract_document_operation
14+
from openprocurement.tender.core.validation import (
15+
validate_role_for_contract_document_operation,
16+
validate_relatedItem_for_contract_document_uploading,
17+
validate_contract_supplier_role_for_contract_document_uploading,
18+
)
1519

1620

1721
@optendersresource(
@@ -64,13 +68,16 @@ def collection_get(self):
6468
return {"data": collection_data}
6569

6670
@json_view(permission="upload_contract_documents", validators=(validate_file_upload,
67-
validate_role_for_contract_document_operation,))
71+
validate_role_for_contract_document_operation,
72+
validate_contract_supplier_role_for_contract_document_uploading,
73+
validate_relatedItem_for_contract_document_uploading))
6874
def collection_post(self):
6975
"""Tender Contract Document Upload
7076
"""
7177
if not self.validate_contract_document("add"):
7278
return
7379
document = upload_file(self.request)
80+
document.author = self.request.authenticated_role
7481
self.context.documents.append(document)
7582
if save_tender(self.request):
7683
self.LOGGER.info(
@@ -98,9 +105,14 @@ def get(self):
98105
]
99106
return {"data": document_data}
100107

101-
@json_view(validators=(validate_file_update, validate_role_for_contract_document_operation,),
108+
@json_view(validators=(validate_file_update,
109+
validate_role_for_contract_document_operation,
110+
validate_contract_supplier_role_for_contract_document_uploading,
111+
validate_relatedItem_for_contract_document_uploading,
112+
),
102113
permission="upload_contract_documents")
103114
def put(self):
115+
104116
"""Tender Contract Document Update"""
105117
if not self.validate_contract_document("update"):
106118
return
@@ -114,7 +126,11 @@ def put(self):
114126
return {"data": document.serialize("view")}
115127

116128
@json_view(content_type="application/json",
117-
validators=(validate_patch_document_data, validate_role_for_contract_document_operation,),
129+
validators=(validate_patch_document_data,
130+
validate_role_for_contract_document_operation,
131+
validate_contract_supplier_role_for_contract_document_uploading,
132+
validate_relatedItem_for_contract_document_uploading,
133+
),
118134
permission="upload_contract_documents")
119135
def patch(self):
120136
"""Tender Contract Document Update"""

src/openprocurement/tender/cfaselectionua/models/submodels/contract.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
# -*- coding: utf-8 -*-
2+
import jmespath
23
from openprocurement.api.roles import RolesFromCsv
34
from schematics.exceptions import ValidationError
45
from schematics.types.compound import ModelType
56
from schematics.types import StringType
67
from openprocurement.tender.core.models import ContractValue
7-
from openprocurement.tender.core.utils import get_contract_supplier_roles, get_contract_supplier_permissions
8+
from openprocurement.tender.core.utils import get_contract_supplier_roles, get_contract_supplier_permissions, flatten_multidimensional_list, get_all_nested_from_the_object
89
from openprocurement.api.utils import get_now
910
from openprocurement.api.models import Model, ListType, Contract as BaseContract, Document
11+
from openprocurement.tender.core.models import get_tender
12+
13+
14+
class ContractDocument(Document):
15+
documentOf = StringType(required=True, choices=["tender","document"], default="tender")
16+
17+
def validate_relatedItem(self, data, relatedItem):
18+
if not relatedItem and data.get("documentOf") in ["document"]:
19+
raise ValidationError(u"This field is required.")
20+
parent = data["__parent__"]
21+
tender = get_tender(parent)
22+
if data.get("documentOf") == "document":
23+
documents = get_all_nested_from_the_object("documents",tender) + get_all_nested_from_the_object("documents",parent)
24+
if relatedItem not in [i.id for i in documents]:
25+
raise ValidationError(u"relatedItem should be one of documents")
1026

1127

1228
class Contract(BaseContract):
@@ -15,7 +31,7 @@ class Options:
1531

1632
value = ModelType(ContractValue)
1733
awardID = StringType(required=True)
18-
documents = ListType(ModelType(Document, required=True), default=list())
34+
documents = ListType(ModelType(ContractDocument, required=True), default=list())
1935

2036
def __acl__(self):
2137
return get_contract_supplier_permissions(self)

src/openprocurement/tender/cfaselectionua/tests/contract.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ class TenderContractDocumentResourceTest(TenderContentWebTest, TenderContractDoc
143143
initial_status = "active.awarded"
144144
initial_bids = test_bids
145145
initial_lots = test_lots
146-
146+
docservice = True
147+
147148
test_create_tender_contract_document_by_supplier = snitch(create_tender_contract_document_by_supplier)
148149
test_create_tender_contract_document_by_others = snitch(create_tender_contract_document_by_others)
149150
test_put_tender_contract_document_by_supplier = snitch(put_tender_contract_document_by_supplier)

src/openprocurement/tender/cfaselectionua/tests/contract_blanks.py

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -642,13 +642,31 @@ def create_tender_contract_document(self):
642642
response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}]
643643
)
644644

645-
response = self.app.get(
646-
"/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key)
647-
)
648-
self.assertEqual(response.status, "200 OK")
649-
self.assertEqual(response.content_type, "application/msword")
650-
self.assertEqual(response.content_length, 7)
651-
self.assertEqual(response.body, "content")
645+
if self.docservice:
646+
response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key))
647+
self.assertEqual(response.status, "302 Moved Temporarily")
648+
self.assertIn("http://localhost/get/", response.location)
649+
self.assertIn("Signature=", response.location)
650+
self.assertIn("KeyID=", response.location)
651+
self.assertNotIn("Expires=", response.location)
652+
else:
653+
response = self.app.get(
654+
"/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id),
655+
status=404,
656+
)
657+
self.assertEqual(response.status, "404 Not Found")
658+
self.assertEqual(response.content_type, "application/json")
659+
self.assertEqual(response.json["status"], "error")
660+
self.assertEqual(
661+
response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}]
662+
)
663+
response = self.app.get(
664+
"/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key)
665+
)
666+
self.assertEqual(response.status, "200 OK")
667+
self.assertEqual(response.content_type, "application/msword")
668+
self.assertEqual(response.content_length, 7)
669+
self.assertEqual(response.body, "content")
652670

653671
response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id))
654672
self.assertEqual(response.status, "200 OK")
@@ -752,13 +770,31 @@ def put_tender_contract_document(self):
752770
self.assertEqual(doc_id, response.json["data"]["id"])
753771
key = response.json["data"]["url"].split("?")[-1]
754772

755-
response = self.app.get(
756-
"/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key)
757-
)
758-
self.assertEqual(response.status, "200 OK")
759-
self.assertEqual(response.content_type, "application/msword")
760-
self.assertEqual(response.content_length, 8)
761-
self.assertEqual(response.body, "content2")
773+
if self.docservice:
774+
response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key))
775+
self.assertEqual(response.status, "302 Moved Temporarily")
776+
self.assertIn("http://localhost/get/", response.location)
777+
self.assertIn("Signature=", response.location)
778+
self.assertIn("KeyID=", response.location)
779+
self.assertNotIn("Expires=", response.location)
780+
else:
781+
response = self.app.get(
782+
"/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id),
783+
status=404,
784+
)
785+
self.assertEqual(response.status, "404 Not Found")
786+
self.assertEqual(response.content_type, "application/json")
787+
self.assertEqual(response.json["status"], "error")
788+
self.assertEqual(
789+
response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}]
790+
)
791+
response = self.app.get(
792+
"/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key)
793+
)
794+
self.assertEqual(response.status, "200 OK")
795+
self.assertEqual(response.content_type, "application/msword")
796+
self.assertEqual(response.content_length, 8)
797+
self.assertEqual(response.body, "content2")
762798

763799
response = self.app.get("/tenders/{}/contracts/{}/documents/{}".format(self.tender_id, self.contract_id, doc_id))
764800
self.assertEqual(response.status, "200 OK")
@@ -778,13 +814,31 @@ def put_tender_contract_document(self):
778814
self.assertEqual(doc_id, response.json["data"]["id"])
779815
key = response.json["data"]["url"].split("?")[-1]
780816

781-
response = self.app.get(
782-
"/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key)
783-
)
784-
self.assertEqual(response.status, "200 OK")
785-
self.assertEqual(response.content_type, "application/msword")
786-
self.assertEqual(response.content_length, 8)
787-
self.assertEqual(response.body, "content3")
817+
if self.docservice:
818+
response = self.app.get("/tenders/{}/contracts/{}/documents/{}?download={}".format(self.tender_id, self.contract_id, doc_id, key))
819+
self.assertEqual(response.status, "302 Moved Temporarily")
820+
self.assertIn("http://localhost/get/", response.location)
821+
self.assertIn("Signature=", response.location)
822+
self.assertIn("KeyID=", response.location)
823+
self.assertNotIn("Expires=", response.location)
824+
else:
825+
response = self.app.get(
826+
"/tenders/{}/contracts/{}/documents/{}?download=some_id".format(self.tender_id, self.contract_id, doc_id),
827+
status=404,
828+
)
829+
self.assertEqual(response.status, "404 Not Found")
830+
self.assertEqual(response.content_type, "application/json")
831+
self.assertEqual(response.json["status"], "error")
832+
self.assertEqual(
833+
response.json["errors"], [{u"description": u"Not Found", u"location": u"url", u"name": u"download"}]
834+
)
835+
response = self.app.get(
836+
"/tenders/{}/contracts/{}/documents/{}?{}".format(self.tender_id, self.contract_id, doc_id, key)
837+
)
838+
self.assertEqual(response.status, "200 OK")
839+
self.assertEqual(response.content_type, "application/msword")
840+
self.assertEqual(response.content_length, 8)
841+
self.assertEqual(response.body, "content3")
788842

789843
tender = self.db.get(self.tender_id)
790844
tender["contracts"][-1]["status"] = "cancelled"

src/openprocurement/tender/cfaselectionua/views/contract_document.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
from openprocurement.api.validation import validate_file_update, validate_file_upload, validate_patch_document_data
1212

1313
from openprocurement.tender.core.utils import save_tender, optendersresource, apply_patch
14-
from openprocurement.tender.core.validation import validate_role_for_contract_document_operation
14+
from openprocurement.tender.core.validation import(
15+
validate_role_for_contract_document_operation,
16+
validate_relatedItem_for_contract_document_uploading,
17+
validate_contract_supplier_role_for_contract_document_uploading,
18+
)
1519

1620

1721
@optendersresource(
@@ -64,7 +68,9 @@ def collection_get(self):
6468
return {"data": collection_data}
6569

6670
@json_view(permission="upload_contract_documents", validators=(validate_file_upload,
67-
validate_role_for_contract_document_operation,))
71+
validate_role_for_contract_document_operation,
72+
validate_relatedItem_for_contract_document_uploading,
73+
validate_contract_supplier_role_for_contract_document_uploading,))
6874
def collection_post(self):
6975
"""Tender Contract Document Upload
7076
"""
@@ -98,8 +104,11 @@ def get(self):
98104
]
99105
return {"data": document_data}
100106

101-
@json_view(validators=(validate_file_update, validate_role_for_contract_document_operation,),
102-
permission="upload_contract_documents")
107+
@json_view(permission="upload_contract_documents", validators=(validate_file_update,
108+
validate_role_for_contract_document_operation,
109+
validate_relatedItem_for_contract_document_uploading,
110+
validate_contract_supplier_role_for_contract_document_uploading,
111+
))
103112
def put(self):
104113
"""Tender Contract Document Update"""
105114
if not self.validate_contract_document("update"):
@@ -114,8 +123,12 @@ def put(self):
114123
return {"data": document.serialize("view")}
115124

116125
@json_view(content_type="application/json",
117-
validators=(validate_patch_document_data, validate_role_for_contract_document_operation,),
118-
permission="upload_contract_documents")
126+
permission="upload_contract_documents",
127+
validators=(validate_patch_document_data,
128+
validate_role_for_contract_document_operation,
129+
validate_relatedItem_for_contract_document_uploading,
130+
validate_contract_supplier_role_for_contract_document_uploading,
131+
))
119132
def patch(self):
120133
"""Tender Contract Document Update"""
121134
if not self.validate_contract_document("update"):

0 commit comments

Comments
 (0)