Release govoplan-notifications v0.1.20: batch attempts and unify multi-select filters

This commit is contained in:
2026-09-08 01:32:46 +02:00
parent 713f2d3c63
commit ca22d9e706
10 changed files with 313 additions and 52 deletions
+47
View File
@@ -5,6 +5,7 @@ import unittest
from unittest.mock import patch
from pathlib import Path
from types import SimpleNamespace
from datetime import datetime, timedelta, timezone
from fastapi import HTTPException
from sqlalchemy import create_engine
@@ -24,6 +25,7 @@ from govoplan_notifications.backend.service import (
NotificationError,
create_notification,
deliver_pending,
list_notifications,
notification_preferences_response,
notification_response,
notification_summary,
@@ -174,6 +176,51 @@ class NotificationServiceTests(unittest.TestCase):
api_get_notification(other_tenant.id, view="personal", session=session, principal=principal)
self.assertEqual(cross_tenant.exception.status_code, 404)
def test_status_multiselection_filters_before_limit_and_preserves_visibility(self) -> None:
with self.Session() as session:
for index, (state, recipient, tenant) in enumerate([
("pending", "user-1", "tenant-1"), ("failed", "user-1", "tenant-1"),
("sent", "user-1", "tenant-1"), ("sent", "user-1", "tenant-1"),
("failed", "user-2", "tenant-1"), ("failed", "user-1", "tenant-2"),
]):
item = create_notification(session, tenant_id=tenant,
payload=self._inbox_payload(recipient_id=recipient, subject=f"Message {index}"))
item.status = state
item.created_at = datetime(2026, 1, 1, tzinfo=timezone.utc) + timedelta(minutes=index)
session.flush()
principal = self._principal(tenant_id="tenant-1", user_id="user-1", account_id="account-1",
scopes={"notifications:notification:read"})
result = api_list_notifications(status_filter=["pending", "failed"], channel=None,
source_module=None, recipient_id=None, view="personal", limit=2, session=session, principal=principal)
self.assertEqual([item.status for item in result.notifications], ["failed", "pending"])
self.assertEqual(list_notifications(session, tenant_id="tenant-1", status=[]), [])
single = list_notifications(session, tenant_id="tenant-1", status="pending")
self.assertEqual(len(single), 1)
def test_http_repeated_status_parameters_use_or_filter(self) -> None:
from fastapi import FastAPI
from fastapi.testclient import TestClient
from govoplan_core.auth import get_api_principal
from govoplan_core.db.session import get_session
from govoplan_notifications.backend.router import router
app = FastAPI()
app.include_router(router)
principal = self._principal(tenant_id="tenant-1", user_id="user-1", account_id="account-1",
scopes={"notifications:notification:read"})
app.dependency_overrides[get_api_principal] = lambda: principal
app.dependency_overrides[get_session] = lambda: object()
with patch("govoplan_notifications.backend.router.get_notification_preferences", return_value=SimpleNamespace(muted_source_modules=[])), \
patch("govoplan_notifications.backend.router.list_notifications", return_value=[]) as listing, TestClient(app) as client:
response = client.get("/notifications?status=pending&status=failed")
self.assertEqual(response.status_code, 200)
self.assertEqual(listing.call_args.kwargs["status"], ["pending", "failed"])
self.assertIn("user-1", listing.call_args.kwargs["recipient_ids"])
self.assertEqual(client.get("/notifications?status=sent").status_code, 200)
self.assertEqual(listing.call_args.kwargs["status"], ["sent"])
self.assertEqual(client.get("/notifications").status_code, 200)
self.assertIsNone(listing.call_args.kwargs["status"])
def test_tenant_notification_view_is_an_explicit_admin_operation(self) -> None:
with self.Session() as session:
another_user = create_notification(