From 25530c7c94c4d5b7867279c0f2d251a14af4cbfb Mon Sep 17 00:00:00 2001 From: Christian Date: Mon, 4 May 2026 19:20:55 +0200 Subject: [PATCH] release: v2.2.81 contacts visibility and telephony/date/deploy fixes --- RELEASE_NOTES_v2.2.81.md | 29 +++++++++++++++++++ VERSION | 2 +- app/contacts/backend/router_simple.py | 2 +- app/contacts/frontend/contacts.html | 7 ----- app/modules/telefoni/backend/router.py | 26 +++++++++++++---- updateto.sh | 39 ++++++++++++++------------ 6 files changed, 72 insertions(+), 33 deletions(-) create mode 100644 RELEASE_NOTES_v2.2.81.md mode change 100644 => 100755 updateto.sh diff --git a/RELEASE_NOTES_v2.2.81.md b/RELEASE_NOTES_v2.2.81.md new file mode 100644 index 0000000..f312f2e --- /dev/null +++ b/RELEASE_NOTES_v2.2.81.md @@ -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 +``` diff --git a/VERSION b/VERSION index ceadef4..4a3f268 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.2.80 +2.2.81 diff --git a/app/contacts/backend/router_simple.py b/app/contacts/backend/router_simple.py index 349ddc1..5d1ecfe 100644 --- a/app/contacts/backend/router_simple.py +++ b/app/contacts/backend/router_simple.py @@ -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]) diff --git a/app/contacts/frontend/contacts.html b/app/contacts/frontend/contacts.html index 1f1d3d6..22fd7f9 100644 --- a/app/contacts/frontend/contacts.html +++ b/app/contacts/frontend/contacts.html @@ -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(); diff --git a/app/modules/telefoni/backend/router.py b/app/modules/telefoni/backend/router.py index 6c00a2e..df2aeab 100644 --- a/app/modules/telefoni/backend/router.py +++ b/app/modules/telefoni/backend/router.py @@ -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") diff --git a/updateto.sh b/updateto.sh old mode 100644 new mode 100755 index c7a1fe6..4637817 --- a/updateto.sh +++ b/updateto.sh @@ -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" \ + podman ps -a --format '{{.Names}} {{.Ports}}' \ + | grep -E "${POSTGRES_BIND_ADDR}:${POSTGRES_PORT}->5432/tcp" \ + | 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,19 +219,19 @@ 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)" sleep 2 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" \ + echo "📄 Kører alle migrations fra /docker-entrypoint-initdb.d (sorteret)..." + 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"