feat: add nowcast point alarm unregister client with confirmation and backup

Shows environment, count and an irreversibility warning, requires typing the confirmation word (plus the environment name on prod), backs every registration up through get-by-id before deleting and aborts the whole run if the backup cannot be completed.
This commit is contained in:
2026-10-23 19:14:08 +03:00
parent 8587669ea5
commit 4d270aea05
4 changed files with 208 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Delete point alarm registrations listed in a CSV/TXT file, with confirmation and backup."""
from __future__ import annotations
import argparse
import logging
import sys
from pathlib import Path
from common import ApiError, ConfigurationError, IklimClient, configure_logging
from point_alarm import (
PointAlarmService,
PointUnregisterProcessor,
read_id_list,
timestamped_path,
write_records,
)
BASE_DIR = Path(__file__).resolve().parent
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Dosyadaki registrationId'leri siler (DELETE /v1/alarms/points/unregister/{id}). "
"Girdi CSV (registrationId sütunu) veya TXT (satır başına bir ID). Başlamadan önce "
"ortam, silinecek sayı ve 'geri alınamaz' uyarısı gösterilir; onay için SİL yazılmalıdır "
"(prod ortamında ek olarak 'prod' yazılır). Bir hesabın son kaydı silinirse webhook da "
"silinir. Silmeden önce her kayıt get-by-id ile yedeklenir; yedek yazılamazsa hiçbir "
"kayıt silinmez."
)
)
parser.add_argument("input_file", type=Path, help="ID listesi (.csv veya .txt)")
parser.add_argument(
"--backup",
type=Path,
default=BASE_DIR / "nowcast-point-unregister-backup.csv",
help="Yedek dosyası (.csv/.txt, zaman soneki eklenir; varsayılan: nowcast-point-unregister-backup.csv)",
)
parser.add_argument("--no-backup", action="store_true", help="Silmeden önce yedek almayı kapatır")
parser.add_argument(
"--output",
type=Path,
help="Sonuç dosyası (.csv/.txt, zaman soneki eklenir); verilmezse yalnızca özet yazılır",
)
parser.add_argument(
"--debug-log",
type=Path,
default=BASE_DIR / "logs" / "iklim-api-debug.log",
help="Maskelenmiş HTTP debug log dosyası",
)
return parser.parse_args()
def main() -> int:
args = parse_args()
configure_logging(args.debug_log)
try:
ids = read_id_list(args.input_file, "registrationId")
client = IklimClient.from_env(BASE_DIR / ".env")
processor = PointUnregisterProcessor(
PointAlarmService(client),
ids=ids,
environment=client.settings.environment,
base_url=client.settings.base_url,
backup_path=None if args.no_backup else timestamped_path(args.backup),
)
results = processor.run()
if not results:
return 1
failed = sum(1 for row in results if row["status"] == "FAILED")
print(f"{len(results) - failed} silindi, {failed} başarısız.")
if args.output:
path = timestamped_path(args.output)
write_records(path, results, [], columns=["registrationId", "status", "httpStatus", "errorBody"])
print(f"Sonuçlar yazıldı: {path.resolve()}")
return 1 if failed else 0
except (ConfigurationError, ApiError, OSError) as exc:
logging.error("İşlem durduruldu: %s", exc)
return 1
if __name__ == "__main__":
sys.exit(main())