From db724cf8be9a6a750d03f22f3bdd584d9bfbe69e Mon Sep 17 00:00:00 2001 From: Isaac To Date: Fri, 15 Dec 2023 20:25:04 -0800 Subject: [PATCH] Have disabled endpoint in read-only mode respond 405 Instead of 418 --- .../blueprints/api/dataset_urls/__init__.py | 8 ++-- datalad_registry/blueprints/api/utils.py | 37 +++++++++++++++++-- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/datalad_registry/blueprints/api/dataset_urls/__init__.py b/datalad_registry/blueprints/api/dataset_urls/__init__.py index 499594a1..2356c863 100644 --- a/datalad_registry/blueprints/api/dataset_urls/__init__.py +++ b/datalad_registry/blueprints/api/dataset_urls/__init__.py @@ -19,10 +19,7 @@ mark_for_chk, process_dataset_url, ) -from datalad_registry.utils.flask_tools import ( - disable_in_read_only_mode, - json_resp_from_str, -) +from datalad_registry.utils.flask_tools import json_resp_from_str from .models import ( DatasetURLPage, @@ -36,6 +33,7 @@ ) from .. import API_URL_PREFIX, COMMON_API_RESPONSES, HTTPExceptionResp from ..url_metadata.models import URLMetadataRef +from ..utils import disable_in_read_only_mode _ORDER_KEY_TO_SQLA_ATTR = { OrderKey.url: RepoUrl.url, @@ -60,7 +58,7 @@ responses={ "201": DatasetURLRespModel, "202": DatasetURLRespModel, - "418": HTTPExceptionResp, # Occurs only when the server is in read-only mode + "405": HTTPExceptionResp, # Occurs only when the server is in read-only mode }, ) @disable_in_read_only_mode diff --git a/datalad_registry/blueprints/api/utils.py b/datalad_registry/blueprints/api/utils.py index abbe48c3..f8265727 100644 --- a/datalad_registry/blueprints/api/utils.py +++ b/datalad_registry/blueprints/api/utils.py @@ -1,9 +1,12 @@ from functools import wraps from http import HTTPStatus -from flask import abort, current_app +from flask import current_app, request from datalad_registry import OperationMode +from datalad_registry.utils.flask_tools import json_resp_from_str + +from . import HTTPExceptionResp def disable_in_read_only_mode(view_func): @@ -20,10 +23,36 @@ def wrapper(*args, **kwargs): current_app.config["DATALAD_REGISTRY_OPERATION_MODE"] is OperationMode.READ_ONLY ): - abort( - HTTPStatus.IM_A_TEAPOT, - description="This operation is not available from a read-only server.", + + resp_status = HTTPStatus.METHOD_NOT_ALLOWED + + # Construct the response body + resp_body = HTTPExceptionResp( + code=resp_status, + name=resp_status.phrase, + description="This method on the requested resource is not available " + "through a read-only server.", ) + + # Get remaining supported methods on the endpoint, representing a resource, + # to construct the required `Allow` header for a 405, Method Not Allowed, + # response + remaining_supported_methods: set[str] = set() + for rule in current_app.url_map.iter_rules(): + if ( + str(rule) == str(request.url_rule) + and rule.endpoint != request.endpoint + ): + # `rule` is of the current requested path + # but not of the current endpoint + remaining_supported_methods.update(rule.methods) + + return json_resp_from_str( + resp_body.json(exclude_none=True), + status=resp_status, + headers={"Allow": ", ".join(remaining_supported_methods)}, + ) + else: return view_func(*args, **kwargs)