diff --git a/aurweb/routers/rpc.py b/aurweb/routers/rpc.py index 66376067..942f4e9d 100644 --- a/aurweb/routers/rpc.py +++ b/aurweb/routers/rpc.py @@ -12,7 +12,7 @@ from fastapi.responses import JSONResponse from aurweb import defaults from aurweb.ratelimit import check_ratelimit -from aurweb.rpc import RPC +from aurweb.rpc import RPC, documentation router = APIRouter() @@ -74,6 +74,9 @@ async def rpc(request: Request, args: Optional[List[str]] = Query(default=[], alias="arg[]"), callback: Optional[str] = Query(default=None)): + if not request.url.query: + return documentation() + # Create a handle to our RPC class. rpc = RPC(version=v, type=type) diff --git a/aurweb/rpc.py b/aurweb/rpc.py index 7bdae638..30fd2fbd 100644 --- a/aurweb/rpc.py +++ b/aurweb/rpc.py @@ -1,6 +1,9 @@ +import os + from collections import defaultdict from typing import Any, Callable, Dict, List, NewType, Union +from fastapi.responses import HTMLResponse from sqlalchemy import and_, literal import aurweb.config as config @@ -23,6 +26,18 @@ DataGenerator = NewType("DataGenerator", Callable[[models.Package], Dict[str, Any]]) +def documentation(): + aurwebdir = config.get("options", "aurwebdir") + rpc_doc = os.path.join(aurwebdir, "doc", "rpc.html") + + if not os.path.exists(rpc_doc): + raise OSError("doc/rpc.html could not be read") + + with open(rpc_doc) as f: + data = f.read() + return HTMLResponse(data) + + class RPC: """ RPC API handler class. diff --git a/test/test_rpc.py b/test/test_rpc.py index 6540b4a5..4e81a7cb 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -14,7 +14,7 @@ from redis.client import Pipeline import aurweb.models.dependency_type as dt import aurweb.models.relation_type as rt -from aurweb import asgi, config, db, scripts +from aurweb import asgi, config, db, rpc, scripts from aurweb.models.account_type import USER_ID from aurweb.models.license import License from aurweb.models.package import Package @@ -215,6 +215,29 @@ def pipeline(): yield pipeline +def test_rpc_documentation(client: TestClient): + with client as request: + resp = request.get("/rpc") + assert resp.status_code == int(HTTPStatus.OK) + assert "aurweb RPC Interface" in resp.text + + +def test_rpc_documentation_missing(): + config_get = config.get + + def mock_get(section: str, key: str) -> str: + if section == "options" and key == "aurwebdir": + return "/missing" + return config_get(section, key) + + with mock.patch("aurweb.config.get", side_effect=mock_get): + config.rehash() + expr = r"^doc/rpc\.html could not be read$" + with pytest.raises(OSError, match=expr): + rpc.documentation() + config.rehash() + + def test_rpc_singular_info(client: TestClient, user: User, packages: List[Package],