def validate_patch_tender_stage2_data(request): data = validate_json_data(request) if request.context.status == 'draft': default_statuses = ['active.tendering', STAGE2_STATUS] if data.get('status') not in default_statuses: raise_operation_error(request, 'Can\'t update tender in current ({0}) status'.format(data['status'])) request.validated['data'] = {'status': data.get('status')} request.context.status = data.get('status') return if data: if 'items' in data: items = request.context.items cpv_group_lists = [i.classification.id[:3] for i in items] for item in data['items']: if 'classification' in item and 'id' in item['classification']: cpv_group_lists.append(item['classification']['id'][:3]) if len(set(cpv_group_lists)) != 1: request.errors.add('body', 'item', 'Can\'t change classification') request.errors.status = 403 raise error_handler(request.errors) if 'enquiryPeriod' in data: if apply_data_patch(request.context.enquiryPeriod.serialize(), data['enquiryPeriod']): request.errors.add('body', 'item', 'Can\'t change enquiryPeriod') request.errors.status = 403 raise error_handler(request.errors) if request.context.status == STAGE2_STATUS and data.get('status') == 'active.tendering': data = validate_data(request, type(request.tender), True, data) if data: # if no error then add status to validate data request.context.status = 'active.tendering' data['status'] = 'active.tendering' else: data = validate_data(request, type(request.tender), True, data) return data
def validate_bid_status_update_not_to_pending_or_draft(request): if request.authenticated_role != 'Administrator': bid_status_to = request.validated['data'].get("status", request.context.status) if bid_status_to not in ['pending', 'draft']: request.errors.add('body', 'bid', 'Can\'t update bid to ({}) status'.format(bid_status_to)) request.errors.status = 403 raise error_handler(request.errors)
def validate_json_data(request): try: json = request.json_body except ValueError, e: request.errors.add('body', 'data', e.message) request.errors.status = 422 raise error_handler(request.errors)
def factory(request): request.validated['tender_src'] = {} root = Root(request) if not request.matchdict or not request.matchdict.get('tender_id'): return root request.validated['tender_id'] = request.matchdict['tender_id'] tender = Tender.load(root.db, request.matchdict['tender_id']) if not tender: request.errors.add('url', 'tender_id', 'Not Found') request.errors.status = 404 raise error_handler(request.errors) tender.__parent__ = root request.validated['tender'] = tender request.validated['tender_status'] = tender.status if request.method != 'GET': request.validated['tender_src'] = tender.serialize('plain') if request.matchdict.get('award_id'): award = get_item(tender, 'award', request, root) if request.matchdict.get('complaint_id'): complaint = get_item(award, 'complaint', request, root) if request.matchdict.get('document_id'): return get_item(complaint, 'document', request, root) else: return complaint elif request.matchdict.get('document_id'): return get_item(award, 'document', request, root) else: return award elif request.matchdict.get('contract_id'): contract = get_item(tender, 'contract', request, root) if request.matchdict.get('document_id'): return get_item(contract, 'document', request, root) else: return contract elif request.matchdict.get('bid_id'): bid = get_item(tender, 'bid', request, root) if request.matchdict.get('document_id'): return get_item(bid, 'document', request, root) else: return bid elif request.matchdict.get('complaint_id'): complaint = get_item(tender, 'complaint', request, root) if request.matchdict.get('document_id'): return get_item(complaint, 'document', request, root) else: return complaint elif request.matchdict.get('cancellation_id'): cancellation = get_item(tender, 'cancellation', request, root) if request.matchdict.get('document_id'): return get_item(cancellation, 'document', request, root) else: return cancellation elif request.matchdict.get('document_id'): return get_item(tender, 'document', request, root) elif request.matchdict.get('question_id'): return get_item(tender, 'question', request, root) elif request.matchdict.get('lot_id'): return get_item(tender, 'lot', request, root) request.validated['id'] = request.matchdict['tender_id'] return tender
def validate_data(request, model, partial=False, data=None): if data is None: data = validate_json_data(request) try: if partial and isinstance(request.context, model): initial_data = request.context.serialize() m = model(initial_data) new_patch = apply_data_patch(initial_data, data) if new_patch: m.import_data(new_patch, partial=True, strict=True) m.__parent__ = request.context.__parent__ m.validate() role = request.context.get_role() method = m.to_patch else: m = model(data) m.__parent__ = request.context m.validate() method = m.serialize role = 'create' except (ModelValidationError, ModelConversionError), e: for i in e.message: request.errors.add('body', i, e.message[i]) request.errors.status = 422 raise error_handler(request.errors)
def validate_contract_data(request): update_logging_context(request, {'contract_id': '__new__'}) data = request.validated['json_data'] = validate_json_data(request) model = request.contract_from_data(data, create=False) if hasattr(request, 'check_accreditation') and not request.check_accreditation(model.create_accreditation): request.errors.add('contract', 'accreditation', 'Broker Accreditation level does not permit contract creation') request.errors.status = 403 raise error_handler(request.errors) return validate_data(request, model, data=data)
def tender_from_data(request, data, raise_error=True, create=True): procurementMethodType = data.get("procurementMethodType", "belowThreshold") model = request.registry.tender_procurementMethodTypes.get(procurementMethodType) if model is None and raise_error: request.errors.add("body", "procurementMethodType", "Not implemented") request.errors.status = 415 raise error_handler(request) update_logging_context(request, {"tender_type": procurementMethodType}) if model is not None and create: model = model(data) return model
def validate_bid_operation_not_in_tendering(request): if request.validated['tender_status'] != 'active.tendering': operation = 'add' if request.method == 'POST' else 'delete' if request.authenticated_role != 'Administrator' and request.method in ( 'PUT', 'PATCH'): operation = 'update' request.errors.add( 'body', 'data', 'Can\'t {} bid in current ({}) tender status'.format( operation, request.validated['tender_status'])) request.errors.status = 403 raise error_handler(request.errors)
def validate_update_contract_value(request): tender = request.validated['tender'] data = request.validated['data'] if data['value']: for ro_attr in ('valueAddedTaxIncluded', 'currency'): if data['value'][ro_attr] != getattr(request.context.value, ro_attr): request.errors.add( 'body', 'data', 'Can\'t update {} for contract value'.format(ro_attr)) request.errors.status = 403 raise error_handler(request.errors) award = [a for a in tender.awards if a.id == request.context.awardID][0] if data['value']['amount'] > award.value.amount: request.errors.add( 'body', 'data', 'Value amount should be less or equal to awarded amount ({})'. format(award.value.amount)) request.errors.status = 403 raise error_handler(request.errors)
def validate_agreement_patch(request, **kwargs): data = validate_json_data(request) if data: if "features" in data: if apply_data_patch( [f.serialize() for f in request.context.features], data["features"]): request.errors.add("body", "features", "Can't change features") request.errors.status = 403 raise error_handler(request) return validate_data(request, type(request.agreement), True, data=data)
def validate_patch_tender_data(request): data = validate_json_data(request) if request.context.status != 'draft': return validate_data(request, type(request.tender), True, data) default_status = type(request.tender).fields['status'].default if data.get('status') != default_status: request.errors.add('body', 'data', 'Can\'t update tender in current (draft) status') request.errors.status = 403 raise error_handler(request.errors) request.validated['data'] = {'status': default_status} request.context.status = default_status
def validate_access_to_award_document_upload(request, **kwargs): document = request.validated.get('document') # bid_owner in some cases has permission to change award if request.authenticated_role == 'bid_owner': # bid_owner(winner) can`t upload rejection protocol to award if document and document.documentType == 'rejectionProtocol': err_msg = 'You can\'t upload rejection protocol to award' request.errors.add('body', 'data', err_msg) request.errors.status = 403 raise error_handler(request) return True
def validate_json_data(request, allow_bulk=False): try: json = request.json except JSONDecodeError as e: request.errors.add("body", "data", str(e)) # request.errors.add("body", "data", "No JSON object could be decoded") # Expecting value: line 1 column 1 (char 0) request.errors.status = 422 raise error_handler(request) data = json.get("data") if isinstance(json, dict) else None allowed_types = (list, dict) if allow_bulk else dict if any([ not isinstance(data, allowed_types), isinstance(data, list) and not data, isinstance(data, list) and not all(isinstance(i, dict) for i in data) ]): request.errors.add("body", "data", "Data not available") request.errors.status = 422 raise error_handler(request) request.validated["json_data"] = data return json["data"]
def validate_bid_data(request): if not request.check_accreditation(request.tender.edit_accreditation): request.errors.add('procurementMethodType', 'accreditation', 'Broker Accreditation level does not permit bid creation') request.errors.status = 403 raise error_handler(request.errors) if request.tender.get('mode', None) is None and request.check_accreditation('t'): request.errors.add('procurementMethodType', 'mode', 'Broker Accreditation level does not permit bid creation') request.errors.status = 403 raise error_handler(request.errors) update_logging_context(request, {'bid_id': '__new__'}) model = type(request.tender).bids.model_class bid = validate_data(request, model) validated_bid = request.validated.get('bid') if validated_bid: if any([key == 'documents' or 'Documents' in key for key in validated_bid.keys()]): bid_documents = validate_bid_documents(request) if not bid_documents: return for documents_type, documents in bid_documents.items(): validated_bid[documents_type] = documents return bid
def validate_patch_tender_stage2_data(request): data = validate_json_data(request) if request.context.status == "draft": default_statuses = ["active.tendering", STAGE2_STATUS] if "status" in data and data.get("status") not in default_statuses: raise_operation_error( request, "Can't update tender in current ({0}) status".format( data["status"])) request.validated["data"] = {"status": data.get("status")} request.context.status = data.get("status") return if data: if "items" in data: items = request.context.items cpv_group_lists = [i.classification.id[:3] for i in items] for item in data["items"]: if "classification" in item and "id" in item["classification"]: cpv_group_lists.append(item["classification"]["id"][:3]) if len(set(cpv_group_lists)) != 1: request.errors.add("body", "item", "Can't change classification") request.errors.status = 403 raise error_handler(request.errors) if "enquiryPeriod" in data: if apply_data_patch(request.context.enquiryPeriod.serialize(), data["enquiryPeriod"]): request.errors.add("body", "item", "Can't change enquiryPeriod") request.errors.status = 403 raise error_handler(request.errors) if request.context.status == STAGE2_STATUS and data.get( "status") == "active.tendering": data = validate_data(request, type(request.tender), True, data) if data: # if no error then add status to validate data request.context.status = "active.tendering" data["status"] = "active.tendering" else: data = validate_data(request, type(request.tender), True, data) return data
def factory(request): request.validated['tender_src'] = {} root = Root(request) if not request.matchdict or not request.matchdict.get('tender_id'): return root request.validated['tender_id'] = request.matchdict['tender_id'] tender = Tender.load(root.db, request.matchdict['tender_id']) if not tender: request.errors.add('url', 'tender_id', 'Not Found') request.errors.status = 404 raise error_handler(request.errors) tender.__parent__ = root request.validated['tender'] = tender request.validated['tender_status'] = tender.status if request.method != 'GET': request.validated['tender_src'] = tender.serialize('plain') if request.matchdict.get('award_id'): award = get_item(tender, 'award', request, root) if request.matchdict.get('complaint_id'): complaint = get_item(award, 'complaint', request, root) if request.matchdict.get('document_id'): return get_item(complaint, 'document', request, root) else: return complaint elif request.matchdict.get('contract_id'): contract = get_item(award, 'contract', request, root) if request.matchdict.get('document_id'): return get_item(contract, 'document', request, root) else: return contract elif request.matchdict.get('document_id'): return get_item(award, 'document', request, root) else: return award elif request.matchdict.get('bid_id'): bid = get_item(tender, 'bid', request, root) if request.matchdict.get('document_id'): return get_item(bid, 'document', request, root) else: return bid elif request.matchdict.get('complaint_id'): complaint = get_item(tender, 'complaint', request, root) if request.matchdict.get('document_id'): return get_item(complaint, 'document', request, root) else: return complaint elif request.matchdict.get('document_id'): return get_item(tender, 'document', request, root) elif request.matchdict.get('question_id'): return get_item(tender, 'question', request, root) request.validated['id'] = request.matchdict['tender_id'] return tender
def validate_plan_data(request): update_logging_context(request, {'plan_id': '__new__'}) data = validate_json_data(request) if data is None: return model = request.plan_from_data(data, create=False) if hasattr(request, 'check_accreditation') \ and not any([request.check_accreditation(acc) for acc in model.create_accreditations]): request.errors.add( 'plan', 'accreditation', 'Broker Accreditation level does not permit plan creation') request.errors.status = 403 raise error_handler(request.errors) data = validate_data(request, model, data=data) if data and data.get('mode', None) is None and request.check_accreditation('t'): request.errors.add( 'plan', 'mode', 'Broker Accreditation level does not permit plan creation') request.errors.status = 403 raise error_handler(request.errors) return data
def validate_patch_tender_ua_data(request, **kwargs): data = validate_json_data(request) if request.context.status == "draft": validate_patch_tender_data_draft(request) if data: if "items" in data: items = request.context.items cpv_group_lists = [i.classification.id[:3] for i in items] for item in data["items"]: if "classification" in item and "id" in item["classification"]: cpv_group_lists.append(item["classification"]["id"][:3]) if len(set(cpv_group_lists)) != 1: request.errors.add("body", "item", "Can't change classification") request.errors.status = 403 raise error_handler(request) if "enquiryPeriod" in data: if apply_data_patch(request.context.enquiryPeriod.serialize(), data["enquiryPeriod"]): request.errors.add("body", "item", "Can't change enquiryPeriod") request.errors.status = 403 raise error_handler(request) return validate_data(request, type(request.tender), True, data)
def agreement_from_data(request, data, raise_error=True, create=True): if request.authenticated_role == "agreements": data["agreementType"] = "cfaua" if not data.get("agreementType") and raise_error: request.errors.add("data", "agreementType", "This field is required") request.errors.status = 422 raise error_handler(request) return object_from_data(request, data, "agreement", raise_error=raise_error, create=create)
def validate_contract_data(request): update_logging_context(request, {'contract_id': '__new__'}) data = request.validated['json_data'] = validate_json_data(request) model = request.contract_from_data(data, create=False) if hasattr(request, 'check_accreditation') and not request.check_accreditation( model.create_accreditation): request.errors.add( 'contract', 'accreditation', 'Broker Accreditation level does not permit contract creation') request.errors.status = 403 raise error_handler(request.errors) return validate_data(request, model, data=data)
def object_from_data(request, data, obj_name, raise_error=True, create=True): objType = data.get("%sType" % obj_name, "electronicCatalogue") model_types = getattr(request.registry, "%s_%sTypes" % (obj_name, obj_name)) model = model_types.get(objType) if model is None and raise_error: request.errors.add("body", "%sType" % obj_name, "Not implemented") request.errors.status = 415 raise error_handler(request) update_logging_context(request, {"%s_type" % obj_name: objType}) if model is not None and create: model = model(data) return model
def validate_tender_data(request): update_logging_context(request, {'tender_id': '__new__'}) data = validate_json_data(request) model = request.tender_from_data(data, create=False) #if not request.check_accreditation(model.create_accreditation): #if not any([request.check_accreditation(acc) for acc in getattr(model, 'create_accreditations', [getattr(model, 'create_accreditation', '')])]): if not any([request.check_accreditation(acc) for acc in iter(str(model.create_accreditation))]): request.errors.add('procurementMethodType', 'accreditation', 'Broker Accreditation level does not permit tender creation') request.errors.status = 403 raise error_handler(request.errors) data = validate_data(request, model, data=data) if data and data.get('mode', None) is None and request.check_accreditation('t'): request.errors.add('procurementMethodType', 'mode', 'Broker Accreditation level does not permit tender creation') request.errors.status = 403 raise error_handler(request.errors) if data and data.get('procuringEntity', {}).get('kind', '') not in model.procuring_entity_kinds: request.errors.add('procuringEntity', 'kind', '{kind!r} procuringEntity cannot publish this type of procedure. ' 'Only {kinds} are allowed.'.format(kind=data.get('procuringEntity', {}).get('kind', ''), kinds=', '.join(model.procuring_entity_kinds))) request.errors.status = 403
def validate_milestone_author(request, **kwargs): milestone = request.validated["milestone"] plan = request.validated["plan"] author = milestone.author plan_identifier = plan.procuringEntity.identifier milestone_identifier = author.identifier if (plan_identifier.scheme, plan_identifier.id) != ( milestone_identifier.scheme, milestone_identifier.id): request.errors.add("body", "author", "Should match plan.procuringEntity") request.errors.status = 422 raise error_handler(request) if any((m.author.identifier.scheme, m.author.identifier.id) == (author.identifier.scheme, author.identifier.id) for m in plan.milestones if m.status in Milestone.ACTIVE_STATUSES): request.errors.add( "body", "author", "An active milestone already exists for this author") request.errors.status = 422 raise error_handler(request)
def patch(self): """Tender Document Update""" if not self.validate_update_tender(): raise error_handler(self.request.errors) if self.request.authenticated_role == 'tender_owner' and self.request.validated[ 'tender_status'] == 'active.tendering': self.request.validated['tender'].invalidate_bids_data() if apply_patch(self.request, src=self.request.context.serialize()): update_file_content_type(self.request) self.LOGGER.info( 'Updated tender document {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_document_patch'})) return {'data': self.request.context.serialize("view")}
def validate_award_document(self, operation): """ TODO move validators This class is inherited in openua package, but validate_award_document function has different validators. For now, we have no way to use different validators on methods according to procedure type. """ if self.request.validated['tender_status'] != 'active.qualification': raise_operation_error(self.request, 'Can\'t {} document in current ({}) tender status'.format(operation, self.request.validated['tender_status'])) if any([i.status != 'active' for i in self.request.validated['tender'].lots if i.id == self.request.validated['award'].lotID]): raise_operation_error(self.request, 'Can {} document only in active lot status'.format(operation)) if operation == 'update' and self.request.authenticated_role != (self.context.author or 'tender_owner'): self.request.errors.add('url', 'role', 'Can update document only author') self.request.errors.status = 403 raise error_handler(self.request.errors) return True
def validate_plan_with_tender(request): plan = request.validated["plan"] if plan.tender_id: json_data = request.validated["json_data"] names = [] if "procuringEntity" in json_data: names.append("procuringEntity") if "budget" in json_data and "breakdown" in json_data["budget"]: names.append("budget.breakdown") for name in names: request.errors.add("data", name, "Changing this field is not allowed after tender creation") if request.errors: request.errors.status = 422 raise error_handler(request.errors)
def lot_from_data(request, data, raise_error=True, create=True): lotType = data.get('lotType') if not lotType: lot_types = get_lot_types(request.registry, (DEFAULT_LOT_TYPE, )) lotType = lot_types[0] if lot_types else DEFAULT_LOT_TYPE model = request.registry.lotTypes.get(lotType) if model is None and raise_error: request.errors.add('body', 'lotType', 'Not implemented') request.errors.status = 415 raise error_handler(request) update_logging_context(request, {'lot_type': lotType}) if model is not None and create: model = model(data) return model
def put(self): """Tender Document Update""" if not self.validate_update_tender(): raise error_handler(self.request.errors) document = upload_file(self.request) self.request.validated['tender'].documents.append(document) if self.request.authenticated_role == 'tender_owner' and self.request.validated[ 'tender_status'] == 'active.tendering': self.request.validated['tender'].invalidate_bids_data() if save_tender(self.request): self.LOGGER.info( 'Updated tender document {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_document_put'})) return {'data': document.serialize("view")}
def validate_tender_plan_procurement_method_type(request): plan = request.validated["plan"] tender = request.validated["tender"] if plan.tender.procurementMethodType not in (tender.procurementMethodType, "centralizedProcurement"): request.errors.add( "data", "procurementMethodType", u"procurementMethodType doesn't match: {} != {}".format( plan.tender.procurementMethodType, tender.procurementMethodType), ) request.errors.status = 422 raise error_handler(request.errors)
def validate_rectification_period_editing(request): if request.context.status == 'active.tendering' and request.authenticated_role not in [ 'chronograph', 'Administrator' ]: auction = request.validated['auction'] rectificationPeriod = auction.rectificationPeriod or generate_rectificationPeriod( auction) if rectificationPeriod.endDate.astimezone(TZ) < get_now(): request.errors.add( 'body', 'data', 'Auction can be edited only during the rectification period: from ({}) to ({}).' .format(rectificationPeriod.startDate.isoformat(), rectificationPeriod.endDate.isoformat())) request.errors.status = 403 raise error_handler(request.errors)
def validate_award_data_post_common(request, **kwargs): auction = request.validated['auction'] award = request.validated['award'] if auction.status != 'active.qualification': request.errors.add( 'body', 'data', 'Can\'t create award in current ({})' ' auction status'.format(auction.status)) elif any( [i.status != 'active' for i in auction.lots if i.id == award.lotID]): request.errors.add('body', 'data', 'Can create award only in active lot status') else: return request.errors.status = 403 raise error_handler(request)
def validate_tender(request): tender = request.validated["tender"] if tender.status in [ "complete", "unsuccessful", "cancelled", "active.stage2.waiting", "draft.pending", "draft.unsuccessful", ]: request.errors.add( "body", "data", "Can't update credentials in current ({}) tender status".format(tender.status) ) request.errors.status = 403 raise error_handler(request.errors)
def validate_document_upload_contract_not_terminal_status(request, **kwargs): contract = request.context document_of = request.validated['document'].documentOf if not document_of == 'contract': return forbidden_statuses = CONTRACT_TERMINAL_STATUSES + CONTRACT_PRE_TERMINAL_STATUSES if contract.status in forbidden_statuses: request.errors.add( 'body', 'status', "Can\'t attach document to contract in current ({0}) status". format(contract.status)) request.errors.status = 403 raise error_handler(request)
def validate_patch_award_access(request, **kwargs): auction = request.validated['auction'] award = request.context next_status = request.validated['json_data'].get('status') # bid_owner in some cases has permission to change award if request.authenticated_role == 'bid_owner': # bid_owner(winner) can switch award form status 'pending.waiting' to cancelled if award.status == 'pending.waiting' and next_status == 'cancelled': return True else: err_msg = 'Bidder is not allowed to switch award from pending to active.' request.errors.add('body', 'data', err_msg) request.errors.status = 403 raise error_handler(request) return True
def extract_transfer(request, transfer_id=None): """ Extract transfer from db :param request: :param transfer_id: uuid4 :return: transfer as Transfer instance or raise 404 """ db = request.registry.db if not transfer_id: transfer_id = request.matchdict['transfer_id'] doc = db.get(transfer_id) if doc is None or doc.get('doc_type') != 'Transfer': request.errors.add('url', 'transfer_id', 'Not Found') request.errors.status = 404 raise error_handler(request.errors) return request.transfer_from_data(doc)
def validate_bid_document_operation_period(request): tender = request.validated['tender'] if request.validated['tender_status'] == 'active.tendering' and ( tender.tenderPeriod.startDate and get_now() < tender.tenderPeriod.startDate or get_now() > tender.tenderPeriod.endDate): request.errors.add( 'body', 'data', 'Document can be {} only during the tendering period: from ({}) to ({}).' .format( 'added' if request.method == 'POST' else 'updated', tender.tenderPeriod.startDate and tender.tenderPeriod.startDate.isoformat(), tender.tenderPeriod.endDate.isoformat())) request.errors.status = 403 raise error_handler(request.errors)