diff --git a/.gitignore b/.gitignore index 36adfde..f1cf96c 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ nowcast-point-*-backup-* point-alarm-registrations-*.csv nowcast-point-registrations.csv nowcast-point-update.csv +nowcast-point-alarm-records-*.csv diff --git a/README.md b/README.md index 46d9e6c..05f532a 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ python nowcast-geo-register.py nowcast-geo-alarm-registrations.csv \ ## Nokta alarm (nowcast point) istemcileri -Nokta alarm istemcileri `BE-NowcastPointAlarm` servisinin `/v1/alarms/points` endpoint'lerini çağırır. Tüm komutlarda `--help` seçeneklerin tam dökümünü verir. Gerçek filtre değerleri için `nowcast-point-alarm-filter.example.json` dosyasını `nowcast-point-alarm-filter.json` olarak kopyalayın (git'e eklenmez). Webhook için mevcut `webhook.json` ve `IKLIM_WEBHOOK_INITIALIZED` mekanizması aynen kullanılır. +Nokta alarm istemcileri `BE-NowcastPointAlarm` servisinin `/v1/alarms/points` endpoint'lerini çağırır. Tüm komutlarda `--help` seçeneklerin tam dökümünü verir. Gerçek filtre değerleri için `nowcast-point-alarm-filter.example.json` dosyasını `nowcast-point-alarm-filter.json` olarak kopyalayın (git'e eklenmez). Webhook için mevcut `webhook.json` kullanılır, ancak geo alarmdan farklı olarak her register isteğinde `webhook.json` içindeki tam webhook (`deliveryPolicy` dahil) gönderilir; `IKLIM_WEBHOOK_INITIALIZED` ve `/v1/users/me` kullanılmaz. Backend nokta alarm kaydında webhook ve `deliveryPolicy` zorunlu tutar, hesabı kullanıcıdan kendisi bulur ve hesapta kayıtlı webhook varsa onu yeniden kullanır. | Komut | Ne yapar | | --- | --- | diff --git a/point_alarm.py b/point_alarm.py index 0f34cdc..4e64d8f 100644 --- a/point_alarm.py +++ b/point_alarm.py @@ -18,10 +18,8 @@ from uuid import uuid4 from common import ApiError, ConfigurationError, IklimClient from common.client import ApiResponse from common.client import RETRYABLE_STATUS_CODES -from common.config import env_bool from nowcast_common import ( as_uuid, - fetch_account_id, load_webhook_config, read_json_object, response_warnings, @@ -355,9 +353,6 @@ class PointAlarmService: def __init__(self, client: IklimClient) -> None: self.client = client - def get_account_id(self) -> str: - return fetch_account_id(self.client) - def page( self, *, @@ -652,10 +647,11 @@ class PointRegistrationProcessor: def run(self) -> None: rows, fieldnames = self._read_csv() filters = load_point_alarm_filter(self.filter_config_path) - webhook_initialized = env_bool("IKLIM_WEBHOOK_INITIALIZED", False) - full_webhook = None if webhook_initialized else load_webhook_config(self.webhook_config_path) - account_id = self.service.get_account_id() - LOGGER.info("Kullanıcı hesabı doğrulandı; accountId API'den alındı.") + # The backend requires a webhook with a delivery policy on every register call; it reuses + # the account's stored webhook and resolves the account from the caller, so accountId is not sent. + webhook = load_webhook_config(self.webhook_config_path) + if not isinstance(webhook.get("deliveryPolicy"), dict): + raise ConfigurationError("Nokta alarm kaydı için webhook.deliveryPolicy zorunludur.") for row_number, row in enumerate(rows, start=2): if str(row.get("status", "")).strip().upper() == "SUCCESS": LOGGER.info("Satır %s zaten SUCCESS; atlandı.", row_number) @@ -670,13 +666,10 @@ class PointRegistrationProcessor: payload = { "recipientId": recipient_id, "boundary": {"point": {"lat": lat, "lng": lng}, "radius": radius}, - "webhook": {"accountId": account_id} if webhook_initialized else deepcopy(full_webhook), + "webhook": deepcopy(webhook), "filter": deepcopy(filters), } - registered = self._register(row_number, payload, row) - if registered and not webhook_initialized: - webhook_initialized = True - self.service.client.token_store.set_webhook_initialized(True) + self._register(row_number, payload, row) self._write_csv(rows, fieldnames) def _register(self, row_number: int, payload: dict[str, Any], row: dict[str, Any]) -> bool: diff --git a/tests/test_point_alarm.py b/tests/test_point_alarm.py index 4d7dbe7..938994d 100644 --- a/tests/test_point_alarm.py +++ b/tests/test_point_alarm.py @@ -176,9 +176,6 @@ class FakeRegisterService: self.payloads: list[dict] = [] self.recipient_hits: list = [] - def get_account_id(self): - return "acc" - def register(self, payload, key): self.payloads.append(payload) result = self.results.pop(0) @@ -199,7 +196,11 @@ class RegisterTest(unittest.TestCase): self.filter = self.dir / "filter.json" self.filter.write_text(json.dumps({"lightning": {"type": "PULSE_IN_CLOUD"}}), encoding="utf-8") self.webhook = self.dir / "webhook.json" - self.webhook.write_text("{}", encoding="utf-8") + self.webhook.write_text(json.dumps({ + "url": "https://example.com/hook", "httpMethod": "POST", "contentType": "application/json", + "authentication": {"selected": "JWT_TOKEN", "options": {"JWT_TOKEN": {"jwtToken": "t"}}}, + "deliveryPolicy": {"maxAttempts": 3}, + }), encoding="utf-8") self.csv = self.dir / "r.csv" def run_processor(self, rows: str | None, service) -> list[dict]: @@ -208,8 +209,7 @@ class RegisterTest(unittest.TestCase): processor = PointRegistrationProcessor( service, csv_path=self.csv, webhook_config_path=self.webhook, filter_config_path=self.filter ) - with patch.dict(os.environ, {"IKLIM_WEBHOOK_INITIALIZED": "true"}): - processor.run() + processor.run() with self.csv.open(encoding="utf-8-sig", newline="") as handle: return list(csv.DictReader(handle, delimiter=";")) @@ -226,7 +226,8 @@ class RegisterTest(unittest.TestCase): self.assertEqual(rows[0]["registrationId"], REG_ID) self.assertIn("duplicate", rows[1]["errorBody"]) self.assertEqual(rows[2]["httpStatus"], "NOT_SENT") - self.assertEqual(service.payloads[0]["webhook"], {"accountId": "acc"}) + self.assertEqual(service.payloads[0]["webhook"]["deliveryPolicy"], {"maxAttempts": 3}) + self.assertNotIn("accountId", service.payloads[0]["webhook"]) self.assertEqual(service.payloads[0]["filter"]["lightning"]["type"], "PULSE_IN_CLOUD") # Re-run: SUCCESS row is skipped, the failed one is retried. service2 = FakeRegisterService(