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:
@@ -943,3 +943,78 @@ class PointUpdateProcessor:
|
||||
row["status"] = status
|
||||
row["httpStatus"] = http_status
|
||||
row["errorBody"] = error_body
|
||||
|
||||
|
||||
CONFIRM_WORD = "SİL"
|
||||
|
||||
|
||||
class PointUnregisterProcessor:
|
||||
"""Delete registrations listed in a CSV/TXT after a typed confirmation and a backup."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
service: PointAlarmService,
|
||||
*,
|
||||
ids: list[str],
|
||||
environment: str,
|
||||
base_url: str,
|
||||
backup_path: Path | None,
|
||||
input_fn: Callable[[str], str] = input,
|
||||
out: TextIO | None = None,
|
||||
) -> None:
|
||||
self.service = service
|
||||
self.ids = ids
|
||||
self.environment = environment
|
||||
self.base_url = base_url
|
||||
self.backup_path = backup_path
|
||||
self.input_fn = input_fn
|
||||
self.out = out or sys.stdout
|
||||
|
||||
def confirm(self) -> bool:
|
||||
say = lambda text: self.out.write(text + "\n")
|
||||
say(f"Ortam: {self.environment or '-'} ({self.base_url})")
|
||||
say(f"Silinecek kayıt sayısı: {len(self.ids)}")
|
||||
say("Bu işlem geri alınamaz. Bir hesabın SON kaydı silinirse hesabın webhook tanımı da silinir.")
|
||||
if self.environment == "prod":
|
||||
if self.input_fn("PROD ortamında işlem yapıyorsunuz. Onaylamak için 'prod' yazın: ").strip() != "prod":
|
||||
say("Ortam adı eşleşmedi; işlem iptal edildi.")
|
||||
return False
|
||||
if self.input_fn(f"Devam etmek için '{CONFIRM_WORD}' yazın: ").strip() != CONFIRM_WORD:
|
||||
say("Onay verilmedi; işlem iptal edildi.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def run(self) -> list[dict[str, Any]]:
|
||||
if not self.confirm():
|
||||
return []
|
||||
backups: list[dict[str, Any]] = []
|
||||
results: list[dict[str, Any]] = []
|
||||
webhooks: list[dict[str, Any]] = []
|
||||
if self.backup_path:
|
||||
for registration_id in self.ids:
|
||||
try:
|
||||
data = self.service.get_by_id(registration_id).data
|
||||
except ApiError as exc:
|
||||
if exc.status_code == 404:
|
||||
LOGGER.warning("%s bulunamadı; yedeklenemedi.", registration_id)
|
||||
continue
|
||||
# An unreadable record cannot be backed up, so nothing is deleted.
|
||||
raise
|
||||
if isinstance(data, dict):
|
||||
backups.append(flatten_registration(data))
|
||||
webhook = registration_webhook(data)
|
||||
if webhook and webhook not in webhooks:
|
||||
webhooks.append(webhook)
|
||||
# A backup that cannot be written must stop the run before anything is deleted.
|
||||
write_records(self.backup_path, backups, webhooks)
|
||||
LOGGER.info("Yedek yazıldı: %s (%s kayıt)", self.backup_path, len(backups))
|
||||
for registration_id in self.ids:
|
||||
try:
|
||||
response = self.service.unregister(registration_id)
|
||||
except ApiError as exc:
|
||||
results.append({"registrationId": registration_id, "status": "FAILED", "httpStatus": exc.status_code, "errorBody": error_body_text(exc)})
|
||||
LOGGER.error("%s silinemedi: %s", registration_id, exc)
|
||||
else:
|
||||
results.append({"registrationId": registration_id, "status": "SUCCESS", "httpStatus": response.status_code, "errorBody": ""})
|
||||
LOGGER.info("%s silindi.", registration_id)
|
||||
return results
|
||||
|
||||
Reference in New Issue
Block a user