Merge branch 'test' into 'ai_0.3_install_api'

# Conflicts:
#   internal/router/ui.go
This commit is contained in:
aichy 2022-11-02 09:57:36 +00:00
commit 6d9e5578dc
38 changed files with 738 additions and 149 deletions

View File

@ -44,6 +44,7 @@ import (
auth2 "github.com/answerdev/answer/internal/service/auth"
"github.com/answerdev/answer/internal/service/collection_common"
comment2 "github.com/answerdev/answer/internal/service/comment"
"github.com/answerdev/answer/internal/service/dashboard"
export2 "github.com/answerdev/answer/internal/service/export"
"github.com/answerdev/answer/internal/service/follow"
meta2 "github.com/answerdev/answer/internal/service/meta"
@ -76,7 +77,6 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
if err != nil {
return nil, nil, err
}
langController := controller.NewLangController(i18nTranslator)
engine, err := data.NewDB(debug, dbConf)
if err != nil {
return nil, nil, err
@ -90,17 +90,19 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
cleanup()
return nil, nil, err
}
siteInfoRepo := site_info.NewSiteInfo(dataData)
configRepo := config.NewConfigRepo(dataData)
emailRepo := export.NewEmailRepo(dataData)
emailService := export2.NewEmailService(configRepo, emailRepo, siteInfoRepo)
siteInfoService := service.NewSiteInfoService(siteInfoRepo, emailService)
langController := controller.NewLangController(i18nTranslator, siteInfoService)
authRepo := auth.NewAuthRepo(dataData)
authService := auth2.NewAuthService(authRepo)
configRepo := config.NewConfigRepo(dataData)
userRepo := user.NewUserRepo(dataData, configRepo)
uniqueIDRepo := unique.NewUniqueIDRepo(dataData)
activityRepo := activity_common.NewActivityRepo(dataData, uniqueIDRepo, configRepo)
userRankRepo := rank.NewUserRankRepo(dataData, configRepo)
userActiveActivityRepo := activity.NewUserActiveActivityRepo(dataData, activityRepo, userRankRepo, configRepo)
emailRepo := export.NewEmailRepo(dataData)
siteInfoRepo := site_info.NewSiteInfo(dataData)
emailService := export2.NewEmailService(configRepo, emailRepo, siteInfoRepo)
userService := service.NewUserService(userRepo, userActiveActivityRepo, emailService, authService, serviceConf)
captchaRepo := captcha.NewCaptchaRepo(dataData)
captchaService := action.NewCaptchaService(captchaRepo)
@ -148,7 +150,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
questionService := service.NewQuestionService(questionRepo, tagCommonService, questionCommon, userCommon, revisionService, metaService, collectionCommon, answerActivityService)
questionController := controller.NewQuestionController(questionService, rankService)
answerService := service.NewAnswerService(answerRepo, questionRepo, questionCommon, userCommon, collectionCommon, userRepo, revisionService, answerActivityService, answerCommon, voteRepo)
answerController := controller.NewAnswerController(answerService, rankService)
dashboardService := dashboard.NewDashboardService(questionRepo, answerRepo, commentCommonRepo, voteRepo, userRepo, reportRepo, configRepo)
answerController := controller.NewAnswerController(answerService, rankService, dashboardService)
searchRepo := search_common.NewSearchRepo(dataData, uniqueIDRepo, userCommon)
searchService := service.NewSearchService(searchRepo, tagRepo, userCommon, followRepo)
searchController := controller.NewSearchController(searchService)
@ -166,14 +169,14 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
reasonService := reason2.NewReasonService(reasonRepo)
reasonController := controller.NewReasonController(reasonService)
themeController := controller_backyard.NewThemeController()
siteInfoService := service.NewSiteInfoService(siteInfoRepo, emailService)
siteInfoController := controller_backyard.NewSiteInfoController(siteInfoService)
siteinfoController := controller.NewSiteinfoController(siteInfoService)
notificationRepo := notification.NewNotificationRepo(dataData)
notificationCommon := notificationcommon.NewNotificationCommon(dataData, notificationRepo, userCommon, activityRepo, followRepo, objService)
notificationService := notification2.NewNotificationService(dataData, notificationRepo, notificationCommon)
notificationController := controller.NewNotificationController(notificationService)
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_backyardReportController, userBackyardController, reasonController, themeController, siteInfoController, siteinfoController, notificationController)
dashboardController := controller.NewDashboardController(dashboardService)
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_backyardReportController, userBackyardController, reasonController, themeController, siteInfoController, siteinfoController, notificationController, dashboardController)
swaggerRouter := router.NewSwaggerRouter(swaggerConf)
uiRouter := router.NewUIRouter()
authUserMiddleware := middleware.NewAuthUserMiddleware(authService)

View File

@ -119,13 +119,36 @@ const docTemplate = `{
}
}
},
"/answer/admin/api/language/options": {
"/answer/admin/api/dashboard": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "DashboardInfo",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "DashboardInfo",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.RespBody"
}
}
}
}
},
"/answer/admin/api/language/options": {
"get": {
"description": "Get language options",
"produces": [
"application/json"
@ -487,14 +510,14 @@ const docTemplate = `{
"ApiKeyAuth": []
}
],
"description": "Get siteinfo general",
"description": "get site general information",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo general",
"summary": "get site general information",
"responses": {
"200": {
"description": "OK",
@ -522,14 +545,14 @@ const docTemplate = `{
"ApiKeyAuth": []
}
],
"description": "Get siteinfo interface",
"description": "update site general information",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo interface",
"summary": "update site general information",
"parameters": [
{
"description": "general",
@ -558,25 +581,14 @@ const docTemplate = `{
"ApiKeyAuth": []
}
],
"description": "Get siteinfo interface",
"description": "get site interface",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo interface",
"parameters": [
{
"description": "general",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/schema.AddCommentReq"
}
}
],
"summary": "get site interface",
"responses": {
"200": {
"description": "OK",
@ -604,14 +616,14 @@ const docTemplate = `{
"ApiKeyAuth": []
}
],
"description": "Get siteinfo interface",
"description": "update site info interface",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo interface",
"summary": "update site info interface",
"parameters": [
{
"description": "general",
@ -1432,11 +1444,6 @@ const docTemplate = `{
},
"/answer/api/v1/language/options": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get language options",
"produces": [
"application/json"
@ -3391,6 +3398,52 @@ const docTemplate = `{
}
}
},
"/answer/api/v1/user/interface": {
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "UserUpdateInterface update user interface config",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "UserUpdateInterface update user interface config",
"parameters": [
{
"type": "string",
"description": "access-token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "UpdateInfoRequest",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/schema.UpdateUserInterfaceRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.RespBody"
}
}
}
}
},
"/answer/api/v1/user/login/email": {
"post": {
"description": "UserEmailLogin",
@ -4822,6 +4875,10 @@ const docTemplate = `{
"description": "is admin",
"type": "boolean"
},
"language": {
"description": "language",
"type": "string"
},
"last_login_date": {
"description": "last login date",
"type": "integer"
@ -4918,6 +4975,10 @@ const docTemplate = `{
"description": "is admin",
"type": "boolean"
},
"language": {
"description": "language",
"type": "string"
},
"last_login_date": {
"description": "last login date",
"type": "integer"
@ -5326,7 +5387,8 @@ const docTemplate = `{
"type": "object",
"required": [
"language",
"theme"
"theme",
"time_zone"
],
"properties": {
"language": {
@ -5340,6 +5402,10 @@ const docTemplate = `{
"theme": {
"type": "string",
"maxLength": 128
},
"time_zone": {
"type": "string",
"maxLength": 128
}
}
},
@ -5347,7 +5413,8 @@ const docTemplate = `{
"type": "object",
"required": [
"language",
"theme"
"theme",
"time_zone"
],
"properties": {
"language": {
@ -5361,6 +5428,10 @@ const docTemplate = `{
"theme": {
"type": "string",
"maxLength": 128
},
"time_zone": {
"type": "string",
"maxLength": 128
}
}
},
@ -5573,6 +5644,19 @@ const docTemplate = `{
}
}
},
"schema.UpdateUserInterfaceRequest": {
"type": "object",
"required": [
"language"
],
"properties": {
"language": {
"description": "language",
"type": "string",
"maxLength": 100
}
}
},
"schema.UpdateUserStatusReq": {
"type": "object",
"required": [

View File

@ -107,13 +107,36 @@
}
}
},
"/answer/admin/api/language/options": {
"/answer/admin/api/dashboard": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "DashboardInfo",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "DashboardInfo",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.RespBody"
}
}
}
}
},
"/answer/admin/api/language/options": {
"get": {
"description": "Get language options",
"produces": [
"application/json"
@ -475,14 +498,14 @@
"ApiKeyAuth": []
}
],
"description": "Get siteinfo general",
"description": "get site general information",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo general",
"summary": "get site general information",
"responses": {
"200": {
"description": "OK",
@ -510,14 +533,14 @@
"ApiKeyAuth": []
}
],
"description": "Get siteinfo interface",
"description": "update site general information",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo interface",
"summary": "update site general information",
"parameters": [
{
"description": "general",
@ -546,25 +569,14 @@
"ApiKeyAuth": []
}
],
"description": "Get siteinfo interface",
"description": "get site interface",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo interface",
"parameters": [
{
"description": "general",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/schema.AddCommentReq"
}
}
],
"summary": "get site interface",
"responses": {
"200": {
"description": "OK",
@ -592,14 +604,14 @@
"ApiKeyAuth": []
}
],
"description": "Get siteinfo interface",
"description": "update site info interface",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Get siteinfo interface",
"summary": "update site info interface",
"parameters": [
{
"description": "general",
@ -1420,11 +1432,6 @@
},
"/answer/api/v1/language/options": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get language options",
"produces": [
"application/json"
@ -3379,6 +3386,52 @@
}
}
},
"/answer/api/v1/user/interface": {
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "UserUpdateInterface update user interface config",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"User"
],
"summary": "UserUpdateInterface update user interface config",
"parameters": [
{
"type": "string",
"description": "access-token",
"name": "Authorization",
"in": "header",
"required": true
},
{
"description": "UpdateInfoRequest",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/schema.UpdateUserInterfaceRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.RespBody"
}
}
}
}
},
"/answer/api/v1/user/login/email": {
"post": {
"description": "UserEmailLogin",
@ -4810,6 +4863,10 @@
"description": "is admin",
"type": "boolean"
},
"language": {
"description": "language",
"type": "string"
},
"last_login_date": {
"description": "last login date",
"type": "integer"
@ -4906,6 +4963,10 @@
"description": "is admin",
"type": "boolean"
},
"language": {
"description": "language",
"type": "string"
},
"last_login_date": {
"description": "last login date",
"type": "integer"
@ -5314,7 +5375,8 @@
"type": "object",
"required": [
"language",
"theme"
"theme",
"time_zone"
],
"properties": {
"language": {
@ -5328,6 +5390,10 @@
"theme": {
"type": "string",
"maxLength": 128
},
"time_zone": {
"type": "string",
"maxLength": 128
}
}
},
@ -5335,7 +5401,8 @@
"type": "object",
"required": [
"language",
"theme"
"theme",
"time_zone"
],
"properties": {
"language": {
@ -5349,6 +5416,10 @@
"theme": {
"type": "string",
"maxLength": 128
},
"time_zone": {
"type": "string",
"maxLength": 128
}
}
},
@ -5561,6 +5632,19 @@
}
}
},
"schema.UpdateUserInterfaceRequest": {
"type": "object",
"required": [
"language"
],
"properties": {
"language": {
"description": "language",
"type": "string",
"maxLength": 100
}
}
},
"schema.UpdateUserStatusReq": {
"type": "object",
"required": [

View File

@ -652,6 +652,9 @@ definitions:
is_admin:
description: is admin
type: boolean
language:
description: language
type: string
last_login_date:
description: last login date
type: integer
@ -723,6 +726,9 @@ definitions:
is_admin:
description: is admin
type: boolean
language:
description: language
type: string
last_login_date:
description: last login date
type: integer
@ -1024,9 +1030,13 @@ definitions:
theme:
maxLength: 128
type: string
time_zone:
maxLength: 128
type: string
required:
- language
- theme
- time_zone
type: object
schema.SiteInterfaceResp:
properties:
@ -1039,9 +1049,13 @@ definitions:
theme:
maxLength: 128
type: string
time_zone:
maxLength: 128
type: string
required:
- language
- theme
- time_zone
type: object
schema.TagItem:
properties:
@ -1195,6 +1209,15 @@ definitions:
- synonym_tag_list
- tag_id
type: object
schema.UpdateUserInterfaceRequest:
properties:
language:
description: language
maxLength: 100
type: string
required:
- language
type: object
schema.UpdateUserStatusReq:
properties:
status:
@ -1434,6 +1457,23 @@ paths:
summary: AdminSetAnswerStatus
tags:
- admin
/answer/admin/api/dashboard:
get:
consumes:
- application/json
description: DashboardInfo
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handler.RespBody'
security:
- ApiKeyAuth: []
summary: DashboardInfo
tags:
- admin
/answer/admin/api/language/options:
get:
description: Get language options
@ -1444,8 +1484,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/handler.RespBody'
security:
- ApiKeyAuth: []
summary: Get language options
tags:
- Lang
@ -1662,7 +1700,7 @@ paths:
- admin
/answer/admin/api/siteinfo/general:
get:
description: Get siteinfo general
description: get site general information
produces:
- application/json
responses:
@ -1677,11 +1715,11 @@ paths:
type: object
security:
- ApiKeyAuth: []
summary: Get siteinfo general
summary: get site general information
tags:
- admin
put:
description: Get siteinfo interface
description: update site general information
parameters:
- description: general
in: body
@ -1698,19 +1736,12 @@ paths:
$ref: '#/definitions/handler.RespBody'
security:
- ApiKeyAuth: []
summary: Get siteinfo interface
summary: update site general information
tags:
- admin
/answer/admin/api/siteinfo/interface:
get:
description: Get siteinfo interface
parameters:
- description: general
in: body
name: data
required: true
schema:
$ref: '#/definitions/schema.AddCommentReq'
description: get site interface
produces:
- application/json
responses:
@ -1725,11 +1756,11 @@ paths:
type: object
security:
- ApiKeyAuth: []
summary: Get siteinfo interface
summary: get site interface
tags:
- admin
put:
description: Get siteinfo interface
description: update site info interface
parameters:
- description: general
in: body
@ -1746,7 +1777,7 @@ paths:
$ref: '#/definitions/handler.RespBody'
security:
- ApiKeyAuth: []
summary: Get siteinfo interface
summary: update site info interface
tags:
- admin
/answer/admin/api/theme/options:
@ -2237,8 +2268,6 @@ paths:
description: OK
schema:
$ref: '#/definitions/handler.RespBody'
security:
- ApiKeyAuth: []
summary: Get language options
tags:
- Lang
@ -3425,6 +3454,35 @@ paths:
summary: UserUpdateInfo update user info
tags:
- User
/answer/api/v1/user/interface:
put:
consumes:
- application/json
description: UserUpdateInterface update user interface config
parameters:
- description: access-token
in: header
name: Authorization
required: true
type: string
- description: UpdateInfoRequest
in: body
name: data
required: true
schema:
$ref: '#/definitions/schema.UpdateUserInterfaceRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handler.RespBody'
security:
- ApiKeyAuth: []
summary: UserUpdateInterface update user interface config
tags:
- User
/answer/api/v1/user/login/email:
post:
consumes:

6
i18n/i18n.yaml Normal file
View File

@ -0,0 +1,6 @@
# all support language
language_options:
- label: "简体中文(CN)"
value: "zh_CN"
- label: "English(US)"
value: "en_US"

View File

@ -1,17 +1,58 @@
package translator
import (
"fmt"
"os"
"path/filepath"
"github.com/google/wire"
myTran "github.com/segmentfault/pacman/contrib/i18n"
"github.com/segmentfault/pacman/i18n"
"sigs.k8s.io/yaml"
)
// ProviderSet is providers.
var ProviderSet = wire.NewSet(NewTranslator)
var GlobalTrans i18n.Translator
// LangOption language option
type LangOption struct {
Label string `json:"label"`
Value string `json:"value"`
}
// LanguageOptions language
var LanguageOptions []*LangOption
// NewTranslator new a translator
func NewTranslator(c *I18n) (tr i18n.Translator, err error) {
GlobalTrans, err = myTran.NewTranslator(c.BundleDir)
if err != nil {
return nil, err
}
i18nFile, err := os.ReadFile(filepath.Join(c.BundleDir, "i18n.yaml"))
if err != nil {
return nil, fmt.Errorf("read i18n file failed: %s", err)
}
s := struct {
LangOption []*LangOption `json:"language_options"`
}{}
err = yaml.Unmarshal(i18nFile, &s)
if err != nil {
return nil, fmt.Errorf("i18n file parsing failed: %s", err)
}
LanguageOptions = s.LangOption
return GlobalTrans, err
}
// CheckLanguageIsValid check user input language is valid
func CheckLanguageIsValid(lang string) bool {
for _, option := range LanguageOptions {
if option.Value == lang {
return true
}
}
return false
}

View File

@ -9,6 +9,7 @@ import (
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service"
"github.com/answerdev/answer/internal/service/dashboard"
"github.com/answerdev/answer/internal/service/rank"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/errors"
@ -16,13 +17,21 @@ import (
// AnswerController answer controller
type AnswerController struct {
answerService *service.AnswerService
rankService *rank.RankService
answerService *service.AnswerService
rankService *rank.RankService
dashboardService *dashboard.DashboardService
}
// NewAnswerController new controller
func NewAnswerController(answerService *service.AnswerService, rankService *rank.RankService) *AnswerController {
return &AnswerController{answerService: answerService, rankService: rankService}
func NewAnswerController(answerService *service.AnswerService,
rankService *rank.RankService,
dashboardService *dashboard.DashboardService,
) *AnswerController {
return &AnswerController{
answerService: answerService,
rankService: rankService,
dashboardService: dashboardService,
}
}
// RemoveAnswer delete answer

View File

@ -20,4 +20,5 @@ var ProviderSetController = wire.NewSet(
NewReasonController,
NewNotificationController,
NewSiteinfoController,
NewDashboardController,
)

View File

@ -0,0 +1,36 @@
package controller
import (
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/service/dashboard"
"github.com/gin-gonic/gin"
)
type DashboardController struct {
dashboardService *dashboard.DashboardService
}
// NewDashboardController new controller
func NewDashboardController(
dashboardService *dashboard.DashboardService,
) *DashboardController {
return &DashboardController{
dashboardService: dashboardService,
}
}
// DashboardInfo godoc
// @Summary DashboardInfo
// @Description DashboardInfo
// @Tags admin
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Router /answer/admin/api/dashboard [get]
// @Success 200 {object} handler.RespBody
func (ac *DashboardController) DashboardInfo(ctx *gin.Context) {
info, err := ac.dashboardService.Statistical(ctx)
handler.HandleResponse(ctx, err, gin.H{
"info": info,
})
}

View File

@ -4,18 +4,20 @@ import (
"encoding/json"
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/base/translator"
"github.com/answerdev/answer/internal/service"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/i18n"
)
type LangController struct {
translator i18n.Translator
translator i18n.Translator
siteInfoService *service.SiteInfoService
}
// NewLangController new language controller.
func NewLangController(tr i18n.Translator) *LangController {
return &LangController{translator: tr}
func NewLangController(tr i18n.Translator, siteInfoService *service.SiteInfoService) *LangController {
return &LangController{translator: tr, siteInfoService: siteInfoService}
}
// GetLangMapping get language config mapping
@ -33,15 +35,38 @@ func (u *LangController) GetLangMapping(ctx *gin.Context) {
handler.HandleResponse(ctx, nil, resp)
}
// GetLangOptions Get language options
// GetAdminLangOptions Get language options
// @Summary Get language options
// @Description Get language options
// @Security ApiKeyAuth
// @Tags Lang
// @Produce json
// @Success 200 {object} handler.RespBody{}
// @Router /answer/api/v1/language/options [get]
// @Router /answer/admin/api/language/options [get]
func (u *LangController) GetLangOptions(ctx *gin.Context) {
handler.HandleResponse(ctx, nil, schema.GetLangOptions)
func (u *LangController) GetAdminLangOptions(ctx *gin.Context) {
handler.HandleResponse(ctx, nil, translator.LanguageOptions)
}
// GetUserLangOptions Get language options
// @Summary Get language options
// @Description Get language options
// @Tags Lang
// @Produce json
// @Success 200 {object} handler.RespBody{}
// @Router /answer/api/v1/language/options [get]
func (u *LangController) GetUserLangOptions(ctx *gin.Context) {
siteInterfaceResp, err := u.siteInfoService.GetSiteInterface(ctx)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
}
options := translator.LanguageOptions
if len(siteInterfaceResp.Language) > 0 {
defaultOption := []*translator.LangOption{
{Label: "Default", Value: siteInterfaceResp.Language},
}
options = append(defaultOption, options...)
}
handler.HandleResponse(ctx, nil, options)
}

View File

@ -373,6 +373,27 @@ func (uc *UserController) UserUpdateInfo(ctx *gin.Context) {
handler.HandleResponse(ctx, err, nil)
}
// UserUpdateInterface update user interface config
// @Summary UserUpdateInterface update user interface config
// @Description UserUpdateInterface update user interface config
// @Tags User
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param Authorization header string true "access-token"
// @Param data body schema.UpdateUserInterfaceRequest true "UpdateInfoRequest"
// @Success 200 {object} handler.RespBody
// @Router /answer/api/v1/user/interface [put]
func (uc *UserController) UserUpdateInterface(ctx *gin.Context) {
req := &schema.UpdateUserInterfaceRequest{}
if handler.BindAndCheck(ctx, req) {
return
}
req.UserId = middleware.GetLoginUserIDFromContext(ctx)
err := uc.userService.UserUpdateInterface(ctx, req)
handler.HandleResponse(ctx, err, nil)
}
// UploadUserAvatar godoc
// @Summary UserUpdateInfo
// @Description UserUpdateInfo

View File

@ -18,9 +18,9 @@ func NewSiteInfoController(siteInfoService *service.SiteInfoService) *SiteInfoCo
}
}
// GetGeneral godoc
// @Summary Get siteinfo general
// @Description Get siteinfo general
// GetGeneral get site general information
// @Summary get site general information
// @Description get site general information
// @Security ApiKeyAuth
// @Tags admin
// @Produce json
@ -31,23 +31,22 @@ func (sc *SiteInfoController) GetGeneral(ctx *gin.Context) {
handler.HandleResponse(ctx, err, resp)
}
// GetInterface godoc
// @Summary Get siteinfo interface
// @Description Get siteinfo interface
// GetInterface get site interface
// @Summary get site interface
// @Description get site interface
// @Security ApiKeyAuth
// @Tags admin
// @Produce json
// @Success 200 {object} handler.RespBody{data=schema.SiteInterfaceResp}
// @Router /answer/admin/api/siteinfo/interface [get]
// @Param data body schema.AddCommentReq true "general"
func (sc *SiteInfoController) GetInterface(ctx *gin.Context) {
resp, err := sc.siteInfoService.GetSiteInterface(ctx)
handler.HandleResponse(ctx, err, resp)
}
// UpdateGeneral godoc
// @Summary Get siteinfo interface
// @Description Get siteinfo interface
// UpdateGeneral update site general information
// @Summary update site general information
// @Description update site general information
// @Security ApiKeyAuth
// @Tags admin
// @Produce json
@ -63,9 +62,9 @@ func (sc *SiteInfoController) UpdateGeneral(ctx *gin.Context) {
handler.HandleResponse(ctx, err, nil)
}
// UpdateInterface godoc
// @Summary Get siteinfo interface
// @Description Get siteinfo interface
// UpdateInterface update site interface
// @Summary update site info interface
// @Description update site info interface
// @Security ApiKeyAuth
// @Tags admin
// @Produce json

View File

@ -45,6 +45,7 @@ type User struct {
Location string `xorm:"not null default '' VARCHAR(100) location"`
IPInfo string `xorm:"not null default '' VARCHAR(255) ip_info"`
IsAdmin bool `xorm:"not null default false BOOL is_admin"`
Language string `xorm:"not null default '' VARCHAR(100) language"`
}
// TableName user table name

View File

@ -5,7 +5,6 @@ import (
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/entity"
"github.com/segmentfault/pacman/log"
"xorm.io/xorm"
)
@ -43,6 +42,7 @@ var noopMigration = func(_ *xorm.Engine) error { return nil }
var migrations = []Migration{
// 0->1
NewMigration("this is first version, no operation", noopMigration),
NewMigration("add user language", addUserLanguage),
}
// GetCurrentDBVersion returns the current db version
@ -86,17 +86,17 @@ func Migrate(dataConf *data.Database) error {
expectedVersion := ExpectedVersion()
for currentDBVersion < expectedVersion {
log.Infof("[migrate] current db version is %d, try to migrate version %d, latest version is %d",
fmt.Printf("[migrate] current db version is %d, try to migrate version %d, latest version is %d\n",
currentDBVersion, currentDBVersion+1, expectedVersion)
migrationFunc := migrations[currentDBVersion]
log.Infof("[migrate] try to migrate db version %d, description: %s", currentDBVersion+1, migrationFunc.Description())
fmt.Printf("[migrate] try to migrate db version %d, description: %s\n", currentDBVersion+1, migrationFunc.Description())
if err := migrationFunc.Migrate(engine); err != nil {
log.Errorf("[migrate] migrate to db version %d failed: ", currentDBVersion+1, err.Error())
fmt.Printf("[migrate] migrate to db version %d failed: %s\n", currentDBVersion+1, err.Error())
return err
}
log.Infof("[migrate] migrate to db version %d success", currentDBVersion+1)
fmt.Printf("[migrate] migrate to db version %d success\n", currentDBVersion+1)
if _, err := engine.Update(&entity.Version{ID: 1, VersionNumber: currentDBVersion + 1}); err != nil {
log.Errorf("[migrate] migrate to db version %d, update failed: %s", currentDBVersion+1, err.Error())
fmt.Printf("[migrate] migrate to db version %d, update failed: %s", currentDBVersion+1, err.Error())
return err
}
currentDBVersion++

12
internal/migrations/v1.go Normal file
View File

@ -0,0 +1,12 @@
package migrations
import (
"xorm.io/xorm"
)
func addUserLanguage(x *xorm.Engine) error {
type User struct {
Language string `xorm:"not null default '' VARCHAR(100) language"`
}
return x.Sync(new(User))
}

View File

@ -4,8 +4,10 @@ import (
"context"
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/service/activity_common"
"github.com/segmentfault/pacman/errors"
)
// VoteRepo activity repository
@ -39,3 +41,12 @@ func (vr *VoteRepo) GetVoteStatus(ctx context.Context, objectID, userID string)
}
return ""
}
func (vr *VoteRepo) GetVoteCount(ctx context.Context, activityTypes []int) (count int64, err error) {
list := make([]*entity.Activity, 0)
count, err = vr.data.DB.Where("cancelled =0").In("activity_type", activityTypes).FindAndCount(&list)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}

View File

@ -5,6 +5,7 @@ import (
"strings"
"time"
"unicode"
"xorm.io/builder"
"github.com/answerdev/answer/internal/base/constant"
@ -102,6 +103,16 @@ func (ar *answerRepo) GetAnswer(ctx context.Context, id string) (
return
}
// GetQuestionCount
func (ar *answerRepo) GetAnswerCount(ctx context.Context) (count int64, err error) {
list := make([]*entity.Answer, 0)
count, err = ar.data.DB.Where("status = ?", entity.AnswerStatusAvailable).FindAndCount(&list)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// GetAnswerList get answer list all
func (ar *answerRepo) GetAnswerList(ctx context.Context, answer *entity.Answer) (answerList []*entity.Answer, err error) {
answerList = make([]*entity.Answer, 0)

View File

@ -79,6 +79,15 @@ func (cr *commentRepo) GetComment(ctx context.Context, commentID string) (
return
}
func (cr *commentRepo) GetCommentCount(ctx context.Context) (count int64, err error) {
list := make([]*entity.Comment, 0)
count, err = cr.data.DB.Where("status = ?", entity.CommentStatusAvailable).FindAndCount(&list)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// GetCommentPage get comment page
func (cr *commentRepo) GetCommentPage(ctx context.Context, commentQuery *comment.CommentQuery) (
commentList []*entity.Comment, total int64, err error,

View File

@ -5,6 +5,7 @@ import (
"strings"
"time"
"unicode"
"xorm.io/builder"
"github.com/answerdev/answer/internal/base/constant"
@ -162,6 +163,16 @@ func (qr *questionRepo) GetQuestionList(ctx context.Context, question *entity.Qu
return
}
func (qr *questionRepo) GetQuestionCount(ctx context.Context) (count int64, err error) {
questionList := make([]*entity.Question, 0)
count, err = qr.data.DB.In("question.status", []int{entity.QuestionStatusAvailable, entity.QuestionStatusclosed}).FindAndCount(&questionList)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// GetQuestionPage get question page
func (qr *questionRepo) GetQuestionPage(ctx context.Context, page, pageSize int, question *entity.Question) (questionList []*entity.Question, total int64, err error) {
questionList = make([]*entity.Question, 0)

View File

@ -94,3 +94,12 @@ func (ar *reportRepo) UpdateByID(
}
return
}
func (vr *reportRepo) GetReportCount(ctx context.Context) (count int64, err error) {
list := make([]*entity.Report, 0)
count, err = vr.data.DB.Where("status =?", entity.ReportStatusPending).FindAndCount(&list)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}

View File

@ -101,6 +101,14 @@ func (ur *userRepo) UpdateEmail(ctx context.Context, userID, email string) (err
return
}
func (ur *userRepo) UpdateLanguage(ctx context.Context, userID, language string) (err error) {
_, err = ur.data.DB.Where("id = ?", userID).Update(&entity.User{Language: language})
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// UpdateInfo update user info
func (ur *userRepo) UpdateInfo(ctx context.Context, userInfo *entity.User) (err error) {
_, err = ur.data.DB.Where("id = ?", userInfo.ID).
@ -149,3 +157,12 @@ func (ur *userRepo) GetByEmail(ctx context.Context, email string) (userInfo *ent
}
return
}
func (vr *userRepo) GetUserCount(ctx context.Context) (count int64, err error) {
list := make([]*entity.User, 0)
count, err = vr.data.DB.Where("mail_status =?", entity.EmailStatusAvailable).And("status =?", entity.UserStatusAvailable).FindAndCount(&list)
if err != nil {
return count, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}

View File

@ -27,6 +27,7 @@ type AnswerAPIRouter struct {
siteInfoController *controller_backyard.SiteInfoController
siteinfoController *controller.SiteinfoController
notificationController *controller.NotificationController
dashboardController *controller.DashboardController
}
func NewAnswerAPIRouter(
@ -50,6 +51,7 @@ func NewAnswerAPIRouter(
siteInfoController *controller_backyard.SiteInfoController,
siteinfoController *controller.SiteinfoController,
notificationController *controller.NotificationController,
dashboardController *controller.DashboardController,
) *AnswerAPIRouter {
return &AnswerAPIRouter{
@ -73,13 +75,14 @@ func NewAnswerAPIRouter(
siteInfoController: siteInfoController,
notificationController: notificationController,
siteinfoController: siteinfoController,
dashboardController: dashboardController,
}
}
func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r *gin.RouterGroup) {
// i18n
r.GET("/language/config", a.langController.GetLangMapping)
r.GET("/language/options", a.langController.GetLangOptions)
r.GET("/language/options", a.langController.GetUserLangOptions)
// comment
r.GET("/comment/page", a.commentController.GetCommentWithPage)
@ -177,6 +180,7 @@ func (a *AnswerAPIRouter) RegisterAnswerAPIRouter(r *gin.RouterGroup) {
// user
r.PUT("/user/password", a.userController.UserModifyPassWord)
r.PUT("/user/info", a.userController.UserUpdateInfo)
r.PUT("/user/interface", a.userController.UserUpdateInterface)
r.POST("/user/avatar/upload", a.userController.UploadUserAvatar)
r.POST("/user/post/file", a.userController.UploadUserPostFile)
r.POST("/user/notice/set", a.userController.UserNoticeSet)
@ -213,7 +217,7 @@ func (a *AnswerAPIRouter) RegisterAnswerCmsAPIRouter(r *gin.RouterGroup) {
r.GET("/reasons", a.reasonController.Reasons)
// language
r.GET("/language/options", a.langController.GetLangOptions)
r.GET("/language/options", a.langController.GetAdminLangOptions)
// theme
r.GET("/theme/options", a.themeController.GetThemeOptions)
@ -225,4 +229,7 @@ func (a *AnswerAPIRouter) RegisterAnswerCmsAPIRouter(r *gin.RouterGroup) {
r.PUT("/siteinfo/interface", a.siteInfoController.UpdateInterface)
r.GET("/setting/smtp", a.siteInfoController.GetSMTPConfig)
r.PUT("/setting/smtp", a.siteInfoController.UpdateSMTPConfig)
//dashboard
r.GET("/dashboard", a.dashboardController.DashboardInfo)
}

View File

@ -7,7 +7,9 @@ import (
"net/http"
"os"
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/i18n"
"github.com/answerdev/answer/ui"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/log"
@ -41,6 +43,7 @@ func (r *_resource) Open(name string) (fs.File, error) {
// Register a new static resource which generated by ui directory
func (a *UIRouter) Register(r *gin.Engine) {
staticPath := os.Getenv("ANSWER_STATIC_PATH")
r.StaticFS("/i18n/", http.FS(i18n.I18n))
// if ANSWER_STATIC_PATH is set and not empty, ignore embed resource
if staticPath != "" {

View File

@ -0,0 +1,15 @@
package schema
type DashboardInfo struct {
QuestionCount int64 `json:"question_count"`
AnswerCount int64 `json:"answer_count"`
CommentCount int64 `json:"comment_count"`
VoteCount int64 `json:"vote_count"`
UserCount int64 `json:"user_count"`
ReportCount int64 `json:"report_count"`
UploadingFiles string `json:"uploading_files"` //Allowed or Not allowed
SMTP string `json:"smtp"` //Enabled or Disabled
TimeZone string `json:"time_zone"`
OccupyingStorageSpace string `json:"occupying_storage_space"`
AppStartTime string `json:"app_start_time"`
}

View File

@ -1,18 +0,0 @@
package schema
// GetLangOption get label option
type GetLangOption struct {
Label string `json:"label"`
Value string `json:"value"`
}
var GetLangOptions = []*GetLangOption{
{
Label: "English(US)",
Value: "en_US",
},
{
Label: "中文(CN)",
Value: "zh_CN",
},
}

View File

@ -2,16 +2,17 @@ package schema
// SiteGeneralReq site general request
type SiteGeneralReq struct {
Name string `validate:"required,gt=1,lte=128" comment:"site name" form:"name" json:"name"`
ShortDescription string `validate:"required,gt=3,lte=255" comment:"short site description" form:"short_description" json:"short_description"`
Description string `validate:"required,gt=3,lte=2000" comment:"site description" form:"description" json:"description"`
Name string `validate:"required,gt=1,lte=128" form:"name" json:"name"`
ShortDescription string `validate:"required,gt=3,lte=255" form:"short_description" json:"short_description"`
Description string `validate:"required,gt=3,lte=2000" form:"description" json:"description"`
}
// SiteInterfaceReq site interface request
type SiteInterfaceReq struct {
Logo string `validate:"omitempty,gt=0,lte=256" comment:"logo" form:"logo" json:"logo"`
Theme string `validate:"required,gt=1,lte=128" comment:"theme" form:"theme" json:"theme"`
Language string `validate:"required,gt=1,lte=128" comment:"interface language" form:"language" json:"language"`
Logo string `validate:"omitempty,gt=0,lte=256" form:"logo" json:"logo"`
Theme string `validate:"required,gt=1,lte=128" form:"theme" json:"theme"`
Language string `validate:"required,gt=1,lte=128" form:"language" json:"language"`
TimeZone string `validate:"required,gt=1,lte=128" form:"time_zone" json:"time_zone"`
}
// SiteGeneralResp site general response

View File

@ -62,6 +62,8 @@ type GetUserResp struct {
Location string `json:"location"`
// ip info
IPInfo string `json:"ip_info"`
// language
Language string `json:"language"`
// access token
AccessToken string `json:"access_token"`
// is admin
@ -305,6 +307,14 @@ func (u *UpdateInfoRequest) Check() (errField *validator.ErrorField, err error)
return nil, nil
}
// UpdateUserInterfaceRequest update user interface request
type UpdateUserInterfaceRequest struct {
// language
Language string `validate:"required,gt=1,lte=100" json:"language"`
// user id
UserId string `json:"-" `
}
type UserRetrievePassWordRequest struct {
Email string `validate:"required,email,gt=0,lte=500" json:"e_mail" ` // e_mail
CaptchaID string `json:"captcha_id" ` // captcha_id

View File

@ -7,4 +7,5 @@ import (
// VoteRepo activity repository
type VoteRepo interface {
GetVoteStatus(ctx context.Context, objectId, userId string) (status string)
GetVoteCount(ctx context.Context, activityTypes []int) (count int64, err error)
}

View File

@ -20,6 +20,7 @@ type AnswerRepo interface {
SearchList(ctx context.Context, search *entity.AnswerSearch) ([]*entity.Answer, int64, error)
CmsSearchList(ctx context.Context, search *entity.CmsAnswerSearch) ([]*entity.Answer, int64, error)
UpdateAnswerStatus(ctx context.Context, answer *entity.Answer) (err error)
GetAnswerCount(ctx context.Context) (count int64, err error)
}
// AnswerCommon user service

View File

@ -12,6 +12,7 @@ import (
// CommentCommonRepo comment repository
type CommentCommonRepo interface {
GetComment(ctx context.Context, commentID string) (comment *entity.Comment, exist bool, err error)
GetCommentCount(ctx context.Context) (count int64, err error)
}
// CommentCommonService user service

View File

@ -0,0 +1,105 @@
package dashboard
import (
"context"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/activity_common"
answercommon "github.com/answerdev/answer/internal/service/answer_common"
"github.com/answerdev/answer/internal/service/comment_common"
"github.com/answerdev/answer/internal/service/config"
questioncommon "github.com/answerdev/answer/internal/service/question_common"
"github.com/answerdev/answer/internal/service/report_common"
usercommon "github.com/answerdev/answer/internal/service/user_common"
)
type DashboardService struct {
questionRepo questioncommon.QuestionRepo
answerRepo answercommon.AnswerRepo
commentRepo comment_common.CommentCommonRepo
voteRepo activity_common.VoteRepo
userRepo usercommon.UserRepo
reportRepo report_common.ReportRepo
configRepo config.ConfigRepo
}
func NewDashboardService(
questionRepo questioncommon.QuestionRepo,
answerRepo answercommon.AnswerRepo,
commentRepo comment_common.CommentCommonRepo,
voteRepo activity_common.VoteRepo,
userRepo usercommon.UserRepo,
reportRepo report_common.ReportRepo,
configRepo config.ConfigRepo,
) *DashboardService {
return &DashboardService{
questionRepo: questionRepo,
answerRepo: answerRepo,
commentRepo: commentRepo,
voteRepo: voteRepo,
userRepo: userRepo,
reportRepo: reportRepo,
configRepo: configRepo,
}
}
// Statistical
func (ds *DashboardService) Statistical(ctx context.Context) (*schema.DashboardInfo, error) {
dashboardInfo := &schema.DashboardInfo{}
questionCount, err := ds.questionRepo.GetQuestionCount(ctx)
if err != nil {
return dashboardInfo, err
}
answerCount, err := ds.answerRepo.GetAnswerCount(ctx)
if err != nil {
return dashboardInfo, err
}
commentCount, err := ds.commentRepo.GetCommentCount(ctx)
if err != nil {
return dashboardInfo, err
}
typeKeys := []string{
"question.vote_up",
"question.vote_down",
"answer.vote_up",
"answer.vote_down",
}
var activityTypes []int
for _, typeKey := range typeKeys {
var t int
t, err = ds.configRepo.GetConfigType(typeKey)
if err != nil {
continue
}
activityTypes = append(activityTypes, t)
}
voteCount, err := ds.voteRepo.GetVoteCount(ctx, activityTypes)
if err != nil {
return dashboardInfo, err
}
userCount, err := ds.userRepo.GetUserCount(ctx)
if err != nil {
return dashboardInfo, err
}
reportCount, err := ds.reportRepo.GetReportCount(ctx)
if err != nil {
return dashboardInfo, err
}
dashboardInfo.QuestionCount = questionCount
dashboardInfo.AnswerCount = answerCount
dashboardInfo.CommentCount = commentCount
dashboardInfo.VoteCount = voteCount
dashboardInfo.UserCount = userCount
dashboardInfo.ReportCount = reportCount
dashboardInfo.UploadingFiles = "Allowed"
dashboardInfo.SMTP = "Enabled"
dashboardInfo.OccupyingStorageSpace = "1MB"
dashboardInfo.AppStartTime = "102"
return dashboardInfo, nil
}

View File

@ -0,0 +1 @@
package dashboard

View File

@ -8,6 +8,7 @@ import (
collectioncommon "github.com/answerdev/answer/internal/service/collection_common"
"github.com/answerdev/answer/internal/service/comment"
"github.com/answerdev/answer/internal/service/comment_common"
"github.com/answerdev/answer/internal/service/dashboard"
"github.com/answerdev/answer/internal/service/export"
"github.com/answerdev/answer/internal/service/follow"
"github.com/answerdev/answer/internal/service/meta"
@ -65,4 +66,5 @@ var ProviderSetService = wire.NewSet(
notficationcommon.NewNotificationCommon,
notification.NewNotificationService,
activity.NewAnswerActivityService,
dashboard.NewDashboardService,
)

View File

@ -38,6 +38,7 @@ type QuestionRepo interface {
UpdateLastAnswer(ctx context.Context, question *entity.Question) (err error)
FindByID(ctx context.Context, id []string) (questionList []*entity.Question, err error)
CmsSearchList(ctx context.Context, search *schema.CmsQuestionSearch) ([]*entity.Question, int64, error)
GetQuestionCount(ctx context.Context) (count int64, err error)
}
// QuestionCommon user service

View File

@ -2,6 +2,7 @@ package report_common
import (
"context"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
)
@ -12,4 +13,5 @@ type ReportRepo interface {
GetReportListPage(ctx context.Context, query schema.GetReportListPageDTO) (reports []entity.Report, total int64, err error)
GetByID(ctx context.Context, id string) (report entity.Report, exist bool, err error)
UpdateByID(ctx context.Context, id string, handleData entity.Report) (err error)
GetReportCount(ctx context.Context) (count int64, err error)
}

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/base/translator"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/export"
@ -77,10 +78,9 @@ func (s *SiteInfoService) SaveSiteGeneral(ctx context.Context, req schema.SiteGe
func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.SiteInterfaceReq) (err error) {
var (
siteType = "interface"
themeExist,
langExist bool
content []byte
siteType = "interface"
themeExist bool
content []byte
)
// check theme
@ -96,13 +96,7 @@ func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.Site
}
// check language
for _, lang := range schema.GetLangOptions {
if lang.Value == req.Language {
langExist = true
break
}
}
if !langExist {
if !translator.CheckLanguageIsValid(req.Language) {
err = errors.BadRequest(reason.LangNotFound)
return
}

View File

@ -15,12 +15,14 @@ type UserRepo interface {
UpdateEmailStatus(ctx context.Context, userID string, emailStatus int) error
UpdateNoticeStatus(ctx context.Context, userID string, noticeStatus int) error
UpdateEmail(ctx context.Context, userID, email string) error
UpdateLanguage(ctx context.Context, userID, language string) error
UpdatePass(ctx context.Context, userID, pass string) error
UpdateInfo(ctx context.Context, userInfo *entity.User) (err error)
GetByUserID(ctx context.Context, userID string) (userInfo *entity.User, exist bool, err error)
BatchGetByID(ctx context.Context, ids []string) ([]*entity.User, error)
GetByUsername(ctx context.Context, username string) (userInfo *entity.User, exist bool, err error)
GetByEmail(ctx context.Context, email string) (userInfo *entity.User, exist bool, err error)
GetUserCount(ctx context.Context) (count int64, err error)
}
// UserCommon user service

View File

@ -11,6 +11,7 @@ import (
"github.com/Chain-Zhang/pinyin"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/base/translator"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/activity"
@ -283,6 +284,18 @@ func (us *UserService) UserEmailHas(ctx context.Context, email string) (bool, er
return has, nil
}
// UserUpdateInterface update user interface
func (us *UserService) UserUpdateInterface(ctx context.Context, req *schema.UpdateUserInterfaceRequest) (err error) {
if !translator.CheckLanguageIsValid(req.Language) {
return errors.BadRequest(reason.LangNotFound)
}
err = us.userRepo.UpdateLanguage(ctx, req.UserId, req.Language)
if err != nil {
return
}
return nil
}
// UserRegisterByEmail user register
func (us *UserService) UserRegisterByEmail(ctx context.Context, registerUserInfo *schema.UserRegisterReq) (
resp *schema.GetUserResp, err error,