mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
refactor: allow event to receive keyword arguments
This change also replaces the dataclass implementation of the class to custom one
This commit is contained in:
parent
23cd843e44
commit
31e59df2c8
@ -116,6 +116,14 @@ ahriman.core.database.migrations.m013\_dependencies module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.database.migrations.m014\_auditlog module
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.migrations.m014_auditlog
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
Module contents
|
Module contents
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -36,6 +36,14 @@ ahriman.core.database.operations.dependencies\_operations module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.database.operations.event\_operations module
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.database.operations.event_operations
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.core.database.operations.logs\_operations module
|
ahriman.core.database.operations.logs\_operations module
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
@ -68,6 +68,14 @@ ahriman.models.dependencies module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.models.event module
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.event
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.models.filesystem\_package module
|
ahriman.models.filesystem\_package module
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
@ -100,6 +108,14 @@ ahriman.models.log\_record\_id module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.models.metrics\_timer module
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.models.metrics_timer
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.models.migration module
|
ahriman.models.migration module
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
|
@ -60,6 +60,22 @@ ahriman.web.schemas.error\_schema module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.web.schemas.event\_schema module
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.schemas.event_schema
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.web.schemas.event\_search\_schema module
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.schemas.event_search_schema
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.web.schemas.file\_schema module
|
ahriman.web.schemas.file\_schema module
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
21
docs/ahriman.web.views.v1.auditlog.rst
Normal file
21
docs/ahriman.web.views.v1.auditlog.rst
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
ahriman.web.views.v1.auditlog package
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Submodules
|
||||||
|
----------
|
||||||
|
|
||||||
|
ahriman.web.views.v1.auditlog.events module
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.v1.auditlog.events
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
Module contents
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.web.views.v1.auditlog
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
@ -7,6 +7,7 @@ Subpackages
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 4
|
:maxdepth: 4
|
||||||
|
|
||||||
|
ahriman.web.views.v1.auditlog
|
||||||
ahriman.web.views.v1.distributed
|
ahriman.web.views.v1.distributed
|
||||||
ahriman.web.views.v1.packages
|
ahriman.web.views.v1.packages
|
||||||
ahriman.web.views.v1.service
|
ahriman.web.views.v1.service
|
||||||
|
@ -48,13 +48,8 @@ class EventOperations(Operations):
|
|||||||
|
|
||||||
def run(connection: Connection) -> list[Event]:
|
def run(connection: Connection) -> list[Event]:
|
||||||
return [
|
return [
|
||||||
Event(
|
Event.from_json(row)
|
||||||
event=row["event"],
|
for row in connection.execute(
|
||||||
object_id=row["object_id"],
|
|
||||||
message=row["message"],
|
|
||||||
data=row["data"],
|
|
||||||
created=row["created"],
|
|
||||||
) for row in connection.execute(
|
|
||||||
"""
|
"""
|
||||||
select created, event, object_id, message, data from auditlog
|
select created, event, object_id, message, data from auditlog
|
||||||
where (:event is null or event = :event)
|
where (:event is null or event = :event)
|
||||||
|
@ -17,11 +17,10 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from dataclasses import dataclass, field, fields
|
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
from typing import Any, Self
|
from typing import Any, Self
|
||||||
|
|
||||||
from ahriman.core.utils import dataclass_view, filter_json, utcnow
|
from ahriman.core.utils import utcnow
|
||||||
|
|
||||||
|
|
||||||
class EventType(StrEnum):
|
class EventType(StrEnum):
|
||||||
@ -41,7 +40,6 @@ class EventType(StrEnum):
|
|||||||
PackageUpdated = "package-updated"
|
PackageUpdated = "package-updated"
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class Event:
|
class Event:
|
||||||
"""
|
"""
|
||||||
audit log event
|
audit log event
|
||||||
@ -54,18 +52,24 @@ class Event:
|
|||||||
object_id(str): object identifier
|
object_id(str): object identifier
|
||||||
"""
|
"""
|
||||||
|
|
||||||
event: str | EventType
|
def __init__(self, event: str | EventType, object_id: str, message: str | None = None, created: int | None = None,
|
||||||
object_id: str
|
**kwargs: Any):
|
||||||
message: str | None = None
|
"""
|
||||||
data: dict[str, Any] = field(default_factory=dict)
|
default constructor
|
||||||
created: int = field(default_factory=lambda: int(utcnow().timestamp()))
|
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
Args:
|
||||||
|
event(str | EventType): event type
|
||||||
|
object_id(str): object identifier
|
||||||
|
message(str | None): event message if available
|
||||||
|
created(int | None, optional): event timestamp (Default value = None)
|
||||||
|
**kwargs(Any): event metadata
|
||||||
"""
|
"""
|
||||||
convert event type to enum if it is a well-known event type
|
self.event = EventType(event) if event in EventType else event
|
||||||
"""
|
self.object_id = object_id
|
||||||
if self.event in EventType:
|
self.created = created or int(utcnow().timestamp())
|
||||||
object.__setattr__(self, "event", EventType(self.event))
|
|
||||||
|
self.message = message
|
||||||
|
self.data = kwargs
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_json(cls, dump: dict[str, Any]) -> Self:
|
def from_json(cls, dump: dict[str, Any]) -> Self:
|
||||||
@ -78,9 +82,25 @@ class Event:
|
|||||||
Returns:
|
Returns:
|
||||||
Self: dependencies object
|
Self: dependencies object
|
||||||
"""
|
"""
|
||||||
# filter to only known fields
|
return cls(
|
||||||
known_fields = [pair.name for pair in fields(cls)]
|
event=dump["event"],
|
||||||
return cls(**filter_json(dump, known_fields))
|
object_id=dump["object_id"],
|
||||||
|
message=dump.get("message"),
|
||||||
|
created=dump.get("created"),
|
||||||
|
**dump.get("data", {}),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get(self, key: str) -> Any:
|
||||||
|
"""
|
||||||
|
get a property
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key(str): key to lookup in data
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Any: metadata property if available or ``None`` otherwise
|
||||||
|
"""
|
||||||
|
return self.data.get(key)
|
||||||
|
|
||||||
def view(self) -> dict[str, Any]:
|
def view(self) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
@ -89,4 +109,32 @@ class Event:
|
|||||||
Returns:
|
Returns:
|
||||||
dict[str, Any]: json-friendly dictionary
|
dict[str, Any]: json-friendly dictionary
|
||||||
"""
|
"""
|
||||||
return dataclass_view(self)
|
dump = {
|
||||||
|
"event": self.event,
|
||||||
|
"object_id": self.object_id,
|
||||||
|
"created": self.created,
|
||||||
|
}
|
||||||
|
if self.message is not None:
|
||||||
|
dump["message"] = self.message
|
||||||
|
if self.data:
|
||||||
|
dump["data"] = self.data
|
||||||
|
|
||||||
|
return dump
|
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool:
|
||||||
|
"""
|
||||||
|
check if other is the same object
|
||||||
|
|
||||||
|
Args:
|
||||||
|
other(Any): other object instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if the other object is the same and ``False`` otherwise
|
||||||
|
"""
|
||||||
|
if not isinstance(other, Event):
|
||||||
|
return False
|
||||||
|
return self.event == other.event \
|
||||||
|
and self.object_id == other.object_id \
|
||||||
|
and self.message == other.message \
|
||||||
|
and self.created == other.created \
|
||||||
|
and self.data == other.data
|
||||||
|
@ -8,7 +8,7 @@ def test_event_insert_get(database: SQLite, package_ahriman: Package) -> None:
|
|||||||
"""
|
"""
|
||||||
must insert and get event
|
must insert and get event
|
||||||
"""
|
"""
|
||||||
event = Event(EventType.PackageUpdated, package_ahriman.base, "Updated", {"key": "value"})
|
event = Event(EventType.PackageUpdated, package_ahriman.base, "Updated", key="value")
|
||||||
database.event_insert(event)
|
database.event_insert(event)
|
||||||
assert database.event_get() == [event]
|
assert database.event_get() == [event]
|
||||||
|
|
||||||
|
@ -1,17 +1,57 @@
|
|||||||
from ahriman.models.event import Event, EventType
|
from ahriman.models.event import Event, EventType
|
||||||
|
|
||||||
|
|
||||||
def test_post_init() -> None:
|
def test_init() -> None:
|
||||||
"""
|
"""
|
||||||
must replace event type for known types
|
must replace event type for known types
|
||||||
"""
|
"""
|
||||||
assert Event("random", "")
|
assert Event("random", "")
|
||||||
assert isinstance(Event(str(EventType.PackageUpdated), "").event, EventType)
|
assert isinstance(Event(str(EventType.PackageUpdated), "").event, EventType)
|
||||||
|
|
||||||
|
assert Event("", "", key="value").data == {"key": "value"}
|
||||||
|
|
||||||
|
assert Event("", "").created > 0
|
||||||
|
|
||||||
|
|
||||||
def test_from_json_view() -> None:
|
def test_from_json_view() -> None:
|
||||||
"""
|
"""
|
||||||
must construct and serialize event to json
|
must construct and serialize event to json
|
||||||
"""
|
"""
|
||||||
event = Event("event", "object", "message", {"key": "value"})
|
event = Event("event", "object", "message", key="value")
|
||||||
assert Event.from_json(event.view()) == event
|
assert Event.from_json(event.view()) == event
|
||||||
|
|
||||||
|
|
||||||
|
def test_get() -> None:
|
||||||
|
"""
|
||||||
|
must return property correctly
|
||||||
|
"""
|
||||||
|
assert Event("event", "object", "message", key="value").get("key") == "value"
|
||||||
|
assert Event("event", "object").get("key") is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_view_empty() -> None:
|
||||||
|
"""
|
||||||
|
must skip empty fields during (de-)serialization
|
||||||
|
"""
|
||||||
|
event = Event("event", "object")
|
||||||
|
assert Event.from_json(event.view()) == event
|
||||||
|
assert "message" not in event.view()
|
||||||
|
assert "data" not in event.view()
|
||||||
|
|
||||||
|
|
||||||
|
def test_eq() -> None:
|
||||||
|
"""
|
||||||
|
must compare two events
|
||||||
|
"""
|
||||||
|
event1 = Event("1", "1", "1", 1, key="value")
|
||||||
|
assert event1 == event1
|
||||||
|
|
||||||
|
event2 = Event("2", "2", "2", 2, key="value")
|
||||||
|
assert event1 != event2
|
||||||
|
|
||||||
|
|
||||||
|
def test_eq_other() -> None:
|
||||||
|
"""
|
||||||
|
must return False in case if object is not an instance of event
|
||||||
|
"""
|
||||||
|
assert Event("1", "1") != 42
|
||||||
|
@ -27,7 +27,7 @@ async def test_get(client: TestClient) -> None:
|
|||||||
"""
|
"""
|
||||||
must return all events
|
must return all events
|
||||||
"""
|
"""
|
||||||
event1 = Event("event1", "object1", "message", {"key": "value"})
|
event1 = Event("event1", "object1", "message", key="value")
|
||||||
event2 = Event("event2", "object2")
|
event2 = Event("event2", "object2")
|
||||||
await client.post("/api/v1/events", json=event1.view())
|
await client.post("/api/v1/events", json=event1.view())
|
||||||
await client.post("/api/v1/events", json=event2.view())
|
await client.post("/api/v1/events", json=event2.view())
|
||||||
@ -46,7 +46,7 @@ async def test_get_with_pagination(client: TestClient) -> None:
|
|||||||
"""
|
"""
|
||||||
must get events with pagination
|
must get events with pagination
|
||||||
"""
|
"""
|
||||||
event1 = Event("event1", "object1", "message", {"key": "value"})
|
event1 = Event("event1", "object1", "message", key="value")
|
||||||
event2 = Event("event2", "object2")
|
event2 = Event("event2", "object2")
|
||||||
await client.post("/api/v1/events", json=event1.view())
|
await client.post("/api/v1/events", json=event1.view())
|
||||||
await client.post("/api/v1/events", json=event2.view())
|
await client.post("/api/v1/events", json=event2.view())
|
||||||
@ -83,7 +83,7 @@ async def test_post(client: TestClient) -> None:
|
|||||||
"""
|
"""
|
||||||
must create event
|
must create event
|
||||||
"""
|
"""
|
||||||
event = Event("event1", "object1", "message", {"key": "value"})
|
event = Event("event1", "object1", "message", key="value")
|
||||||
request_schema = pytest.helpers.schema_request(EventsView.post)
|
request_schema = pytest.helpers.schema_request(EventsView.post)
|
||||||
|
|
||||||
payload = event.view()
|
payload = event.view()
|
||||||
|
Loading…
Reference in New Issue
Block a user