"""Blueprint for contract terms API.""" from abacus_common_logic.constants.error import ERROR_ENTITY_DOES_NOT_EXIST from abacus_common_logic.utils.authorization import permissions_authorize_many_accounts from abacus_common_logic.views.create_view import CreateView from abacus_common_logic.views.item_view import ItemView from abacus_common_logic.views.validations import validated_request_body from flask import Blueprint from flask import g from flask import request from flask import Response from flask import stream_with_context from owsrequest import flask_request from owsresponse import response from owsresponse.adaptors.flask import flaskify from abacus_contract.config import ows_client from abacus_contract.constants import error from abacus_contract.logic import contract as contract_logic from abacus_contract.logic import contract_term as logic from abacus_contract.models.contract_term import ContractTerm from abacus_contract.schemas.contract_term import ContractTermPostSchema from abacus_contract.schemas.contract_term import ContractTermPutSchema from abacus_contract.schemas.contract_term import \ ContractTermsByAccountTermTypePostSchema from abacus_contract.schemas.contract_term import ContractTermSchema from abacus_contract.utils.authorization import pdp_authorize_many_accounts from abacus_contract.utils.request import get_optional_numeric_list_from_params contract_term_api = Blueprint('contract_term_api', __name__) class ContractTermCreateView(CreateView): """Handles contract terms creation.""" post_schema = ContractTermPostSchema() def post(self, **kwargs): """Create contract term.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify(response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, )) return super().post(**kwargs) def create_handler(self, **params): """Create contract term.""" return logic.create_contract_term(**params) class ContractTermItemView(ItemView): """Handles update, delete and get operation on existing contract_term.""" model_class = ContractTerm put_schema = ContractTermPutSchema() object_detail_schema = ContractTermSchema() def get(self, object_id): """Find object by its id or return an error.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify(response.create_error_response( code=error.ERROR_CODE_FORBIDDEN, message='Unauthorized', status=403, )) obj = self.model_class.get_by_id(object_id) if not obj or obj.deleted_at is not None or obj.deleted_by is not None: return flaskify(response.create_not_found_response( message=ERROR_ENTITY_DOES_NOT_EXIST.format( object_type='Contract Term', object_id=object_id ) )) body = self.object_detail_schema.dump(obj) return flaskify(response.Response(message=body, status=200)) def put(self, object_id, **kwargs): """Update a contract_term.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify(response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, )) return super().put(object_id, **kwargs) def update_handler(self, obj, **params): """Handle contract_term updates.""" return logic.update_contract_term(obj, **params) def delete(self, object_id): """Soft delete a contract_term.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify(response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, )) obj = self.model_class.get_by_id_or_error(object_id) return flaskify(logic.soft_delete_contract_term_and_conditions(obj)) contract_term_api.add_url_rule( '/contract//contract-term', view_func=ContractTermCreateView.as_view('create_contract_term') ) contract_term_api.add_url_rule( '/contract-term//', methods=['PUT', 'GET', 'DELETE'], view_func=ContractTermItemView.as_view('contract_term') ) @contract_term_api.route('/contracts//contract-terms', methods=['GET']) def get_contract_terms_by_contract_handler(contract_id): """Handle getting contract terms associated to the specified contract.""" account_id = contract_logic.get_account_id_by_contract_id(contract_id) if not account_id: return flaskify(response.create_error_response( code=error.ERROR_CODE_NOT_FOUND, message=error.ERROR_ACCOUNT_NOT_FOUND_FOR_CONTRACT, status=404, )) access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: authorized = pdp_authorize_many_accounts([account_id]) if not authorized: return flaskify(response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message=error.ERROR_MESSAGE_FORBIDDEN_USER, status=403, )) authorized = permissions_authorize_many_accounts( ows_client, g.request_context.profile_type, g.request_context.profile_id, [account_id] ) if not authorized: return flaskify(response.create_error_response( code=error.ERROR_CODE_FORBIDDEN, message=error.ERROR_MESSAGE_FORBIDDEN_USER, status=403, )) return flaskify(logic.get_contract_terms_by_contract(contract_id)) @contract_term_api.route('/contract-terms/snapshot', methods=['POST']) def get_tsv_contract_terms_snapshot(): """Get contract terms as a TSV snapshot.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify(response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, )) try: optional_contract_ids = get_optional_numeric_list_from_params(optional=True) except ValueError: return Response(status=400, response='contract_ids must be integers') return Response( stream_with_context(logic.contract_term_export(optional_contract_ids)), mimetype='text/tsv' ) @contract_term_api.route( '/account//contract-terms/', methods=['POST']) def get_contract_terms_for_account_and_term_type(account_id): """Get contract terms for a specific account and term_type.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify(response.create_error_response( code=error.ERROR_CODE_AUTHORIZATION, message='Unauthorized', status=401, )) post_schema = ContractTermsByAccountTermTypePostSchema() params = validated_request_body(post_schema) return flaskify( logic.get_contract_terms_for_account_and_term_type( account_id, params))