Merge remote-tracking branch 'origin/main' into feat/orm-init

This commit is contained in:
LinkinStar 2022-10-21 17:23:06 +08:00
commit 25e167d957
11 changed files with 155 additions and 70 deletions

View File

@ -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": {
@ -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"
}
}
},

View File

@ -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": {
@ -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"
}
}
},

View File

@ -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
@ -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:

View File

@ -1,6 +1,6 @@
package entity
// UserCacheInfo 用户缓存信息
// UserCacheInfo User Cache Information
type UserCacheInfo struct {
UserID string `json:"user_id"`
UserStatus int `json:"user_status"`

View File

@ -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
}

View File

@ -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

View File

@ -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"`
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 TLS
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"`
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 TLS
Encryption string `json:"encryption"` // "" SSL
SMTPUsername string `json:"smtp_username"`
SMTPPassword string `json:"smtp_password"`
SMTPAuthentication bool `json:"smtp_authentication"`
}

View File

@ -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 {

View File

@ -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"`
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,13 +98,17 @@ 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)
}
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 {

View File

@ -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
}

View File

@ -14,13 +14,13 @@ const (
)
/*
* minLength: 指定密码的最小长度
* maxLength指定密码的最大长度
* minLevel指定密码最低要求的强度等级
* pwd明文密码
* minLength: Specifies the minimum length of a password
* maxLengthSpecifies the maximum length of a password
* minLevelSpecifies the minimum strength level required for passwords
* pwdText 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. ")
}