From 6b63d1762358aff412daa4bbdceb50723ff79769 Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Mon, 14 Nov 2022 11:50:00 +0800 Subject: [PATCH 01/12] feat: add site info about branding --- internal/base/constant/constant.go | 1 + internal/controller/siteinfo_controller.go | 16 ++++++--- .../siteinfo_controller.go | 34 ++++++++++++++++++- internal/router/answer_api_router.go | 2 ++ internal/router/ui.go | 13 ++++--- internal/schema/siteinfo_schema.go | 16 +++++++-- internal/service/siteinfo/siteinfo_service.go | 11 ++++++ .../siteinfo_common/siteinfo_service.go | 14 ++++++++ 8 files changed, 93 insertions(+), 14 deletions(-) diff --git a/internal/base/constant/constant.go b/internal/base/constant/constant.go index e41d50ea..dafa49a8 100644 --- a/internal/base/constant/constant.go +++ b/internal/base/constant/constant.go @@ -53,4 +53,5 @@ var ( const ( SiteTypeGeneral = "general" SiteTypeInterface = "interface" + SiteTypeBranding = "branding" ) diff --git a/internal/controller/siteinfo_controller.go b/internal/controller/siteinfo_controller.go index 5f547eb7..d0d90a9e 100644 --- a/internal/controller/siteinfo_controller.go +++ b/internal/controller/siteinfo_controller.go @@ -5,6 +5,7 @@ import ( "github.com/answerdev/answer/internal/schema" "github.com/answerdev/answer/internal/service/siteinfo_common" "github.com/gin-gonic/gin" + "github.com/segmentfault/pacman/log" ) type SiteinfoController struct { @@ -30,9 +31,16 @@ func (sc *SiteinfoController) GetSiteInfo(ctx *gin.Context) { resp := &schema.SiteInfoResp{} resp.General, err = sc.siteInfoService.GetSiteGeneral(ctx) if err != nil { - handler.HandleResponse(ctx, err, resp) - return + log.Error(err) } - resp.Face, err = sc.siteInfoService.GetSiteInterface(ctx) - handler.HandleResponse(ctx, err, resp) + resp.Interface, err = sc.siteInfoService.GetSiteInterface(ctx) + if err != nil { + log.Error(err) + } + + resp.Branding, err = sc.siteInfoService.GetSiteBranding(ctx) + if err != nil { + log.Error(err) + } + handler.HandleResponse(ctx, nil, resp) } diff --git a/internal/controller_backyard/siteinfo_controller.go b/internal/controller_backyard/siteinfo_controller.go index 3a554c22..38c92ad8 100644 --- a/internal/controller_backyard/siteinfo_controller.go +++ b/internal/controller_backyard/siteinfo_controller.go @@ -7,11 +7,12 @@ import ( "github.com/gin-gonic/gin" ) +// SiteInfoController site info controller type SiteInfoController struct { siteInfoService *siteinfo.SiteInfoService } -// NewSiteInfoController new siteinfo controller. +// NewSiteInfoController new site info controller func NewSiteInfoController(siteInfoService *siteinfo.SiteInfoService) *SiteInfoController { return &SiteInfoController{ siteInfoService: siteInfoService, @@ -44,6 +45,19 @@ func (sc *SiteInfoController) GetInterface(ctx *gin.Context) { handler.HandleResponse(ctx, err, resp) } +// GetBranding get site interface +// @Summary get site interface +// @Description get site interface +// @Security ApiKeyAuth +// @Tags admin +// @Produce json +// @Success 200 {object} handler.RespBody{data=schema.SiteBrandingResp} +// @Router /answer/admin/api/siteinfo/branding [get] +func (sc *SiteInfoController) GetBranding(ctx *gin.Context) { + resp, err := sc.siteInfoService.GetSiteInterface(ctx) + handler.HandleResponse(ctx, err, resp) +} + // UpdateGeneral update site general information // @Summary update site general information // @Description update site general information @@ -80,6 +94,24 @@ func (sc *SiteInfoController) UpdateInterface(ctx *gin.Context) { handler.HandleResponse(ctx, err, nil) } +// UpdateBranding update site branding +// @Summary update site info branding +// @Description update site info branding +// @Security ApiKeyAuth +// @Tags admin +// @Produce json +// @Param data body schema.SiteInterfaceReq true "branding info" +// @Success 200 {object} handler.RespBody{} +// @Router /answer/admin/api/siteinfo/branding [put] +func (sc *SiteInfoController) UpdateBranding(ctx *gin.Context) { + req := &schema.SiteBrandingReq{} + if handler.BindAndCheck(ctx, req) { + return + } + err := sc.siteInfoService.SaveSiteBranding(ctx, req) + handler.HandleResponse(ctx, err, nil) +} + // GetSMTPConfig get smtp config // @Summary GetSMTPConfig get smtp config // @Description GetSMTPConfig get smtp config diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index fc7fab95..04eff49b 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -224,8 +224,10 @@ func (a *AnswerAPIRouter) RegisterAnswerCmsAPIRouter(r *gin.RouterGroup) { // siteinfo r.GET("/siteinfo/general", a.siteInfoController.GetGeneral) r.GET("/siteinfo/interface", a.siteInfoController.GetInterface) + r.GET("/siteinfo/branding", a.siteInfoController.GetBranding) r.PUT("/siteinfo/general", a.siteInfoController.UpdateGeneral) r.PUT("/siteinfo/interface", a.siteInfoController.UpdateInterface) + r.PUT("/siteinfo/branding", a.siteInfoController.UpdateBranding) r.GET("/setting/smtp", a.siteInfoController.GetSMTPConfig) r.PUT("/setting/smtp", a.siteInfoController.UpdateSMTPConfig) diff --git a/internal/router/ui.go b/internal/router/ui.go index f1296d9f..6f0e174f 100644 --- a/internal/router/ui.go +++ b/internal/router/ui.go @@ -68,24 +68,23 @@ func (a *UIRouter) Register(r *gin.Engine) { // specify the not router for default routes and redirect r.NoRoute(func(c *gin.Context) { - name := c.Request.URL.Path + urlPath := c.Request.URL.Path filePath := "" - var file []byte - var err error - switch name { + switch urlPath { case "/favicon.ico": c.Header("content-type", "image/vnd.microsoft.icon") - filePath = UIRootFilePath + name + filePath = UIRootFilePath + urlPath case "/manifest.json": - filePath = UIRootFilePath + name + filePath = UIRootFilePath + urlPath case "/install": + // if answer is running by run command user can not access install page. c.Redirect(http.StatusFound, "/") return default: filePath = UIIndexFilePath c.Header("content-type", "text/html;charset=utf-8") } - file, err = ui.Build.ReadFile(filePath) + file, err := ui.Build.ReadFile(filePath) if err != nil { log.Error(err) c.Status(http.StatusNotFound) diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go index 85a643ed..1ea01fd6 100644 --- a/internal/schema/siteinfo_schema.go +++ b/internal/schema/siteinfo_schema.go @@ -30,15 +30,27 @@ type SiteInterfaceReq struct { TimeZone string `validate:"required,gt=1,lte=128" form:"time_zone" json:"time_zone"` } +// SiteBrandingReq site branding request +type SiteBrandingReq struct { + MobileLogo string `validate:"omitempty,gt=0,lte=512" form:"mobile_logo" json:"mobile_logo"` + SquareIcon string `validate:"required,gt=0,lte=512" form:"square_icon" json:"square_icon"` + Favicon string `validate:"omitempty,gt=0,lte=512" form:"favicon" json:"favicon"` +} + // SiteGeneralResp site general response type SiteGeneralResp SiteGeneralReq // SiteInterfaceResp site interface response type SiteInterfaceResp SiteInterfaceReq +// SiteBrandingResp site branding response +type SiteBrandingResp SiteBrandingReq + +// SiteInfoResp get site info response type SiteInfoResp struct { - General *SiteGeneralResp `json:"general"` - Face *SiteInterfaceResp `json:"interface"` + General *SiteGeneralResp `json:"general"` + Interface *SiteInterfaceResp `json:"interface"` + Branding *SiteBrandingResp `json:"branding"` } // UpdateSMTPConfigReq get smtp config request diff --git a/internal/service/siteinfo/siteinfo_service.go b/internal/service/siteinfo/siteinfo_service.go index 66c49479..6db2f34a 100644 --- a/internal/service/siteinfo/siteinfo_service.go +++ b/internal/service/siteinfo/siteinfo_service.go @@ -109,6 +109,17 @@ func (s *SiteInfoService) SaveSiteInterface(ctx context.Context, req schema.Site return } +// SaveSiteBranding save site branding information +func (s *SiteInfoService) SaveSiteBranding(ctx context.Context, req *schema.SiteBrandingReq) (err error) { + content, _ := json.Marshal(req) + data := &entity.SiteInfo{ + Type: constant.SiteTypeBranding, + Content: string(content), + Status: 1, + } + return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeBranding, data) +} + // GetSMTPConfig get smtp config func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) ( resp *schema.GetSMTPConfigResp, err error, diff --git a/internal/service/siteinfo_common/siteinfo_service.go b/internal/service/siteinfo_common/siteinfo_service.go index 5dd565d0..69ff7fe6 100644 --- a/internal/service/siteinfo_common/siteinfo_service.go +++ b/internal/service/siteinfo_common/siteinfo_service.go @@ -48,3 +48,17 @@ func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *sch _ = json.Unmarshal([]byte(siteInfo.Content), resp) return resp, nil } + +// GetSiteBranding get site info branding +func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error) { + siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, constant.SiteTypeBranding) + if err != nil { + return nil, err + } + if !exist { + return nil, errors.BadRequest(reason.SiteInfoNotFound) + } + resp = &schema.SiteBrandingResp{} + _ = json.Unmarshal([]byte(siteInfo.Content), resp) + return resp, nil +} From 74ba5620bbd9778a7cb0bcd12eef2681d95a8100 Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Mon, 14 Nov 2022 14:56:56 +0800 Subject: [PATCH 02/12] feat: move logo field to site info --- internal/schema/siteinfo_schema.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go index 1ea01fd6..1c9a3aaf 100644 --- a/internal/schema/siteinfo_schema.go +++ b/internal/schema/siteinfo_schema.go @@ -24,7 +24,6 @@ func (r *SiteGeneralReq) FormatSiteUrl() { // SiteInterfaceReq site interface request type SiteInterfaceReq struct { - 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"` @@ -32,6 +31,7 @@ type SiteInterfaceReq struct { // SiteBrandingReq site branding request type SiteBrandingReq struct { + Logo string `validate:"required,gt=0,lte=512" form:"logo" json:"logo"` MobileLogo string `validate:"omitempty,gt=0,lte=512" form:"mobile_logo" json:"mobile_logo"` SquareIcon string `validate:"required,gt=0,lte=512" form:"square_icon" json:"square_icon"` Favicon string `validate:"omitempty,gt=0,lte=512" form:"favicon" json:"favicon"` From cca5bcb59b625dfefd0c81b24a4617fa6ca1cd6b Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Mon, 14 Nov 2022 15:17:49 +0800 Subject: [PATCH 03/12] feat: add site info tag config --- internal/base/constant/constant.go | 1 + .../siteinfo_controller.go | 39 +++++++++++++++++-- internal/router/answer_api_router.go | 4 +- internal/schema/siteinfo_schema.go | 8 ++++ internal/service/siteinfo/siteinfo_service.go | 39 +++++++++++++++++++ 5 files changed, 86 insertions(+), 5 deletions(-) diff --git a/internal/base/constant/constant.go b/internal/base/constant/constant.go index dafa49a8..7953916c 100644 --- a/internal/base/constant/constant.go +++ b/internal/base/constant/constant.go @@ -54,4 +54,5 @@ const ( SiteTypeGeneral = "general" SiteTypeInterface = "interface" SiteTypeBranding = "branding" + SiteTypeWrite = "write" ) diff --git a/internal/controller_backyard/siteinfo_controller.go b/internal/controller_backyard/siteinfo_controller.go index 38c92ad8..b32bbf77 100644 --- a/internal/controller_backyard/siteinfo_controller.go +++ b/internal/controller_backyard/siteinfo_controller.go @@ -45,7 +45,7 @@ func (sc *SiteInfoController) GetInterface(ctx *gin.Context) { handler.HandleResponse(ctx, err, resp) } -// GetBranding get site interface +// GetSiteBranding get site interface // @Summary get site interface // @Description get site interface // @Security ApiKeyAuth @@ -53,8 +53,21 @@ func (sc *SiteInfoController) GetInterface(ctx *gin.Context) { // @Produce json // @Success 200 {object} handler.RespBody{data=schema.SiteBrandingResp} // @Router /answer/admin/api/siteinfo/branding [get] -func (sc *SiteInfoController) GetBranding(ctx *gin.Context) { - resp, err := sc.siteInfoService.GetSiteInterface(ctx) +func (sc *SiteInfoController) GetSiteBranding(ctx *gin.Context) { + resp, err := sc.siteInfoService.GetSiteBranding(ctx) + handler.HandleResponse(ctx, err, resp) +} + +// GetSiteWrite get site interface +// @Summary get site interface +// @Description get site interface +// @Security ApiKeyAuth +// @Tags admin +// @Produce json +// @Success 200 {object} handler.RespBody{data=schema.SiteWriteResp} +// @Router /answer/admin/api/siteinfo/branding [get] +func (sc *SiteInfoController) GetSiteWrite(ctx *gin.Context) { + resp, err := sc.siteInfoService.GetSiteWrite(ctx) handler.HandleResponse(ctx, err, resp) } @@ -100,7 +113,7 @@ func (sc *SiteInfoController) UpdateInterface(ctx *gin.Context) { // @Security ApiKeyAuth // @Tags admin // @Produce json -// @Param data body schema.SiteInterfaceReq true "branding info" +// @Param data body schema.SiteBrandingReq true "branding info" // @Success 200 {object} handler.RespBody{} // @Router /answer/admin/api/siteinfo/branding [put] func (sc *SiteInfoController) UpdateBranding(ctx *gin.Context) { @@ -112,6 +125,24 @@ func (sc *SiteInfoController) UpdateBranding(ctx *gin.Context) { handler.HandleResponse(ctx, err, nil) } +// UpdateSiteWrite update site write info +// @Summary update site write info +// @Description update site write info +// @Security ApiKeyAuth +// @Tags admin +// @Produce json +// @Param data body schema.SiteWriteReq true "write info" +// @Success 200 {object} handler.RespBody{} +// @Router /answer/admin/api/siteinfo/write [put] +func (sc *SiteInfoController) UpdateSiteWrite(ctx *gin.Context) { + req := &schema.SiteWriteReq{} + if handler.BindAndCheck(ctx, req) { + return + } + err := sc.siteInfoService.SaveSiteWrite(ctx, req) + handler.HandleResponse(ctx, err, nil) +} + // GetSMTPConfig get smtp config // @Summary GetSMTPConfig get smtp config // @Description GetSMTPConfig get smtp config diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index 04eff49b..53b3e3fe 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -224,10 +224,12 @@ func (a *AnswerAPIRouter) RegisterAnswerCmsAPIRouter(r *gin.RouterGroup) { // siteinfo r.GET("/siteinfo/general", a.siteInfoController.GetGeneral) r.GET("/siteinfo/interface", a.siteInfoController.GetInterface) - r.GET("/siteinfo/branding", a.siteInfoController.GetBranding) + r.GET("/siteinfo/branding", a.siteInfoController.GetSiteBranding) + r.GET("/siteinfo/write", a.siteInfoController.GetSiteWrite) r.PUT("/siteinfo/general", a.siteInfoController.UpdateGeneral) r.PUT("/siteinfo/interface", a.siteInfoController.UpdateInterface) r.PUT("/siteinfo/branding", a.siteInfoController.UpdateBranding) + r.PUT("/siteinfo/write", a.siteInfoController.UpdateSiteWrite) r.GET("/setting/smtp", a.siteInfoController.GetSMTPConfig) r.PUT("/setting/smtp", a.siteInfoController.UpdateSMTPConfig) diff --git a/internal/schema/siteinfo_schema.go b/internal/schema/siteinfo_schema.go index 1c9a3aaf..8684be8b 100644 --- a/internal/schema/siteinfo_schema.go +++ b/internal/schema/siteinfo_schema.go @@ -37,6 +37,11 @@ type SiteBrandingReq struct { Favicon string `validate:"omitempty,gt=0,lte=512" form:"favicon" json:"favicon"` } +// SiteWriteReq site write request +type SiteWriteReq struct { + RequiredTag bool `validate:"required" form:"required_tag" json:"required_tag"` +} + // SiteGeneralResp site general response type SiteGeneralResp SiteGeneralReq @@ -46,6 +51,9 @@ type SiteInterfaceResp SiteInterfaceReq // SiteBrandingResp site branding response type SiteBrandingResp SiteBrandingReq +// SiteWriteResp site write response +type SiteWriteResp SiteWriteReq + // SiteInfoResp get site info response type SiteInfoResp struct { General *SiteGeneralResp `json:"general"` diff --git a/internal/service/siteinfo/siteinfo_service.go b/internal/service/siteinfo/siteinfo_service.go index 6db2f34a..66917ae4 100644 --- a/internal/service/siteinfo/siteinfo_service.go +++ b/internal/service/siteinfo/siteinfo_service.go @@ -56,6 +56,34 @@ func (s *SiteInfoService) GetSiteInterface(ctx context.Context) (resp *schema.Si return resp, nil } +// GetSiteBranding get site info branding +func (s *SiteInfoService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingReq, err error) { + siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, constant.SiteTypeBranding) + if err != nil { + return nil, err + } + if !exist { + return nil, errors.BadRequest(reason.SiteInfoNotFound) + } + resp = &schema.SiteBrandingReq{} + _ = json.Unmarshal([]byte(siteInfo.Content), resp) + return resp, nil +} + +// GetSiteWrite get site info write +func (s *SiteInfoService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteReq, err error) { + siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, constant.SiteTypeWrite) + if err != nil { + return nil, err + } + if !exist { + return nil, errors.BadRequest(reason.SiteInfoNotFound) + } + resp = &schema.SiteWriteReq{} + _ = json.Unmarshal([]byte(siteInfo.Content), resp) + return resp, nil +} + func (s *SiteInfoService) SaveSiteGeneral(ctx context.Context, req schema.SiteGeneralReq) (err error) { req.FormatSiteUrl() var ( @@ -120,6 +148,17 @@ func (s *SiteInfoService) SaveSiteBranding(ctx context.Context, req *schema.Site return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeBranding, data) } +// SaveSiteWrite save site configuration about write +func (s *SiteInfoService) SaveSiteWrite(ctx context.Context, req *schema.SiteWriteReq) (err error) { + content, _ := json.Marshal(req) + data := &entity.SiteInfo{ + Type: constant.SiteTypeWrite, + Content: string(content), + Status: 1, + } + return s.siteInfoRepo.SaveByType(ctx, constant.SiteTypeWrite, data) +} + // GetSMTPConfig get smtp config func (s *SiteInfoService) GetSMTPConfig(ctx context.Context) ( resp *schema.GetSMTPConfigResp, err error, From 00336de025100b2a4b5a2348bdf072866f84ccb7 Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Mon, 14 Nov 2022 15:21:17 +0800 Subject: [PATCH 04/12] feat: add site info write common service --- .../service/siteinfo_common/siteinfo_service.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/service/siteinfo_common/siteinfo_service.go b/internal/service/siteinfo_common/siteinfo_service.go index 69ff7fe6..9b5006d9 100644 --- a/internal/service/siteinfo_common/siteinfo_service.go +++ b/internal/service/siteinfo_common/siteinfo_service.go @@ -62,3 +62,17 @@ func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *sche _ = json.Unmarshal([]byte(siteInfo.Content), resp) return resp, nil } + +// GetSiteWrite get site info write +func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) { + siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, constant.SiteTypeWrite) + if err != nil { + return nil, err + } + if !exist { + return nil, errors.BadRequest(reason.SiteInfoNotFound) + } + resp = &schema.SiteWriteResp{} + _ = json.Unmarshal([]byte(siteInfo.Content), resp) + return resp, nil +} From 9e5c6c7a44679504f9d8a494588d130351b8b0fc Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Mon, 14 Nov 2022 15:25:34 +0800 Subject: [PATCH 05/12] feat: add site info common service in tag service --- internal/service/tag/tag_service.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/internal/service/tag/tag_service.go b/internal/service/tag/tag_service.go index 6384eb82..f9de052a 100644 --- a/internal/service/tag/tag_service.go +++ b/internal/service/tag/tag_service.go @@ -3,7 +3,9 @@ package tag import ( "context" "encoding/json" + "github.com/answerdev/answer/internal/service/revision_common" + "github.com/answerdev/answer/internal/service/siteinfo_common" "github.com/answerdev/answer/pkg/htmltext" "github.com/answerdev/answer/internal/base/pager" @@ -24,17 +26,20 @@ type TagService struct { tagRepo tagcommon.TagRepo revisionService *revision_common.RevisionService followCommon activity_common.FollowRepo + siteInfoService *siteinfo_common.SiteInfoCommonService } // NewTagService new tag service func NewTagService( tagRepo tagcommon.TagRepo, revisionService *revision_common.RevisionService, - followCommon activity_common.FollowRepo) *TagService { + followCommon activity_common.FollowRepo, + siteInfoService *siteinfo_common.SiteInfoCommonService) *TagService { return &TagService{ tagRepo: tagRepo, revisionService: revisionService, followCommon: followCommon, + siteInfoService: siteInfoService, } } From 2f6448b2c757f870a7b4fd4c3d61a1ebc6128c32 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Mon, 14 Nov 2022 16:41:10 +0800 Subject: [PATCH 06/12] update recommend tag --- cmd/answer/wire_gen.go | 4 +- docs/docs.go | 187 +++++++++++++++++++++- docs/swagger.json | 187 +++++++++++++++++++++- docs/swagger.yaml | 119 +++++++++++++- internal/entity/tag_entity.go | 1 + internal/repo/tag/tag_repo.go | 11 +- internal/schema/tag_schema.go | 7 +- internal/service/tag/tag_service.go | 7 +- internal/service/tag_common/tag_common.go | 13 ++ 9 files changed, 507 insertions(+), 29 deletions(-) diff --git a/cmd/answer/wire_gen.go b/cmd/answer/wire_gen.go index 7b7a6937..0e8bdc49 100644 --- a/cmd/answer/wire_gen.go +++ b/cmd/answer/wire_gen.go @@ -130,7 +130,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, revisionRepo := revision.NewRevisionRepo(dataData, uniqueIDRepo) revisionService := revision_common.NewRevisionService(revisionRepo, userRepo) followRepo := activity_common.NewFollowRepo(dataData, uniqueIDRepo, activityRepo) - tagService := tag2.NewTagService(tagRepo, revisionService, followRepo) + tagService := tag2.NewTagService(tagRepo, revisionService, followRepo, siteInfoCommonService) tagController := controller.NewTagController(tagService, rankService) followFollowRepo := activity.NewFollowRepo(dataData, uniqueIDRepo, activityRepo) followService := follow.NewFollowService(followFollowRepo, followRepo, tagRepo) @@ -138,7 +138,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, collectionRepo := collection.NewCollectionRepo(dataData, uniqueIDRepo) collectionGroupRepo := collection.NewCollectionGroupRepo(dataData) tagRelRepo := tag.NewTagRelRepo(dataData) - tagCommonService := tagcommon.NewTagCommonService(tagRepo, tagRelRepo, revisionService) + tagCommonService := tagcommon.NewTagCommonService(tagRepo, tagRelRepo, revisionService, siteInfoCommonService) collectionCommon := collectioncommon.NewCollectionCommon(collectionRepo) answerCommon := answercommon.NewAnswerCommon(answerRepo) metaRepo := meta.NewMetaRepo(dataData) diff --git a/docs/docs.go b/docs/docs.go index 27ec7532..eb16fc2d 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -503,6 +503,77 @@ const docTemplate = `{ } } }, + "/answer/admin/api/siteinfo/branding": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get site interface", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "get site interface", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/schema.SiteWriteResp" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update site info branding", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "update site info branding", + "parameters": [ + { + "description": "branding info", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.SiteBrandingReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/answer/admin/api/siteinfo/general": { "get": { "security": [ @@ -645,6 +716,42 @@ const docTemplate = `{ } } }, + "/answer/admin/api/siteinfo/write": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update site write info", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "update site write info", + "parameters": [ + { + "description": "write info", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.SiteWriteReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/answer/admin/api/theme/options": { "get": { "security": [ @@ -5571,6 +5678,56 @@ const docTemplate = `{ } } }, + "schema.SiteBrandingReq": { + "type": "object", + "required": [ + "logo", + "square_icon" + ], + "properties": { + "favicon": { + "type": "string", + "maxLength": 512 + }, + "logo": { + "type": "string", + "maxLength": 512 + }, + "mobile_logo": { + "type": "string", + "maxLength": 512 + }, + "square_icon": { + "type": "string", + "maxLength": 512 + } + } + }, + "schema.SiteBrandingResp": { + "type": "object", + "required": [ + "logo", + "square_icon" + ], + "properties": { + "favicon": { + "type": "string", + "maxLength": 512 + }, + "logo": { + "type": "string", + "maxLength": 512 + }, + "mobile_logo": { + "type": "string", + "maxLength": 512 + }, + "square_icon": { + "type": "string", + "maxLength": 512 + } + } + }, "schema.SiteGeneralReq": { "type": "object", "required": [ @@ -5647,10 +5804,6 @@ const docTemplate = `{ "type": "string", "maxLength": 128 }, - "logo": { - "type": "string", - "maxLength": 256 - }, "theme": { "type": "string", "maxLength": 128 @@ -5673,10 +5826,6 @@ const docTemplate = `{ "type": "string", "maxLength": 128 }, - "logo": { - "type": "string", - "maxLength": 256 - }, "theme": { "type": "string", "maxLength": 128 @@ -5687,6 +5836,28 @@ const docTemplate = `{ } } }, + "schema.SiteWriteReq": { + "type": "object", + "required": [ + "required_tag" + ], + "properties": { + "required_tag": { + "type": "boolean" + } + } + }, + "schema.SiteWriteResp": { + "type": "object", + "required": [ + "required_tag" + ], + "properties": { + "required_tag": { + "type": "boolean" + } + } + }, "schema.TagItem": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 39b4c363..4428992e 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -491,6 +491,77 @@ } } }, + "/answer/admin/api/siteinfo/branding": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "get site interface", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "get site interface", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/schema.SiteWriteResp" + } + } + } + ] + } + } + } + }, + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update site info branding", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "update site info branding", + "parameters": [ + { + "description": "branding info", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.SiteBrandingReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/answer/admin/api/siteinfo/general": { "get": { "security": [ @@ -633,6 +704,42 @@ } } }, + "/answer/admin/api/siteinfo/write": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update site write info", + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "update site write info", + "parameters": [ + { + "description": "write info", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.SiteWriteReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, "/answer/admin/api/theme/options": { "get": { "security": [ @@ -5559,6 +5666,56 @@ } } }, + "schema.SiteBrandingReq": { + "type": "object", + "required": [ + "logo", + "square_icon" + ], + "properties": { + "favicon": { + "type": "string", + "maxLength": 512 + }, + "logo": { + "type": "string", + "maxLength": 512 + }, + "mobile_logo": { + "type": "string", + "maxLength": 512 + }, + "square_icon": { + "type": "string", + "maxLength": 512 + } + } + }, + "schema.SiteBrandingResp": { + "type": "object", + "required": [ + "logo", + "square_icon" + ], + "properties": { + "favicon": { + "type": "string", + "maxLength": 512 + }, + "logo": { + "type": "string", + "maxLength": 512 + }, + "mobile_logo": { + "type": "string", + "maxLength": 512 + }, + "square_icon": { + "type": "string", + "maxLength": 512 + } + } + }, "schema.SiteGeneralReq": { "type": "object", "required": [ @@ -5635,10 +5792,6 @@ "type": "string", "maxLength": 128 }, - "logo": { - "type": "string", - "maxLength": 256 - }, "theme": { "type": "string", "maxLength": 128 @@ -5661,10 +5814,6 @@ "type": "string", "maxLength": 128 }, - "logo": { - "type": "string", - "maxLength": 256 - }, "theme": { "type": "string", "maxLength": 128 @@ -5675,6 +5824,28 @@ } } }, + "schema.SiteWriteReq": { + "type": "object", + "required": [ + "required_tag" + ], + "properties": { + "required_tag": { + "type": "boolean" + } + } + }, + "schema.SiteWriteResp": { + "type": "object", + "required": [ + "required_tag" + ], + "properties": { + "required_tag": { + "type": "boolean" + } + } + }, "schema.TagItem": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 72801460..03a44709 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1050,6 +1050,42 @@ definitions: description: object_type type: string type: object + schema.SiteBrandingReq: + properties: + favicon: + maxLength: 512 + type: string + logo: + maxLength: 512 + type: string + mobile_logo: + maxLength: 512 + type: string + square_icon: + maxLength: 512 + type: string + required: + - logo + - square_icon + type: object + schema.SiteBrandingResp: + properties: + favicon: + maxLength: 512 + type: string + logo: + maxLength: 512 + type: string + mobile_logo: + maxLength: 512 + type: string + square_icon: + maxLength: 512 + type: string + required: + - logo + - square_icon + type: object schema.SiteGeneralReq: properties: contact_email: @@ -1103,9 +1139,6 @@ definitions: language: maxLength: 128 type: string - logo: - maxLength: 256 - type: string theme: maxLength: 128 type: string @@ -1122,9 +1155,6 @@ definitions: language: maxLength: 128 type: string - logo: - maxLength: 256 - type: string theme: maxLength: 128 type: string @@ -1136,6 +1166,20 @@ definitions: - theme - time_zone type: object + schema.SiteWriteReq: + properties: + required_tag: + type: boolean + required: + - required_tag + type: object + schema.SiteWriteResp: + properties: + required_tag: + type: boolean + required: + - required_tag + type: object schema.TagItem: properties: display_name: @@ -1784,6 +1828,47 @@ paths: summary: update smtp config tags: - admin + /answer/admin/api/siteinfo/branding: + get: + description: get site interface + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + $ref: '#/definitions/schema.SiteWriteResp' + type: object + security: + - ApiKeyAuth: [] + summary: get site interface + tags: + - admin + put: + description: update site info branding + parameters: + - description: branding info + in: body + name: data + required: true + schema: + $ref: '#/definitions/schema.SiteBrandingReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.RespBody' + security: + - ApiKeyAuth: [] + summary: update site info branding + tags: + - admin /answer/admin/api/siteinfo/general: get: description: get site general information @@ -1866,6 +1951,28 @@ paths: summary: update site info interface tags: - admin + /answer/admin/api/siteinfo/write: + put: + description: update site write info + parameters: + - description: write info + in: body + name: data + required: true + schema: + $ref: '#/definitions/schema.SiteWriteReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.RespBody' + security: + - ApiKeyAuth: [] + summary: update site write info + tags: + - admin /answer/admin/api/theme/options: get: description: Get theme options diff --git a/internal/entity/tag_entity.go b/internal/entity/tag_entity.go index 2bef34d0..4fabe1f1 100644 --- a/internal/entity/tag_entity.go +++ b/internal/entity/tag_entity.go @@ -21,6 +21,7 @@ type Tag struct { FollowCount int `xorm:"not null default 0 INT(11) follow_count"` QuestionCount int `xorm:"not null default 0 INT(11) question_count"` Status int `xorm:"not null default 1 INT(11) status"` + Recommend bool `xorm:"not null default false BOOL recommend"` RevisionID string `xorm:"not null default 0 BIGINT(20) revision_id"` } diff --git a/internal/repo/tag/tag_repo.go b/internal/repo/tag/tag_repo.go index 44154593..e72a7cf9 100644 --- a/internal/repo/tag/tag_repo.go +++ b/internal/repo/tag/tag_repo.go @@ -73,10 +73,17 @@ func (tr *tagRepo) GetTagBySlugName(ctx context.Context, slugName string) (tagIn // GetTagListByName get tag list all like name func (tr *tagRepo) GetTagListByName(ctx context.Context, name string, limit int) (tagList []*entity.Tag, err error) { tagList = make([]*entity.Tag, 0) - session := tr.data.DB.Where("slug_name LIKE ?", name+"%") + cond := &entity.Tag{} + session := tr.data.DB.Where("") + if name != "" { + session.Where("slug_name LIKE ?", name+"%") + } else { + cond.Recommend = true + } session.Where(builder.Eq{"status": entity.TagStatusAvailable}) session.Limit(limit).Asc("slug_name") - err = session.Find(&tagList) + session.UseBool("recommend") + err = session.Find(&tagList, cond) if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } diff --git a/internal/schema/tag_schema.go b/internal/schema/tag_schema.go index d6b70c39..84160570 100644 --- a/internal/schema/tag_schema.go +++ b/internal/schema/tag_schema.go @@ -11,7 +11,7 @@ import ( // SearchTagLikeReq get tag list all request type SearchTagLikeReq struct { // tag - Tag string `validate:"required,gt=0,lte=35" form:"tag"` + Tag string `validate:"omitempty" form:"tag"` } // GetTagInfoReq get tag info request @@ -218,3 +218,8 @@ type GetFollowingTagsResp struct { // if main tag slug name is not empty, this tag is synonymous with the main tag MainTagSlugName string `json:"main_tag_slug_name"` } + +type SearchTagLikeResp struct { + SlugName string `json:"slug_name"` + Recommend bool `json:"recommend"` +} diff --git a/internal/service/tag/tag_service.go b/internal/service/tag/tag_service.go index f9de052a..3e4966c7 100644 --- a/internal/service/tag/tag_service.go +++ b/internal/service/tag/tag_service.go @@ -44,13 +44,16 @@ func NewTagService( } // SearchTagLike get tag list all -func (ts *TagService) SearchTagLike(ctx context.Context, req *schema.SearchTagLikeReq) (resp []string, err error) { +func (ts *TagService) SearchTagLike(ctx context.Context, req *schema.SearchTagLikeReq) (resp []schema.SearchTagLikeResp, err error) { tags, err := ts.tagRepo.GetTagListByName(ctx, req.Tag, 5) if err != nil { return } for _, tag := range tags { - resp = append(resp, tag.SlugName) + item := schema.SearchTagLikeResp{} + item.SlugName = tag.SlugName + item.Recommend = tag.Recommend + resp = append(resp, item) } return resp, nil } diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index 8e91da62..4ed9a209 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/answerdev/answer/internal/service/revision_common" + "github.com/answerdev/answer/internal/service/siteinfo_common" "github.com/answerdev/answer/internal/entity" "github.com/answerdev/answer/internal/schema" @@ -42,19 +43,31 @@ type TagCommonService struct { revisionService *revision_common.RevisionService tagRepo TagRepo tagRelRepo TagRelRepo + siteInfoService *siteinfo_common.SiteInfoCommonService } // NewTagCommonService new tag service func NewTagCommonService(tagRepo TagRepo, tagRelRepo TagRelRepo, revisionService *revision_common.RevisionService, + siteInfoService *siteinfo_common.SiteInfoCommonService, ) *TagCommonService { return &TagCommonService{ tagRepo: tagRepo, tagRelRepo: tagRelRepo, revisionService: revisionService, + siteInfoService: siteInfoService, } } +func (ts *TagCommonService) GetSiteWriteTag(ctx context.Context) (tags []string, err error) { + return []string{}, nil +} + +func (ts *TagCommonService) SetSiteWriteTag(ctx context.Context, tags []string, required bool) (err error) { + + return nil +} + // GetTagListByName func (ts *TagCommonService) GetTagListByName(ctx context.Context, tagName string) (tagInfo *entity.Tag, exist bool, err error) { tagName = strings.ToLower(tagName) From d701ae60fb28ec264c2f32853167b594a030744a Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Mon, 14 Nov 2022 16:44:48 +0800 Subject: [PATCH 07/12] question tags add recommend --- docs/docs.go | 3 +++ docs/swagger.json | 3 +++ docs/swagger.yaml | 2 ++ internal/schema/search_schema.go | 1 + internal/service/tag_common/tag_common.go | 1 + 5 files changed, 10 insertions(+) diff --git a/docs/docs.go b/docs/docs.go index eb16fc2d..c91f4263 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -5891,6 +5891,9 @@ const docTemplate = `{ "description": "if main tag slug name is not empty, this tag is synonymous with the main tag", "type": "string" }, + "recommend": { + "type": "boolean" + }, "slug_name": { "type": "string" } diff --git a/docs/swagger.json b/docs/swagger.json index 4428992e..8c12e472 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -5879,6 +5879,9 @@ "description": "if main tag slug name is not empty, this tag is synonymous with the main tag", "type": "string" }, + "recommend": { + "type": "boolean" + }, "slug_name": { "type": "string" } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 03a44709..53f7449a 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1205,6 +1205,8 @@ definitions: description: if main tag slug name is not empty, this tag is synonymous with the main tag type: string + recommend: + type: boolean slug_name: type: string type: object diff --git a/internal/schema/search_schema.go b/internal/schema/search_schema.go index 5cf8c577..143a93c1 100644 --- a/internal/schema/search_schema.go +++ b/internal/schema/search_schema.go @@ -29,6 +29,7 @@ type TagResp struct { DisplayName string `json:"display_name"` // if main tag slug name is not empty, this tag is synonymous with the main tag MainTagSlugName string `json:"main_tag_slug_name"` + Recommend bool `json:"recommend"` } type SearchResp struct { diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index 4ed9a209..4ed9af2f 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -103,6 +103,7 @@ func (ts *TagCommonService) GetObjectTag(ctx context.Context, objectId string) ( SlugName: tagInfo.SlugName, DisplayName: tagInfo.DisplayName, MainTagSlugName: tagInfo.MainTagSlugName, + Recommend: tagInfo.Recommend, }) } return objTags, nil From 678d903a0904bda05f50cd338813c1dc81092425 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Mon, 14 Nov 2022 17:05:49 +0800 Subject: [PATCH 08/12] verify question has recommend tag --- i18n/en_US.yaml | 2 ++ internal/base/reason/reason.go | 1 + internal/service/question_service.go | 10 ++++++++++ internal/service/tag_common/tag_common.go | 17 +++++++++++++++++ 4 files changed, 30 insertions(+) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index f3fe2602..c89a01ce 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -74,6 +74,8 @@ backend: tag: not_found: other: "Tag not found." + recommend_tag_not_found: + other: "Recommend Tag is not exist." theme: not_found: other: "Theme not found." diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go index 6765a883..200e20cb 100644 --- a/internal/base/reason/reason.go +++ b/internal/base/reason/reason.go @@ -43,4 +43,5 @@ const ( InstallCreateTableFailed = "error.database.create_table_failed" InstallConfigFailed = "error.install.create_config_failed" SiteInfoNotFound = "error.site_info.not_found" + RecommendTagNotExist = "error.tag.recommend_tag_not_found" ) diff --git a/internal/service/question_service.go b/internal/service/question_service.go index 72f885b1..85bf7673 100644 --- a/internal/service/question_service.go +++ b/internal/service/question_service.go @@ -105,6 +105,16 @@ func (qs *QuestionService) CloseMsgList(ctx context.Context, lang i18n.Language) // AddQuestion add question func (qs *QuestionService) AddQuestion(ctx context.Context, req *schema.QuestionAdd) (questionInfo *schema.QuestionInfo, err error) { + recommendExist, err := qs.tagCommon.ExistRecommend(ctx, req.Tags) + if err != nil { + return + } + if !recommendExist { + err = fmt.Errorf("recommend is not exist") + err = errors.BadRequest(reason.RecommendTagNotExist).WithError(err).WithStack() + return + } + questionInfo = &schema.QuestionInfo{} question := &entity.Question{} now := time.Now() diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index 4ed9af2f..ef4a4872 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -81,6 +81,23 @@ func (ts *TagCommonService) GetTagListByNames(ctx context.Context, tagNames []st return ts.tagRepo.GetTagListByNames(ctx, tagNames) } +func (ts *TagCommonService) ExistRecommend(ctx context.Context, tags []*schema.TagItem) (bool, error) { + tagNames := make([]string, 0) + for _, item := range tags { + tagNames = append(tagNames, item.SlugName) + } + list, err := ts.GetTagListByNames(ctx, tagNames) + if err != nil { + return false, err + } + for _, item := range list { + if item.Recommend { + return true, nil + } + } + return false, nil +} + // // GetObjectTag get object tag From a390227c179f0def1ae2136d16203d948136641d Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Mon, 14 Nov 2022 18:06:58 +0800 Subject: [PATCH 09/12] update reserved tags --- internal/repo/user/user_backyard_repo.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/repo/user/user_backyard_repo.go b/internal/repo/user/user_backyard_repo.go index ad20794d..71ae7fca 100644 --- a/internal/repo/user/user_backyard_repo.go +++ b/internal/repo/user/user_backyard_repo.go @@ -7,6 +7,7 @@ import ( "strings" "time" "unicode" + "xorm.io/builder" "github.com/answerdev/answer/internal/base/data" From baf0fce1c18d1a4a09c23381793277481fc47030 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Mon, 14 Nov 2022 18:07:28 +0800 Subject: [PATCH 10/12] update reserved tags --- internal/controller/tag_controller.go | 3 +- internal/entity/auth_user_entity.go | 1 + internal/entity/tag_entity.go | 1 + internal/repo/tag/tag_repo.go | 37 ++++++++++++++++++++++- internal/schema/tag_schema.go | 4 ++- internal/service/auth/auth.go | 1 + internal/service/tag/tag_service.go | 3 +- internal/service/tag_common/tag_common.go | 31 ++++++++++++++++--- internal/service/user_service.go | 3 ++ 9 files changed, 76 insertions(+), 8 deletions(-) diff --git a/internal/controller/tag_controller.go b/internal/controller/tag_controller.go index 601c2c6d..034bf6e4 100644 --- a/internal/controller/tag_controller.go +++ b/internal/controller/tag_controller.go @@ -36,7 +36,8 @@ func (tc *TagController) SearchTagLike(ctx *gin.Context) { if handler.BindAndCheck(ctx, req) { return } - + userinfo := middleware.GetUserInfoFromContext(ctx) + req.IsAdmin = userinfo.IsAdmin resp, err := tc.tagService.SearchTagLike(ctx, req) handler.HandleResponse(ctx, err, resp) } diff --git a/internal/entity/auth_user_entity.go b/internal/entity/auth_user_entity.go index d1f366a4..f71d79df 100644 --- a/internal/entity/auth_user_entity.go +++ b/internal/entity/auth_user_entity.go @@ -5,4 +5,5 @@ type UserCacheInfo struct { UserID string `json:"user_id"` UserStatus int `json:"user_status"` EmailStatus int `json:"email_status"` + IsAdmin bool `json:"is_admin"` } diff --git a/internal/entity/tag_entity.go b/internal/entity/tag_entity.go index 4fabe1f1..4d934e2d 100644 --- a/internal/entity/tag_entity.go +++ b/internal/entity/tag_entity.go @@ -22,6 +22,7 @@ type Tag struct { QuestionCount int `xorm:"not null default 0 INT(11) question_count"` Status int `xorm:"not null default 1 INT(11) status"` Recommend bool `xorm:"not null default false BOOL recommend"` + Reserved bool `xorm:"not null default false BOOL reserved"` RevisionID string `xorm:"not null default 0 BIGINT(20) revision_id"` } diff --git a/internal/repo/tag/tag_repo.go b/internal/repo/tag/tag_repo.go index e72a7cf9..ad7e17b9 100644 --- a/internal/repo/tag/tag_repo.go +++ b/internal/repo/tag/tag_repo.go @@ -71,7 +71,7 @@ func (tr *tagRepo) GetTagBySlugName(ctx context.Context, slugName string) (tagIn } // GetTagListByName get tag list all like name -func (tr *tagRepo) GetTagListByName(ctx context.Context, name string, limit int) (tagList []*entity.Tag, err error) { +func (tr *tagRepo) GetTagListByName(ctx context.Context, name string, limit int, hasReserved bool) (tagList []*entity.Tag, err error) { tagList = make([]*entity.Tag, 0) cond := &entity.Tag{} session := tr.data.DB.Where("") @@ -82,6 +82,26 @@ func (tr *tagRepo) GetTagListByName(ctx context.Context, name string, limit int) } session.Where(builder.Eq{"status": entity.TagStatusAvailable}) session.Limit(limit).Asc("slug_name") + if !hasReserved { + cond.Recommend = false + session.UseBool("recommend", "reserved") + } else { + session.UseBool("recommend") + } + err = session.Find(&tagList, cond) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + +func (tr *tagRepo) GetRecommendTagList(ctx context.Context) (tagList []*entity.Tag, err error) { + tagList = make([]*entity.Tag, 0) + cond := &entity.Tag{} + session := tr.data.DB.Where("") + cond.Recommend = true + session.Where(builder.Eq{"status": entity.TagStatusAvailable}) + session.Asc("slug_name") session.UseBool("recommend") err = session.Find(&tagList, cond) if err != nil { @@ -90,6 +110,21 @@ func (tr *tagRepo) GetTagListByName(ctx context.Context, name string, limit int) return } +func (tr *tagRepo) GetReservedTagList(ctx context.Context) (tagList []*entity.Tag, err error) { + tagList = make([]*entity.Tag, 0) + cond := &entity.Tag{} + session := tr.data.DB.Where("") + cond.Reserved = true + session.Where(builder.Eq{"status": entity.TagStatusAvailable}) + session.Asc("slug_name") + session.UseBool("reserved") + err = session.Find(&tagList, cond) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + // GetTagListByNames get tag list all like name func (tr *tagRepo) GetTagListByNames(ctx context.Context, names []string) (tagList []*entity.Tag, err error) { tagList = make([]*entity.Tag, 0) diff --git a/internal/schema/tag_schema.go b/internal/schema/tag_schema.go index 84160570..f22b89b3 100644 --- a/internal/schema/tag_schema.go +++ b/internal/schema/tag_schema.go @@ -11,7 +11,8 @@ import ( // SearchTagLikeReq get tag list all request type SearchTagLikeReq struct { // tag - Tag string `validate:"omitempty" form:"tag"` + Tag string `validate:"omitempty" form:"tag"` + IsAdmin bool `json:"-"` } // GetTagInfoReq get tag info request @@ -222,4 +223,5 @@ type GetFollowingTagsResp struct { type SearchTagLikeResp struct { SlugName string `json:"slug_name"` Recommend bool `json:"recommend"` + Reserved bool `json:"reserved"` } diff --git a/internal/service/auth/auth.go b/internal/service/auth/auth.go index 95604a14..0afffc28 100644 --- a/internal/service/auth/auth.go +++ b/internal/service/auth/auth.go @@ -43,6 +43,7 @@ func (as *AuthService) GetUserCacheInfo(ctx context.Context, accessToken string) log.Infof("user status updated: %+v", cacheInfo) userCacheInfo.UserStatus = cacheInfo.UserStatus userCacheInfo.EmailStatus = cacheInfo.EmailStatus + userCacheInfo.IsAdmin = cacheInfo.IsAdmin // update current user cache info err := as.authRepo.SetUserCacheInfo(ctx, accessToken, userCacheInfo) if err != nil { diff --git a/internal/service/tag/tag_service.go b/internal/service/tag/tag_service.go index 3e4966c7..aa012be3 100644 --- a/internal/service/tag/tag_service.go +++ b/internal/service/tag/tag_service.go @@ -45,7 +45,7 @@ func NewTagService( // SearchTagLike get tag list all func (ts *TagService) SearchTagLike(ctx context.Context, req *schema.SearchTagLikeReq) (resp []schema.SearchTagLikeResp, err error) { - tags, err := ts.tagRepo.GetTagListByName(ctx, req.Tag, 5) + tags, err := ts.tagRepo.GetTagListByName(ctx, req.Tag, 5, req.IsAdmin) if err != nil { return } @@ -53,6 +53,7 @@ func (ts *TagService) SearchTagLike(ctx context.Context, req *schema.SearchTagLi item := schema.SearchTagLikeResp{} item.SlugName = tag.SlugName item.Recommend = tag.Recommend + item.Reserved = tag.Reserved resp = append(resp, item) } return resp, nil diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index ef4a4872..12e916f3 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -17,7 +17,7 @@ type TagRepo interface { AddTagList(ctx context.Context, tagList []*entity.Tag) (err error) GetTagListByIDs(ctx context.Context, ids []string) (tagList []*entity.Tag, err error) GetTagBySlugName(ctx context.Context, slugName string) (tagInfo *entity.Tag, exist bool, err error) - GetTagListByName(ctx context.Context, name string, limit int) (tagList []*entity.Tag, err error) + GetTagListByName(ctx context.Context, name string, limit int, hasReserved bool) (tagList []*entity.Tag, err error) GetTagListByNames(ctx context.Context, names []string) (tagList []*entity.Tag, err error) RemoveTag(ctx context.Context, tagID string) (err error) UpdateTag(ctx context.Context, tag *entity.Tag) (err error) @@ -26,6 +26,8 @@ type TagRepo interface { GetTagByID(ctx context.Context, tagID string) (tag *entity.Tag, exist bool, err error) GetTagList(ctx context.Context, tag *entity.Tag) (tagList []*entity.Tag, err error) GetTagPage(ctx context.Context, page, pageSize int, tag *entity.Tag, queryCond string) (tagList []*entity.Tag, total int64, err error) + GetRecommendTagList(ctx context.Context) (tagList []*entity.Tag, err error) + GetReservedTagList(ctx context.Context) (tagList []*entity.Tag, err error) } type TagRelRepo interface { @@ -59,15 +61,36 @@ func NewTagCommonService(tagRepo TagRepo, tagRelRepo TagRelRepo, } } -func (ts *TagCommonService) GetSiteWriteTag(ctx context.Context) (tags []string, err error) { - return []string{}, nil +func (ts *TagCommonService) GetSiteWriteRecommendTag(ctx context.Context) (tags []string, err error) { + tags = make([]string, 0) + list, err := ts.tagRepo.GetRecommendTagList(ctx) + for _, item := range list { + tags = append(tags, item.SlugName) + } + return tags, nil } -func (ts *TagCommonService) SetSiteWriteTag(ctx context.Context, tags []string, required bool) (err error) { +func (ts *TagCommonService) SetSiteWriteRecommendTag(ctx context.Context, tags []string, required bool) (err error) { return nil } +func (ts *TagCommonService) GetSiteWriteReservedTag(ctx context.Context) (tags []string, err error) { + tags = make([]string, 0) + list, err := ts.tagRepo.GetReservedTagList(ctx) + for _, item := range list { + tags = append(tags, item.SlugName) + } + return tags, nil +} + +func (ts *TagCommonService) SetSiteWriteReservedTag(ctx context.Context, tags []string, required bool) (err error) { + + return nil +} + +// + // GetTagListByName func (ts *TagCommonService) GetTagListByName(ctx context.Context, tagName string) (tagInfo *entity.Tag, exist bool, err error) { tagName = strings.ToLower(tagName) diff --git a/internal/service/user_service.go b/internal/service/user_service.go index 8673c3d2..288161c5 100644 --- a/internal/service/user_service.go +++ b/internal/service/user_service.go @@ -112,6 +112,7 @@ func (us *UserService) EmailLogin(ctx context.Context, req *schema.UserEmailLogi UserID: userInfo.ID, EmailStatus: userInfo.MailStatus, UserStatus: userInfo.Status, + IsAdmin: userInfo.IsAdmin, } resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo) if err != nil { @@ -322,6 +323,7 @@ func (us *UserService) UserRegisterByEmail(ctx context.Context, registerUserInfo UserID: userInfo.ID, EmailStatus: userInfo.MailStatus, UserStatus: userInfo.Status, + IsAdmin: userInfo.IsAdmin, } resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo) if err != nil { @@ -408,6 +410,7 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri UserID: userInfo.ID, EmailStatus: userInfo.MailStatus, UserStatus: userInfo.Status, + IsAdmin: userInfo.IsAdmin, } resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo) if err != nil { From 3a992965dfb9c3e086d3b5db54466c4dcebf43a7 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Mon, 14 Nov 2022 18:55:09 +0800 Subject: [PATCH 11/12] update recommendTag --- internal/service/tag_common/tag_common.go | 77 +++++++++++++++++++++-- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index 12e916f3..d6a53595 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -70,8 +70,11 @@ func (ts *TagCommonService) GetSiteWriteRecommendTag(ctx context.Context) (tags return tags, nil } -func (ts *TagCommonService) SetSiteWriteRecommendTag(ctx context.Context, tags []string, required bool) (err error) { - +func (ts *TagCommonService) SetSiteWriteRecommendTag(ctx context.Context, tags []string, required bool, userID string) (err error) { + err = ts.UpdateTag(ctx, tags, userID) + if err != nil { + return err + } return nil } @@ -84,8 +87,11 @@ func (ts *TagCommonService) GetSiteWriteReservedTag(ctx context.Context) (tags [ return tags, nil } -func (ts *TagCommonService) SetSiteWriteReservedTag(ctx context.Context, tags []string, required bool) (err error) { - +func (ts *TagCommonService) SetSiteWriteReservedTag(ctx context.Context, tags []string, userID string) (err error) { + err = ts.UpdateTag(ctx, tags, userID) + if err != nil { + return err + } return nil } @@ -184,6 +190,69 @@ func (ts *TagCommonService) BatchGetObjectTag(ctx context.Context, objectIds []s return objectIDTagMap, nil } +func (ts *TagCommonService) UpdateTag(ctx context.Context, tags []string, userID string) (err error) { + if len(tags) == 0 { + return nil + } + + thisTagNameList := make([]string, 0) + thisTagIDList := make([]string, 0) + for _, t := range tags { + t = strings.ToLower(t) + thisTagNameList = append(thisTagNameList, t) + } + + // find tags name + tagListInDb, err := ts.tagRepo.GetTagListByNames(ctx, thisTagNameList) + if err != nil { + return err + } + + tagInDbMapping := make(map[string]*entity.Tag) + for _, tag := range tagListInDb { + tagInDbMapping[tag.SlugName] = tag + thisTagIDList = append(thisTagIDList, tag.ID) + } + + addTagList := make([]*entity.Tag, 0) + for _, tag := range tags { + _, ok := tagInDbMapping[tag] + if ok { + continue + } + item := &entity.Tag{} + item.SlugName = tag + item.DisplayName = tag + item.OriginalText = "" + item.ParsedText = "" + item.Status = entity.TagStatusAvailable + addTagList = append(addTagList, item) + } + + if len(addTagList) > 0 { + err = ts.tagRepo.AddTagList(ctx, addTagList) + if err != nil { + return err + } + for _, tag := range addTagList { + thisTagIDList = append(thisTagIDList, tag.ID) + revisionDTO := &schema.AddRevisionDTO{ + UserID: userID, + ObjectID: tag.ID, + Title: tag.SlugName, + } + tagInfoJson, _ := json.Marshal(tag) + revisionDTO.Content = string(tagInfoJson) + err = ts.revisionService.AddRevision(ctx, revisionDTO, true) + if err != nil { + return err + } + } + } + + return nil +} + // ObjectChangeTag change object tag list func (ts *TagCommonService) ObjectChangeTag(ctx context.Context, objectTagData *schema.TagChange) (err error) { if len(objectTagData.Tags) == 0 { From 3662182ff302485273122bd4450ecd09d156feb7 Mon Sep 17 00:00:00 2001 From: aichy126 <16996097+aichy126@users.noreply.github.com> Date: Tue, 15 Nov 2022 10:40:54 +0800 Subject: [PATCH 12/12] update tags attribute --- internal/repo/tag/tag_repo.go | 18 +++++++++++++ internal/service/tag_common/tag_common.go | 31 ++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/internal/repo/tag/tag_repo.go b/internal/repo/tag/tag_repo.go index ad7e17b9..e6251f0f 100644 --- a/internal/repo/tag/tag_repo.go +++ b/internal/repo/tag/tag_repo.go @@ -179,6 +179,24 @@ func (tr *tagRepo) UpdateTagSynonym(ctx context.Context, tagSlugNameList []strin return } +func (tr *tagRepo) UpdateTagsAttribute(ctx context.Context, tags []string, attribute string, value bool) (err error) { + bean := &entity.Tag{} + switch attribute { + case "recommend": + bean.Recommend = value + case "reserved": + bean.Reserved = value + default: + return + } + session := tr.data.DB.In("slug_name", tags).Cols(attribute).UseBool(attribute) + _, err = session.Update(bean) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + // GetTagByID get tag one func (tr *tagRepo) GetTagByID(ctx context.Context, tagID string) ( tag *entity.Tag, exist bool, err error, diff --git a/internal/service/tag_common/tag_common.go b/internal/service/tag_common/tag_common.go index d6a53595..b50fbcf0 100644 --- a/internal/service/tag_common/tag_common.go +++ b/internal/service/tag_common/tag_common.go @@ -28,6 +28,7 @@ type TagRepo interface { GetTagPage(ctx context.Context, page, pageSize int, tag *entity.Tag, queryCond string) (tagList []*entity.Tag, total int64, err error) GetRecommendTagList(ctx context.Context) (tagList []*entity.Tag, err error) GetReservedTagList(ctx context.Context) (tagList []*entity.Tag, err error) + UpdateTagsAttribute(ctx context.Context, tags []string, attribute string, value bool) (err error) } type TagRelRepo interface { @@ -75,6 +76,10 @@ func (ts *TagCommonService) SetSiteWriteRecommendTag(ctx context.Context, tags [ if err != nil { return err } + err = ts.SetTagsAttribute(ctx, tags, "recommend", true) + if err != nil { + return err + } return nil } @@ -92,10 +97,34 @@ func (ts *TagCommonService) SetSiteWriteReservedTag(ctx context.Context, tags [] if err != nil { return err } + err = ts.SetTagsAttribute(ctx, tags, "reserved", true) + if err != nil { + return err + } return nil } -// +// SetTagsAttribute +func (ts *TagCommonService) SetTagsAttribute(ctx context.Context, tags []string, attribute string, value bool) (err error) { + var tagslist []string + switch attribute { + case "recommend": + tagslist, err = ts.GetSiteWriteRecommendTag(ctx) + case "reserved": + tagslist, err = ts.GetSiteWriteReservedTag(ctx) + default: + return + } + err = ts.tagRepo.UpdateTagsAttribute(ctx, tagslist, attribute, false) + if err != nil { + return err + } + err = ts.tagRepo.UpdateTagsAttribute(ctx, tags, attribute, value) + if err != nil { + return err + } + return nil +} // GetTagListByName func (ts *TagCommonService) GetTagListByName(ctx context.Context, tagName string) (tagInfo *entity.Tag, exist bool, err error) {