Skip to content

Commit

Permalink
Merge pull request #19 from ProzorroUKR/feature/risk-indicators-integ…
Browse files Browse the repository at this point in the history
…ration

Tender monitorings list
  • Loading branch information
alekseystryukov committed Jun 27, 2018
2 parents e593f55 + 63bccf3 commit fe7c16b
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 3 deletions.
29 changes: 29 additions & 0 deletions openprocurement/audit/api/design.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,32 @@ def add_design():
emit(doc._local_seq, data);
}
}''' % CHANGES_FIELDS)


MONITORINGS_BY_TENDER_FIELDS = [
'status',
]

monitorings_by_tender_id_view = ViewDefinition('monitorings', 'by_tender_id', '''function(doc) {
if(doc.doc_type == 'Monitoring' && !doc.mode) {
var fields=%s, data={};
for (var i in fields) {
if (doc[fields[i]]) {
data[fields[i]] = doc[fields[i]]
}
}
emit([doc.tender_id, doc.dateCreated], data);
}
}''' % MONITORINGS_BY_TENDER_FIELDS)

test_monitorings_by_tender_id_view = ViewDefinition('monitorings', 'test_by_tender_id', '''function(doc) {
if(doc.doc_type == 'Monitoring' && doc.mode == 'test') {
var fields=%s, data={};
for (var i in fields) {
if (doc[fields[i]]) {
data[fields[i]] = doc[fields[i]]
}
}
emit([doc.tender_id, doc.dateCreated], data);
}
}''' % MONITORINGS_BY_TENDER_FIELDS)
5 changes: 4 additions & 1 deletion openprocurement/audit/api/tests/auth.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ test = token
test_sas = test_sas_token

[contracting]
test_contracting = test_contracting_token
test_contracting = test_contracting_token

[risk_indicators]
risk_indicator_bot = test_risk_indicator_bot_token
1 change: 1 addition & 0 deletions openprocurement/audit/api/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def setUp(self):
config.read(os.path.join(os.path.dirname(__file__), 'auth.ini'))
self.broker_token = config.get("brokers", "broker")
self.sas_token = config.get("sas", "test_sas")
self.risk_indicator_token = config.get("risk_indicators", "risk_indicator_bot")

def tearDown(self):
del self.couchdb_server[self.db.name]
Expand Down
34 changes: 34 additions & 0 deletions openprocurement/audit/api/tests/test_monitorings.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,40 @@ def test_post_monitoring_sas(self):
)
self.assertEqual(response.json["data"]["status"], "draft")

def test_post_monitoring_risk_bot(self):
self.app.authorization = ('Basic', (self.risk_indicator_token, ''))
response = self.app.post_json(
'/monitorings',
{"data": {
"tender_id": "f" * 32,
"reasons": ["public", "fiscal"],
"procuringStages": ["awarding", "contracting"]
}},
status=201
)

self.assertIn("data", response.json)
self.assertEqual(
set(response.json["data"]),
{"id", "status", "tender_id", "dateModified",
"dateCreated", "reasons", "monitoring_id", "procuringStages"}
)
self.assertEqual(response.json["data"]["status"], "draft")

def test_post_active_monitoring_risk_bot(self):
self.app.authorization = ('Basic', (self.risk_indicator_token, ''))
response = self.app.post_json(
'/monitorings',
{"data": {
"tender_id": "f" * 32,
"reasons": ["public", "fiscal"],
"procuringStages": ["awarding", "contracting"],
"status": "active",
}},
status=422
)
self.assertEqual(response.json["errors"][0]["description"], "Can't create a monitoring in 'active' status")


class BaseFeedResourceTest(BaseWebTest):
feed = ""
Expand Down
86 changes: 86 additions & 0 deletions openprocurement/audit/api/tests/test_tender_monitorings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from openprocurement.audit.api.tests.base import BaseWebTest
import unittest


class TenderMonitoringsResourceTest(BaseWebTest):

def test_get_empty_list(self):
response = self.app.get('/tenders/f9f9f9/monitorings')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['data'], [])

def test_get(self):
tender_id = "f" * 32

ids = []
for i in range(10):
self.create_monitoring(tender_id=tender_id)
ids.append(self.monitoring_id)

for i in range(5): # these are not on the list
self.create_monitoring(tender_id="a" * 32)

response = self.app.get('/tenders/{}/monitorings'.format(tender_id))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual([e["id"] for e in response.json['data']], ids)
self.assertEqual(set(response.json['data'][0].keys()),
{"id", "dateCreated", "status"})

def test_get_custom_fields(self):
tender_id = "a" * 32

ids = []
for i in range(10):
self.create_monitoring(tender_id=tender_id)
ids.append(self.monitoring_id)

response = self.app.get(
'/tenders/{}/monitorings?opt_fields=dateModified%2Creasons'.format(
tender_id
)
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')

self.assertEqual([e["id"] for e in response.json['data']], ids)
self.assertEqual(set(response.json['data'][0].keys()),
{"id", "dateCreated", "dateModified", "status", "reasons"})

def test_get_test_empty(self):
tender_id = "a" * 32
for i in range(10):
self.create_monitoring(tender_id=tender_id, mode="test")

response = self.app.get(
'/tenders/{}/monitorings'.format(tender_id)
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['data'], [])

def test_get_test(self):
tender_id = "a" * 32

ids = []
for i in range(10):
self.create_monitoring(tender_id=tender_id, mode="test")
ids.append(self.monitoring_id)

response = self.app.get(
'/tenders/{}/monitorings?mode=test'.format(tender_id)
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual([e["id"] for e in response.json['data']], ids)


def suite():
s = unittest.TestSuite()
s.addTest(unittest.makeSuite(TenderMonitoringsResourceTest))
return s


if __name__ == '__main__':
unittest.main(defaultTest='suite')
1 change: 1 addition & 0 deletions openprocurement/audit/api/traversal.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Root(object):
(Allow, Everyone, 'view_monitoring'),
(Allow, Everyone, 'revision_monitoring'),
(Allow, 'g:brokers', 'generate_credentials'),
(Allow, 'g:risk_indicators', 'create_monitoring'),
(Allow, 'g:sas', 'create_monitoring'),
(Allow, 'g:sas', 'edit_monitoring'),
(Allow, 'g:sas', 'upload_monitoring_documents'),
Expand Down
13 changes: 11 additions & 2 deletions openprocurement/audit/api/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@ def validate_monitoring_data(request):
"""
Validate monitoring data POST
"""
update_logging_context(request, {'MONITORING_ID': '__new__'})
return validate_data(request, Monitoring)
update_logging_context(request, {'MONITOR_ID': '__new__'})
data = validate_data(request, Monitoring)

monitoring = request.validated['monitoring']
if monitoring.status != DRAFT_STATUS:
request.errors.add(
'body', 'status', "Can't create a monitoring in '{}' status".format(monitoring.status)
)
request.errors.status = 422
raise error_handler(request.errors)
return data


def validate_patch_monitoring_data(request):
Expand Down
67 changes: 67 additions & 0 deletions openprocurement/audit/api/views/tender.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from openprocurement.api.utils import json_view
from openprocurement.audit.api.utils import (
op_resource,
context_unpack,
APIResource,
monitoring_serialize,
)
from openprocurement.audit.api.design import (
monitorings_by_tender_id_view,
test_monitorings_by_tender_id_view,
MONITORINGS_BY_TENDER_FIELDS,
)
from logging import getLogger

LOGGER = getLogger(__name__)


@op_resource(name='Tender Monitorings', path='/tenders/{tender_id}/monitorings')
class TenderMonitoringResource(APIResource):

def __init__(self, request, context):
super(TenderMonitoringResource, self).__init__(request, context)
self.views = {
"": monitorings_by_tender_id_view,
"test": test_monitorings_by_tender_id_view,
}
self.default_fields = set(MONITORINGS_BY_TENDER_FIELDS) | {"id", "dateCreated"}

@json_view(permission='view_listing')
def get(self):
tender_id = self.request.matchdict["tender_id"]

opt_fields = self.request.params.get('opt_fields', '')
opt_fields = set(e for e in opt_fields.split(',') if e)

mode = self.request.params.get('mode', '')
list_view = self.views.get(mode, "")

view_kwargs = dict(
limit=500, # TODO: pagination
startkey=[tender_id, None],
endkey=[tender_id, {}],
)

if opt_fields - self.default_fields:
self.LOGGER.info(
'Used custom fields for monitoring list: {}'.format(','.join(sorted(opt_fields))),
extra=context_unpack(self.request, {'MESSAGE_ID': "CUSTOM_MONITORING_LIST"}))

results = [
monitoring_serialize(self.request, i[u'doc'], opt_fields | self.default_fields)
for i in list_view(self.db, include_docs=True, **view_kwargs)
]
else:
results = [
dict(
id=e.id,
dateCreated=e.key[1],
**e.value
)
for e in list_view(self.db, **view_kwargs)
]

data = {
'data': results,
}
return data

0 comments on commit fe7c16b

Please sign in to comment.