mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-26 16:27:17 +00:00
Compare commits
2 Commits
7885df0dae
...
a1374dd477
Author | SHA1 | Date | |
---|---|---|---|
a1374dd477 | |||
faef091959 |
@ -27,7 +27,7 @@ Let's imagine, that the new class implements ``help-web``, which prints server i
|
||||
result = response.json()
|
||||
print(result)
|
||||
|
||||
The main functionality of the class is already described, but command is still not available yet. To do so, it is required to set ``arguments`` property, which is list of functions, which takes argument parser object, creates new subcommand and returns the modified parser, e.g.:
|
||||
The main functionality of the class is already described, but command is still not available yet. To do so, it is required to set ``arguments`` property, which is the list of the functions, each of them which takes argument parser object, creates new subcommand and returns the modified parser, e.g.:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
Writing own API endpoint
|
||||
========================
|
||||
|
||||
The web service loads views dynamically, thus it is possible to add custom API endpoint or even web page. The views must be derived from ``ahriman.web.views.base.BaseView`` and implements HTTP methods. The API specification will be also loaded (if available), but optional. The implementation must be saved into the ``ahriman.web.views`` package
|
||||
The web service loads views dynamically, thus it is possible to add custom API endpoint or even web page. The view must be derived from ``ahriman.web.views.base.BaseView`` and should implement desired HTTP methods. The API specification will be also loaded automatically if available, but optional. The implementation must be saved into the ``ahriman.web.views`` package
|
||||
|
||||
Let's consider example for API endpoint which always returns 204 with no response:
|
||||
Let's consider example of API endpoint which always returns 204 with no response:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -18,9 +18,9 @@ Let's consider example for API endpoint which always returns 204 with no respons
|
||||
# check public methods of the BaseView class for all available controls
|
||||
raise HTTPNoContent
|
||||
|
||||
The ``get()`` method can be decorated by ``aiohttp_apispec`` methods, but we will leave it for self-study. Consider checking examples of usages in the main package.
|
||||
The ``get()`` method can be decorated by ``aiohttp_apispec`` methods, but we will leave it for a self-study, please, consider to check examples of usages in the main package.
|
||||
|
||||
In order to view to be set correctly to routes list, few more options are required to be set. First of all, it is required to specify ``ROUTES`` (list of strings), which contains list of all available routes, e.g.:
|
||||
In order to view to be added to the route list correctly, few more properties are required to be set. First of all, it is required to specify ``ROUTES`` (list of strings), which contains list of all available routes, e.g.:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -440,7 +440,7 @@ Different APIs are separated into different packages:
|
||||
* ``ahriman.web.views.api`` not a real API, but some views which provide OpenAPI support.
|
||||
* ``ahriman.web.views.*.auditlog`` provides event log API.
|
||||
* ``ahriman.web.views.*.distributed`` is an API for builders interaction for multi-node setup.
|
||||
* ``ahriman.web.views.*.pacakges`` contains views which provide information about existing packages.
|
||||
* ``ahriman.web.views.*.packages`` contains views which provide information about existing packages.
|
||||
* ``ahriman.web.views.*.service`` provides views for application controls.
|
||||
* ``ahriman.web.views.*.status`` package provides REST API for application reporting.
|
||||
* ``ahriman.web.views.*.user`` package provides login and logout methods which can be called without authorization.
|
||||
|
@ -13,7 +13,7 @@ TL;DR
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
yay -S ahriman
|
||||
yay -S ahriman-core
|
||||
ahriman -a x86_64 -r aur service-setup --packager "ahriman bot <ahriman@example.com>"
|
||||
systemctl enable --now ahriman@x86_64-aur.timer
|
||||
|
||||
|
@ -9,7 +9,7 @@ How to setup web service
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
yay -S -ahriman-web
|
||||
yay -S ahriman-web
|
||||
|
||||
#.
|
||||
Configure service:
|
||||
|
@ -2,7 +2,7 @@ Initial setup
|
||||
=============
|
||||
|
||||
#.
|
||||
Install package as usual.
|
||||
Install package(s) as usual. At least, ``ahriman-core`` package is required; other features can be installed separately. Alternatively, it is possible to install meta-package, which includes everything.
|
||||
#.
|
||||
Change settings if required, see :doc:`configuration reference <configuration>` for more details.
|
||||
#.
|
||||
|
@ -27,6 +27,7 @@ from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.spawn import Spawn
|
||||
from ahriman.core.triggers import TriggerLoader
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.web.web import run_server, setup_server
|
||||
|
||||
|
||||
class Web(Handler):
|
||||
@ -48,9 +49,6 @@ class Web(Handler):
|
||||
configuration(Configuration): configuration instance
|
||||
report(bool): force enable or disable reporting
|
||||
"""
|
||||
# we are using local import for optional dependencies
|
||||
from ahriman.web.web import run_server, setup_server
|
||||
|
||||
spawner_args = Web.extract_arguments(args, configuration)
|
||||
spawner = Spawn(args.parser(), list(spawner_args))
|
||||
spawner.start()
|
||||
|
@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from aiohttp.web import Application, View
|
||||
from collections.abc import Generator
|
||||
|
||||
import ahriman.web.views
|
||||
|
||||
@ -29,22 +30,19 @@ from ahriman.web.views.base import BaseView
|
||||
__all__ = ["setup_routes"]
|
||||
|
||||
|
||||
def _dynamic_routes(configuration: Configuration) -> dict[str, type[View]]:
|
||||
def _dynamic_routes(configuration: Configuration) -> Generator[tuple[str, type[View]], None, None]:
|
||||
"""
|
||||
extract dynamic routes based on views
|
||||
|
||||
Args:
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
dict[str, type[View]]: map of the route to its view
|
||||
Yields:
|
||||
tuple[str, type[View]]: map of the route to its view
|
||||
"""
|
||||
routes: dict[str, type[View]] = {}
|
||||
for view in implementations(ahriman.web.views, BaseView):
|
||||
view_routes = view.routes(configuration)
|
||||
routes.update([(route, view) for route in view_routes])
|
||||
|
||||
return routes
|
||||
for route in view.routes(configuration):
|
||||
yield route, view
|
||||
|
||||
|
||||
def setup_routes(application: Application, configuration: Configuration) -> None:
|
||||
@ -57,5 +55,5 @@ def setup_routes(application: Application, configuration: Configuration) -> None
|
||||
"""
|
||||
application.router.add_static("/static", configuration.getpath("web", "static_path"), follow_symlinks=True)
|
||||
|
||||
for route, view in _dynamic_routes(configuration).items():
|
||||
for route, view in _dynamic_routes(configuration):
|
||||
application.router.add_view(route, view)
|
||||
|
@ -1 +1,9 @@
|
||||
# nothing to test here
|
||||
from ahriman.application.handlers.triggers import Triggers
|
||||
from ahriman.application.handlers.triggers_support import TriggersSupport
|
||||
|
||||
|
||||
def test_arguments() -> None:
|
||||
"""
|
||||
must define own arguments
|
||||
"""
|
||||
assert TriggersSupport.arguments != Triggers.arguments
|
||||
|
@ -36,8 +36,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
|
||||
"""
|
||||
args = _default_args(args)
|
||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
||||
setup_mock = mocker.patch("ahriman.web.web.setup_server")
|
||||
run_mock = mocker.patch("ahriman.web.web.run_server")
|
||||
setup_mock = mocker.patch("ahriman.application.handlers.web.setup_server")
|
||||
run_mock = mocker.patch("ahriman.application.handlers.web.run_server")
|
||||
start_mock = mocker.patch("ahriman.core.spawn.Spawn.start")
|
||||
trigger_mock = mocker.patch("ahriman.core.triggers.TriggerLoader.load")
|
||||
stop_mock = mocker.patch("ahriman.core.spawn.Spawn.stop")
|
||||
|
@ -6,6 +6,15 @@ from ahriman.core.module_loader import _modules, implementations
|
||||
from ahriman.web.views.base import BaseView
|
||||
|
||||
|
||||
def test_modules() -> None:
|
||||
"""
|
||||
must load modules
|
||||
"""
|
||||
modules = list(_modules(Path(__file__).parent.parent, "ahriman.web.views"))
|
||||
assert modules
|
||||
assert all(not module.ispkg for module in modules)
|
||||
|
||||
|
||||
def test_implementations() -> None:
|
||||
"""
|
||||
must load implementations from the package
|
||||
@ -14,12 +23,3 @@ def test_implementations() -> None:
|
||||
assert routes
|
||||
assert all(isinstance(view, type) for view in routes)
|
||||
assert all(issubclass(view, BaseView) for view in routes)
|
||||
|
||||
|
||||
def test_modules() -> None:
|
||||
"""
|
||||
must load modules
|
||||
"""
|
||||
modules = list(_modules(Path(__file__).parent.parent, "ahriman.web.views"))
|
||||
assert modules
|
||||
assert all(not module.ispkg for module in modules)
|
||||
|
@ -17,7 +17,7 @@ def test_dynamic_routes(resource_path_root: Path, configuration: Configuration)
|
||||
if file.suffix == ".py" and file.name not in ("__init__.py", "base.py", "status_view_guard.py")
|
||||
]
|
||||
|
||||
routes = _dynamic_routes(configuration)
|
||||
routes = dict(_dynamic_routes(configuration))
|
||||
assert all(isinstance(view, type) for view in routes.values())
|
||||
assert len(set(routes.values())) == len(expected_views)
|
||||
|
||||
|
@ -36,7 +36,6 @@ async def test_get_not_found(client_with_auth: TestClient, mocker: MockerFixture
|
||||
"""
|
||||
must raise not found if path is invalid
|
||||
"""
|
||||
print([route.handler for route in client_with_auth.app.router.routes()])
|
||||
static_route = next(route for route in client_with_auth.app.router.routes() if route.handler == StaticView)
|
||||
mocker.patch.object(static_route.handler, "ROUTES", [])
|
||||
response = await client_with_auth.get("/favicon.ico", allow_redirects=False)
|
||||
|
Loading…
Reference in New Issue
Block a user