254 lines
8.1 KiB
Python
254 lines
8.1 KiB
Python
from collections.abc import Mapping
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from sqlalchemy import text
|
|
|
|
from banban.dao import BaseDAO
|
|
|
|
|
|
class DeviceAlarmDAO(BaseDAO):
|
|
async def create(
|
|
self,
|
|
*,
|
|
device_id: str,
|
|
owner_user_id: int | None,
|
|
child_id: int | None,
|
|
source_msg_id: str = "010",
|
|
location: Mapping[str, Any] | None = None,
|
|
) -> int:
|
|
location = location or {}
|
|
address = str(location.get("address") or "").strip() or None
|
|
address_status = location.get("address_resolve_status")
|
|
if address and address_status is None:
|
|
address_status = 1
|
|
elif address_status is None and location.get("lat") is not None and location.get("lng") is not None:
|
|
address_status = 0
|
|
result = await self.execute(
|
|
"""
|
|
INSERT INTO device_alarm_events (
|
|
device_id,
|
|
owner_user_id,
|
|
child_id,
|
|
source_msg_id,
|
|
coord_type,
|
|
lat,
|
|
lng,
|
|
location_updated_at,
|
|
address,
|
|
address_resolved_at,
|
|
address_resolve_status,
|
|
created_at
|
|
)
|
|
VALUES (
|
|
:device_id,
|
|
:owner_user_id,
|
|
:child_id,
|
|
:source_msg_id,
|
|
:coord_type,
|
|
:lat,
|
|
:lng,
|
|
:location_updated_at,
|
|
:address,
|
|
:address_resolved_at,
|
|
:address_resolve_status,
|
|
CURRENT_TIMESTAMP
|
|
)
|
|
""",
|
|
{
|
|
"device_id": device_id,
|
|
"owner_user_id": owner_user_id,
|
|
"child_id": child_id,
|
|
"source_msg_id": source_msg_id,
|
|
"coord_type": location.get("coord_type"),
|
|
"lat": location.get("lat"),
|
|
"lng": location.get("lng"),
|
|
"location_updated_at": location.get("updated_at"),
|
|
"address": address,
|
|
"address_resolved_at": location.get("address_resolved_at"),
|
|
"address_resolve_status": address_status,
|
|
},
|
|
)
|
|
await self.commit()
|
|
return int(result.lastrowid)
|
|
|
|
async def get_by_id(self, *, alarm_id: int, device_id: str | None = None) -> Mapping[str, Any] | None:
|
|
where_device = "AND device_id = :device_id" if device_id is not None else ""
|
|
params: dict[str, Any] = {"alarm_id": alarm_id}
|
|
if device_id is not None:
|
|
params["device_id"] = device_id
|
|
|
|
result = await self.execute(
|
|
text(
|
|
f"""
|
|
SELECT
|
|
alarm_id,
|
|
device_id,
|
|
owner_user_id,
|
|
child_id,
|
|
source_msg_id,
|
|
coord_type,
|
|
lat,
|
|
lng,
|
|
location_updated_at,
|
|
address,
|
|
address_resolved_at,
|
|
address_resolve_status,
|
|
created_at
|
|
FROM device_alarm_events
|
|
WHERE alarm_id = :alarm_id
|
|
{where_device}
|
|
LIMIT 1
|
|
"""
|
|
),
|
|
params,
|
|
)
|
|
return result.mappings().first()
|
|
|
|
async def get_current_location_snapshot(self, *, child_id: int) -> Mapping[str, Any] | None:
|
|
result = await self.execute(
|
|
text(
|
|
"""
|
|
SELECT
|
|
coord_type,
|
|
lat,
|
|
lng,
|
|
updated_at,
|
|
address,
|
|
address_resolved_at,
|
|
address_resolve_status
|
|
FROM child_location_current
|
|
WHERE child_id = :child_id
|
|
LIMIT 1
|
|
"""
|
|
),
|
|
{"child_id": child_id},
|
|
)
|
|
return result.mappings().first()
|
|
|
|
async def update_resolved_address(
|
|
self,
|
|
*,
|
|
alarm_id: int,
|
|
address: str | None,
|
|
status: int,
|
|
) -> bool:
|
|
result = await self.execute(
|
|
text(
|
|
"""
|
|
UPDATE device_alarm_events
|
|
SET address = :address,
|
|
address_resolve_status = :status,
|
|
address_resolved_at = CURRENT_TIMESTAMP
|
|
WHERE alarm_id = :alarm_id
|
|
"""
|
|
),
|
|
{
|
|
"alarm_id": alarm_id,
|
|
"address": address,
|
|
"status": status,
|
|
},
|
|
)
|
|
await self.commit()
|
|
return bool(result.rowcount)
|
|
|
|
async def update_location_snapshot(
|
|
self,
|
|
*,
|
|
alarm_id: int,
|
|
location: Mapping[str, Any],
|
|
) -> bool:
|
|
lat = location.get("lat")
|
|
lng = location.get("lng")
|
|
address = str(location.get("address") or "").strip() or None
|
|
address_status = location.get("address_resolve_status")
|
|
address_resolved_at = location.get("address_resolved_at")
|
|
if address and address_status is None:
|
|
address_status = 1
|
|
elif address_status is None and lat is not None and lng is not None:
|
|
address_status = 0
|
|
if address and address_resolved_at is None:
|
|
address_resolved_at = datetime.now()
|
|
result = await self.execute(
|
|
text(
|
|
"""
|
|
UPDATE device_alarm_events
|
|
SET coord_type = :coord_type,
|
|
lat = :lat,
|
|
lng = :lng,
|
|
location_updated_at = :location_updated_at,
|
|
address = :address,
|
|
address_resolved_at = :address_resolved_at,
|
|
address_resolve_status = :address_resolve_status
|
|
WHERE alarm_id = :alarm_id
|
|
"""
|
|
),
|
|
{
|
|
"alarm_id": alarm_id,
|
|
"coord_type": location.get("coord_type"),
|
|
"lat": lat,
|
|
"lng": lng,
|
|
"location_updated_at": location.get("updated_at"),
|
|
"address": address,
|
|
"address_resolved_at": address_resolved_at,
|
|
"address_resolve_status": address_status,
|
|
},
|
|
)
|
|
await self.commit()
|
|
return bool(result.rowcount)
|
|
|
|
async def get_active_binding_context(self, *, device_id: str) -> Mapping[str, Any] | None:
|
|
result = await self.execute(
|
|
text(
|
|
"""
|
|
SELECT owner_user_id, child_id
|
|
FROM device_bindings
|
|
WHERE device_id = :device_id
|
|
AND status = 1
|
|
LIMIT 1
|
|
"""
|
|
),
|
|
{"device_id": device_id},
|
|
)
|
|
return result.mappings().first()
|
|
|
|
async def list_by_device(
|
|
self,
|
|
*,
|
|
device_id: str,
|
|
limit: int,
|
|
) -> list[Mapping[str, Any]]:
|
|
result = await self.execute(
|
|
text(
|
|
"""
|
|
SELECT
|
|
dae.alarm_id,
|
|
dae.device_id,
|
|
dae.owner_user_id,
|
|
dae.child_id,
|
|
dae.source_msg_id,
|
|
dae.coord_type,
|
|
dae.lat,
|
|
dae.lng,
|
|
dae.location_updated_at,
|
|
dae.address,
|
|
dae.address_resolved_at,
|
|
dae.address_resolve_status,
|
|
dae.created_at,
|
|
c.child_name
|
|
FROM device_alarm_events AS dae
|
|
LEFT JOIN children AS c
|
|
ON c.child_id = dae.child_id
|
|
AND c.status = 1
|
|
WHERE dae.device_id = :device_id
|
|
ORDER BY dae.created_at DESC, dae.alarm_id DESC
|
|
LIMIT :limit
|
|
"""
|
|
),
|
|
{
|
|
"device_id": device_id,
|
|
"limit": limit,
|
|
},
|
|
)
|
|
return list(result.mappings().all())
|