mirror of https://gitee.com/answerdev/answer.git
feat(admin): allow admin resend activation email
This commit is contained in:
parent
69f250ee04
commit
3283e09c9a
|
@ -188,7 +188,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
reportAdminService := report_admin.NewReportAdminService(reportRepo, userCommon, answerRepo, questionRepo, commentCommonRepo, reportHandle, configService, objService)
|
||||
controller_adminReportController := controller_admin.NewReportController(reportAdminService)
|
||||
userAdminRepo := user.NewUserAdminRepo(dataData, authRepo)
|
||||
userAdminService := user_admin.NewUserAdminService(userAdminRepo, userRoleRelService, authService, userCommon, userActiveActivityRepo, siteInfoCommonService)
|
||||
userAdminService := user_admin.NewUserAdminService(userAdminRepo, userRoleRelService, authService, userCommon, userActiveActivityRepo, siteInfoCommonService, emailService)
|
||||
userAdminController := controller_admin.NewUserAdminController(userAdminService)
|
||||
reasonRepo := reason.NewReasonRepo(configService)
|
||||
reasonService := reason2.NewReasonService(reasonRepo)
|
||||
|
|
106
docs/docs.go
106
docs/docs.go
|
@ -1695,6 +1695,86 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/admin/api/users/activation": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "get user activation",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "get user activation",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "user id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/schema.GetUserActivationResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "send user activation",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "send user activation",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "SendUserActivationReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.SendUserActivationReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/admin/api/users/page": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
@ -3444,7 +3524,7 @@ const docTemplate = `{
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "user's vote",
|
||||
"description": "get user personal votes",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -3454,7 +3534,7 @@ const docTemplate = `{
|
|||
"tags": [
|
||||
"Activity"
|
||||
],
|
||||
"summary": "user's votes",
|
||||
"summary": "get user personal votes",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
@ -6345,7 +6425,8 @@ const docTemplate = `{
|
|||
"properties": {
|
||||
"display_name": {
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
"maxLength": 30,
|
||||
"minLength": 4
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
|
@ -7397,6 +7478,14 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserActivationResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"activation_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserPageResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8012,6 +8101,17 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.SendUserActivationReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"user_id"
|
||||
],
|
||||
"properties": {
|
||||
"user_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.SiteBrandingReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -1683,6 +1683,86 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/answer/admin/api/users/activation": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "get user activation",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "get user activation",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "user id",
|
||||
"name": "user_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/schema.GetUserActivationResp"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "send user activation",
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"admin"
|
||||
],
|
||||
"summary": "send user activation",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "SendUserActivationReq",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/schema.SendUserActivationReq"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/handler.RespBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/answer/admin/api/users/page": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
@ -3432,7 +3512,7 @@
|
|||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "user's vote",
|
||||
"description": "get user personal votes",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -3442,7 +3522,7 @@
|
|||
"tags": [
|
||||
"Activity"
|
||||
],
|
||||
"summary": "user's votes",
|
||||
"summary": "get user personal votes",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
@ -6333,7 +6413,8 @@
|
|||
"properties": {
|
||||
"display_name": {
|
||||
"type": "string",
|
||||
"maxLength": 30
|
||||
"maxLength": 30,
|
||||
"minLength": 4
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
|
@ -7385,6 +7466,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserActivationResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"activation_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.GetUserPageResp": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8000,6 +8089,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"schema.SendUserActivationReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"user_id"
|
||||
],
|
||||
"properties": {
|
||||
"user_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"schema.SiteBrandingReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -206,6 +206,7 @@ definitions:
|
|||
properties:
|
||||
display_name:
|
||||
maxLength: 30
|
||||
minLength: 4
|
||||
type: string
|
||||
email:
|
||||
maxLength: 500
|
||||
|
@ -952,6 +953,11 @@ definitions:
|
|||
unreviewed_info:
|
||||
$ref: '#/definitions/schema.GetRevisionResp'
|
||||
type: object
|
||||
schema.GetUserActivationResp:
|
||||
properties:
|
||||
activation_url:
|
||||
type: string
|
||||
type: object
|
||||
schema.GetUserPageResp:
|
||||
properties:
|
||||
avatar:
|
||||
|
@ -1382,6 +1388,13 @@ definitions:
|
|||
description: object_type
|
||||
type: string
|
||||
type: object
|
||||
schema.SendUserActivationReq:
|
||||
properties:
|
||||
user_id:
|
||||
type: string
|
||||
required:
|
||||
- user_id
|
||||
type: object
|
||||
schema.SiteBrandingReq:
|
||||
properties:
|
||||
favicon:
|
||||
|
@ -3291,6 +3304,53 @@ paths:
|
|||
summary: update user
|
||||
tags:
|
||||
- admin
|
||||
/answer/admin/api/users/activation:
|
||||
get:
|
||||
description: get user activation
|
||||
parameters:
|
||||
- description: user id
|
||||
in: query
|
||||
name: user_id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/handler.RespBody'
|
||||
- properties:
|
||||
data:
|
||||
$ref: '#/definitions/schema.GetUserActivationResp'
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: get user activation
|
||||
tags:
|
||||
- admin
|
||||
post:
|
||||
description: send user activation
|
||||
parameters:
|
||||
- description: SendUserActivationReq
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/schema.SendUserActivationReq'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/handler.RespBody'
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: send user activation
|
||||
tags:
|
||||
- admin
|
||||
/answer/admin/api/users/page:
|
||||
get:
|
||||
description: get user page
|
||||
|
@ -4364,7 +4424,7 @@ paths:
|
|||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: user's vote
|
||||
description: get user personal votes
|
||||
parameters:
|
||||
- description: page size
|
||||
in: query
|
||||
|
@ -4395,7 +4455,7 @@ paths:
|
|||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: user's votes
|
||||
summary: get user personal votes
|
||||
tags:
|
||||
- Activity
|
||||
/answer/api/v1/post/render:
|
||||
|
|
|
@ -135,3 +135,41 @@ func (uc *UserAdminController) GetUserPage(ctx *gin.Context) {
|
|||
resp, err := uc.userService.GetUserPage(ctx, req)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// GetUserActivation get user activation
|
||||
// @Summary get user activation
|
||||
// @Description get user activation
|
||||
// @Security ApiKeyAuth
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Param user_id query string true "user id"
|
||||
// @Success 200 {object} handler.RespBody{data=schema.GetUserActivationResp}
|
||||
// @Router /answer/admin/api/users/activation [get]
|
||||
func (uc *UserAdminController) GetUserActivation(ctx *gin.Context) {
|
||||
req := &schema.GetUserActivationReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := uc.userService.GetUserActivation(ctx, req)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// SendUserActivation send user activation
|
||||
// @Summary send user activation
|
||||
// @Description send user activation
|
||||
// @Security ApiKeyAuth
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Param data body schema.SendUserActivationReq true "SendUserActivationReq"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/admin/api/users/activation [post]
|
||||
func (uc *UserAdminController) SendUserActivation(ctx *gin.Context) {
|
||||
req := &schema.SendUserActivationReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
|
||||
err := uc.userService.SendUserActivation(ctx, req)
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
|
|
@ -257,6 +257,8 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
|||
r.GET("/users/page", a.adminUserController.GetUserPage)
|
||||
r.PUT("/user/status", a.adminUserController.UpdateUserStatus)
|
||||
r.PUT("/user/role", a.adminUserController.UpdateUserRole)
|
||||
r.GET("/user/activation", a.adminUserController.GetUserActivation)
|
||||
r.POST("/user/activation", a.adminUserController.SendUserActivation)
|
||||
r.POST("/user", a.adminUserController.AddUser)
|
||||
r.PUT("/user/password", a.adminUserController.UpdateUserPassword)
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ type UpdateUserRoleReq struct {
|
|||
|
||||
// AddUserReq add user request
|
||||
type AddUserReq struct {
|
||||
DisplayName string `validate:"required,gt=4,lte=30" json:"display_name"`
|
||||
DisplayName string `validate:"required,gte=4,lte=30" json:"display_name"`
|
||||
Email string `validate:"required,email,gt=0,lte=500" json:"email"`
|
||||
Password string `validate:"required,gte=8,lte=32" json:"password"`
|
||||
LoginUserID string `json:"-"`
|
||||
|
@ -98,3 +98,18 @@ type UpdateUserPasswordReq struct {
|
|||
Password string `validate:"required,gte=8,lte=32" json:"password"`
|
||||
LoginUserID string `json:"-"`
|
||||
}
|
||||
|
||||
// GetUserActivationReq get user activation
|
||||
type GetUserActivationReq struct {
|
||||
UserID string `validate:"required" form:"user_id"`
|
||||
}
|
||||
|
||||
// GetUserActivationResp get user activation
|
||||
type GetUserActivationResp struct {
|
||||
ActivationURL string `json:"activation_url"`
|
||||
}
|
||||
|
||||
// SendUserActivationReq send user activation
|
||||
type SendUserActivationReq struct {
|
||||
UserID string `validate:"required" json:"user_id"`
|
||||
}
|
||||
|
|
|
@ -79,6 +79,14 @@ type TestTemplateData struct {
|
|||
SiteName string
|
||||
}
|
||||
|
||||
// SaveCode save code
|
||||
func (es *EmailService) SaveCode(ctx context.Context, code, codeContent string) {
|
||||
err := es.emailRepo.SetCode(ctx, code, codeContent, 10*time.Minute)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// SendAndSaveCode send email and save code
|
||||
func (es *EmailService) SendAndSaveCode(ctx context.Context, toEmailAddr, subject, body, code, codeContent string) {
|
||||
es.Send(ctx, toEmailAddr, subject, body)
|
||||
|
|
|
@ -3,6 +3,8 @@ package user_admin
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/answerdev/answer/internal/service/export"
|
||||
"github.com/google/uuid"
|
||||
"net/mail"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -42,6 +44,7 @@ type UserAdminService struct {
|
|||
userCommonService *usercommon.UserCommon
|
||||
userActivity activity.UserActiveActivityRepo
|
||||
siteInfoCommonService siteinfo_common.SiteInfoCommonService
|
||||
emailService *export.EmailService
|
||||
}
|
||||
|
||||
// NewUserAdminService new user admin service
|
||||
|
@ -52,6 +55,7 @@ func NewUserAdminService(
|
|||
userCommonService *usercommon.UserCommon,
|
||||
userActivity activity.UserActiveActivityRepo,
|
||||
siteInfoCommonService siteinfo_common.SiteInfoCommonService,
|
||||
emailService *export.EmailService,
|
||||
) *UserAdminService {
|
||||
return &UserAdminService{
|
||||
userRepo: userRepo,
|
||||
|
@ -60,6 +64,7 @@ func NewUserAdminService(
|
|||
userCommonService: userCommonService,
|
||||
userActivity: userActivity,
|
||||
siteInfoCommonService: siteInfoCommonService,
|
||||
emailService: emailService,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -293,3 +298,61 @@ func (us *UserAdminService) setUserRoleInfo(ctx context.Context, resp []*schema.
|
|||
u.RoleName = r.Name
|
||||
}
|
||||
}
|
||||
|
||||
func (us *UserAdminService) GetUserActivation(ctx context.Context, req *schema.GetUserActivationReq) (
|
||||
resp *schema.GetUserActivationResp, err error) {
|
||||
user, exist, err := us.userRepo.GetUserInfo(ctx, req.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !exist {
|
||||
return nil, errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
|
||||
general, err := us.siteInfoCommonService.GetSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := &schema.EmailCodeContent{
|
||||
Email: user.EMail,
|
||||
UserID: user.ID,
|
||||
}
|
||||
code := uuid.NewString()
|
||||
us.emailService.SaveCode(ctx, code, data.ToJSONString())
|
||||
resp = &schema.GetUserActivationResp{
|
||||
ActivationURL: fmt.Sprintf("%s/users/account-activation?code=%s", general.SiteUrl, code),
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// SendUserActivation send user activation email
|
||||
func (us *UserAdminService) SendUserActivation(ctx context.Context, req *schema.SendUserActivationReq) (err error) {
|
||||
user, exist, err := us.userRepo.GetUserInfo(ctx, req.UserID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exist {
|
||||
return errors.BadRequest(reason.UserNotFound)
|
||||
}
|
||||
|
||||
general, err := us.siteInfoCommonService.GetSiteGeneral(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := &schema.EmailCodeContent{
|
||||
Email: user.EMail,
|
||||
UserID: user.ID,
|
||||
}
|
||||
code := uuid.NewString()
|
||||
us.emailService.SaveCode(ctx, code, data.ToJSONString())
|
||||
|
||||
verifyEmailURL := fmt.Sprintf("%s/users/account-activation?code=%s", general.SiteUrl, code)
|
||||
title, body, err := us.emailService.RegisterTemplate(ctx, verifyEmailURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go us.emailService.SendAndSaveCode(ctx, user.EMail, title, body, code, data.ToJSONString())
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue