feat: Add Gotify Notification Channel for Quota Alerts - #1948
Conversation
WalkthroughAdds Gotify as a new notification channel across backend and frontend: DTO/constants, user settings update/validation, quota notification formatting, notification sending helper with worker/direct paths and SSRF checks, UI fields/validation, and an email fallback when user email is missing. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Web as Web UI
participant API as Controller
participant Svc as Notify Service
participant Gotify as Gotify Server
participant Mail as Email Provider
participant Hook as Webhook
rect rgba(230,240,255,0.35)
User->>Web: Choose "Gotify", enter URL/Token/Priority
Web->>API: PUT /user/settings { gotify_url, gotify_token, gotify_priority, warning_type: "gotify" }
API->>API: Validate URL scheme & token, clamp priority
API-->>Web: 200 OK
end
Note over Svc: Quota warning trigger
API->>Svc: NotifyUser(user, settings, dto.Notify)
alt warning_type == "gotify"
Svc->>Svc: Build Gotify payload (title, text, clamp priority)
par via worker
Svc->>Svc: Enqueue worker job with payload
and direct HTTP
Svc->>Gotify: POST /message?token=... (SSRF-checked)
end
Gotify-->>Svc: 200/4xx
else warning_type == "email"
Svc->>Svc: Resolve email (settings email or user email)
opt email exists
Svc->>Mail: Send email
Mail-->>Svc: Result
end
else warning_type == "webhook"
Svc->>Hook: POST payload
Hook-->>Svc: Result
else warning_type == "bark"
Svc->>...: Bark send (unchanged)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
🔇 Additional comments (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
web/src/components/settings/personal/cards/NotificationSettings.jsx (1)
648-665: Consider adding numeric input validation for priority.The priority field uses
AutoCompletewith predefined values (0, 2, 5, 8, 10), but users can potentially enter custom values. Consider adding a validator to ensure the value is numeric and within the 0-10 range, consistent with the backend validation at controller/user.go lines 1270-1274.Add validation rule:
<Form.AutoComplete field='gotifyPriority' label={t('消息优先级')} placeholder={t('请选择消息优先级')} data={[ { value: 0, label: t('0 - 最低') }, { value: 2, label: t('2 - 低') }, { value: 5, label: t('5 - 正常(默认)') }, { value: 8, label: t('8 - 高') }, { value: 10, label: t('10 - 最高') }, ]} onChange={(val) => handleFormChange('gotifyPriority', val) } prefix={<IconBell />} extraText={t('消息优先级,范围0-10,默认为5')} style={{ width: '100%', maxWidth: '300px' }} + rules={[ + { + validator: (rule, value) => { + const numValue = Number(value); + if (isNaN(numValue) || numValue < 0 || numValue > 10) { + return Promise.reject(t('优先级必须在0-10之间')); + } + return Promise.resolve(); + }, + }, + ]} />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
controller/user.go(4 hunks)dto/user_settings.go(2 hunks)service/quota.go(1 hunks)service/user_notify.go(4 hunks)web/src/components/settings/PersonalSetting.jsx(3 hunks)web/src/components/settings/personal/cards/NotificationSettings.jsx(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
service/user_notify.go (7)
common/sys_log.go (1)
SysLog(11-14)dto/user_settings.go (1)
NotifyTypeGotify(22-22)setting/system_setting/system_setting_old.go (2)
EnableWorker(8-10)WorkerValidKey(5-5)service/download.go (2)
WorkerRequest(14-20)DoWorkerRequest(23-49)setting/system_setting/fetch_setting.go (1)
GetFetchSetting(32-34)common/ssrf_protection.go (1)
ValidateURLWithFetchSetting(305-327)service/http_client.go (1)
GetHttpClient(32-34)
controller/user.go (1)
dto/user_settings.go (4)
NotifyTypeEmail(19-19)NotifyTypeWebhook(20-20)NotifyTypeBark(21-21)NotifyTypeGotify(22-22)
service/quota.go (2)
dto/user_settings.go (1)
NotifyTypeGotify(22-22)logger/logger.go (1)
FormatQuota(102-108)
web/src/components/settings/personal/cards/NotificationSettings.jsx (1)
web/src/components/settings/PersonalSetting.jsx (1)
notificationSettings(77-89)
🔇 Additional comments (21)
dto/user_settings.go (2)
10-12: LGTM! Field definitions are correct.The Gotify fields are properly structured:
GotifyUrlandGotifyTokencorrectly useomitemptyfor optional stringsGotifyPriorityintentionally omitsomitemptysince 0 is a valid priority value (Gotify supports 0-10 range)
22-22: LGTM! Constant follows existing pattern.The new
NotifyTypeGotifyconstant aligns with the existing notification type constants.web/src/components/settings/personal/cards/NotificationSettings.jsx (4)
403-403: LGTM! Radio option integrated correctly.The Gotify notification option is added consistently with existing notification types.
604-627: LGTM! URL validation is comprehensive.The Gotify URL field includes:
- Required validation when Gotify is selected
- Regex pattern validation for http/https schemes
- Clear user guidance
629-646: LGTM! Token field properly validated.The Gotify token field correctly requires input when Gotify notification type is selected.
667-698: LGTM! Excellent user guidance.The configuration panel provides clear setup instructions and links to official documentation, improving the user experience.
service/quota.go (1)
552-559: LGTM! Content formatting differentiated appropriately.The Gotify notification path correctly formats content as plain text (no HTML), distinct from the Email/Webhook path which includes HTML links. The message structure is clear and includes the necessary placeholder variables.
web/src/components/settings/PersonalSetting.jsx (3)
84-86: LGTM! Initial state correctly configured.The Gotify fields are properly initialized with sensible defaults, especially
gotifyPriority: 5which aligns with Gotify's default priority level.
155-160: LGTM! Loading logic handles undefined priority correctly.The conditional check ensures that if
gotify_priorityis undefined, it defaults to 5, preventing potential issues with missing values.
418-423: LGTM! Priority parsing with fallback is robust.The save logic correctly:
- Parses the priority to integer
- Falls back to default value 5 if parsing fails
- Aligns with backend validation at controller/user.go lines 1270-1274
controller/user.go (4)
1105-1107: LGTM! Request struct extended correctly.The Gotify fields are properly added to
UpdateUserSettingRequestwith appropriate JSON tags andomitemptyfor optional fields.
1123-1123: LGTM! Notification type validation complete.The validation now includes all four notification types: email, webhook, bark, and gotify.
1198-1230: LGTM! Gotify validation is comprehensive and consistent.The validation block correctly:
- Enforces required URL and token fields
- Validates URL format using
url.ParseRequestURI- Checks for http/https scheme prefix
- Mirrors the validation pattern used for Bark (lines 1172-1196)
1265-1275: LGTM! Settings storage handles priority range correctly.The Gotify settings are properly stored with:
- URL and token assignment
- Priority clamping to valid range (0-10) with sensible default (5)
- Conditional application only when notification type is Gotify
service/user_notify.go (7)
4-5: LGTM!The new imports are necessary for Gotify JSON payload marshaling and HTTP request construction.
41-51: LGTM!The email fallback logic correctly prioritizes the notification email from settings and falls back to the user's default email, with appropriate logging when both are unavailable.
69-76: LGTM!The Gotify case integration follows the established pattern for other notification types, with appropriate validation and error handling.
161-176: LGTM!Placeholder replacement, URL construction, and priority clamping are implemented correctly. The priority is appropriately constrained to Gotify's 0-10 range with a sensible default.
177-194: LGTM!The Gotify payload structure and JSON marshaling are correct and follow Gotify's API specification.
199-221: LGTM!The worker-based sending path correctly constructs the worker request with appropriate headers, body, and error handling.
222-251: LGTM (pending User-Agent fix).The direct HTTP path correctly applies SSRF protection, constructs the request, and validates the response. Once the User-Agent inconsistency is fixed, this implementation will be complete.
| Method: http.MethodPost, | ||
| Headers: map[string]string{ | ||
| "Content-Type": "application/json; charset=utf-8", | ||
| "User-Agent": "OneAPI-Gotify-Notify/1.0", |
There was a problem hiding this comment.
Inconsistent User-Agent strings between worker and direct paths.
Line 207 uses "OneAPI-Gotify-Notify/1.0" while line 237 uses "NewAPI-Gotify-Notify/1.0". These should be consistent for proper identification and monitoring.
Apply this diff to standardize the User-Agent:
- req.Header.Set("User-Agent", "NewAPI-Gotify-Notify/1.0")
+ req.Header.Set("User-Agent", "OneAPI-Gotify-Notify/1.0")Also applies to: 237-237
🤖 Prompt for AI Agents
In service/user_notify.go around lines 207 and 237 the User-Agent strings are
inconsistent ("OneAPI-Gotify-Notify/1.0" vs "NewAPI-Gotify-Notify/1.0"); update
both occurrences to the same canonical value (choose one, e.g.,
"OneAPI-Gotify-Notify/1.0") so both code paths use the identical User-Agent, and
search the file/repo for any other User-Agent occurrences to standardize them as
well; after changing, run tests/lint to ensure no formatting or build issues.
feat: Add Gotify Notification Channel for Quota Alerts
…ount-test-responses-stream fix(openai): tighten responses stream account tests
PR 类型
PR 是否包含破坏性更新?
PR 描述
支持使用Gotify发送余额预警

Summary by CodeRabbit
New Features
Bug Fixes
Documentation