release: v2.2.81 contacts visibility and telephony/date/deploy fixes

This commit is contained in:
Christian 2026-05-04 19:20:55 +02:00
parent 8ec9400b15
commit 25530c7c94
6 changed files with 72 additions and 33 deletions

29
RELEASE_NOTES_v2.2.81.md Normal file
View File

@ -0,0 +1,29 @@
# Release Notes v2.2.81
Dato: 2026-05-04
## Fixes
- Kontakter: Stabiliseret paginering i `/api/v1/contacts` ved at tilfoeje deterministisk tie-break (`ORDER BY ... , c.id`).
- Kontakter: Fjernet skrøbelig frontend query-key short-circuit i kontaktlisten, som kunne medfoere at listen ikke blev genindlaest korrekt efter afbrudte requests.
- Telefoni: Rettet datofilter i `/api/v1/telefoni/calls` saa `date_to` er inklusiv hele dagen.
- Telefoni: Validerer nu tydeligt `date_from`/`date_to` format (`YYYY-MM-DD`) med 422 ved ugyldig input.
- Deployment: `updateto.sh` bruger nu dynamiske containernavne baseret paa `STACK_NAME` i stedet for hardcoded `-prod`.
## Beroerte filer
- `app/contacts/backend/router_simple.py`
- `app/contacts/frontend/contacts.html`
- `app/modules/telefoni/backend/router.py`
- `updateto.sh`
- `VERSION`
## Drift
Hvis stacken koerer som `v2`, deploy med:
```bash
sudo -iu bmcadmin
cd /srv/podman/bmc_hub_v2
./updateto.sh v2.2.81
```

View File

@ -1 +1 @@
2.2.80
2.2.81

View File

@ -140,7 +140,7 @@ async def get_contacts(
{where_sql}
GROUP BY c.id, c.first_name, c.last_name, c.email, c.phone, c.mobile,
c.title, c.department, c.user_company, c.is_active, c.created_at, c.updated_at
ORDER BY company_count DESC, c.last_name, c.first_name
ORDER BY company_count DESC, c.last_name, c.first_name, c.id
LIMIT %s OFFSET %s
"""
params.extend([limit, offset])

View File

@ -813,7 +813,6 @@ let searchQuery = '';
let totalContacts = 0;
let searchTimeout = null;
let currentRequestController = null;
let lastLoadedQueryKey = '';
let availableCompanies = [];
let selectedCompanyIds = new Set();
let currentContactsData = [];
@ -941,12 +940,6 @@ async function loadContacts() {
params.append('is_active', 'false');
}
const queryKey = `${currentPage}|${pageSize}|${searchQuery}|${currentFilter}`;
if (queryKey === lastLoadedQueryKey) {
return;
}
lastLoadedQueryKey = queryKey;
const response = await fetch(`/api/v1/contacts?${params}`, { signal: currentRequestController.signal });
const data = await response.json();

View File

@ -3,7 +3,7 @@ import logging
import base64
import ipaddress
import re
from datetime import datetime
from datetime import datetime, timedelta
from typing import Optional
from urllib.error import URLError, HTTPError
from urllib.request import Request as UrlRequest, urlopen
@ -653,15 +653,29 @@ async def list_calls(
where = []
params = []
parsed_date_from = None
parsed_date_to = None
if date_from:
try:
parsed_date_from = datetime.strptime(date_from, "%Y-%m-%d")
except ValueError:
raise HTTPException(status_code=422, detail="Invalid date_from format, expected YYYY-MM-DD")
if date_to:
try:
# Make date_to inclusive for the whole selected day.
parsed_date_to = datetime.strptime(date_to, "%Y-%m-%d") + timedelta(days=1)
except ValueError:
raise HTTPException(status_code=422, detail="Invalid date_to format, expected YYYY-MM-DD")
if user_id is not None:
where.append("t.bruger_id = %s")
params.append(user_id)
if date_from:
if parsed_date_from is not None:
where.append("t.started_at >= %s")
params.append(date_from)
if date_to:
where.append("t.started_at <= %s")
params.append(date_to)
params.append(parsed_date_from)
if parsed_date_to is not None:
where.append("t.started_at < %s")
params.append(parsed_date_to)
if without_case:
where.append("t.sag_id IS NULL")

33
updateto.sh Normal file → Executable file
View File

@ -17,6 +17,9 @@ if [ "${EUID:-$(id -u)}" -eq 0 ]; then
fi
PODMAN_COMPOSE_FILE="docker-compose.prod.yml"
STACK_NAME="${STACK_NAME:-prod}"
POSTGRES_CONTAINER="bmc-hub-postgres-${STACK_NAME}"
API_CONTAINER="bmc-hub-api-${STACK_NAME}"
if [ -z "$VERSION" ]; then
echo "❌ Fejl: Ingen version angivet"
@ -103,7 +106,7 @@ fi
# Guard against host port conflicts before attempting startup
POSTGRES_BIND_ADDR="${POSTGRES_BIND_ADDR:-127.0.0.1}"
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
if podman ps --format '{{.Names}} {{.Ports}}' | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" | grep -v "bmc-hub-postgres-prod" >/dev/null 2>&1; then
if podman ps --format '{{.Names}} {{.Ports}}' | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" | grep -v "$POSTGRES_CONTAINER" >/dev/null 2>&1; then
echo "❌ Fejl: Portkonflikt på ${POSTGRES_BIND_ADDR}:${POSTGRES_PORT} (Postgres host-port)"
echo " Sæt en ledig port i .env, fx POSTGRES_PORT=5433"
podman ps --format 'table {{.Names}}\t{{.Ports}}'
@ -111,11 +114,11 @@ if podman ps --format '{{.Names}} {{.Ports}}' | grep -E "${POSTGRES_BIND_ADDR}:$
fi
# Also detect stopped containers reserving legacy port mappings in config (rootlessport conflicts)
if podman ps -a --format '{{.Names}} {{.Ports}}' | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" | grep -v "bmc-hub-postgres-prod" >/dev/null 2>&1; then
if podman ps -a --format '{{.Names}} {{.Ports}}' | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" | grep -v "$POSTGRES_CONTAINER" >/dev/null 2>&1; then
echo "⚠️ Finder gamle containere med portbinding ${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}; forsøger oprydning..."
podman ps -a --format '{{.Names}} {{.Ports}}' \
| grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" \
| grep -v "bmc-hub-postgres-prod" \
| grep -v "$POSTGRES_CONTAINER" \
| awk '{print $1}' \
| while read -r holder; do
[ -z "$holder" ] && continue
@ -140,14 +143,14 @@ if ! podman-compose -f "$PODMAN_COMPOSE_FILE" build --no-cache && podman-compose
fi
# Validate that key containers are actually running after startup
if ! podman ps --format '{{.Names}}' | grep -q '^bmc-hub-postgres-prod$'; then
echo "❌ Fejl: bmc-hub-postgres-prod kører ikke efter startup"
if ! podman ps --format '{{.Names}}' | grep -q "^${POSTGRES_CONTAINER}$"; then
echo "❌ Fejl: ${POSTGRES_CONTAINER} kører ikke efter startup"
podman ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
exit 1
fi
if ! podman ps --format '{{.Names}}' | grep -q '^bmc-hub-api-prod$'; then
echo "❌ Fejl: bmc-hub-api-prod kører ikke efter startup"
if ! podman ps --format '{{.Names}}' | grep -q "^${API_CONTAINER}$"; then
echo "❌ Fejl: ${API_CONTAINER} kører ikke efter startup"
podman ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
exit 1
fi
@ -165,7 +168,7 @@ done
if [ "$HEALTH_OK" != "true" ]; then
echo "❌ Fejl: API health fejlede på http://localhost:${API_PORT}/health"
podman logs --tail 120 bmc-hub-api-prod || true
podman logs --tail 120 "$API_CONTAINER" || true
exit 1
fi
@ -175,7 +178,7 @@ echo "📁 Syncer migrations fra container til host..."
SYNC_OK=false
for i in {1..20}; do
rm -rf ./migrations_temp
if podman cp bmc-hub-api-prod:/app/migrations ./migrations_temp 2>/dev/null; then
if podman cp "$API_CONTAINER":/app/migrations ./migrations_temp 2>/dev/null; then
rm -rf ./migrations
mv ./migrations_temp ./migrations
chmod -R 755 ./migrations
@ -188,7 +191,7 @@ for i in {1..20}; do
done
if [ "$SYNC_OK" != "true" ]; then
echo "❌ Fejl: Kunne ikke sync'e migrations fra bmc-hub-api-prod:/app/migrations"
echo "❌ Fejl: Kunne ikke sync'e migrations fra ${API_CONTAINER}:/app/migrations"
echo " Afbryder for at undgå kørsel af gamle migrations"
exit 1
fi
@ -216,7 +219,7 @@ if [ "${RUN_MIGRATIONS:-false}" = "true" ]; then
fi
for i in {1..30}; do
if podman exec bmc-hub-postgres-prod pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" >/dev/null 2>&1; then
if podman exec "$POSTGRES_CONTAINER" pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" >/dev/null 2>&1; then
break
fi
echo "⏳ Venter på postgres... ($i/30)"
@ -224,11 +227,11 @@ if [ "${RUN_MIGRATIONS:-false}" = "true" ]; then
done
echo "📄 Kører alle migrations fra /docker-entrypoint-initdb.d (sorteret)..."
podman exec bmc-hub-postgres-prod sh -lc "ls -1 /docker-entrypoint-initdb.d/*.sql 2>/dev/null | sort" \
podman exec "$POSTGRES_CONTAINER" sh -lc "ls -1 /docker-entrypoint-initdb.d/*.sql 2>/dev/null | sort" \
| while read -r file; do
[ -z "$file" ] && continue
echo "➡️ $file"
podman exec -i bmc-hub-postgres-prod psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" -f "$file"
podman exec -i "$POSTGRES_CONTAINER" psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" -f "$file"
done
echo "✅ Migrations kørt"
@ -240,14 +243,14 @@ fi
echo ""
echo "📋 Logs fra startup:"
echo "================================"
podman logs --tail 50 bmc-hub-api-prod
podman logs --tail 50 "$API_CONTAINER"
echo ""
echo "✅ Deployment fuldført!"
echo ""
echo "🔍 Tjek status med:"
echo " podman-compose -f $PODMAN_COMPOSE_FILE ps"
echo " podman logs -f bmc-hub-api-prod"
echo " podman logs -f ${API_CONTAINER}"
echo ""
echo "🌐 Test health endpoint:"
echo " curl http://localhost:${API_PORT}/health"