From a7c9183aa015a7e4667a6b2053e7c1af2dc197b8 Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Wed, 23 Nov 2022 22:24:36 +0200 Subject: [PATCH] add curl examples to web views --- .readthedocs.yaml | 4 +- docs/conf.py | 4 +- src/ahriman/web/views/service/add.py | 25 +++++++++--- src/ahriman/web/views/service/remove.py | 24 +++++++++-- src/ahriman/web/views/service/request.py | 24 +++++++++-- src/ahriman/web/views/service/search.py | 21 ++++++++-- src/ahriman/web/views/status/logs.py | 47 ++++++++++++++++++++++ src/ahriman/web/views/status/package.py | 51 +++++++++++++++++++++++- src/ahriman/web/views/status/packages.py | 31 ++++++++++++++ src/ahriman/web/views/status/status.py | 33 +++++++++++++++ src/ahriman/web/views/user/login.py | 30 +++++++++++++- src/ahriman/web/views/user/logout.py | 23 ++++++++++- tox.ini | 2 +- 13 files changed, 296 insertions(+), 23 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index c62a2ed0..187dc132 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,6 +1,7 @@ version: 2 -formats: all +formats: + - pdf build: os: ubuntu-20.04 @@ -10,6 +11,7 @@ build: sphinx: builder: html configuration: docs/conf.py + fail_on_warning: true python: install: diff --git a/docs/conf.py b/docs/conf.py index 3656b997..beca9e87 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -27,6 +27,8 @@ on_rtd = os.environ.get("READTHEDOCS", None) == "True" for module in ( "pyalpm", ): + if module in sys.modules: + continue sys.modules[module] = mock.Mock() @@ -77,7 +79,7 @@ html_theme = "default" if on_rtd else "alabaster" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] +html_static_path = [] add_module_names = False diff --git a/src/ahriman/web/views/service/add.py b/src/ahriman/web/views/service/add.py index 5992d64e..d25fb018 100644 --- a/src/ahriman/web/views/service/add.py +++ b/src/ahriman/web/views/service/add.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from aiohttp.web import HTTPAccepted +from aiohttp.web import HTTPNoContent from ahriman.models.user_access import UserAccess from ahriman.web.views.base import BaseView @@ -40,16 +40,31 @@ class AddView(BaseView): JSON body must be supplied, the following model is used:: { - "packages": "ahriman" # either list of packages or package name as in AUR + "packages": ["ahriman"] # either list of packages or package name as in AUR } Raises: - HTTPAccepted: in case of success response - HTTPBadRequest: if bad data is supplied + HTTPNoContent: in case of success response + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/service/add' -d '{"packages": ["ahriman"]}' + > POST /api/v1/service/add HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 25 + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 18:44:21 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ data = await self.extract_data(["packages"]) packages = data.get("packages", []) self.spawner.packages_add(packages, now=True) - raise HTTPAccepted() + raise HTTPNoContent() diff --git a/src/ahriman/web/views/service/remove.py b/src/ahriman/web/views/service/remove.py index c6f74f5a..4aa0bdbe 100644 --- a/src/ahriman/web/views/service/remove.py +++ b/src/ahriman/web/views/service/remove.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from aiohttp.web import HTTPAccepted, HTTPBadRequest +from aiohttp.web import HTTPBadRequest, HTTPNoContent from ahriman.models.user_access import UserAccess from ahriman.web.views.base import BaseView @@ -40,12 +40,28 @@ class RemoveView(BaseView): JSON body must be supplied, the following model is used:: { - "packages": "ahriman", # either list of packages or package name + "packages": ["ahriman"] # either list of packages or package name } Raises: - HTTPAccepted: in case of success response HTTPBadRequest: if bad data is supplied + HTTPNoContent: in case of success response + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/service/remove' -d '{"packages": ["ahriman"]}' + > POST /api/v1/service/remove HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 25 + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 18:57:56 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ try: data = await self.extract_data(["packages"]) @@ -55,4 +71,4 @@ class RemoveView(BaseView): self.spawner.packages_remove(packages) - raise HTTPAccepted() + raise HTTPNoContent() diff --git a/src/ahriman/web/views/service/request.py b/src/ahriman/web/views/service/request.py index 5b6c8e3b..07bef5ff 100644 --- a/src/ahriman/web/views/service/request.py +++ b/src/ahriman/web/views/service/request.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -from aiohttp.web import HTTPAccepted, HTTPBadRequest +from aiohttp.web import HTTPBadRequest, HTTPNoContent from ahriman.models.user_access import UserAccess from ahriman.web.views.base import BaseView @@ -40,12 +40,28 @@ class RequestView(BaseView): JSON body must be supplied, the following model is used:: { - "packages": "ahriman" # either list of packages or package name as in AUR + "packages": ["ahriman"] # either list of packages or package name as in AUR } Raises: - HTTPAccepted: in case of success response HTTPBadRequest: if bad data is supplied + HTTPNoContent: in case of success response + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/service/request' -d '{"packages": ["ahriman"]}' + > POST /api/v1/service/request HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 25 + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 18:59:32 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ try: data = await self.extract_data(["packages"]) @@ -55,4 +71,4 @@ class RequestView(BaseView): self.spawner.packages_add(packages, now=False) - raise HTTPAccepted() + raise HTTPNoContent() diff --git a/src/ahriman/web/views/service/search.py b/src/ahriman/web/views/service/search.py index d82fe146..7cb4cbf7 100644 --- a/src/ahriman/web/views/service/search.py +++ b/src/ahriman/web/views/service/search.py @@ -39,15 +39,30 @@ class SearchView(BaseView): async def get(self) -> Response: """ - search packages in AUR - - search string (non empty) must be supplied as ``for`` parameter + search packages in AUR. Search string (non-empty) must be supplied as ``for`` parameter Returns: Response: 200 with found package bases and descriptions sorted by base Raises: HTTPNotFound: if no packages found + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/service/search?for=ahriman' + > GET /api/v1/service/search?for=ahriman HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: application/json + > + < HTTP/1.1 200 OK + < Content-Type: application/json; charset=utf-8 + < Content-Length: 148 + < Date: Wed, 23 Nov 2022 19:07:13 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < + [{"package": "ahriman", "description": "ArcH linux ReposItory MANager"}, {"package": "ahriman-git", "description": "ArcH Linux ReposItory MANager"}] """ search: List[str] = self.request.query.getall("for", default=[]) packages = AUR.multisearch(*search, pacman=self.service.repository.pacman) diff --git a/src/ahriman/web/views/status/logs.py b/src/ahriman/web/views/status/logs.py index 4dbcf9dc..e48f911d 100644 --- a/src/ahriman/web/views/status/logs.py +++ b/src/ahriman/web/views/status/logs.py @@ -46,6 +46,20 @@ class LogsView(BaseView): Raises: HTTPNoContent: on success response + + Examples: + Example of command by using curl:: + + $ curl -v -XDELETE 'http://example.com/api/v1/packages/ahriman/logs' + > DELETE /api/v1/packages/ahriman/logs HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 19:26:40 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ package_base = self.request.match_info["package"] self.service.remove_logs(package_base, None) @@ -58,6 +72,23 @@ class LogsView(BaseView): Returns: Response: 200 with package logs on success + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/packages/ahriman/logs' + > GET /api/v1/packages/ahriman/logs HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: application/json + > + < HTTP/1.1 200 OK + < Content-Type: application/json; charset=utf-8 + < Content-Length: 100112 + < Date: Wed, 23 Nov 2022 19:24:14 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < + {"package_base": "ahriman", "status": {"status": "success", "timestamp": 1669231136}, "logs": "[2022-11-23 19:17:32] clone remote https://aur.archlinux.org/ahriman.git to /tmp/tmpy9j6fq9p using branch master"} """ package_base = self.request.match_info["package"] @@ -89,6 +120,22 @@ class LogsView(BaseView): Raises: HTTPBadRequest: if bad data is supplied HTTPNoContent: in case of success response + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/packages/ahriman/logs' -d '{"created": 1669231764.042444, "message": "my log message", "process_id": 1}' + > POST /api/v1/packages/ahriman/logs HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 76 + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 19:30:45 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ package_base = self.request.match_info["package"] data = await self.extract_data() diff --git a/src/ahriman/web/views/status/package.py b/src/ahriman/web/views/status/package.py index f6258563..0b92ae1c 100644 --- a/src/ahriman/web/views/status/package.py +++ b/src/ahriman/web/views/status/package.py @@ -46,6 +46,20 @@ class PackageView(BaseView): Raises: HTTPNoContent: on success response + + Examples: + Example of command by using curl:: + + $ curl -v -XDELETE 'http://example.com/api/v1/packages/ahriman' + > DELETE /api/v1/packages/ahriman HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 19:43:40 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ package_base = self.request.match_info["package"] self.service.remove(package_base) @@ -61,6 +75,23 @@ class PackageView(BaseView): Raises: HTTPNotFound: if no package was found + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/packages/ahriman' + > GET /api/v1/packages/ahriman HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: application/json + > + < HTTP/1.1 200 OK + < Content-Type: application/json; charset=utf-8 + < Content-Length: 743 + < Date: Wed, 23 Nov 2022 19:41:01 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < + [{"package": {"base": "ahriman", "version": "2.3.0-1", "remote": {"git_url": "https://aur.archlinux.org/ahriman.git", "web_url": "https://aur.archlinux.org/packages/ahriman", "path": ".", "branch": "master", "source": "aur"}, "packages": {"ahriman": {"architecture": "any", "archive_size": 247573, "build_date": 1669231069, "depends": ["devtools", "git", "pyalpm", "python-inflection", "python-passlib", "python-requests", "python-setuptools", "python-srcinfo"], "description": "ArcH linux ReposItory MANager", "filename": "ahriman-2.3.0-1-any.pkg.tar.zst", "groups": [], "installed_size": 1676153, "licenses": ["GPL3"], "provides": [], "url": "https://github.com/arcan1s/ahriman"}}}, "status": {"status": "success", "timestamp": 1669231136}}] """ package_base = self.request.match_info["package"] @@ -85,13 +116,29 @@ class PackageView(BaseView): { "status": "unknown", # package build status string, must be valid ``BuildStatusEnum`` - "package": {} # package body (use ``dataclasses.asdict`` to generate one), optional. - # Must be supplied in case if package base is unknown + "package": {} # package body (use ``dataclasses.asdict`` to generate one), optional. + # Must be supplied in case if package base is unknown } Raises: HTTPBadRequest: if bad data is supplied HTTPNoContent: in case of success response + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/packages/ahriman' -d '{"status": "success"}' + > POST /api/v1/packages/ahriman HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 21 + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 19:42:49 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ package_base = self.request.match_info["package"] data = await self.extract_data() diff --git a/src/ahriman/web/views/status/packages.py b/src/ahriman/web/views/status/packages.py index 7d786b47..667a68d6 100644 --- a/src/ahriman/web/views/status/packages.py +++ b/src/ahriman/web/views/status/packages.py @@ -42,6 +42,23 @@ class PackagesView(BaseView): Returns: Response: 200 with package description on success + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/packages' + > GET /api/v1/packages HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: application/json + > + < HTTP/1.1 200 OK + < Content-Type: application/json; charset=utf-8 + < Content-Length: 2687 + < Date: Wed, 23 Nov 2022 19:35:24 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < + [{"package": {"base": "ahriman", "version": "2.3.0-1", "remote": {"git_url": "https://aur.archlinux.org/ahriman.git", "web_url": "https://aur.archlinux.org/packages/ahriman", "path": ".", "branch": "master", "source": "aur"}, "packages": {"ahriman": {"architecture": "any", "archive_size": 247573, "build_date": 1669231069, "depends": ["devtools", "git", "pyalpm", "python-inflection", "python-passlib", "python-requests", "python-setuptools", "python-srcinfo"], "description": "ArcH linux ReposItory MANager", "filename": "ahriman-2.3.0-1-any.pkg.tar.zst", "groups": [], "installed_size": 1676153, "licenses": ["GPL3"], "provides": [], "url": "https://github.com/arcan1s/ahriman"}}}, "status": {"status": "success", "timestamp": 1669231136}}] """ response = [ { @@ -57,6 +74,20 @@ class PackagesView(BaseView): Raises: HTTPNoContent: on success response + + Examples: + Example of command by using curl:: + + $ curl -v -XPOST 'http://example.com/api/v1/packages' + > POST /api/v1/packages HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 19:38:06 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ self.service.load() diff --git a/src/ahriman/web/views/status/status.py b/src/ahriman/web/views/status/status.py index 9fb7f308..4e32c326 100644 --- a/src/ahriman/web/views/status/status.py +++ b/src/ahriman/web/views/status/status.py @@ -46,6 +46,23 @@ class StatusView(BaseView): Returns: Response: 200 with service status object + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/status' + > GET /api/v1/status HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: application/json + > + < HTTP/1.1 200 OK + < Content-Type: application/json; charset=utf-8 + < Content-Length: 222 + < Date: Wed, 23 Nov 2022 19:32:31 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < + {"status": {"status": "success", "timestamp": 1669231237}, "architecture": "x86_64", "packages": {"total": 4, "unknown": 0, "pending": 0, "building": 0, "failed": 0, "success": 4}, "repository": "repo", "version": "2.3.0"} """ counters = Counters.from_packages(self.service.packages) status = InternalStatus( @@ -70,6 +87,22 @@ class StatusView(BaseView): Raises: HTTPBadRequest: if bad data is supplied HTTPNoContent: in case of success response + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/status' -d '{"status": "success"}' + > POST /api/v1/status HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 21 + > + < HTTP/1.1 204 No Content + < Date: Wed, 23 Nov 2022 19:33:57 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < """ try: data = await self.extract_data() diff --git a/src/ahriman/web/views/user/login.py b/src/ahriman/web/views/user/login.py index c57249d9..ba7d07ea 100644 --- a/src/ahriman/web/views/user/login.py +++ b/src/ahriman/web/views/user/login.py @@ -41,12 +41,17 @@ class LoginView(BaseView): OAuth2 response handler In case if code provided it will do a request to get user email. In case if no code provided it will redirect - to authorization url provided by OAuth client + to authorization url provided by OAuth client. + + The authentication session will be passed in ``Set-Cookie`` header. Raises: HTTPFound: on success response HTTPMethodNotAllowed: in case if method is used, but OAuth is disabled HTTPUnauthorized: if case of authorization error + + Examples: + This request must not be used directly. """ from ahriman.core.auth import OAuth @@ -78,9 +83,32 @@ class LoginView(BaseView): "password": "pa55w0rd" # password to use for login } + The authentication session will be passed in ``Set-Cookie`` header. + Raises: HTTPFound: on success response HTTPUnauthorized: if case of authorization error + + Examples: + Example of command by using curl:: + + $ curl -v -H 'Content-Type: application/json' 'http://example.com/api/v1/login' -d '{"username": "test", "password": "test"}' + > POST /api/v1/login HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 40 + > + < HTTP/1.1 302 Found + < Content-Type: text/plain; charset=utf-8 + < Location: / + < Content-Length: 10 + < Set-Cookie: ... + < Date: Wed, 23 Nov 2022 17:51:27 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < + 302: Found """ data = await self.extract_data() username = data.get("username") diff --git a/src/ahriman/web/views/user/logout.py b/src/ahriman/web/views/user/logout.py index 471ac732..3ab32c87 100644 --- a/src/ahriman/web/views/user/logout.py +++ b/src/ahriman/web/views/user/logout.py @@ -37,10 +37,31 @@ class LogoutView(BaseView): async def post(self) -> None: """ - logout user from the service. No parameters supported here + logout user from the service. No parameters supported here. + + The server will respond with ``Set-Cookie`` header, in which API session cookie will be nullified. Raises: HTTPFound: on success response + + Examples: + Example of command by using curl:: + + $ curl -v -XPOST 'http://example.com/api/v1/logout' + > POST /api/v1/logout HTTP/1.1 + > Host: example.com + > User-Agent: curl/7.86.0 + > Accept: */* + > + < HTTP/1.1 302 Found + < Content-Type: text/plain; charset=utf-8 + < Location: / + < Content-Length: 10 + < Set-Cookie: ... + < Date: Wed, 23 Nov 2022 19:10:51 GMT + < Server: Python/3.10 aiohttp/3.8.3 + < + 302: Found """ try: await check_authorized(self.request) diff --git a/tox.ini b/tox.ini index 57c57964..98449b02 100644 --- a/tox.ini +++ b/tox.ini @@ -44,7 +44,7 @@ deps = {[tox]dependencies} -e .[docs] commands = - sphinx-build -b html -a -j auto docs docs/html + sphinx-build -b html -a -j auto -W docs docs/html [testenv:tests] deps =