From a39173c227621f6749af24457e151d3095a60e5c Mon Sep 17 00:00:00 2001 From: Jake Armstrong <65635253+jakearmstrong59@users.noreply.github.com> Date: Tue, 7 Apr 2026 03:03:18 +0200 Subject: [PATCH] refactor(api): type notification response with NotificationResponseDict TypedDict (#34616) --- api/controllers/console/notification.py | 47 +++++++++++++++++-------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/api/controllers/console/notification.py b/api/controllers/console/notification.py index 53e4aa3d86..180167402a 100644 --- a/api/controllers/console/notification.py +++ b/api/controllers/console/notification.py @@ -1,3 +1,5 @@ +from typing import TypedDict + from flask import request from flask_restx import Resource from pydantic import BaseModel, Field @@ -11,6 +13,21 @@ from services.billing_service import BillingService _FALLBACK_LANG = "en-US" +class NotificationItemDict(TypedDict): + notification_id: str | None + frequency: str | None + lang: str + title: str + subtitle: str + body: str + title_pic_url: str + + +class NotificationResponseDict(TypedDict): + should_show: bool + notifications: list[NotificationItemDict] + + def _pick_lang_content(contents: dict, lang: str) -> dict: """Return the single LangContent for *lang*, falling back to English.""" return contents.get(lang) or contents.get(_FALLBACK_LANG) or next(iter(contents.values()), {}) @@ -45,28 +62,30 @@ class NotificationApi(Resource): result = BillingService.get_account_notification(str(current_user.id)) # Proto JSON uses camelCase field names (Kratos default marshaling). + response: NotificationResponseDict if not result.get("shouldShow"): - return {"should_show": False, "notifications": []}, 200 + response = {"should_show": False, "notifications": []} + return response, 200 lang = current_user.interface_language or _FALLBACK_LANG - notifications = [] + notifications: list[NotificationItemDict] = [] for notification in result.get("notifications") or []: contents: dict = notification.get("contents") or {} lang_content = _pick_lang_content(contents, lang) - notifications.append( - { - "notification_id": notification.get("notificationId"), - "frequency": notification.get("frequency"), - "lang": lang_content.get("lang", lang), - "title": lang_content.get("title", ""), - "subtitle": lang_content.get("subtitle", ""), - "body": lang_content.get("body", ""), - "title_pic_url": lang_content.get("titlePicUrl", ""), - } - ) + item: NotificationItemDict = { + "notification_id": notification.get("notificationId"), + "frequency": notification.get("frequency"), + "lang": lang_content.get("lang", lang), + "title": lang_content.get("title", ""), + "subtitle": lang_content.get("subtitle", ""), + "body": lang_content.get("body", ""), + "title_pic_url": lang_content.get("titlePicUrl", ""), + } + notifications.append(item) - return {"should_show": bool(notifications), "notifications": notifications}, 200 + response = {"should_show": bool(notifications), "notifications": notifications} + return response, 200 @console_ns.route("/notification/dismiss")