Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add fields to store when an event was acknowledged and by whom #278

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Dockerfile-dev
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM pyroapi:python3.8-alpine3.10
FROM pyronear/pyro-api:python3.8-alpine3.10

# copy requirements file
COPY requirements-dev.txt requirements-dev.txt
Expand Down
7 changes: 6 additions & 1 deletion src/app/api/endpoints/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# This program is licensed under the Apache License 2.0.
# See LICENSE or go to <https://opensource.org/licenses/Apache-2.0> for full license details.

from datetime import datetime
from typing import List, cast

from fastapi import APIRouter, Depends, Path, Security, status
Expand Down Expand Up @@ -103,7 +104,11 @@ async def acknowledge_event(
"""
requested_group_id = await get_entity_group_id(events, event_id)
await check_group_update(requester.id, cast(int, requested_group_id))
return await crud.update_entry(events, Acknowledgement(is_acknowledged=True), event_id)
return await crud.update_entry(
events,
Acknowledgement(is_acknowledged=True, acknowledged_by=requester.id, acknowledged_ts=datetime.utcnow()),
event_id,
)


@router.delete("/{event_id}/", response_model=EventOut, summary="Delete a specific event")
Expand Down
5 changes: 4 additions & 1 deletion src/app/models/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import enum

from sqlalchemy import Boolean, Column, DateTime, Enum, Float, Integer
from sqlalchemy import Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer
from sqlalchemy.orm import RelationshipProperty, relationship
from sqlalchemy.sql import func

Expand All @@ -28,9 +28,12 @@ class Event(Base):
start_ts = Column(DateTime, default=func.now())
end_ts = Column(DateTime, default=None, nullable=True)
is_acknowledged = Column(Boolean, default=False)
acknowledged_by = Column(Integer, ForeignKey("users.id"))
acknowledged_ts = Column(DateTime, default=None, nullable=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to follow the other named fields, perhaps a "acknowledged_at"?

created_at = Column(DateTime, default=func.now())

alerts: RelationshipProperty = relationship("Alert", back_populates="event")
acknowledger: RelationshipProperty = relationship("User", back_populates="acknowledged_events")

def __repr__(self):
return (
Expand Down
1 change: 1 addition & 0 deletions src/app/models/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class User(Base):

access: RelationshipProperty = relationship("Access", uselist=False, back_populates="user")
device: RelationshipProperty = relationship("Device", uselist=False, back_populates="owner")
acknowledged_events: RelationshipProperty = relationship("Event", back_populates="acknowledger")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmmh, that's a tricky column to maintain I think?
We could get that information by querying the event table with the user.id. Especially for French regions were everyone uses the same login, that field value could become huge otherwise


def __repr__(self):
return f"<User(login='{self.login}', created_at='{self.created_at}'>"
7 changes: 7 additions & 0 deletions src/app/schemas/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@ class EventIn(_FlatLocation):
None, description="timestamp of event end", example=datetime.utcnow().replace(tzinfo=None)
)
is_acknowledged: bool = Field(False, description="whether the event has been acknowledged")
acknowledged_by: Optional[int] = Field(None, description="id of the user who acknowledged the event")
acknowledged_ts: Optional[datetime] = Field(None, description="event acknowledgement timestamp")

_validate_start_ts = validator("start_ts", pre=True, always=True, allow_reuse=True)(validate_datetime_none)
_validate_end_ts = validator("end_ts", pre=True, always=True, allow_reuse=True)(validate_datetime_none)
_validate_ack_ts = validator("acknowledged_ts", pre=True, always=True, allow_reuse=True)(validate_datetime_none)


class EventOut(EventIn, _CreatedAt, _Id):
Expand All @@ -36,6 +39,10 @@ class EventOut(EventIn, _CreatedAt, _Id):

class Acknowledgement(BaseModel):
is_acknowledged: bool = Field(False, description="whether the event has been acknowledged")
acknowledged_by: Optional[int] = Field(None, description="id of the user who acknowledged the event")
acknowledged_ts: Optional[datetime] = Field(None, description="event acknowledgement timestamp")

_validate_ack_ts = validator("acknowledged_ts", pre=True, always=True, allow_reuse=True)(validate_datetime_none)


class AcknowledgementOut(Acknowledgement, _Id):
Expand Down
17 changes: 15 additions & 2 deletions src/tests/routes/test_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"start_ts": "2020-09-13T08:18:45.447773",
"end_ts": "2020-09-13T08:18:45.447773",
"is_acknowledged": True,
"acknowledged_by": 2,
"acknowledged_ts": "2020-09-13T08:18:45.447773",
"created_at": "2020-10-13T08:18:45.447773",
},
{
Expand All @@ -34,6 +36,8 @@
"start_ts": "2020-09-13T08:18:45.447773",
"end_ts": None,
"is_acknowledged": True,
"acknowledged_by": 2,
"acknowledged_ts": "2020-09-13T08:18:45.447773",
"created_at": "2020-09-13T08:18:45.447773",
},
{
Expand All @@ -44,6 +48,8 @@
"start_ts": "2021-03-13T08:18:45.447773",
"end_ts": "2021-03-13T10:18:45.447773",
"is_acknowledged": False,
"acknowledged_by": None,
"acknowledged_ts": None,
"created_at": "2020-09-13T08:18:45.447773",
},
]
Expand Down Expand Up @@ -274,10 +280,14 @@ async def test_create_event(test_app_asyncio, init_test_db, test_db, access_idx,
if response.status_code // 100 == 2:
json_response = response.json()
test_response = {"id": len(EVENT_TABLE) + 1, **payload, "end_ts": None, "is_acknowledged": False}
assert {k: v for k, v in json_response.items() if k not in ("created_at", "start_ts")} == test_response
assert {
k: v
for k, v in json_response.items()
if k not in ("created_at", "start_ts", "acknowledged_ts", "acknowledged_by")
} == test_response
new_event_in_db = await get_entry(test_db, db.events, json_response["id"])
new_event_in_db = dict(**new_event_in_db)
assert new_event_in_db["created_at"] > utc_dt and new_event_in_db["created_at"] < datetime.utcnow()
assert utc_dt < new_event_in_db["created_at"] < datetime.utcnow()


@pytest.mark.parametrize(
Expand Down Expand Up @@ -474,6 +484,7 @@ async def test_acknowledge_event(
if isinstance(access_idx, int):
auth = await pytest.get_token(ACCESS_TABLE[access_idx]["id"], ACCESS_TABLE[access_idx]["scope"].split())

utc_dt = datetime.utcnow()
response = await test_app_asyncio.put(f"/events/{event_id}/acknowledge", headers=auth)
assert response.status_code == status_code
if isinstance(status_details, str):
Expand All @@ -483,6 +494,8 @@ async def test_acknowledge_event(
updated_event = await get_entry(test_db, db.events, event_id)
updated_event = dict(**updated_event)
assert updated_event["is_acknowledged"]
assert updated_event["acknowledged_by"] == ACCESS_TABLE[access_idx]["id"]
assert utc_dt < updated_event["acknowledged_ts"] < datetime.utcnow()


@pytest.mark.parametrize(
Expand Down
4 changes: 3 additions & 1 deletion src/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

def update_only_datetime(entity_as_dict: Dict[str, Any]):
return {
k: parse_time(v) if isinstance(v, str) and k in ("created_at", "start_ts", "end_ts", "last_ping") else v
k: parse_time(v)
if isinstance(v, str) and k in ("created_at", "start_ts", "end_ts", "last_ping", "acknowledged_ts")
else v
for k, v in entity_as_dict.items()
}

Expand Down