Implement Manticore fully and re-theme
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Count, Max, Q
|
||||
from django.shortcuts import render
|
||||
from django.views import View
|
||||
|
||||
from core.models import (
|
||||
ContactAvailabilityEvent,
|
||||
ContactAvailabilitySettings,
|
||||
)
|
||||
from core.events.manticore import get_behavioral_availability_stats
|
||||
from core.events.shadow import get_shadow_behavioral_availability_stats
|
||||
from core.models import ContactAvailabilitySettings, Person
|
||||
|
||||
|
||||
def _to_int(value, default=0):
|
||||
@@ -64,42 +62,105 @@ class AvailabilitySettingsPage(LoginRequiredMixin, View):
|
||||
return self.get(request)
|
||||
|
||||
def get(self, request):
|
||||
settings_row = self._settings(request)
|
||||
contact_stats = list(
|
||||
ContactAvailabilityEvent.objects.filter(
|
||||
user=request.user, person__isnull=False
|
||||
)
|
||||
.values("person_id", "person__name", "service")
|
||||
.annotate(
|
||||
total_events=Count("id"),
|
||||
available_events=Count("id", filter=Q(availability_state="available")),
|
||||
fading_events=Count("id", filter=Q(availability_state="fading")),
|
||||
unavailable_events=Count(
|
||||
"id", filter=Q(availability_state="unavailable")
|
||||
),
|
||||
unknown_events=Count("id", filter=Q(availability_state="unknown")),
|
||||
native_presence_events=Count(
|
||||
"id", filter=Q(source_kind="native_presence")
|
||||
),
|
||||
read_receipt_events=Count("id", filter=Q(source_kind="read_receipt")),
|
||||
typing_events=Count(
|
||||
"id",
|
||||
filter=Q(source_kind="typing_start") | Q(source_kind="typing_stop"),
|
||||
),
|
||||
message_activity_events=Count(
|
||||
"id",
|
||||
filter=Q(source_kind="message_in") | Q(source_kind="message_out"),
|
||||
),
|
||||
inferred_timeout_events=Count(
|
||||
"id", filter=Q(source_kind="inferred_timeout")
|
||||
),
|
||||
last_event_ts=Max("ts"),
|
||||
)
|
||||
.order_by("-total_events", "person__name", "service")
|
||||
)
|
||||
|
||||
behavioral_stats, stats_source = self._behavioral_stats(request.user)
|
||||
transport_stats = self._transport_stats(behavioral_stats)
|
||||
totals = self._totals(behavioral_stats)
|
||||
context = {
|
||||
"settings_row": settings_row,
|
||||
"contact_stats": contact_stats,
|
||||
"settings_row": self._settings(request),
|
||||
"behavioral_stats": behavioral_stats,
|
||||
"behavioral_stats_source": stats_source,
|
||||
"transport_stats": transport_stats,
|
||||
"behavioral_totals": totals,
|
||||
}
|
||||
return render(request, self.template_name, context)
|
||||
|
||||
def _behavioral_stats(self, user):
|
||||
try:
|
||||
person_map = {
|
||||
str(row["id"]): str(row["name"] or "")
|
||||
for row in Person.objects.filter(user=user).values("id", "name")
|
||||
}
|
||||
rows = []
|
||||
for row in list(
|
||||
get_behavioral_availability_stats(user_id=int(user.id)) or []
|
||||
):
|
||||
person_id = str(row.get("person_id") or "").strip()
|
||||
rows.append(
|
||||
{
|
||||
"person_id": person_id,
|
||||
"person_name": person_map.get(person_id, person_id or "-"),
|
||||
"service": str(row.get("transport") or "").strip().lower(),
|
||||
"total_events": _to_int(row.get("total_events"), 0),
|
||||
"presence_events": _to_int(row.get("presence_events"), 0),
|
||||
"read_events": _to_int(row.get("read_events"), 0),
|
||||
"typing_events": _to_int(row.get("typing_events"), 0),
|
||||
"message_events": _to_int(row.get("message_events"), 0),
|
||||
"abandoned_events": _to_int(row.get("abandoned_events"), 0),
|
||||
"last_event_ts": _to_int(row.get("last_event_ts"), 0),
|
||||
}
|
||||
)
|
||||
if rows:
|
||||
return rows, "manticore"
|
||||
except Exception:
|
||||
pass
|
||||
return list(get_shadow_behavioral_availability_stats(user=user)), "conversation_event_shadow"
|
||||
|
||||
def _transport_stats(self, behavioral_stats: list[dict]) -> list[dict]:
|
||||
by_transport = {}
|
||||
for row in list(behavioral_stats or []):
|
||||
service = str(row.get("service") or "").strip().lower() or "-"
|
||||
state = by_transport.setdefault(
|
||||
service,
|
||||
{
|
||||
"service": service,
|
||||
"contacts": 0,
|
||||
"total_events": 0,
|
||||
"presence_events": 0,
|
||||
"read_events": 0,
|
||||
"typing_events": 0,
|
||||
"message_events": 0,
|
||||
"abandoned_events": 0,
|
||||
"last_event_ts": 0,
|
||||
},
|
||||
)
|
||||
state["contacts"] += 1
|
||||
for key in (
|
||||
"total_events",
|
||||
"presence_events",
|
||||
"read_events",
|
||||
"typing_events",
|
||||
"message_events",
|
||||
"abandoned_events",
|
||||
):
|
||||
state[key] += _to_int(row.get(key), 0)
|
||||
state["last_event_ts"] = max(
|
||||
int(state.get("last_event_ts") or 0),
|
||||
_to_int(row.get("last_event_ts"), 0),
|
||||
)
|
||||
return sorted(
|
||||
by_transport.values(),
|
||||
key=lambda row: (-int(row.get("total_events") or 0), str(row.get("service") or "")),
|
||||
)
|
||||
|
||||
def _totals(self, behavioral_stats: list[dict]) -> dict:
|
||||
totals = {
|
||||
"contacts": 0,
|
||||
"total_events": 0,
|
||||
"presence_events": 0,
|
||||
"read_events": 0,
|
||||
"typing_events": 0,
|
||||
"message_events": 0,
|
||||
"abandoned_events": 0,
|
||||
}
|
||||
for row in list(behavioral_stats or []):
|
||||
totals["contacts"] += 1
|
||||
for key in (
|
||||
"total_events",
|
||||
"presence_events",
|
||||
"read_events",
|
||||
"typing_events",
|
||||
"message_events",
|
||||
"abandoned_events",
|
||||
):
|
||||
totals[key] += _to_int(row.get(key), 0)
|
||||
return totals
|
||||
|
||||
Reference in New Issue
Block a user