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) } // 需要认证的当前用户信息