From d19ce5eb2860ab37ea546c551a6bf6abe0cef6d1 Mon Sep 17 00:00:00 2001 From: Zhang Minghan Date: Wed, 27 Dec 2023 17:42:27 +0800 Subject: [PATCH] feat: smtp test feature --- app/src/dialogs/PackageDialog.tsx | 15 ++++--- app/src/resources/i18n/cn.json | 1 + app/src/routes/admin/System.tsx | 72 +++++++++++++++++++++++++++---- auth/auth.go | 12 +++--- utils/smtp.go | 13 ++++++ 5 files changed, 91 insertions(+), 22 deletions(-) diff --git a/app/src/dialogs/PackageDialog.tsx b/app/src/dialogs/PackageDialog.tsx index 22079223..2ecf353f 100644 --- a/app/src/dialogs/PackageDialog.tsx +++ b/app/src/dialogs/PackageDialog.tsx @@ -23,7 +23,7 @@ import { Separator } from "@/components/ui/separator.tsx"; import { Badge } from "@/components/ui/badge.tsx"; import { useEffectAsync } from "@/utils/hook.ts"; import { selectAuthenticated } from "@/store/auth.ts"; -import { deeptrainEndpoint } from "@/utils/env.ts"; +import { deeptrainEndpoint, useDeeptrain } from "@/utils/env.ts"; function PackageDialog() { const { t } = useTranslation(); @@ -33,13 +33,14 @@ function PackageDialog() { const teenager = useSelector(teenagerSelector); const auth = useSelector(selectAuthenticated); - useEffectAsync(async () => { - if (!auth) return; - const task = setInterval(() => refreshPackage(dispatch), 20000); - await refreshPackage(dispatch); + useDeeptrain && + useEffectAsync(async () => { + if (!auth) return; + const task = setInterval(() => refreshPackage(dispatch), 20000); + await refreshPackage(dispatch); - return () => clearInterval(task); - }, [auth]); + return () => clearInterval(task); + }, [auth]); return ( dispatch(setDialog(open))}> diff --git a/app/src/resources/i18n/cn.json b/app/src/resources/i18n/cn.json index 78989962..19ed87ea 100644 --- a/app/src/resources/i18n/cn.json +++ b/app/src/resources/i18n/cn.json @@ -464,6 +464,7 @@ "search": "联网搜索", "mail": "SMTP 发件设置", "save": "保存", + "test": "测试发件", "backend": "后端域名", "backendTip": "后端回调域名(docker 安装默认路径为 /api),接收回调参数。", "mailHost": "发件域名", diff --git a/app/src/routes/admin/System.tsx b/app/src/routes/admin/System.tsx index 698119c4..cff5681b 100644 --- a/app/src/routes/admin/System.tsx +++ b/app/src/routes/admin/System.tsx @@ -13,7 +13,7 @@ import Paragraph, { import { Button } from "@/components/ui/button.tsx"; import { Label } from "@/components/ui/label.tsx"; import { Input } from "@/components/ui/input.tsx"; -import { useReducer } from "react"; +import { useReducer, useState } from "react"; import { formReducer } from "@/utils/form.ts"; import { NumberInput } from "@/components/ui/number-input.tsx"; import { @@ -27,12 +27,22 @@ import { } from "@/admin/api/system.ts"; import { useEffectAsync } from "@/utils/hook.ts"; import { toastState } from "@/admin/utils.ts"; -import { useToast } from "@/components/ui/use-toast.ts"; +import { toast, useToast } from "@/components/ui/use-toast.ts"; +import { doVerify } from "@/api/auth.ts"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTrigger, +} from "@/components/ui/dialog.tsx"; +import { DialogTitle } from "@radix-ui/react-dialog"; type CompProps = { data: T; dispatch: (action: any) => void; - onChange: () => void; + onChange: (doToast?: boolean) => Promise; }; function General({ data, dispatch, onChange }: CompProps) { @@ -72,6 +82,18 @@ function General({ data, dispatch, onChange }: CompProps) { function Mail({ data, dispatch, onChange }: CompProps) { const { t } = useTranslation(); + const [email, setEmail] = useState(""); + + const [mailDialog, setMailDialog] = useState(false); + + const onTest = async () => { + if (!email.trim()) return; + await onChange(false); + const res = await doVerify(email); + toastState(toast, t, res, true); + + if (res.status) setMailDialog(false); + }; return ( ) {
+ + + + + + + {t("admin.system.test")} + + setEmail(e.target.value)} + /> + + + + + + + + @@ -206,9 +261,10 @@ function System() { initialSystemState, ); - const save = async () => { + const doSaving = async (doToast?: boolean) => { const res = await setConfig(data); - toastState(toast, t, res, true); + + if (doToast !== false) toastState(toast, t, res, true); }; useEffectAsync(async () => { @@ -226,9 +282,9 @@ function System() { {t("admin.settings")} - - - + + +
diff --git a/auth/auth.go b/auth/auth.go index cfb2e458..fcf53b79 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -95,17 +95,15 @@ func Verify(c *gin.Context, email string) error { provider := channel.SystemInstance.GetMail() - template, err := provider.RenderTemplate("code.html", struct { - Code string - }{Code: code}) - if err != nil { - return err + type Temp struct { + Code string `json:"code"` } - return provider.SendMail( + return provider.RenderMail( + "code.html", + Temp{Code: code}, email, "Chat Nio | OTP Verification", - template, ) } diff --git a/utils/smtp.go b/utils/smtp.go index 9b8a87e9..d13558f8 100644 --- a/utils/smtp.go +++ b/utils/smtp.go @@ -28,6 +28,10 @@ func NewSmtpPoster(host string, port int, username string, password string, from } func (s *SmtpPoster) SendMail(to string, subject string, body string) error { + if s.Host == "" || s.Port <= 0 || s.Port > 65535 || s.Username == "" || s.Password == "" || s.From == "" { + return fmt.Errorf("smtp not configured properly") + } + addr := fmt.Sprintf("%s:%d", s.Host, s.Port) auth := smtp.PlainAuth("", s.From, s.Password, s.Host) @@ -54,6 +58,15 @@ func (s *SmtpPoster) RenderTemplate(filename string, data interface{}) (string, return buf.String(), nil } +func (s *SmtpPoster) RenderMail(filename string, data interface{}, to string, subject string) error { + body, err := s.RenderTemplate(filename, data) + if err != nil { + return err + } + + return s.SendMail(to, subject, body) +} + func dial(addr string) (*smtp.Client, error) { conn, err := tls.Dial("tcp", addr, nil) if err != nil {