"""API Key 域通知模板。 覆盖 API Key 生命周期里会推送给员工/主管的流程:到期预警 (``expiry_warning``)、共享名单增删(``member.*``)、释放申请的提交与 审批结论(``release.*``)、管理员强制回收(``revoked_by_admin.*``)、 以及凭证轮换的四个阶段(``rotation.*``)。 文案沿用调用点已上线的中文语义,只做「模板化 + 翻译」,未改需求。 每个 ``{placeholder}`` 都来自调用点 ``NotificationEnvelope.context``; ``{portal_url}`` / ``{cta_line}`` 由渲染器按渠道注入,不在 context 里。 """ from __future__ import annotations TEMPLATES: dict[str, dict[str, str]] = { # ── 到期预警(cron: apikey.expiry_check)──────────────────────── # 同一封同时发给申请人本人和其主管,所以正文必须点名申请人 # (``applicant_name``),否则主管看到的是「你的 Key」这种错位人称。 "apikey.expiry_warning": { "subject": "API Key 即将到期({threshold_days} 天):{provider_name}", "subject_en": ( "API key expires in {threshold_days} days: {provider_name}" ), "subject_ja": ( "API キーの有効期限が近づいています({threshold_days} 日前):" "{provider_name}" ), "body_text": ( "{applicant_name} 的 API Key 申请单 [r]{request_number}[/r]" "([b]{provider_name}[/b])将在 {valid_until} 到期" "(还剩 {days_left} 天)。\n\n" "如果仍在使用,请到 Helix「我的 API Keys」页点击「续期」" "按钮延长有效期:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "The API key request [r]{request_number}[/r] " "([b]{provider_name}[/b]) held by {applicant_name} expires on " "{valid_until} ({days_left} days left).\n\n" "If it is still in use, open the Helix \"My API Keys\" page and " "click \"Renew\" to extend it:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "{applicant_name} さんの API キー申請 [r]{request_number}[/r]" "([b]{provider_name}[/b])は {valid_until} に有効期限を迎えます" "(残り {days_left} 日)。\n\n" "引き続きご利用の場合は、Helix の「マイ API キー」ページで" "「更新」をクリックし、有効期限を延長してください。\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "续期 API Key", "card_button_label_en": "Renew API key", "card_button_label_ja": "API キーを更新", }, # ── 共享名单 ─────────────────────────────────────────────────── "apikey.member.added": { "subject": "你被加入 API Key 共享名单:{provider_name}", "subject_en": "You were added to an API key: {provider_name}", "subject_ja": "API キーの共有メンバーに追加されました:{provider_name}", "body_text": ( "{owner_name} 把你加入了 API Key 的共享访问名单:\n\n" " · 服务商: [b]{provider_name}[/b]\n" " · 项目: {project_name}\n" " · 单号: {request_number}\n\n" "你现在可以查看该 Key 的本月用量、明细与密钥本身,用于团队协作:\n" " {detail_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "{owner_name} added you to the shared-access list of an API " "key:\n\n" " · Provider: [b]{provider_name}[/b]\n" " · Project: {project_name}\n" " · Request: {request_number}\n\n" "You can now view this key's month-to-date usage, its cost " "breakdown and the credential itself for team collaboration:\n" " {detail_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "{owner_name} さんが、あなたを API キーの共有アクセス" "リストに追加しました。\n\n" " · プロバイダ: [b]{provider_name}[/b]\n" " · プロジェクト: {project_name}\n" " · 申請番号: {request_number}\n\n" "今月の利用量、明細、および認証情報を確認できるようになりました。" "チームでの共同利用にお使いください。\n" " {detail_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "查看 API Key", "card_button_label_en": "View API key", "card_button_label_ja": "API キーを確認", }, "apikey.member.removed": { "subject": "已退出 API Key 共享名单:{provider_name}", "subject_en": "You were removed from an API key: {provider_name}", "subject_ja": "API キーの共有メンバーから外れました:{provider_name}", "body_text": ( "{owner_name} 把你从 API Key 的共享访问名单中移除:\n\n" " · 服务商: [b]{provider_name}[/b]\n" " · 项目: {project_name}\n" " · 单号: {request_number}\n\n" "你将无法再查看该 Key 的用量与密钥。如有问题请直接联系 Key 的" "负责人。\n\n" "查看我的 API Keys:\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "{owner_name} removed you from the shared-access list of an API " "key:\n\n" " · Provider: [b]{provider_name}[/b]\n" " · Project: {project_name}\n" " · Request: {request_number}\n\n" "You can no longer see this key's usage or its credential. " "Please contact the key owner if you think this is a " "mistake.\n\n" "Your own API keys:\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "{owner_name} さんが、あなたを API キーの共有アクセス" "リストから削除しました。\n\n" " · プロバイダ: [b]{provider_name}[/b]\n" " · プロジェクト: {project_name}\n" " · 申請番号: {request_number}\n\n" "このキーの利用量と認証情報は閲覧できなくなります。" "ご不明な点はキーの担当者に直接ご連絡ください。\n\n" "ご自身の API キーはこちらです。\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "我的 API Keys", "card_button_label_en": "My API keys", "card_button_label_ja": "マイ API キー", }, # ── 释放申请 ─────────────────────────────────────────────────── # ``reason_text`` = reason_code(+ " — " + reason_note),在调用点拼好, # 这样三语模板都只引用一个字段,空备注时也不会留下悬空的破折号。 "apikey.release.pending": { "subject": "API Key 释放申请待审批:{requester_name}", "subject_en": "API key release awaiting your approval: {requester_name}", "subject_ja": "API キー返却申請の承認依頼:{requester_name}", "body_text": ( "{requester_name} 提交了一项 API Key 释放申请,请到 Helix " "审批:\n\n" " · 服务商: [b]{provider_name}[/b]\n" " · 项目: {project_name}\n" " · 单号: {request_number}\n" " · 理由: {reason_text}\n\n" " {approval_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "{requester_name} submitted an API key release request. Please " "review it in Helix:\n\n" " · Provider: [b]{provider_name}[/b]\n" " · Project: {project_name}\n" " · Request: {request_number}\n" " · Reason: {reason_text}\n\n" " {approval_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "{requester_name} さんが API キーの返却を申請しました。" "Helix で承認をお願いします。\n\n" " · プロバイダ: [b]{provider_name}[/b]\n" " · プロジェクト: {project_name}\n" " · 申請番号: {request_number}\n" " · 理由: {reason_text}\n\n" " {approval_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "去 Helix 审批", "card_button_label_en": "Review in Helix", "card_button_label_ja": "Helix で承認する", }, "apikey.release.approved": { "subject": "API Key 释放申请已通过:{provider_name}", "subject_en": "API key release approved: {provider_name}", "subject_ja": "API キーの返却申請が承認されました:{provider_name}", "body_text": ( "你提交的 API Key 释放申请([r]{request_number}[/r]," "[b]{provider_name}[/b])已审批通过,该 Key 已立即作废。\n\n" "如需新 Key,请重新提交申请:\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "Your API key release request ([r]{request_number}[/r], " "[b]{provider_name}[/b]) was approved and the key has been " "revoked immediately.\n\n" "If you need a new key, please submit a new request:\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "お申し込みの API キー返却申請([r]{request_number}[/r]、" "[b]{provider_name}[/b])が承認され、当該キーは直ちに" "無効化されました。\n\n" "新しいキーが必要な場合は、あらためて申請してください。\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "我的 API Keys", "card_button_label_en": "My API keys", "card_button_label_ja": "マイ API キー", }, "apikey.release.rejected": { "subject": "API Key 释放申请已被驳回:{provider_name}", "subject_en": "API key release rejected: {provider_name}", "subject_ja": "API キーの返却申請が却下されました:{provider_name}", "body_text": ( "你提交的 API Key 释放申请([r]{request_number}[/r]," "[b]{provider_name}[/b])已被审批驳回,该 Key 仍可正常使用。\n\n" " · 审批意见: {decision_note}\n\n" "如确实不再需要,请与领导沟通后重新提交:\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "Your API key release request ([r]{request_number}[/r], " "[b]{provider_name}[/b]) was rejected; the key stays " "active.\n\n" " · Reviewer note: {decision_note}\n\n" "If you really no longer need it, please align with your manager " "and submit again:\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "お申し込みの API キー返却申請([r]{request_number}[/r]、" "[b]{provider_name}[/b])は却下されました。" "当該キーは引き続きご利用いただけます。\n\n" " · 承認者コメント: {decision_note}\n\n" "本当に不要な場合は、上長とご相談のうえ、あらためて" "申請してください。\n" " {my_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "我的 API Keys", "card_button_label_en": "My API keys", "card_button_label_ja": "マイ API キー", }, # ── 管理员强制回收 ───────────────────────────────────────────── "apikey.revoked_by_admin.assignee": { "subject": "API Key 已被管理员回收:{provider_name}", "subject_en": "Your API key was revoked by an admin: {provider_name}", "subject_ja": "API キーが管理者により回収されました:{provider_name}", "body_text": ( "你的 API Key 申请单 [r]{request_number}[/r]" "([b]{provider_name}[/b])已被管理员回收,云端凭证已立即" "失效。\n\n" " · 理由: {reason}\n\n" "如对此操作有疑问,请联系 IT 管理员。\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "Your API key request [r]{request_number}[/r] " "([b]{provider_name}[/b]) was revoked by an administrator; the " "cloud-side credential is already disabled.\n\n" " · Reason: {reason}\n\n" "Please contact the IT admins if you have questions about " "this.\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "あなたの API キー申請 [r]{request_number}[/r]" "([b]{provider_name}[/b])が管理者により回収され、" "クラウド側の認証情報は直ちに無効化されました。\n\n" " · 理由: {reason}\n\n" "本対応についてご不明な点は、IT 管理者までお問い合わせ" "ください。\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "我的 API Keys", "card_button_label_en": "My API keys", "card_button_label_ja": "マイ API キー", }, # 主管卡片:envelope 没有 url,渲染器不会注入 {portal_url}, # 因此正文里不放门户链接(注入不了的占位符会字面量露出)。 "apikey.revoked_by_admin.manager": { "subject": "下属 API Key 被管理员回收:{assignee_name}", "subject_en": ( "A direct report's API key was revoked: {assignee_name}" ), "subject_ja": "部下の API キーが管理者により回収されました:{assignee_name}", "body_text": ( "你的下属 {assignee_name} 的 API Key 申请单 " "[r]{request_number}[/r]([b]{provider_name}[/b])已被管理员" "回收,云端凭证已立即失效。\n\n" " · 理由: {reason}\n\n" "— Helix IT 平台" ), "body_text_en": ( "The API key request [r]{request_number}[/r] " "([b]{provider_name}[/b]) belonging to your direct report " "{assignee_name} was revoked by an administrator; the " "cloud-side credential is already disabled.\n\n" " · Reason: {reason}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "部下の {assignee_name} さんの API キー申請 " "[r]{request_number}[/r]([b]{provider_name}[/b])が管理者に" "より回収され、クラウド側の認証情報は直ちに無効化されました。\n\n" " · 理由: {reason}\n\n" "— Helix IT プラットフォーム" ), }, # ── 凭证轮换 ─────────────────────────────────────────────────── # 原调用点按 ``grace_days > 0`` 分支写了两段不同的中文尾巴。模板是 # 静态字符串、没有条件分支,因此把宽限期改成字段行 + 一句括注, # 两种情况(立即停用 / 有宽限期)都读得通。 "apikey.rotation.started": { "subject": "API Key 已轮换:{provider_name}", "subject_en": "API key rotated: {provider_name}", "subject_ja": "API キーをローテーションしました:{provider_name}", "body_text": ( "你的 API Key 申请单 [r]{request_number}[/r]" "([b]{provider_name}[/b])已生成新凭证。\n\n" " · 宽限期: {grace_days} 天(为 0 表示旧凭证已立即停用)\n" " · 旧凭证停用时间: {retire_date}\n\n" "宽限期内新旧凭证同时有效。请在旧凭证停用前,把应用里的凭证" "换成新的。到「我的 API Keys」查看并复制新凭证:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "A new credential was minted for your API key request " "[r]{request_number}[/r] ([b]{provider_name}[/b]).\n\n" " · Grace window: {grace_days} days (0 means the previous " "credential was retired immediately)\n" " · Previous credential retires on: {retire_date}\n\n" "Both credentials work during the grace window. Switch your " "application over before the old one retires — view and copy the " "new credential on your \"My API Keys\" page:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "API キー申請 [r]{request_number}[/r]([b]{provider_name}[/b])" "の新しい認証情報を発行しました。\n\n" " · 猶予期間: {grace_days} 日(0 の場合、旧認証情報は" "即時停止済みです)\n" " · 旧認証情報の停止日: {retire_date}\n\n" "猶予期間中は新旧どちらの認証情報も有効です。停止日までに" "アプリケーション側の認証情報を新しいものへ切り替えてください。" "新しい認証情報は「マイ API キー」ページで確認・コピーできます。\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "查看新凭证", "card_button_label_en": "View new credential", "card_button_label_ja": "新しい認証情報を確認", }, "apikey.rotation.retired": { "subject": "API Key 旧凭证已停用:{provider_name}", "subject_en": "Previous API key credential retired: {provider_name}", "subject_ja": "API キーの旧認証情報を停止しました:{provider_name}", "body_text": ( "你的 API Key 申请单 [r]{request_number}[/r]" "([b]{provider_name}[/b])的旧凭证已停用。\n\n" "如你的应用仍在使用旧凭证,请立即改用新凭证:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "The previous credential for your API key request " "[r]{request_number}[/r] ([b]{provider_name}[/b]) has been " "retired.\n\n" "If your application is still using it, switch to the new " "credential now:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "API キー申請 [r]{request_number}[/r]([b]{provider_name}[/b])" "の旧認証情報を停止しました。\n\n" "アプリケーションで旧認証情報をまだ使用している場合は、" "至急、新しい認証情報へ切り替えてください。\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "查看新凭证", "card_button_label_en": "View new credential", "card_button_label_ja": "新しい認証情報を確認", }, "apikey.rotation.cancelled": { "subject": "API Key 轮换已取消:{provider_name}", "subject_en": "API key rotation cancelled: {provider_name}", "subject_ja": "API キーのローテーションを取り消しました:{provider_name}", "body_text": ( "你的 API Key 申请单 [r]{request_number}[/r]" "([b]{provider_name}[/b])的轮换已取消,新凭证已作废," "继续使用原有凭证即可。\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "The rotation of your API key request [r]{request_number}[/r] " "([b]{provider_name}[/b]) was cancelled and the new credential " "was discarded. Keep using your original credential.\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "API キー申請 [r]{request_number}[/r]([b]{provider_name}[/b])" "のローテーションは取り消され、新しい認証情報は破棄されました。" "これまでの認証情報をそのままお使いください。\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "我的 API Keys", "card_button_label_en": "My API keys", "card_button_label_ja": "マイ API キー", }, "apikey.rotation.reminder": { "subject": "API Key 旧凭证即将停用:{provider_name}", "subject_en": "Previous API key credential retires soon: {provider_name}", "subject_ja": "API キーの旧認証情報がまもなく停止します:{provider_name}", "body_text": ( "你的 API Key 申请单 [r]{request_number}[/r]" "([b]{provider_name}[/b])的旧凭证将于 [r]{retire_date}[/r] " "停用(不足 24 小时)。\n\n" "如尚未切换,请尽快把应用凭证换成新的:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "The previous credential for your API key request " "[r]{request_number}[/r] ([b]{provider_name}[/b]) retires on " "[r]{retire_date}[/r] — less than 24 hours from now.\n\n" "If you haven't switched yet, move your application to the new " "credential now:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "API キー申請 [r]{request_number}[/r]([b]{provider_name}[/b])" "の旧認証情報は [r]{retire_date}[/r] に停止します" "(24 時間を切りました)。\n\n" "まだ切り替えていない場合は、至急アプリケーションの認証情報を" "新しいものへ変更してください。\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "查看新凭证", "card_button_label_en": "View new credential", "card_button_label_ja": "新しい認証情報を確認", }, # ── 自动发放失败(IT-only)──────────────────────────────────── # 收件人只有 global_admin:审批已通过但凭证没发出去,申请人那边什么 # 都看不出来(状态就是「已通过」),所以这张卡是这个故障唯一的出口。 # 2026-08-19 之前这些分支只往 detail JSON 里写一行字,没有任何人收到。 "apikey.autogrant_failed": { "subject": "[Helix] API Key 自动发放失败:{request_number}", "subject_en": "[Helix] API key auto-grant failed: {request_number}", "subject_ja": ( "[Helix] API キーの自動発行に失敗しました:{request_number}" ), "body_text": ( "{requester_name} 的 API Key 申请单 [r]{request_number}[/r]" "([b]{provider_name}[/b],项目「{project_name}」)审批已通过," "但自动发放在 [b]{stage}[/b] 环节失败,申请人目前拿不到凭证。\n\n" "失败原因:\n{error}\n\n" "请到 API Key 管理页人工补发(或修好配置后重新触发):\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT 平台" ), "body_text_en": ( "The API key request [r]{request_number}[/r] " "([b]{provider_name}[/b], project \"{project_name}\") raised by " "{requester_name} was approved, but the auto-grant failed at " "stage [b]{stage}[/b] — the requester has no credential.\n\n" "Reason:\n{error}\n\n" "Fill the key by hand (or fix the configuration and re-run the " "grant) from the API key admin console:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT Platform" ), "body_text_ja": ( "{requester_name} さんの API キー申請 [r]{request_number}[/r]" "([b]{provider_name}[/b]、プロジェクト「{project_name}」)は" "承認されましたが、自動発行が [b]{stage}[/b] の段階で失敗し、" "申請者は認証情報を受け取れていません。\n\n" "失敗理由:\n{error}\n\n" "API キー管理ページから手動で発行(または設定を修正して再実行)" "してください:\n" " {portal_url}\n\n" "{cta_line}\n\n" "— Helix IT プラットフォーム" ), "card_button_label": "去处理", "card_button_label_en": "Open admin console", "card_button_label_ja": "対応する", }, } __all__ = ["TEMPLATES"]