"""Blueprint for file upload config API.""" from http import HTTPStatus from abacus_common_logic.utils.request import BooleanFilter from abacus_common_logic.views.create_view import CreateView from abacus_common_logic.views.item_view import ItemView from abacus_common_logic.views.list_view import ListView from common_apispec import doc, marshal_with, use_kwargs from common_apispec.views import MethodResource from flask import Blueprint, request from owsrequest import flask_request from owsresponse import response from owsresponse.adaptors.flask import flaskify from abacus_file_upload import logic from abacus_file_upload.models import FileUploadConfig from abacus_file_upload.schemas import ( FileUploadConfigDetailSchema, FileUploadConfigDetailVerboseSchema, FileUploadConfigPostSchema, FileUploadConfigPutSchema, ) file_upload_config_api = Blueprint('file_upload_config_api', __name__) class FileUploadConfigCreateView(CreateView, MethodResource): """Handles file upload config creation.""" post_schema = FileUploadConfigPostSchema() def post(self, **kwargs): """Create file upload config. Args: **kwargs: Additional keyword arguments passed to parent class """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code='authorization_error', message='Unauthorized', status=401, ) ) return super().post(**kwargs) def create_handler(self, **params): """Create file upload config. Args: **params: Configuration parameters to pass to logic layer """ return logic.create_file_upload_config(**params) class FileUploadConfigListView(ListView, MethodResource): """View for listing file upload configs.""" model_class = FileUploadConfig list_entry_schema = FileUploadConfigDetailSchema() def get(self): """Get file upload config list. Query Params: verbose (bool): Include audit fields (created_at, created_by, etc.) Accepts: true/false, yes/no, 1/0, on/off, t/f, y/n Default: false """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code='authorization_error', message='Unauthorized', status=401, ) ) # Read verbose query parameter verbose_filter = BooleanFilter.parse( request.args.get('verbose'), BooleanFilter.FALSE ) verbose = verbose_filter.to_bool() return flaskify(logic.get_all_file_upload_configs(verbose=verbose)) class FileUploadConfigItemView(ItemView, MethodResource): """View for finding a file upload config by ID.""" model_class = FileUploadConfig object_detail_schema = FileUploadConfigDetailVerboseSchema() put_schema = FileUploadConfigPutSchema() @doc( summary='Get file upload configuration by ID', params={ 'object_id': { 'description': 'The ID of the file upload configuration', }, 'verbose': { 'description': 'Include audit fields (created_at, created_by, last_modified, last_modified_by, deleted_at, deleted_by)', 'in': 'query', 'schema': {'type': 'boolean'}, 'required': False, }, }, ) @marshal_with( FileUploadConfigDetailVerboseSchema, code=HTTPStatus.OK, description='Returns upload configuration (audit fields included only when verbose=true)', ) @marshal_with( None, code=HTTPStatus.UNAUTHORIZED, description=HTTPStatus.UNAUTHORIZED.phrase, ) @marshal_with( None, code=HTTPStatus.NOT_FOUND, description='Upload configuration not found', ) @marshal_with( None, code=HTTPStatus.INTERNAL_SERVER_ERROR, description='Internal server error', ) def get(self, object_id, **kwargs): """Find file upload config by its id or return an error. Args: object_id: ID of the config to retrieve **kwargs: Additional keyword arguments passed to parent class Query Params: verbose (bool): Include audit fields (created_at, created_by, etc.) Accepts: true/false, yes/no, 1/0, on/off, t/f, y/n Default: false """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code='authorization_error', message='Unauthorized', status=401, ) ) # Read verbose query parameter verbose_filter = BooleanFilter.parse( request.args.get('verbose'), BooleanFilter.FALSE ) verbose = verbose_filter.to_bool() # Call logic with verbose parameter return flaskify(logic.get_file_upload_config(object_id, verbose=verbose)) def update_handler(self, obj, **params): """Handle file upload config updates. Args: obj: FileUploadConfig object to update **params: Update parameters to pass to logic layer """ return logic.update_file_upload_config(obj.file_upload_config_id, **params) @doc( summary='Update file upload configuration', params={ 'object_id': { 'description': 'The ID of the file upload configuration', }, }, ) @use_kwargs(FileUploadConfigPutSchema, location='json', required=True, apply=False) @marshal_with( FileUploadConfigDetailVerboseSchema, code=HTTPStatus.OK, description='Returns updated upload configuration with audit fields', ) @marshal_with( None, code=HTTPStatus.BAD_REQUEST, description='Invalid request body or validation error', ) @marshal_with( None, code=HTTPStatus.UNAUTHORIZED, description=HTTPStatus.UNAUTHORIZED.phrase, ) @marshal_with( None, code=HTTPStatus.NOT_FOUND, description='Upload configuration not found', ) @marshal_with( None, code=HTTPStatus.INTERNAL_SERVER_ERROR, description='Internal server error', ) def put(self, object_id, **kwargs): """Update a file upload config by ID. Args: object_id: ID of the config to update **kwargs: Additional keyword arguments passed to parent class """ access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code='authorization_error', message='Unauthorized', status=401, ) ) return super().put(object_id, **kwargs) @doc( summary='Delete file upload configuration', params={ 'object_id': { 'description': 'The ID of the file upload configuration', }, }, ) @marshal_with( None, code=HTTPStatus.NO_CONTENT, description='Configuration successfully deleted', ) @marshal_with( None, code=HTTPStatus.UNAUTHORIZED, description=HTTPStatus.UNAUTHORIZED.phrase, ) @marshal_with( None, code=HTTPStatus.NOT_FOUND, description='Upload configuration not found', ) @marshal_with( None, code=HTTPStatus.INTERNAL_SERVER_ERROR, description='Internal server error', ) def delete(self, object_id): """Soft delete a file upload config by ID.""" access_rule_decision = flask_request.verify_rules_access_standalone(request) if not access_rule_decision: return flaskify( response.create_error_response( code='authorization_error', message='Unauthorized', status=401, ) ) return flaskify(logic.delete_file_upload_config(object_id)) # Register routes file_upload_config_create_view = FileUploadConfigCreateView.as_view( 'file_upload_config_create' ) file_upload_config_create_view = doc( summary='Create file upload configuration', )(file_upload_config_create_view) file_upload_config_create_view = use_kwargs( FileUploadConfigPostSchema, location='json', required=True, apply=False )(file_upload_config_create_view) file_upload_config_create_view = marshal_with( FileUploadConfigDetailSchema, code=HTTPStatus.CREATED, description='Upload configuration successfully created', )(file_upload_config_create_view) file_upload_config_create_view = marshal_with( None, code=HTTPStatus.BAD_REQUEST, description='Invalid request body or validation error', )(file_upload_config_create_view) file_upload_config_create_view = marshal_with( None, code=HTTPStatus.UNAUTHORIZED, description=HTTPStatus.UNAUTHORIZED.phrase, )(file_upload_config_create_view) file_upload_config_create_view = marshal_with( None, code=HTTPStatus.CONFLICT, description='Configuration with this upload_type already exists', )(file_upload_config_create_view) file_upload_config_create_view = marshal_with( None, code=HTTPStatus.INTERNAL_SERVER_ERROR, description='Internal server error', )(file_upload_config_create_view) file_upload_config_api.add_url_rule( '/file-upload-config', view_func=file_upload_config_create_view, methods=['POST'], ) file_upload_config_list_view = FileUploadConfigListView.as_view( 'file_upload_config_list' ) file_upload_config_list_view = doc( summary='Get list of file upload configurations', params={ 'verbose': { 'description': 'Include audit fields (created_at, created_by, last_modified, last_modified_by, deleted_at, deleted_by)', 'in': 'query', 'schema': {'type': 'boolean'}, 'required': False, }, }, )(file_upload_config_list_view) file_upload_config_list_view = marshal_with( FileUploadConfigDetailVerboseSchema(many=True), code=HTTPStatus.OK, description='Returns list of all active upload configurations (audit fields included only when verbose=true)', )(file_upload_config_list_view) file_upload_config_list_view = marshal_with( None, code=HTTPStatus.UNAUTHORIZED, description=HTTPStatus.UNAUTHORIZED.phrase, )(file_upload_config_list_view) file_upload_config_list_view = marshal_with( None, code=HTTPStatus.INTERNAL_SERVER_ERROR, description='Internal server error', )(file_upload_config_list_view) file_upload_config_api.add_url_rule( '/file-upload-configs', view_func=file_upload_config_list_view, methods=['GET'], ) file_upload_config_item_view = FileUploadConfigItemView.as_view( 'file_upload_config_item' ) file_upload_config_api.add_url_rule( '/file-upload-config/', view_func=file_upload_config_item_view, methods=['GET', 'PUT', 'DELETE'], )