feat: add autoupdate button to package info (#148)

This commit is contained in:
2025-06-29 22:18:54 +03:00
parent 2b1b17a1a3
commit 939a94d889
17 changed files with 219 additions and 25 deletions

View File

@ -29,13 +29,15 @@ class LogsOperations(Operations):
logs operations
"""
def logs_get(self, package_base: str, limit: int = -1, offset: int = 0,
repository_id: RepositoryId | None = None) -> list[LogRecord]:
def logs_get(self, package_base: str, version: str | None = None, process_id: str | None = None,
limit: int = -1, offset: int = 0, repository_id: RepositoryId | None = None) -> list[LogRecord]:
"""
extract logs for specified package base
Args:
package_base(str): package base to extract logs
version(str | None, optional): package version to filter (Default value = None)
process_id(str | None, optional): process identifier to filter (Default value = None)
limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1)
offset(int, optional): records offset (Default value = 0)
repository_id(RepositoryId, optional): repository unique identifier override (Default value = None)
@ -52,12 +54,17 @@ class LogsOperations(Operations):
"""
select created, message, version, process_id from (
select * from logs
where package_base = :package_base and repository = :repository
where package_base = :package_base
and repository = :repository
and (:version is null or version = :version)
and (:process_id is null or process_id = :process_id)
order by created desc limit :limit offset :offset
) order by created asc
""",
{
"package_base": package_base,
"version": version,
"process_id": process_id,
"repository": repository_id.id,
"limit": limit,
"offset": offset,

View File

@ -203,12 +203,15 @@ class Client:
"""
# this method does not raise NotImplementedError because it is actively used as dummy client for http log
def package_logs_get(self, package_base: str, limit: int = -1, offset: int = 0) -> list[LogRecord]:
def package_logs_get(self, package_base: str, version: str | None = None, process_id: str | None = None,
limit: int = -1, offset: int = 0) -> list[LogRecord]:
"""
get package logs
Args:
package_base(str): package base
version(str | None, optional): package version to search (Default value = None)
process_id(str | None, optional): process identifier to search (Default value = None)
limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1)
offset(int, optional): records offset (Default value = 0)

View File

@ -152,19 +152,22 @@ class LocalClient(Client):
"""
self.database.logs_insert(log_record, self.repository_id)
def package_logs_get(self, package_base: str, limit: int = -1, offset: int = 0) -> list[LogRecord]:
def package_logs_get(self, package_base: str, version: str | None = None, process_id: str | None = None,
limit: int = -1, offset: int = 0) -> list[LogRecord]:
"""
get package logs
Args:
package_base(str): package base
version(str | None, optional): package version to search (Default value = None)
process_id(str | None, optional): process identifier to search (Default value = None)
limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1)
offset(int, optional): records offset (Default value = 0)
Returns:
list[LogRecord]: package logs
"""
return self.database.logs_get(package_base, limit, offset, self.repository_id)
return self.database.logs_get(package_base, version, process_id, limit, offset, self.repository_id)
def package_logs_remove(self, package_base: str, version: str | None) -> None:
"""

View File

@ -109,7 +109,7 @@ class Watcher(LazyLogging):
package_logs_add: Callable[[LogRecord], None]
package_logs_get: Callable[[str, int, int], list[LogRecord]]
package_logs_get: Callable[[str, str | None, str | None, int, int], list[LogRecord]]
package_logs_remove: Callable[[str, str | None], None]

View File

@ -326,12 +326,15 @@ class WebClient(Client, SyncAhrimanClient):
self.make_request("POST", self._logs_url(log_record.log_record_id.package_base),
params=self.repository_id.query(), json=payload, suppress_errors=True)
def package_logs_get(self, package_base: str, limit: int = -1, offset: int = 0) -> list[LogRecord]:
def package_logs_get(self, package_base: str, version: str | None = None, process_id: str | None = None,
limit: int = -1, offset: int = 0) -> list[LogRecord]:
"""
get package logs
Args:
package_base(str): package base
version(str | None, optional): package version to search (Default value = None)
process_id(str | None, optional): process identifier to search (Default value = None)
limit(int, optional): limit records to the specified count, -1 means unlimited (Default value = -1)
offset(int, optional): records offset (Default value = 0)
@ -339,6 +342,10 @@ class WebClient(Client, SyncAhrimanClient):
list[LogRecord]: package logs
"""
query = self.repository_id.query() + [("limit", str(limit)), ("offset", str(offset))]
if version is not None:
query.append(("version", version))
if process_id is not None:
query.append(("process_id", process_id))
with contextlib.suppress(Exception):
response = self.make_request("GET", self._logs_url(package_base), params=query)

View File

@ -34,6 +34,7 @@ from ahriman.web.schemas.log_schema import LogSchema
from ahriman.web.schemas.login_schema import LoginSchema
from ahriman.web.schemas.logs_rotate_schema import LogsRotateSchema
from ahriman.web.schemas.logs_schema import LogsSchema
from ahriman.web.schemas.logs_search_schema import LogsSearchSchema
from ahriman.web.schemas.oauth2_schema import OAuth2Schema
from ahriman.web.schemas.package_name_schema import PackageNameSchema
from ahriman.web.schemas.package_names_schema import PackageNamesSchema

View File

@ -0,0 +1,36 @@
#
# Copyright (c) 2021-2025 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 ahriman import __version__
from ahriman.web.apispec import fields
from ahriman.web.schemas.pagination_schema import PaginationSchema
class LogsSearchSchema(PaginationSchema):
"""
request log search schema
"""
version = fields.String(metadata={
"description": "Package version to search",
"example": __version__,
})
process_id = fields.String(metadata={
"description": "Process unique identifier to search",
})

View File

@ -90,7 +90,7 @@ class LogsView(StatusViewGuard, BaseView):
try:
_, status = self.service().package_get(package_base)
logs = self.service(package_base=package_base).package_logs_get(package_base, -1, 0)
logs = self.service(package_base=package_base).package_logs_get(package_base, None, None, -1, 0)
except UnknownPackageError:
raise HTTPNotFound(reason=f"Package {package_base} is unknown")

View File

@ -22,7 +22,7 @@ from typing import ClassVar
from ahriman.models.user_access import UserAccess
from ahriman.web.apispec.decorators import apidocs
from ahriman.web.schemas import LogSchema, PackageNameSchema, PaginationSchema
from ahriman.web.schemas import LogSchema, LogsSearchSchema, PackageNameSchema
from ahriman.web.views.base import BaseView
from ahriman.web.views.status_view_guard import StatusViewGuard
@ -47,7 +47,7 @@ class LogsView(StatusViewGuard, BaseView):
error_404_description="Package base and/or repository are unknown",
schema=LogSchema(many=True),
match_schema=PackageNameSchema,
query_schema=PaginationSchema,
query_schema=LogsSearchSchema,
)
async def get(self) -> Response:
"""
@ -61,8 +61,10 @@ class LogsView(StatusViewGuard, BaseView):
"""
package_base = self.request.match_info["package"]
limit, offset = self.page()
version = self.request.query.get("version", None)
process = self.request.query.get("process_id", None)
logs = self.service(package_base=package_base).package_logs_get(package_base, limit, offset)
logs = self.service(package_base=package_base).package_logs_get(package_base, version, process, limit, offset)
response = [log_record.view() for log_record in logs]
return json_response(response)