From 55b13cd7b4f5fd064c374e5db96692a2be171bbf Mon Sep 17 00:00:00 2001 From: benjamin Date: Wed, 20 May 2026 11:05:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(settings):=20=E6=B7=BB=E5=8A=A0=E9=82=AE?= =?UTF-8?q?=E4=BB=B6=E9=80=80=E8=AE=A2=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- backend/internal/handler/setting_handler.go | 36 +++++++++++++++++++-- backend/internal/server/routes/auth.go | 1 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/backend/internal/handler/setting_handler.go b/backend/internal/handler/setting_handler.go index c4ba43e4..7413b840 100644 --- a/backend/internal/handler/setting_handler.go +++ b/backend/internal/handler/setting_handler.go @@ -1,6 +1,10 @@ package handler import ( + "html" + "net/http" + "strings" + "github.com/Wei-Shaw/sub2api/internal/handler/dto" "github.com/Wei-Shaw/sub2api/internal/pkg/response" "github.com/Wei-Shaw/sub2api/internal/service" @@ -10,8 +14,9 @@ import ( // SettingHandler 公开设置处理器(无需认证) type SettingHandler struct { - settingService *service.SettingService - version string + settingService *service.SettingService + notificationEmailService *service.NotificationEmailService + version string } // NewSettingHandler 创建公开设置处理器 @@ -22,6 +27,12 @@ func NewSettingHandler(settingService *service.SettingService, version string) * } } +// SetNotificationEmailService attaches the public notification email service without +// changing the constructor signature used by existing tests. +func (h *SettingHandler) SetNotificationEmailService(notificationEmailService *service.NotificationEmailService) { + h.notificationEmailService = notificationEmailService +} + // GetPublicSettings 获取公开设置 // GET /api/v1/settings/public func (h *SettingHandler) GetPublicSettings(c *gin.Context) { @@ -90,6 +101,27 @@ func (h *SettingHandler) GetPublicSettings(c *gin.Context) { }) } +// UnsubscribeNotificationEmail handles optional notification email opt-outs. +// GET /api/v1/settings/email-unsubscribe?token=... +func (h *SettingHandler) UnsubscribeNotificationEmail(c *gin.Context) { + if h.notificationEmailService == nil { + response.InternalError(c, "notification email service is not configured") + return + } + token := strings.TrimSpace(c.Query("token")) + if token == "" { + response.BadRequest(c, "token is required") + return + } + result, err := h.notificationEmailService.Unsubscribe(c.Request.Context(), token) + if err != nil { + response.BadRequest(c, err.Error()) + return + } + body := "Unsubscribed

Unsubscribed

You have unsubscribed " + html.EscapeString(result.Email) + " from " + html.EscapeString(result.Event) + " emails.

" + c.Data(http.StatusOK, "text/html; charset=utf-8", []byte(body)) +} + func publicLoginAgreementDocumentsToDTO(items []service.LoginAgreementDocument) []dto.LoginAgreementDocument { result := make([]dto.LoginAgreementDocument, 0, len(items)) for _, item := range items { diff --git a/backend/internal/server/routes/auth.go b/backend/internal/server/routes/auth.go index 19d0fd2a..2c44a2b3 100644 --- a/backend/internal/server/routes/auth.go +++ b/backend/internal/server/routes/auth.go @@ -214,6 +214,7 @@ func RegisterAuthRoutes( settings := v1.Group("/settings") { settings.GET("/public", h.Setting.GetPublicSettings) + settings.GET("/email-unsubscribe", h.Setting.UnsubscribeNotificationEmail) } // 需要认证的当前用户信息