use api generated docs instead of comments (#92)

This commit is contained in:
2023-04-04 01:53:06 +03:00
committed by Evgeniy Alekseev
parent d81e91e117
commit fc01bf3d1c
103 changed files with 2372 additions and 750 deletions

View File

@@ -0,0 +1,19 @@
#
# Copyright (c) 2021-2023 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

View File

@@ -0,0 +1,46 @@
#
# Copyright (c) 2021-2023 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# 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 aiohttp_jinja2
from typing import Any, Dict
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
class DocsView(BaseView):
"""
api docs view
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
"""
GET_PERMISSION = UserAccess.Unauthorized
@aiohttp_jinja2.template("api.jinja2")
async def get(self) -> Dict[str, Any]:
"""
return static docs html
Returns:
Dict[str, Any]: parameters for jinja template
"""
return {}

View File

@@ -0,0 +1,76 @@
#
# Copyright (c) 2021-2023 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from aiohttp.web import Response, json_response
from typing import Callable, Dict
from ahriman.core.util import partition
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
class SwaggerView(BaseView):
"""
api docs specification view
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
"""
GET_PERMISSION = UserAccess.Unauthorized
async def get(self) -> Response:
"""
get api specification
Returns:
Response: 200 with json api specification
"""
spec = self.request.app["swagger_dict"]
is_body_parameter: Callable[[Dict[str, str]], bool] = lambda p: p["in"] == "body"
# special workaround because it writes request body to parameters section
paths = spec["paths"]
for methods in paths.values():
for method in methods.values():
if "parameters" not in method:
continue
body, other = partition(method["parameters"], is_body_parameter)
if not body:
continue # there were no ``body`` parameters found
# there should be only one body parameters
method["requestBody"] = {
"content": {
"application/json": {
"schema": next(iter(body))["schema"]
}
}
}
method["parameters"] = other
# inject security schema
spec["components"]["securitySchemes"] = {
key: value
for schema in spec["security"]
for key, value in schema.items()
}
return json_response(spec)

View File

@@ -19,8 +19,9 @@
#
from __future__ import annotations
from aiohttp.web import Request, View
from typing import Any, Callable, Dict, List, Optional, Type, TypeVar
from aiohttp_cors import CorsViewMixin # type: ignore
from aiohttp.web import Request, StreamResponse, View
from typing import Any, Awaitable, Callable, Dict, List, Optional, Type, TypeVar
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
@@ -28,15 +29,19 @@ from ahriman.core.spawn import Spawn
from ahriman.core.status.watcher import Watcher
from ahriman.models.user_access import UserAccess
T = TypeVar("T", str, List[str])
class BaseView(View):
class BaseView(View, CorsViewMixin):
"""
base web view to make things typed
Attributes:
OPTIONS_PERMISSION(UserAccess): (class attribute) options permissions of self
"""
OPTIONS_PERMISSION = UserAccess.Unauthorized
@property
def configuration(self) -> Configuration:
"""
@@ -92,7 +97,8 @@ class BaseView(View):
Returns:
UserAccess: extracted permission
"""
permission: UserAccess = getattr(cls, f"{request.method.upper()}_PERMISSION", UserAccess.Full)
method = "GET" if (other := request.method.upper()) == "HEAD" else other
permission: UserAccess = getattr(cls, f"{method}_PERMISSION", UserAccess.Full)
return permission
@staticmethod
@@ -118,23 +124,6 @@ class BaseView(View):
raise KeyError(f"Key {key} is missing or empty")
return value
async def extract_data(self, list_keys: Optional[List[str]] = None) -> Dict[str, Any]:
"""
extract json data from either json or form data
Args:
list_keys(Optional[List[str]], optional): optional list of keys which must be forced to list from form data
(Default value = None)
Returns:
Dict[str, Any]: raw json object or form data converted to json
"""
try:
json: Dict[str, Any] = await self.request.json()
return json
except ValueError:
return await self.data_as_json(list_keys or [])
async def data_as_json(self, list_keys: List[str]) -> Dict[str, Any]:
"""
extract form data and convert it to json object
@@ -158,3 +147,39 @@ class BaseView(View):
else:
json[key] = value
return json
async def extract_data(self, list_keys: Optional[List[str]] = None) -> Dict[str, Any]:
"""
extract json data from either json or form data
Args:
list_keys(Optional[List[str]], optional): optional list of keys which must be forced to list from form data
(Default value = None)
Returns:
Dict[str, Any]: raw json object or form data converted to json
"""
try:
json: Dict[str, Any] = await self.request.json()
return json
except ValueError:
return await self.data_as_json(list_keys or [])
# pylint: disable=not-callable,protected-access
async def head(self) -> StreamResponse: # type: ignore
"""
HEAD method implementation based on the result of GET method
Raises:
HTTPMethodNotAllowed: in case if there is no GET method implemented
"""
get_method: Optional[Callable[[], Awaitable[StreamResponse]]] = getattr(self, "get", None)
# using if/else in order to suppress mypy warning which doesn't know that
# ``_raise_allowed_methods`` raises exception
if get_method is not None:
# there is a bug in pylint, see https://github.com/pylint-dev/pylint/issues/6005
response = await get_method()
response._body = b"" # type: ignore
return response
self._raise_allowed_methods()

View File

@@ -41,10 +41,9 @@ class IndexView(BaseView):
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Unauthorized
GET_PERMISSION = UserAccess.Unauthorized
@aiohttp_jinja2.template("build-status.jinja2")
async def get(self) -> Dict[str, Any]:

View File

@@ -17,9 +17,14 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
from ahriman.web.views.base import BaseView
@@ -33,34 +38,28 @@ class AddView(BaseView):
POST_PERMISSION = UserAccess.Full
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Add new package",
description="Add new package(s) from AUR",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.json_schema(PackageNamesSchema)
async def post(self) -> None:
"""
add new package
JSON body must be supplied, the following model is used::
{
"packages": ["ahriman"] # either list of packages or package name as in AUR
}
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/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
<
"""
try:
data = await self.extract_data(["packages"])

View File

@@ -17,9 +17,15 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.pgp_key_id_schema import PGPKeyIdSchema
from ahriman.web.schemas.pgp_key_schema import PGPKeySchema
from ahriman.web.views.base import BaseView
@@ -29,17 +35,31 @@ class PGPView(BaseView):
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
POST_PERMISSION = UserAccess.Full
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Reporter
GET_PERMISSION = UserAccess.Reporter
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Search for PGP key",
description="Search for PGP key and retrieve its body",
responses={
200: {"description": "Success response", "schema": PGPKeySchema},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.querystring_schema(PGPKeyIdSchema)
async def get(self) -> Response:
"""
retrieve key from the key server. It supports two query parameters: ``key`` - pgp key fingerprint and
``server`` which points to valid PGP key server
retrieve key from the key server
Returns:
Response: 200 with key body on success
@@ -47,24 +67,7 @@ class PGPView(BaseView):
Raises:
HTTPBadRequest: if bad data is supplied
HTTPNotFound: if key wasn't found or service was unable to fetch it
Examples:
Example of command by using curl::
$ curl -v -H 'Accept: application/json' 'http://example.com/api/v1/service/pgp?key=0xE989490C&server=keyserver.ubuntu.com'
> GET /api/v1/service/pgp?key=0xE989490C&server=keyserver.ubuntu.com 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: 3275
< Date: Fri, 25 Nov 2022 22:54:02 GMT
< Server: Python/3.10 aiohttp/3.8.3
<
{"key": "key"}
"""
"""
try:
key = self.get_non_empty(self.request.query.getone, "key")
server = self.get_non_empty(self.request.query.getone, "server")
@@ -78,36 +81,28 @@ class PGPView(BaseView):
return json_response({"key": key})
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Fetch PGP key",
description="Fetch PGP key from the key server",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.json_schema(PGPKeyIdSchema)
async def post(self) -> None:
"""
store key to the local service environment
JSON body must be supplied, the following model is used::
{
"key": "0x8BE91E5A773FB48AC05CC1EDBED105AED6246B39", # key fingerprint to import
"server": "keyserver.ubuntu.com" # optional pgp server address
}
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/service/pgp' -d '{"key": "0xE989490C"}'
> POST /api/v1/service/pgp 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: Fri, 25 Nov 2022 22:55:56 GMT
< Server: Python/3.10 aiohttp/3.8.3
<
"""
data = await self.extract_data()

View File

@@ -17,9 +17,14 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
from ahriman.web.views.base import BaseView
@@ -33,40 +38,33 @@ class RebuildView(BaseView):
POST_PERMISSION = UserAccess.Full
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Rebuild packages",
description="Rebuild packages which depend on specified one",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.json_schema(PackageNamesSchema)
async def post(self) -> None:
"""
rebuild packages based on their dependency
JSON body must be supplied, the following model is used::
{
"packages": ["ahriman"] # either list of packages or package name of dependency
}
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/service/rebuild' -d '{"packages": ["python"]}'
> POST /api/v1/service/rebuild HTTP/1.1
> Host: example.com
> User-Agent: curl/7.86.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 24
>
< HTTP/1.1 204 No Content
< Date: Sun, 27 Nov 2022 00:22:26 GMT
< Server: Python/3.10 aiohttp/3.8.3
<
"""
try:
data = await self.extract_data(["packages"])
packages = self.get_non_empty(lambda key: [package for package in data[key] if package], "packages")
depends_on = next(package for package in packages)
depends_on = next(iter(packages))
except Exception as e:
raise HTTPBadRequest(reason=str(e))

View File

@@ -17,9 +17,14 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
from ahriman.web.views.base import BaseView
@@ -33,35 +38,28 @@ class RemoveView(BaseView):
POST_PERMISSION = UserAccess.Full
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Remove packages",
description="Remove specified packages from the repository",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.json_schema(PackageNamesSchema)
async def post(self) -> None:
"""
remove existing packages
JSON body must be supplied, the following model is used::
{
"packages": ["ahriman"] # either list of packages or package name
}
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/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"])

View File

@@ -17,9 +17,14 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.package_names_schema import PackageNamesSchema
from ahriman.web.views.base import BaseView
@@ -33,35 +38,28 @@ class RequestView(BaseView):
POST_PERMISSION = UserAccess.Reporter
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Request new package",
description="Request new package(s) to be added from AUR",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.json_schema(PackageNamesSchema)
async def post(self) -> None:
"""
request to add new package
JSON body must be supplied, the following model is used::
{
"packages": ["ahriman"] # either list of packages or package name as in AUR
}
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/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"])

View File

@@ -17,12 +17,18 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNotFound, Response, json_response
from typing import Callable, List
from ahriman.core.alpm.remote import AUR
from ahriman.models.aur_package import AURPackage
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.aur_package_schema import AURPackageSchema
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.search_schema import SearchSchema
from ahriman.web.views.base import BaseView
@@ -32,14 +38,29 @@ class SearchView(BaseView):
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Reporter
GET_PERMISSION = UserAccess.Reporter
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Search for package",
description="Search for package in AUR",
responses={
200: {"description": "Success response", "schema": AURPackageSchema(many=True)},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.querystring_schema(SearchSchema)
async def get(self) -> Response:
"""
search packages in AUR. Search string (non-empty) must be supplied as ``for`` parameter
search packages in AUR
Returns:
Response: 200 with found package bases and descriptions sorted by base
@@ -47,23 +68,6 @@ class SearchView(BaseView):
Raises:
HTTPBadRequest: in case if bad data is supplied
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"}]
"""
try:
search: List[str] = self.get_non_empty(lambda key: self.request.query.getall(key, default=[]), "for")

View File

@@ -17,9 +17,13 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPNoContent
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.views.base import BaseView
@@ -33,26 +37,25 @@ class UpdateView(BaseView):
POST_PERMISSION = UserAccess.Full
@aiohttp_apispec.docs(
tags=["Actions"],
summary="Update packages",
description="Run repository update process",
responses={
204: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
async def post(self) -> None:
"""
run repository update. No parameters supported here
Raises:
HTTPNoContent: in case of success response
Examples:
Example of command by using curl::
$ curl -v -XPOST 'http://example.com/api/v1/service/update'
> POST /api/v1/service/update HTTP/1.1
> Host: example.com
> User-Agent: curl/7.86.0
> Accept: */*
>
< HTTP/1.1 204 No Content
< Date: Fri, 25 Nov 2022 22:57:56 GMT
< Server: Python/3.10 aiohttp/3.8.3
<
"""
self.spawner.packages_update()

View File

@@ -17,11 +17,18 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
from ahriman.core.exceptions import UnknownPackageError
from ahriman.models.log_record_id import LogRecordId
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.log_schema import LogSchema
from ahriman.web.schemas.logs_schema import LogsSchema
from ahriman.web.schemas.package_name_schema import PackageNameSchema
from ahriman.web.views.base import BaseView
@@ -32,39 +39,53 @@ class LogsView(BaseView):
Attributes:
DELETE_PERMISSION(UserAccess): (class attribute) delete permissions of self
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
DELETE_PERMISSION = POST_PERMISSION = UserAccess.Full
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Reporter
GET_PERMISSION = UserAccess.Reporter
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Delete package logs",
description="Delete all logs which belong to the specified package",
responses={
204: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [DELETE_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.match_info_schema(PackageNameSchema)
async def delete(self) -> None:
"""
delete package logs
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)
raise HTTPNoContent()
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Get package logs",
description="Retrieve all package logs and the last package status",
responses={
200: {"description": "Success response", "schema": LogsSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.match_info_schema(PackageNameSchema)
async def get(self) -> Response:
"""
get last package logs
@@ -72,22 +93,8 @@ 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"}
Raises:
HTTPNotFound: if package base is unknown
"""
package_base = self.request.match_info["package"]
@@ -104,37 +111,29 @@ class LogsView(BaseView):
}
return json_response(response)
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Add package logs",
description="Insert new package log record",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.match_info_schema(PackageNameSchema)
@aiohttp_apispec.json_schema(LogSchema)
async def post(self) -> None:
"""
create new package log record
JSON body must be supplied, the following model is used::
{
"created": 42.001, # log record created timestamp
"message": "log message", # log record
"process_id": 42 # process id from which log record was emitted
}
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()

View File

@@ -17,12 +17,18 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
from ahriman.core.exceptions import UnknownPackageError
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.package_name_schema import PackageNameSchema
from ahriman.web.schemas.package_status_schema import PackageStatusSchema, PackageStatusSimplifiedSchema
from ahriman.web.views.base import BaseView
@@ -33,39 +39,53 @@ class PackageView(BaseView):
Attributes:
DELETE_PERMISSION(UserAccess): (class attribute) delete permissions of self
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
DELETE_PERMISSION = POST_PERMISSION = UserAccess.Full
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Read
GET_PERMISSION = UserAccess.Read
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Delete package",
description="Delete package and its status from service",
responses={
204: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [DELETE_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.match_info_schema(PackageNameSchema)
async def delete(self) -> None:
"""
delete package base from status page
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)
raise HTTPNoContent()
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Get package",
description="Retrieve packages and its descriptor",
responses={
200: {"description": "Success response", "schema": PackageStatusSchema(many=True)},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
404: {"description": "Package base is unknown", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.match_info_schema(PackageNameSchema)
async def get(self) -> Response:
"""
get current package base status
@@ -75,23 +95,6 @@ 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"]
@@ -108,37 +111,29 @@ class PackageView(BaseView):
]
return json_response(response)
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Update package",
description="Update package status and set its descriptior optionally",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.match_info_schema(PackageNameSchema)
@aiohttp_apispec.json_schema(PackageStatusSimplifiedSchema)
async def post(self) -> None:
"""
update package build status
JSON body must be supplied, the following model is used::
{
"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
}
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()

View File

@@ -17,9 +17,14 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPNoContent, Response, json_response
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.package_status_schema import PackageStatusSchema
from ahriman.web.views.base import BaseView
@@ -29,36 +34,31 @@ class PackagesView(BaseView):
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Read
GET_PERMISSION = UserAccess.Read
POST_PERMISSION = UserAccess.Full
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Get packages list",
description="Retrieve all packages and their descriptors",
responses={
200: {"description": "Success response", "schema": PackageStatusSchema(many=True)},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
async def get(self) -> Response:
"""
get current packages status
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 = [
{
@@ -68,26 +68,25 @@ class PackagesView(BaseView):
]
return json_response(response)
@aiohttp_apispec.docs(
tags=["Packages"],
summary="Load packages",
description="Load packages from cache",
responses={
204: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
async def post(self) -> None:
"""
reload all packages from repository. No parameters supported here
reload all packages from repository
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()

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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response
from ahriman import version
@@ -24,6 +26,10 @@ from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.counters import Counters
from ahriman.models.internal_status import InternalStatus
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.internal_status_schema import InternalStatusSchema
from ahriman.web.schemas.status_schema import StatusSchema
from ahriman.web.views.base import BaseView
@@ -33,36 +39,31 @@ class StatusView(BaseView):
Attributes:
GET_PERMISSION(UserAccess): (class attribute) get permissions of self
HEAD_PERMISSION(UserAccess): (class attribute) head permissions of self
POST_PERMISSION(UserAccess): (class attribute) post permissions of self
"""
GET_PERMISSION = HEAD_PERMISSION = UserAccess.Read
GET_PERMISSION = UserAccess.Read
POST_PERMISSION = UserAccess.Full
@aiohttp_apispec.docs(
tags=["Status"],
summary="Web service status",
description="Get web service status counters",
responses={
200: {"description": "Success response", "schema": InternalStatusSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
async def get(self) -> Response:
"""
get current service status
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(
@@ -74,35 +75,28 @@ class StatusView(BaseView):
return json_response(status.view())
@aiohttp_apispec.docs(
tags=["Status"],
summary="Set web service status",
description="Update web service status. Counters will remain unchanged",
responses={
204: {"description": "Success response"},
400: {"description": "Bad data is supplied", "schema": ErrorSchema},
401: {"description": "Authorization required", "schema": ErrorSchema},
403: {"description": "Access is forbidden", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
@aiohttp_apispec.json_schema(StatusSchema)
async def post(self) -> None:
"""
update service status
JSON body must be supplied, the following model is used::
{
"status": "unknown", # service status string, must be valid ``BuildStatusEnum``
}
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()

View File

@@ -17,10 +17,15 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPFound, HTTPMethodNotAllowed, HTTPUnauthorized
from ahriman.core.auth.helpers import remember
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.schemas.login_schema import LoginSchema
from ahriman.web.schemas.oauth2_schema import OAuth2Schema
from ahriman.web.views.base import BaseView
@@ -35,6 +40,18 @@ class LoginView(BaseView):
GET_PERMISSION = POST_PERMISSION = UserAccess.Unauthorized
@aiohttp_apispec.docs(
tags=["Login"],
summary="Login via OAuth2",
description="Login by using OAuth2 authorization code. Only available if OAuth2 is enabled",
responses={
302: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [GET_PERMISSION]}],
)
@aiohttp_apispec.querystring_schema(OAuth2Schema)
async def get(self) -> None:
"""
OAuth2 response handler
@@ -48,9 +65,6 @@ class LoginView(BaseView):
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.oauth import OAuth
@@ -70,43 +84,25 @@ class LoginView(BaseView):
raise HTTPUnauthorized()
@aiohttp_apispec.docs(
tags=["Login"],
summary="Login via basic authorization",
description="Login by using username and password",
responses={
302: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.json_schema(LoginSchema)
async def post(self) -> None:
"""
login user to service
either JSON body or form data must be supplied the following fields are required::
{
"username": "username", # username to use for login
"password": "pa55w0rd" # password to use for login
}
The authentication session will be passed in ``Set-Cookie`` header.
login user to service. 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()
identity = data.get("username")

View File

@@ -17,10 +17,14 @@
# 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 aiohttp_apispec # type: ignore
from aiohttp.web import HTTPFound, HTTPUnauthorized
from ahriman.core.auth.helpers import check_authorized, forget
from ahriman.models.user_access import UserAccess
from ahriman.web.schemas.auth_schema import AuthSchema
from ahriman.web.schemas.error_schema import ErrorSchema
from ahriman.web.views.base import BaseView
@@ -34,33 +38,26 @@ class LogoutView(BaseView):
POST_PERMISSION = UserAccess.Unauthorized
@aiohttp_apispec.docs(
tags=["Login"],
summary="Logout",
description="Logout user and remove authorization cookies",
responses={
302: {"description": "Success response"},
401: {"description": "Authorization required", "schema": ErrorSchema},
500: {"description": "Internal server error", "schema": ErrorSchema},
},
security=[{"token": [POST_PERMISSION]}],
)
@aiohttp_apispec.cookies_schema(AuthSchema)
async def post(self) -> None:
"""
logout user from the service. No parameters supported here.
logout user from the service
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)