From ec950da8886b40c82a635b688913cc7e83bcb9c7 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Fri, 21 Oct 2022 12:00:50 +0800 Subject: [PATCH 1/2] update Annotation document --- docs/docs.go | 4 ++-- docs/swagger.json | 4 ++-- docs/swagger.yaml | 4 ++-- internal/entity/auth_user_entity.go | 2 +- internal/schema/answer_schema.go | 4 ++-- internal/schema/question_schema.go | 22 +++++++++++----------- internal/service/answer_service.go | 1 - pkg/checker/password.go | 16 +++++++++------- 8 files changed, 29 insertions(+), 28 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index aaf70898..529f1d8c 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4092,7 +4092,7 @@ const docTemplate = `{ "type": "string" }, "html": { - "description": "解析后的html", + "description": "html", "type": "string" }, "question_id": { @@ -4146,7 +4146,7 @@ const docTemplate = `{ "type": "string" }, "html": { - "description": "解析后的html", + "description": "html", "type": "string" }, "id": { diff --git a/docs/swagger.json b/docs/swagger.json index 1b8b7b86..ac6454cd 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4080,7 +4080,7 @@ "type": "string" }, "html": { - "description": "解析后的html", + "description": "html", "type": "string" }, "question_id": { @@ -4134,7 +4134,7 @@ "type": "string" }, "html": { - "description": "解析后的html", + "description": "html", "type": "string" }, "id": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 7fb3d432..9d9b87ef 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -129,7 +129,7 @@ definitions: description: content type: string html: - description: 解析后的html + description: html type: string question_id: description: question_id @@ -167,7 +167,7 @@ definitions: description: edit_summary type: string html: - description: 解析后的html + description: html type: string id: description: id diff --git a/internal/entity/auth_user_entity.go b/internal/entity/auth_user_entity.go index 2e846833..d1f366a4 100644 --- a/internal/entity/auth_user_entity.go +++ b/internal/entity/auth_user_entity.go @@ -1,6 +1,6 @@ package entity -// UserCacheInfo 用户缓存信息 +// UserCacheInfo User Cache Information type UserCacheInfo struct { UserID string `json:"user_id"` UserStatus int `json:"user_status"` diff --git a/internal/schema/answer_schema.go b/internal/schema/answer_schema.go index 74c4111c..fde11165 100644 --- a/internal/schema/answer_schema.go +++ b/internal/schema/answer_schema.go @@ -16,7 +16,7 @@ const ( type AnswerAddReq struct { QuestionId string `json:"question_id" ` // question_id Content string `json:"content" ` // content - Html string `json:"html" ` // 解析后的html + Html string `json:"html" ` // html UserID string `json:"-" ` // user_id } @@ -26,7 +26,7 @@ type AnswerUpdateReq struct { UserID string `json:"-" ` // user_id Title string `json:"title" ` // title Content string `json:"content"` // content - Html string `json:"html" ` // 解析后的html + Html string `json:"html" ` // html EditSummary string `validate:"omitempty" json:"edit_summary"` //edit_summary } diff --git a/internal/schema/question_schema.go b/internal/schema/question_schema.go index 139684bf..a619c454 100644 --- a/internal/schema/question_schema.go +++ b/internal/schema/question_schema.go @@ -52,27 +52,27 @@ type QuestionUpdate struct { type QuestionBaseInfo struct { ID string `json:"id" ` - Title string `json:"title" xorm:"title"` // 标题 - ViewCount int `json:"view_count" xorm:"view_count"` // view_count - AnswerCount int `json:"answer_count" xorm:"answer_count"` // 回复总数 - CollectionCount int `json:"collection_count" xorm:"collection_count"` // 收藏总数 - FollowCount int `json:"follow_count" xorm:"follow_count"` // 关注数 + Title string `json:"title" xorm:"title"` // title + ViewCount int `json:"view_count" xorm:"view_count"` // view count + AnswerCount int `json:"answer_count" xorm:"answer_count"` // answer count + CollectionCount int `json:"collection_count" xorm:"collection_count"` // collection count + FollowCount int `json:"follow_count" xorm:"follow_count"` // follow count Status string `json:"status"` AcceptedAnswer bool `json:"accepted_answer"` } type QuestionInfo struct { ID string `json:"id" ` - Title string `json:"title" xorm:"title"` // 标题 - Content string `json:"content" xorm:"content"` // 内容 - Html string `json:"html" xorm:"html"` // 解析后的html + Title string `json:"title" xorm:"title"` // title + Content string `json:"content" xorm:"content"` // content + Html string `json:"html" xorm:"html"` // html Tags []*TagResp `json:"tags" ` // tags ViewCount int `json:"view_count" xorm:"view_count"` // view_count UniqueViewCount int `json:"unique_view_count" xorm:"unique_view_count"` // unique_view_count VoteCount int `json:"vote_count" xorm:"vote_count"` // vote_count - AnswerCount int `json:"answer_count" xorm:"answer_count"` // 回复总数 - CollectionCount int `json:"collection_count" xorm:"collection_count"` // 收藏总数 - FollowCount int `json:"follow_count" xorm:"follow_count"` // 关注数 + AnswerCount int `json:"answer_count" xorm:"answer_count"` // answer count + CollectionCount int `json:"collection_count" xorm:"collection_count"` // collection count + FollowCount int `json:"follow_count" xorm:"follow_count"` // follow count AcceptedAnswerId string `json:"accepted_answer_id" ` // accepted_answer_id LastAnswerId string `json:"last_answer_id" ` // last_answer_id CreateTime int64 `json:"create_time" ` // create_time diff --git a/internal/service/answer_service.go b/internal/service/answer_service.go index 577c2f4a..ec1a8b4a 100644 --- a/internal/service/answer_service.go +++ b/internal/service/answer_service.go @@ -365,7 +365,6 @@ func (as *AnswerService) SearchList(ctx context.Context, search *schema.AnswerLi func (as *AnswerService) SearchFormatInfo(ctx context.Context, dblist []*entity.Answer, loginUserId string) ([]*schema.AnswerInfo, error) { list := make([]*schema.AnswerInfo, 0) - //todo 依赖其他接口 objectIds := make([]string, 0) userIds := make([]string, 0) for _, dbitem := range dblist { diff --git a/pkg/checker/password.go b/pkg/checker/password.go index 4b64ff60..33e4e3da 100644 --- a/pkg/checker/password.go +++ b/pkg/checker/password.go @@ -14,13 +14,13 @@ const ( ) /* - * minLength: 指定密码的最小长度 - * maxLength:指定密码的最大长度 - * minLevel:指定密码最低要求的强度等级 - * pwd:明文密码 + * minLength: Specifies the minimum length of a password + * maxLength:Specifies the maximum length of a password + * minLevel:Specifies the minimum strength level required for passwords + * pwd:Text passwords */ func PassWordCheck(minLength, maxLength, minLevel int, pwd string) error { - // 首先校验密码长度是否在范围内 + // First check whether the password length is within the range if len(pwd) < minLength { return fmt.Errorf("BAD PASSWORD: The password is shorter than %d characters", minLength) } @@ -28,7 +28,9 @@ func PassWordCheck(minLength, maxLength, minLevel int, pwd string) error { return fmt.Errorf("BAD PASSWORD: The password is logner than %d characters", maxLength) } - // 初始化密码强度等级为D,利用正则校验密码强度,若匹配成功则强度自增1 + // The password strength level is initialized to D. + // The regular is used to verify the password strength. + // If the matching is successful, the password strength increases by 1 var level int = levelD patternList := []string{`[0-9]+`, `[a-z]+`, `[A-Z]+`, `[~!@#$%^&*?_-]+`} for _, pattern := range patternList { @@ -38,7 +40,7 @@ func PassWordCheck(minLength, maxLength, minLevel int, pwd string) error { } } - // 如果最终密码强度低于要求的最低强度,返回并报错 + // If the final password strength falls below the required minimum strength, return with an error if level < minLevel { return fmt.Errorf("The password does not satisfy the current policy requirements. ") } From ea9eb3107337fc41e693d66b162f53ac9a46ac10 Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Fri, 21 Oct 2022 17:04:41 +0800 Subject: [PATCH 2/2] feat: smtp update config field, send test email after config --- docs/docs.go | 17 ++++-- docs/swagger.json | 17 ++++-- docs/swagger.yaml | 14 +++-- internal/schema/siteinfo_schema.go | 31 ++++++----- internal/service/export/email_service.go | 68 +++++++++++++++++++----- internal/service/siteinfo_service.go | 21 ++++++-- 6 files changed, 126 insertions(+), 42 deletions(-) diff --git a/docs/docs.go b/docs/docs.go index 529f1d8c..bbdc7c89 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4622,15 +4622,18 @@ const docTemplate = `{ "type": "object", "properties": { "encryption": { - "description": "\"\" SSL TLS", + "description": "\"\" SSL", "type": "string" }, - "from_email_address": { + "from_email": { "type": "string" }, "from_name": { "type": "string" }, + "smtp_authentication": { + "type": "boolean" + }, "smtp_host": { "type": "string" }, @@ -5530,13 +5533,13 @@ const docTemplate = `{ "type": "object", "properties": { "encryption": { - "description": "\"\" SSL TLS", + "description": "\"\" SSL", "type": "string", "enum": [ "SSL" ] }, - "from_email_address": { + "from_email": { "type": "string", "maxLength": 256 }, @@ -5544,6 +5547,9 @@ const docTemplate = `{ "type": "string", "maxLength": 256 }, + "smtp_authentication": { + "type": "boolean" + }, "smtp_host": { "type": "string", "maxLength": 256 @@ -5560,6 +5566,9 @@ const docTemplate = `{ "smtp_username": { "type": "string", "maxLength": 256 + }, + "test_email_recipient": { + "type": "string" } } }, diff --git a/docs/swagger.json b/docs/swagger.json index ac6454cd..3bffef99 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4610,15 +4610,18 @@ "type": "object", "properties": { "encryption": { - "description": "\"\" SSL TLS", + "description": "\"\" SSL", "type": "string" }, - "from_email_address": { + "from_email": { "type": "string" }, "from_name": { "type": "string" }, + "smtp_authentication": { + "type": "boolean" + }, "smtp_host": { "type": "string" }, @@ -5518,13 +5521,13 @@ "type": "object", "properties": { "encryption": { - "description": "\"\" SSL TLS", + "description": "\"\" SSL", "type": "string", "enum": [ "SSL" ] }, - "from_email_address": { + "from_email": { "type": "string", "maxLength": 256 }, @@ -5532,6 +5535,9 @@ "type": "string", "maxLength": 256 }, + "smtp_authentication": { + "type": "boolean" + }, "smtp_host": { "type": "string", "maxLength": 256 @@ -5548,6 +5554,9 @@ "smtp_username": { "type": "string", "maxLength": 256 + }, + "test_email_recipient": { + "type": "string" } } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 9d9b87ef..c0f1febb 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -513,12 +513,14 @@ definitions: schema.GetSMTPConfigResp: properties: encryption: - description: '"" SSL TLS' + description: '"" SSL' type: string - from_email_address: + from_email: type: string from_name: type: string + smtp_authentication: + type: boolean smtp_host: type: string smtp_password: @@ -1167,16 +1169,18 @@ definitions: schema.UpdateSMTPConfigReq: properties: encryption: - description: '"" SSL TLS' + description: '"" SSL' enum: - SSL type: string - from_email_address: + from_email: maxLength: 256 type: string from_name: maxLength: 256 type: string + smtp_authentication: + type: boolean smtp_host: maxLength: 256 type: string @@ -1190,6 +1194,8 @@ definitions: smtp_username: maxLength: 256 type: string + test_email_recipient: + type: string type: object schema.UpdateTagReq: properties: diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go index 39e3f2e7..ff93e72d 100644 --- a/internal/schema/siteinfo_schema.go +++ b/internal/schema/siteinfo_schema.go @@ -27,22 +27,25 @@ type SiteInfoResp struct { // UpdateSMTPConfigReq get smtp config request type UpdateSMTPConfigReq struct { - FromEmailAddress string `validate:"omitempty,gt=0,lte=256" json:"from_email_address"` - FromName string `validate:"omitempty,gt=0,lte=256" json:"from_name"` - SMTPHost string `validate:"omitempty,gt=0,lte=256" json:"smtp_host"` - SMTPPort int `validate:"omitempty,min=1,max=65535" json:"smtp_port"` - Encryption string `validate:"omitempty,oneof=SSL" json:"encryption"` // "" SSL TLS - SMTPUsername string `validate:"omitempty,gt=0,lte=256" json:"smtp_username"` - SMTPPassword string `validate:"omitempty,gt=0,lte=256" json:"smtp_password"` + FromEmail string `validate:"omitempty,gt=0,lte=256" json:"from_email"` + FromName string `validate:"omitempty,gt=0,lte=256" json:"from_name"` + SMTPHost string `validate:"omitempty,gt=0,lte=256" json:"smtp_host"` + SMTPPort int `validate:"omitempty,min=1,max=65535" json:"smtp_port"` + Encryption string `validate:"omitempty,oneof=SSL" json:"encryption"` // "" SSL + SMTPUsername string `validate:"omitempty,gt=0,lte=256" json:"smtp_username"` + SMTPPassword string `validate:"omitempty,gt=0,lte=256" json:"smtp_password"` + SMTPAuthentication bool `validate:"omitempty" json:"smtp_authentication"` + TestEmailRecipient string `validate:"omitempty,email" json:"test_email_recipient"` } // GetSMTPConfigResp get smtp config response type GetSMTPConfigResp struct { - FromEmailAddress string `json:"from_email_address"` - FromName string `json:"from_name"` - SMTPHost string `json:"smtp_host"` - SMTPPort int `json:"smtp_port"` - Encryption string `json:"encryption"` // "" SSL TLS - SMTPUsername string `json:"smtp_username"` - SMTPPassword string `json:"smtp_password"` + FromEmail string `json:"from_email"` + FromName string `json:"from_name"` + SMTPHost string `json:"smtp_host"` + SMTPPort int `json:"smtp_port"` + Encryption string `json:"encryption"` // "" SSL + SMTPUsername string `json:"smtp_username"` + SMTPPassword string `json:"smtp_password"` + SMTPAuthentication bool `json:"smtp_authentication"` } diff --git a/internal/service/export/email_service.go b/internal/service/export/email_service.go index 37f5f354..56dd5530 100644 --- a/internal/service/export/email_service.go +++ b/internal/service/export/email_service.go @@ -3,6 +3,7 @@ package export import ( "bytes" "encoding/json" + "fmt" "html/template" "github.com/segmentfault/answer/internal/base/reason" @@ -35,13 +36,14 @@ func NewEmailService(configRepo config.ConfigRepo, emailRepo EmailRepo) *EmailSe // EmailConfig email config type EmailConfig struct { - FromEmailAddress string `json:"from_email_address"` - FromName string `json:"from_name"` - SMTPHost string `json:"smtp_host"` - SMTPPort int `json:"smtp_port"` - Encryption string `json:"encryption"` // "" SSL - SMTPUsername string `json:"smtp_username"` - SMTPPassword string `json:"smtp_password"` + FromEmail string `json:"from_email"` + FromName string `json:"from_name"` + SMTPHost string `json:"smtp_host"` + SMTPPort int `json:"smtp_port"` + Encryption string `json:"encryption"` // "" SSL + SMTPUsername string `json:"smtp_username"` + SMTPPassword string `json:"smtp_password"` + SMTPAuthentication bool `json:"smtp_authentication"` RegisterTitle string `json:"register_title"` RegisterBody string `json:"register_body"` @@ -49,6 +51,8 @@ type EmailConfig struct { PassResetBody string `json:"pass_reset_body"` ChangeTitle string `json:"change_title"` ChangeBody string `json:"change_body"` + TestTitle string `json:"test_title"` + TestBody string `json:"test_body"` } func (e *EmailConfig) IsSSL() bool { @@ -70,16 +74,21 @@ type ChangeEmailTemplateData struct { ChangeEmailUrl string } +type TestTemplateData struct { + SiteName string +} + // Send email send func (es *EmailService) Send(ctx context.Context, toEmailAddr, subject, body, code, codeContent string) { + log.Infof("try to send email to %s", toEmailAddr) ec, err := es.GetEmailConfig() if err != nil { - log.Error(err) + log.Errorf("get email config failed: %s", err) return } m := gomail.NewMessage() - m.SetHeader("From", ec.FromEmailAddress) + m.SetHeader("From", ec.FromEmail) m.SetHeader("To", toEmailAddr) m.SetHeader("Subject", subject) m.SetBody("text/html", body) @@ -89,12 +98,16 @@ func (es *EmailService) Send(ctx context.Context, toEmailAddr, subject, body, co d.SSL = true } if err := d.DialAndSend(m); err != nil { - log.Error(err) + log.Errorf("send email to %s failed: %s", toEmailAddr, err) + } else { + log.Infof("send email to %s success", toEmailAddr) } - err = es.emailRepo.SetCode(ctx, code, codeContent) - if err != nil { - log.Error(err) + if len(code) > 0 { + err = es.emailRepo.SetCode(ctx, code, codeContent) + if err != nil { + log.Error(err) + } } return } @@ -192,6 +205,35 @@ func (es *EmailService) ChangeEmailTemplate(changeEmailUrl string) (title, body return titleBuf.String(), bodyBuf.String(), nil } +func (es *EmailService) TestTemplate() (title, body string, err error) { + ec, err := es.GetEmailConfig() + if err != nil { + return + } + + templateData := TestTemplateData{ + SiteName: ec.FromName, + } + + titleBuf := &bytes.Buffer{} + bodyBuf := &bytes.Buffer{} + + tmpl, err := template.New("test_title").Parse(ec.TestTitle) + if err != nil { + return "", "", fmt.Errorf("email test title template parse error: %s", err) + } + err = tmpl.Execute(titleBuf, templateData) + if err != nil { + return "", "", fmt.Errorf("email test body template parse error: %s", err) + } + tmpl, err = template.New("test_body").Parse(ec.TestBody) + err = tmpl.Execute(bodyBuf, templateData) + if err != nil { + return "", "", err + } + return titleBuf.String(), bodyBuf.String(), nil +} + func (es *EmailService) GetEmailConfig() (ec *EmailConfig, err error) { emailConf, err := es.configRepo.GetString("email.config") if err != nil { diff --git a/internal/service/siteinfo_service.go b/internal/service/siteinfo_service.go index 022db57f..89db720c 100644 --- a/internal/service/siteinfo_service.go +++ b/internal/service/siteinfo_service.go @@ -132,7 +132,22 @@ func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) ( // UpdateSMTPConfig get smtp config func (s *SiteInfoService) UpdateSMTPConfig(ctx context.Context, req *schema.UpdateSMTPConfigReq) (err error) { - ec := &export.EmailConfig{} - _ = copier.Copy(ec, req) - return s.emailService.SetEmailConfig(ec) + oldEmailConfig, err := s.emailService.GetEmailConfig() + if err != nil { + return err + } + _ = copier.Copy(oldEmailConfig, req) + + err = s.emailService.SetEmailConfig(oldEmailConfig) + if err != nil { + return err + } + if len(req.TestEmailRecipient) > 0 { + title, body, err := s.emailService.TestTemplate() + if err != nil { + return err + } + go s.emailService.Send(ctx, req.TestEmailRecipient, title, body, "", "") + } + return }