diff --git a/src/ahriman/core/watcher/watcher.py b/src/ahriman/core/watcher/watcher.py index e2686a6a..dad851a7 100644 --- a/src/ahriman/core/watcher/watcher.py +++ b/src/ahriman/core/watcher/watcher.py @@ -52,6 +52,13 @@ class Watcher: ''' return [pair for pair in self.known.values()] + def get(self, base: str) -> Tuple[Package, BuildStatus]: + ''' + get current package base build status + :return: package and its status + ''' + return self.known[base] + def load(self) -> None: ''' load packages from local repository. In case if last status is known, it will use it diff --git a/src/ahriman/core/watcher/web_client.py b/src/ahriman/core/watcher/web_client.py index 02b0d284..c0854991 100644 --- a/src/ahriman/core/watcher/web_client.py +++ b/src/ahriman/core/watcher/web_client.py @@ -21,7 +21,6 @@ import logging import requests from dataclasses import asdict -from typing import Any, Dict from ahriman.core.watcher.client import Client from ahriman.models.build_status import BuildStatusEnum @@ -67,7 +66,7 @@ class WebClient(Client): :param package: package properties :param status: current package build status ''' - payload: Dict[str, Any] = { + payload = { 'status': status.value, 'package': asdict(package) } @@ -95,7 +94,7 @@ class WebClient(Client): :param base: package base to update :param status: current package build status ''' - payload: Dict[str, Any] = {'status': status.value} + payload = {'status': status.value} try: response = requests.post(self._package_url(base), json=payload) @@ -108,7 +107,7 @@ class WebClient(Client): update ahriman status itself :param status: current ahriman status ''' - payload: Dict[str, Any] = {'status': status.value} + payload = {'status': status.value} try: response = requests.post(self._ahriman_url(), json=payload) diff --git a/src/ahriman/web/routes.py b/src/ahriman/web/routes.py index 6438a50d..f7f63e10 100644 --- a/src/ahriman/web/routes.py +++ b/src/ahriman/web/routes.py @@ -34,21 +34,27 @@ def setup_routes(application: Application) -> None: GET / get build status page GET /index.html same as above + GET /api/v1/ahriman get current service status POST /api/v1/ahriman update service status + GET /api/v1/packages get all known packages POST /api/v1/packages force update every package from repository - POST /api/v1/package/:base update package base status DELETE /api/v1/package/:base delete package base from status page + GET /api/v1/package/:base get package base status + POST /api/v1/package/:base update package base status :param application: web application instance ''' application.router.add_get('/', IndexView) application.router.add_get('/index.html', IndexView) + application.router.add_get('/api/v1/ahriman', AhrimanView) application.router.add_post('/api/v1/ahriman', AhrimanView) + application.router.add_get('/api/v1/packages', PackagesView) application.router.add_post('/api/v1/packages', PackagesView) application.router.add_delete('/api/v1/packages/{package}', PackageView) + application.router.add_get('/api/v1/packages/{package}', PackageView) application.router.add_post('/api/v1/packages/{package}', PackageView) diff --git a/src/ahriman/web/views/ahriman.py b/src/ahriman/web/views/ahriman.py index e61bf146..2f190624 100644 --- a/src/ahriman/web/views/ahriman.py +++ b/src/ahriman/web/views/ahriman.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 HTTPBadRequest, HTTPOk, Response +from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response from ahriman.models.build_status import BuildStatusEnum from ahriman.web.views.base import BaseView @@ -28,6 +28,13 @@ class AhrimanView(BaseView): service status web view ''' + async def get(self) -> Response: + ''' + get current service status + :return: 200 with service status object + ''' + return json_response(AhrimanView.status_view(self.service.status)) + async def post(self) -> Response: ''' update service status @@ -37,7 +44,7 @@ class AhrimanView(BaseView): "status": "unknown", # service status string, must be valid `BuildStatusEnum` } - :return: 200 on success + :return: 204 on success ''' data = await self.request.json() @@ -48,4 +55,4 @@ class AhrimanView(BaseView): self.service.update_self(status) - return HTTPOk() + return HTTPNoContent() diff --git a/src/ahriman/web/views/base.py b/src/ahriman/web/views/base.py index e5f31ab3..3820b1c2 100644 --- a/src/ahriman/web/views/base.py +++ b/src/ahriman/web/views/base.py @@ -17,9 +17,14 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +from dataclasses import asdict +from typing import Any, Dict + from aiohttp.web import View from ahriman.core.watcher.watcher import Watcher +from ahriman.models.build_status import BuildStatus +from ahriman.models.package import Package class BaseView(View): @@ -34,3 +39,28 @@ class BaseView(View): ''' watcher: Watcher = self.request.app['watcher'] return watcher + + @staticmethod + def package_view(package: Package, status: BuildStatus) -> Dict[str, Any]: + ''' + generate json package view + :param package: package definitions + :param status: package build status + :return: json-friendly dictionary + ''' + return { + 'status': BaseView.status_view(status), + 'package': asdict(package) + } + + @staticmethod + def status_view(status: BuildStatus) -> Dict[str, Any]: + ''' + generate json status view + :param status: build status + :return: json-friendly dictionary + ''' + return { + 'status': status.status.value, + 'timestamp': status.timestamp + } diff --git a/src/ahriman/web/views/package.py b/src/ahriman/web/views/package.py index 061aa1ac..179b795e 100644 --- a/src/ahriman/web/views/package.py +++ b/src/ahriman/web/views/package.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 HTTPBadRequest, HTTPOk, Response +from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response from ahriman.models.build_status import BuildStatusEnum from ahriman.models.package import Package @@ -29,15 +29,30 @@ class PackageView(BaseView): package base specific web view ''' + async def get(self) -> Response: + ''' + get current package base status + :return: 200 with package description on success + ''' + base = self.request.match_info['package'] + + try: + package, status = self.service.get(base) + except KeyError: + raise HTTPNotFound() + + response = PackageView.package_view(package, status) + return json_response(response) + async def delete(self) -> Response: ''' delete package base from status page - :return: 200 on success + :return: 204 on success ''' base = self.request.match_info['package'] self.service.remove(base) - return HTTPOk() + return HTTPNoContent() async def post(self) -> Response: ''' @@ -50,7 +65,7 @@ class PackageView(BaseView): # Must be supplied in case if package base is unknown } - :return: 200 on success + :return: 204 on success ''' base = self.request.match_info['package'] data = await self.request.json() @@ -66,4 +81,4 @@ class PackageView(BaseView): except KeyError: raise HTTPBadRequest(text=f'Package {base} is unknown, but no package body set') - return HTTPOk() + return HTTPNoContent() diff --git a/src/ahriman/web/views/packages.py b/src/ahriman/web/views/packages.py index 911516f0..53d8d44f 100644 --- a/src/ahriman/web/views/packages.py +++ b/src/ahriman/web/views/packages.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 HTTPOk, Response +from aiohttp.web import HTTPNoContent, Response, json_response from ahriman.web.views.base import BaseView @@ -27,11 +27,22 @@ class PackagesView(BaseView): global watcher view ''' + async def get(self) -> Response: + ''' + get current packages status + :return: 200 with package description on success + ''' + response = [ + PackagesView.package_view(package, status) + for package, status in self.service.packages + ] + return json_response(response) + async def post(self) -> Response: ''' reload all packages from repository. No parameters supported here - :return: 200 on success + :return: 204 on success ''' self.service.load() - return HTTPOk() + return HTTPNoContent()