fix: send the full webhook and skip /users/me in the point alarm register client
The backend requires a webhook with a delivery policy on every point alarm register call and resolves the account from the caller, so the register client no longer calls /v1/users/me (account is null for some users), no longer sends the accountId-only webhook and no longer relies on IKLIM_WEBHOOK_INITIALIZED.
This commit is contained in:
@@ -44,3 +44,4 @@ nowcast-point-*-backup-*
|
|||||||
point-alarm-registrations-*.csv
|
point-alarm-registrations-*.csv
|
||||||
nowcast-point-registrations.csv
|
nowcast-point-registrations.csv
|
||||||
nowcast-point-update.csv
|
nowcast-point-update.csv
|
||||||
|
nowcast-point-alarm-records-*.csv
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ python nowcast-geo-register.py nowcast-geo-alarm-registrations.csv \
|
|||||||
|
|
||||||
## Nokta alarm (nowcast point) istemcileri
|
## 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 |
|
| Komut | Ne yapar |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
|||||||
+7
-14
@@ -18,10 +18,8 @@ from uuid import uuid4
|
|||||||
from common import ApiError, ConfigurationError, IklimClient
|
from common import ApiError, ConfigurationError, IklimClient
|
||||||
from common.client import ApiResponse
|
from common.client import ApiResponse
|
||||||
from common.client import RETRYABLE_STATUS_CODES
|
from common.client import RETRYABLE_STATUS_CODES
|
||||||
from common.config import env_bool
|
|
||||||
from nowcast_common import (
|
from nowcast_common import (
|
||||||
as_uuid,
|
as_uuid,
|
||||||
fetch_account_id,
|
|
||||||
load_webhook_config,
|
load_webhook_config,
|
||||||
read_json_object,
|
read_json_object,
|
||||||
response_warnings,
|
response_warnings,
|
||||||
@@ -355,9 +353,6 @@ class PointAlarmService:
|
|||||||
def __init__(self, client: IklimClient) -> None:
|
def __init__(self, client: IklimClient) -> None:
|
||||||
self.client = client
|
self.client = client
|
||||||
|
|
||||||
def get_account_id(self) -> str:
|
|
||||||
return fetch_account_id(self.client)
|
|
||||||
|
|
||||||
def page(
|
def page(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -652,10 +647,11 @@ class PointRegistrationProcessor:
|
|||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
rows, fieldnames = self._read_csv()
|
rows, fieldnames = self._read_csv()
|
||||||
filters = load_point_alarm_filter(self.filter_config_path)
|
filters = load_point_alarm_filter(self.filter_config_path)
|
||||||
webhook_initialized = env_bool("IKLIM_WEBHOOK_INITIALIZED", False)
|
# The backend requires a webhook with a delivery policy on every register call; it reuses
|
||||||
full_webhook = None if webhook_initialized else load_webhook_config(self.webhook_config_path)
|
# the account's stored webhook and resolves the account from the caller, so accountId is not sent.
|
||||||
account_id = self.service.get_account_id()
|
webhook = load_webhook_config(self.webhook_config_path)
|
||||||
LOGGER.info("Kullanıcı hesabı doğrulandı; accountId API'den alındı.")
|
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):
|
for row_number, row in enumerate(rows, start=2):
|
||||||
if str(row.get("status", "")).strip().upper() == "SUCCESS":
|
if str(row.get("status", "")).strip().upper() == "SUCCESS":
|
||||||
LOGGER.info("Satır %s zaten SUCCESS; atlandı.", row_number)
|
LOGGER.info("Satır %s zaten SUCCESS; atlandı.", row_number)
|
||||||
@@ -670,13 +666,10 @@ class PointRegistrationProcessor:
|
|||||||
payload = {
|
payload = {
|
||||||
"recipientId": recipient_id,
|
"recipientId": recipient_id,
|
||||||
"boundary": {"point": {"lat": lat, "lng": lng}, "radius": radius},
|
"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),
|
"filter": deepcopy(filters),
|
||||||
}
|
}
|
||||||
registered = self._register(row_number, payload, row)
|
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._write_csv(rows, fieldnames)
|
self._write_csv(rows, fieldnames)
|
||||||
|
|
||||||
def _register(self, row_number: int, payload: dict[str, Any], row: dict[str, Any]) -> bool:
|
def _register(self, row_number: int, payload: dict[str, Any], row: dict[str, Any]) -> bool:
|
||||||
|
|||||||
@@ -176,9 +176,6 @@ class FakeRegisterService:
|
|||||||
self.payloads: list[dict] = []
|
self.payloads: list[dict] = []
|
||||||
self.recipient_hits: list = []
|
self.recipient_hits: list = []
|
||||||
|
|
||||||
def get_account_id(self):
|
|
||||||
return "acc"
|
|
||||||
|
|
||||||
def register(self, payload, key):
|
def register(self, payload, key):
|
||||||
self.payloads.append(payload)
|
self.payloads.append(payload)
|
||||||
result = self.results.pop(0)
|
result = self.results.pop(0)
|
||||||
@@ -199,7 +196,11 @@ class RegisterTest(unittest.TestCase):
|
|||||||
self.filter = self.dir / "filter.json"
|
self.filter = self.dir / "filter.json"
|
||||||
self.filter.write_text(json.dumps({"lightning": {"type": "PULSE_IN_CLOUD"}}), encoding="utf-8")
|
self.filter.write_text(json.dumps({"lightning": {"type": "PULSE_IN_CLOUD"}}), encoding="utf-8")
|
||||||
self.webhook = self.dir / "webhook.json"
|
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"
|
self.csv = self.dir / "r.csv"
|
||||||
|
|
||||||
def run_processor(self, rows: str | None, service) -> list[dict]:
|
def run_processor(self, rows: str | None, service) -> list[dict]:
|
||||||
@@ -208,8 +209,7 @@ class RegisterTest(unittest.TestCase):
|
|||||||
processor = PointRegistrationProcessor(
|
processor = PointRegistrationProcessor(
|
||||||
service, csv_path=self.csv, webhook_config_path=self.webhook, filter_config_path=self.filter
|
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:
|
with self.csv.open(encoding="utf-8-sig", newline="") as handle:
|
||||||
return list(csv.DictReader(handle, delimiter=";"))
|
return list(csv.DictReader(handle, delimiter=";"))
|
||||||
|
|
||||||
@@ -226,7 +226,8 @@ class RegisterTest(unittest.TestCase):
|
|||||||
self.assertEqual(rows[0]["registrationId"], REG_ID)
|
self.assertEqual(rows[0]["registrationId"], REG_ID)
|
||||||
self.assertIn("duplicate", rows[1]["errorBody"])
|
self.assertIn("duplicate", rows[1]["errorBody"])
|
||||||
self.assertEqual(rows[2]["httpStatus"], "NOT_SENT")
|
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")
|
self.assertEqual(service.payloads[0]["filter"]["lightning"]["type"], "PULSE_IN_CLOUD")
|
||||||
# Re-run: SUCCESS row is skipped, the failed one is retried.
|
# Re-run: SUCCESS row is skipped, the failed one is retried.
|
||||||
service2 = FakeRegisterService(
|
service2 = FakeRegisterService(
|
||||||
|
|||||||
Reference in New Issue
Block a user