Skip to content

Commit

Permalink
Merge pull request #20 from ProzorroUKR/feature/add-posts
Browse files Browse the repository at this point in the history
Refactoring (choices, validators)
  • Loading branch information
alekseystryukov committed Jun 27, 2018
2 parents 0645e66 + 1d1f8c1 commit e593f55
Show file tree
Hide file tree
Showing 19 changed files with 534 additions and 246 deletions.
72 changes: 72 additions & 0 deletions openprocurement/audit/api/choices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from openprocurement.audit.api.constants import (
DECISION_OBJECT_TYPE, CONCLUSION_OBJECT_TYPE, DRAFT_STATUS, ACTIVE_STATUS, ADDRESSED_STATUS,
DECLINED_STATUS, COMPLETED_STATUS, CLOSED_STATUS, STOPPED_STATUS, CANCELLED_STATUS,
CORRUPTION_DESCRIPTION_VIOLATION, CORRUPTION_PROCUREMENT_METHOD_TYPE_VIOLATION,
CORRUPTION_PUBLIC_DISCLOSURE_VIOLATION, CORRUPTION_BIDDING_DOCUMENTS_VIOLATION, DOCUMENTS_FORM_VIOLATION,
CORRUPTION_AWARDED_VIOLATION, CORRUPTION_CANCELLED_VIOLATION, CORRUPTION_CONTRACTING_VIOLATION,
CORRUPTION_CHANGES_VIOLATION, OTHER_VIOLATION, DIALOGUE_OBJECT_TYPE, ELIMINATION_REPORT_OBJECT_TYPE,
APPEAL_OBJECT_TYPE, CREATE_PARTY_ROLE
)
DIALOGUE_TYPE_CHOICES = (
DECISION_OBJECT_TYPE,
CONCLUSION_OBJECT_TYPE,
)

PARTY_ROLES_CHOICES = (
CREATE_PARTY_ROLE,
DECISION_OBJECT_TYPE,
CONCLUSION_OBJECT_TYPE,
APPEAL_OBJECT_TYPE,
ELIMINATION_REPORT_OBJECT_TYPE,
DIALOGUE_OBJECT_TYPE,
)

MONITORING_STATUS_CHOICES = (
DRAFT_STATUS,
ACTIVE_STATUS,
ADDRESSED_STATUS,
DECLINED_STATUS,
COMPLETED_STATUS,
CLOSED_STATUS,
STOPPED_STATUS,
CANCELLED_STATUS,
)

MONITORING_VIOLATION_TYPE_CHOICES = (
CORRUPTION_DESCRIPTION_VIOLATION,
CORRUPTION_PROCUREMENT_METHOD_TYPE_VIOLATION,
CORRUPTION_PUBLIC_DISCLOSURE_VIOLATION,
CORRUPTION_BIDDING_DOCUMENTS_VIOLATION,
DOCUMENTS_FORM_VIOLATION,
CORRUPTION_AWARDED_VIOLATION,
CORRUPTION_CANCELLED_VIOLATION,
CORRUPTION_CONTRACTING_VIOLATION,
CORRUPTION_CHANGES_VIOLATION,
OTHER_VIOLATION,
)

MONITORING_REASON_CHOICES = [
'indicator',
'authorities',
'media',
'fiscal',
'public'
]

MONITORING_PROCURING_STAGES = [
'planning',
'awarding',
'contracting'
]

RESOLUTION_RESULT_CHOICES = [
'completely',
'partly',
'none'
]

RESOLUTION_BY_TYPE_CHOICES = [
'eliminated',
'not_eliminated',
'no_mechanism'
]
39 changes: 39 additions & 0 deletions openprocurement/audit/api/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta

# Time restrictions
MONITORING_TIME = timedelta(days=17)
ELIMINATION_PERIOD_TIME = timedelta(days=10)
ELIMINATION_PERIOD_NO_VIOLATIONS_TIME = timedelta(days=3)

# Object type strings
DECISION_OBJECT_TYPE = 'decision'
CONCLUSION_OBJECT_TYPE = 'conclusion'
APPEAL_OBJECT_TYPE = 'appeal'
ELIMINATION_REPORT_OBJECT_TYPE = 'eliminationReport'
DIALOGUE_OBJECT_TYPE = 'dialogue'

# Custom party roles
CREATE_PARTY_ROLE = 'create'

# Monitoring statuses
DRAFT_STATUS = 'draft'
ACTIVE_STATUS = 'active'
ADDRESSED_STATUS = 'addressed'
DECLINED_STATUS = 'declined'
COMPLETED_STATUS = 'completed'
CLOSED_STATUS = 'closed'
STOPPED_STATUS = 'stopped'
CANCELLED_STATUS = 'cancelled'

# Monitoring violation types
CORRUPTION_DESCRIPTION_VIOLATION = 'corruptionDescription'
CORRUPTION_PROCUREMENT_METHOD_TYPE_VIOLATION = 'corruptionProcurementMethodType'
CORRUPTION_PUBLIC_DISCLOSURE_VIOLATION = 'corruptionPublicDisclosure'
CORRUPTION_BIDDING_DOCUMENTS_VIOLATION = 'corruptionBiddingDocuments'
DOCUMENTS_FORM_VIOLATION = 'documentsForm'
CORRUPTION_AWARDED_VIOLATION = 'corruptionAwarded'
CORRUPTION_CANCELLED_VIOLATION = 'corruptionCancelled'
CORRUPTION_CONTRACTING_VIOLATION = 'corruptionContracting'
CORRUPTION_CHANGES_VIOLATION = 'corruptionChanges'
OTHER_VIOLATION = 'other'
7 changes: 0 additions & 7 deletions openprocurement/audit/api/constraints.py

This file was deleted.

66 changes: 35 additions & 31 deletions openprocurement/audit/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,24 @@
from couchdb_schematics.document import SchematicsDocument
from pyramid.security import Allow

from openprocurement.audit.api.choices import (
DIALOGUE_TYPE_CHOICES,
PARTY_ROLES_CHOICES,
MONITORING_STATUS_CHOICES,
MONITORING_VIOLATION_TYPE_CHOICES,
MONITORING_REASON_CHOICES,
MONITORING_PROCURING_STAGES,
RESOLUTION_RESULT_CHOICES, RESOLUTION_BY_TYPE_CHOICES)
from openprocurement.audit.api.constants import (
DECISION_OBJECT_TYPE,
DRAFT_STATUS,
OTHER_VIOLATION,
)


class Report(Model):
description = StringType(required=True)
documents = ListType(ModelType(Document), default=list())
documents = ListType(ModelType(Document), default=[])
dateCreated = IsoDateTimeType(default=get_now)
datePublished = IsoDateTimeType()

Expand All @@ -27,14 +41,7 @@ class Decision(Report):

class Conclusion(Report):
violationOccurred = BooleanType(required=True)
violationType = ListType(
StringType(choices=(
'corruptionDescription', 'corruptionProcurementMethodType', 'corruptionPublicDisclosure',
'corruptionBiddingDocuments', 'documentsForm', 'corruptionAwarded', 'corruptionCancelled',
'corruptionContracting', 'corruptionChanges', 'other',
)),
default=[]
)
violationType = ListType(StringType(choices=MONITORING_VIOLATION_TYPE_CHOICES), default=[])
otherViolationType = StringType()
auditFinding = StringType()
stringsAttached = StringType()
Expand All @@ -45,11 +52,11 @@ def validate_violationType(self, data, value):
if data["violationOccurred"] and not value:
raise ValidationError(u"This field is required.")

if value and "other" not in value: # drop other type description
if value and OTHER_VIOLATION not in value: # drop other type description
data["otherViolationType"] = None

def validate_otherViolationType(self, data, value):
if "other" in data["violationType"] and not value:
if OTHER_VIOLATION in data["violationType"] and not value:
raise ValidationError(u"This field is required.")


Expand All @@ -58,8 +65,8 @@ class Cancellation(Report):


class EliminationResolution(Report):
result = StringType(choices=['completely', 'partly', 'none'])
resultByType = DictType(StringType(choices=['eliminated', 'not_eliminated', 'no_mechanism']))
result = StringType(choices=RESOLUTION_RESULT_CHOICES)
resultByType = DictType(StringType(choices=RESOLUTION_BY_TYPE_CHOICES))
description = StringType(required=False)

def validate_resultByType(self, data, value):
Expand Down Expand Up @@ -115,11 +122,11 @@ class Options:
title = StringType(required=True)
description = StringType(required=True)
answer = StringType()
documents = ListType(ModelType(Document), default=list())
documents = ListType(ModelType(Document), default=[])
dateSubmitted = IsoDateTimeType(default=get_now())
dateAnswered = IsoDateTimeType()
author = StringType()
dialogueOf = StringType(choices=('decision', 'conclusion'), default='decision')
dialogueOf = StringType(choices=DIALOGUE_TYPE_CHOICES, default=DECISION_OBJECT_TYPE)
relatedParty = StringType()

def validate_relatedParty(self, data, value):
Expand All @@ -142,13 +149,13 @@ class Options:
additionalIdentifiers = ListType(ModelType(Identifier))
address = ModelType(Address, required=True)
contactPoint = ModelType(ContactPoint, required=True)
roles = ListType(StringType(choices=('create', 'decision', 'conclusion', 'dialogue')), default=list())
roles = ListType(StringType(choices=PARTY_ROLES_CHOICES), default=[])


class Monitoring(SchematicsDocument, Model):

class Options:
_perm_edit_whitelist = whitelist("status", "reasons", "procuringStages", "parties")
_perm_edit_whitelist = whitelist('status', 'reasons', 'procuringStages', 'parties')
roles = {
'plain': blacklist('_attachments', 'revisions') + schematics_embedded_role,
'revision': whitelist('revisions'),
Expand All @@ -158,10 +165,10 @@ class Options:
'tender_owner_token', 'tender_owner',
'monitoringPeriod', 'eliminationPeriod'
) + schematics_embedded_role,
'edit_draft': whitelist("decision", "cancellation") + _perm_edit_whitelist,
'edit_active': whitelist("conclusion", "cancellation") + _perm_edit_whitelist,
'edit_addressed': whitelist("eliminationResolution", "cancellation") + _perm_edit_whitelist,
'edit_declined': whitelist("cancellation") + _perm_edit_whitelist,
'edit_draft': whitelist('decision', 'cancellation') + _perm_edit_whitelist,
'edit_active': whitelist('conclusion', 'cancellation') + _perm_edit_whitelist,
'edit_addressed': whitelist('eliminationResolution', 'cancellation') + _perm_edit_whitelist,
'edit_declined': whitelist('cancellation') + _perm_edit_whitelist,
'edit_completed': whitelist(),
'edit_closed': whitelist(),
'edit_stopped': whitelist(),
Expand All @@ -176,31 +183,28 @@ class Options:

tender_id = MD5Type(required=True)
monitoring_id = StringType()
status = StringType(choices=[
'draft', 'active', 'addressed', 'declined',
'completed', 'closed', 'stopped', 'cancelled'
], default='draft')
status = StringType(choices=MONITORING_STATUS_CHOICES, default=DRAFT_STATUS)

reasons = ListType(StringType(choices=['indicator', 'authorities', 'media', 'fiscal', 'public']), required=True)
procuringStages = ListType(StringType(choices=['planning', 'awarding', 'contracting']), required=True)
reasons = ListType(StringType(choices=MONITORING_REASON_CHOICES), required=True)
procuringStages = ListType(StringType(choices=MONITORING_PROCURING_STAGES), required=True)
monitoringPeriod = ModelType(Period)

decision = ModelType(Decision)
conclusion = ModelType(Conclusion)
eliminationReport = ModelType(EliminationReport)
eliminationResolution = ModelType(EliminationResolution)
eliminationPeriod = ModelType(Period)
dialogues = ListType(ModelType(Dialogue), default=list())
dialogues = ListType(ModelType(Dialogue), default=[])
cancellation = ModelType(Cancellation)
appeal = ModelType(Appeal)

parties = ListType(ModelType(Party), default=list())
parties = ListType(ModelType(Party), default=[])

dateModified = IsoDateTimeType()
dateCreated = IsoDateTimeType(default=get_now)
tender_owner = StringType()
tender_owner_token = StringType()
revisions = ListType(ModelType(Revision), default=list())
revisions = ListType(ModelType(Revision), default=[])
_attachments = DictType(DictType(BaseType), default=dict())

mode = StringType(choices=['test'])
Expand All @@ -226,7 +230,7 @@ def monitoring_cancellation(self):
return self.cancellation

def validate_eliminationResolution(self, data, value):
if value is not None and data["eliminationReport"] is None:
if value is not None and data['eliminationReport'] is None:
raise ValidationError(u"Elimination report hasn't been provided.")

def validate_monitoringDetails(self, *args, **kw):
Expand Down
8 changes: 4 additions & 4 deletions openprocurement/audit/api/tests/test_conclusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,13 @@ def test_visibility(self):

self.app.authorization = ('Basic', (self.sas_token, ''))
response = self.app.get('/monitorings/{}'.format(self.monitoring_id))
self.assertEqual(response.status, '200 OK')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['data']["conclusion"]["description"], "text")

self.app.authorization = ('Basic', (self.broker_token, ''))
response = self.app.get('/monitorings/{}'.format(self.monitoring_id))
self.assertEqual(response.status, '200 OK')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertNotIn('conclusion', response.json['data'])

Expand All @@ -294,13 +294,13 @@ def test_visibility(self):

self.app.authorization = ('Basic', (self.sas_token, ''))
response = self.app.get('/monitorings/{}'.format(self.monitoring_id))
self.assertEqual(response.status, '200 OK')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['data']["conclusion"]["description"], "text")

self.app.authorization = ('Basic', (self.broker_token, ''))
response = self.app.get('/monitorings/{}'.format(self.monitoring_id))
self.assertEqual(response.status, '200 OK')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['data']["conclusion"]["description"], "text")

Expand Down
16 changes: 8 additions & 8 deletions openprocurement/audit/api/tests/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_credentials_no_access_token(self):
status=403
)

self.assertEqual(response.status, '403 Forbidden')
self.assertEqual(response.status_code, 403)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual({('body', 'data')}, get_errors_field_names(response, 'No access token was provided'))

Expand All @@ -36,7 +36,7 @@ def test_credentials_query_param_access_token(self, mock_request):
'/monitorings/{}/credentials?acc_token={}'.format(self.monitoring_id, 'tender_token')
)

self.assertEqual(response.status, '200 OK')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertIn('access', response.json)

Expand All @@ -53,7 +53,7 @@ def test_credentials_query_param_wrong_access_token(self, mock_request):
status=403
)

self.assertEqual(response.status, '403 Forbidden')
self.assertEqual(response.status_code, 403)
self.assertEqual(response.content_type, 'application/json')

@mock.patch('restkit.Client.request')
Expand All @@ -68,7 +68,7 @@ def test_credentials_no_tender(self, mock_request):
status=403
)

self.assertEqual(response.status, '403 Forbidden')
self.assertEqual(response.status_code, 403)
self.assertEqual(response.content_type, 'application/json')
self.assertEqual({('body', 'data')}, get_errors_field_names(response, 'Tender {} not found'.format("f" * 32)))

Expand All @@ -85,7 +85,7 @@ def test_credentials_header_access_token(self, mock_request):
headers={'X-access-token': 'tender_token'}
)

self.assertEqual(response.status, '200 OK')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertIn('access', response.json)

Expand All @@ -103,7 +103,7 @@ def test_credentials_header_wrong_access_token(self, mock_request):
status=403
)

self.assertEqual(response.status, '403 Forbidden')
self.assertEqual(response.status_code, 403)
self.assertEqual(response.content_type, 'application/json')

@mock.patch('restkit.Resource.request')
Expand All @@ -119,7 +119,7 @@ def test_credentials_body_access_token(self, mock_request):
{'access': {'token': 'tender_token'}}
)

self.assertEqual(response.status, '200 OK')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, 'application/json')
self.assertIn('access', response.json)

Expand All @@ -137,7 +137,7 @@ def test_credentials_body_wrong_access_token(self, mock_request):
status=403
)

self.assertEqual(response.status, '403 Forbidden')
self.assertEqual(response.status_code, 403)
self.assertEqual(response.content_type, 'application/json')

def suite():
Expand Down
Loading

0 comments on commit e593f55

Please sign in to comment.