add support of named resources

This commit is contained in:
2025-06-17 18:45:59 +03:00
parent 32f99f7f36
commit 930eccc55a
4 changed files with 36 additions and 6 deletions

View File

@ -17,6 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import re
from aiohttp.web import Application, View
from collections.abc import Generator
@ -45,6 +47,23 @@ def _dynamic_routes(configuration: Configuration) -> Generator[tuple[str, type[V
yield route, view
def _identifier(route: str) -> str:
"""
extract valid route identifier (aka name) for the route. This method replaces curly brackets by single colon
and replaces other special symbols (including slashes) by underscore
Args:
route(str): source route
Returns:
str: route with special symbols being replaced
"""
# replace special symbols
alphanum = re.sub(r"[^A-Za-z\d\-{}]", "_", route)
# finally replace curly brackets
return alphanum.replace("{", ":").replace("}", "")
def setup_routes(application: Application, configuration: Configuration) -> None:
"""
setup all defined routes
@ -53,7 +72,8 @@ def setup_routes(application: Application, configuration: Configuration) -> None
application(Application): web application instance
configuration(Configuration): configuration instance
"""
application.router.add_static("/static", configuration.getpath("web", "static_path"), follow_symlinks=True)
application.router.add_static("/static", configuration.getpath("web", "static_path"), name="_static",
follow_symlinks=True)
for route, view in _dynamic_routes(configuration):
application.router.add_view(route, view)
application.router.add_view(route, view, name=_identifier(route))

View File

@ -46,7 +46,7 @@ class PackagesView(StatusViewGuard, BaseView):
ROUTES = ["/api/v1/packages"]
@apidocs(
tags=["packages"],
tags=["Packages"],
summary="Get packages list",
description="Retrieve packages and their descriptors",
permission=GET_PERMISSION,

View File

@ -2,12 +2,12 @@ import importlib
import pytest
import sys
import ahriman.web.middlewares.metrics_handler as metrics_handler
from aiohttp.web import HTTPNotFound
from pytest_mock import MockerFixture
from unittest.mock import AsyncMock
import ahriman.web.middlewares.metrics_handler as metrics_handler
async def test_metrics(mocker: MockerFixture) -> None:
"""

View File

@ -3,7 +3,7 @@ from pathlib import Path
from ahriman.core.configuration import Configuration
from ahriman.core.utils import walk
from ahriman.web.routes import _dynamic_routes, setup_routes
from ahriman.web.routes import _dynamic_routes, _identifier, setup_routes
def test_dynamic_routes(resource_path_root: Path, configuration: Configuration) -> None:
@ -22,9 +22,19 @@ def test_dynamic_routes(resource_path_root: Path, configuration: Configuration)
assert len(set(routes.values())) == len(expected_views)
def test_identifier() -> None:
"""
must correctly extract route identifiers
"""
assert _identifier("/") == "_"
assert _identifier("/api/v1/status") == "_api_v1_status"
assert _identifier("/api/v1/packages/{package}") == "_api_v1_packages_:package"
def test_setup_routes(application: Application, configuration: Configuration) -> None:
"""
must generate non-empty list of routes
"""
application.router._named_resources = {}
setup_routes(application, configuration)
assert application.router.routes()