Files
GIA/core/presence/query.py

60 lines
1.7 KiB
Python

from __future__ import annotations
from django.db.models import Q
from core.models import ContactAvailabilityEvent, ContactAvailabilitySpan, Person, User
from .engine import ensure_fading_state
from .inference import now_ms
def spans_for_range(
*,
user: User,
person: Person,
start_ts: int,
end_ts: int,
service: str = "",
limit: int = 200,
):
qs = ContactAvailabilitySpan.objects.filter(
user=user,
person=person,
).filter(Q(start_ts__lte=end_ts) & Q(end_ts__gte=start_ts))
if service:
qs = qs.filter(service=str(service).strip().lower())
ensure_fading_state(
user=user,
person=person,
person_identifier=None,
service=(str(service or "").strip().lower() or "signal"),
at_ts=now_ms(),
)
return list(qs.order_by("-end_ts")[: max(1, min(int(limit or 200), 500))])
def latest_state_for_people(*, user: User, person_ids: list, service: str = "") -> dict:
out = {}
if not person_ids:
return out
qs = ContactAvailabilityEvent.objects.filter(user=user, person_id__in=person_ids)
if service:
qs = qs.filter(service=str(service).strip().lower())
rows = list(qs.order_by("person_id", "-ts", "-id"))
seen = set()
for row in rows:
person_key = str(row.person_id)
if person_key in seen:
continue
seen.add(person_key)
out[person_key] = {
"state": str(row.availability_state or "unknown"),
"confidence": float(row.confidence or 0.0),
"service": str(row.service or ""),
"ts": int(row.ts or 0),
"source_kind": str(row.source_kind or ""),
}
return out