Merge branch 'feat/1.1.0/sql' into test

This commit is contained in:
aichy126
2023-05-18 10:29:16 +08:00
13 changed files with 316 additions and 46 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
{
"eslint.workingDirectories": [
"ui"
]
],
"commentTranslate.multiLineMerge": true
}
+8
View File
@@ -8925,6 +8925,14 @@ const docTemplate = `{
"pass"
],
"properties": {
"captcha_code": {
"type": "string",
"maxLength": 500
},
"captcha_id": {
"type": "string",
"maxLength": 500
},
"old_pass": {
"type": "string",
"maxLength": 32,
+8
View File
@@ -8913,6 +8913,14 @@
"pass"
],
"properties": {
"captcha_code": {
"type": "string",
"maxLength": 500
},
"captcha_id": {
"type": "string",
"maxLength": 500
},
"old_pass": {
"type": "string",
"maxLength": 32,
+6
View File
@@ -2134,6 +2134,12 @@ definitions:
type: object
schema.UserModifyPasswordReq:
properties:
captcha_code:
maxLength: 500
type: string
captcha_id:
maxLength: 500
type: string
old_pass:
maxLength: 32
minLength: 8
+19
View File
@@ -350,6 +350,21 @@ func (uc *UserController) UserModifyPassWord(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
req.AccessToken = middleware.ExtractToken(ctx)
captchaPass := uc.actionService.ActionRecordVerifyCaptcha(ctx, schema.ActionRecordTypeModifyPass, ctx.ClientIP(),
req.CaptchaID, req.CaptchaCode)
if !captchaPass {
errFields := append([]*validator.FormErrorField{}, &validator.FormErrorField{
ErrorField: "captcha_code",
ErrorMsg: translator.Tr(handler.GetLang(ctx), reason.CaptchaVerificationFailed),
})
handler.HandleResponse(ctx, errors.BadRequest(reason.CaptchaVerificationFailed), errFields)
return
}
_, err := uc.actionService.ActionRecordAdd(ctx, schema.ActionRecordTypeModifyPass, ctx.ClientIP())
if err != nil {
log.Error(err)
}
oldPassVerification, err := uc.userService.UserModifyPassWordVerification(ctx, req)
if err != nil {
handler.HandleResponse(ctx, err, nil)
@@ -363,6 +378,7 @@ func (uc *UserController) UserModifyPassWord(ctx *gin.Context) {
handler.HandleResponse(ctx, errors.BadRequest(reason.OldPasswordVerificationFailed), errFields)
return
}
if req.OldPass == req.Pass {
errFields := append([]*validator.FormErrorField{}, &validator.FormErrorField{
ErrorField: "pass",
@@ -372,6 +388,9 @@ func (uc *UserController) UserModifyPassWord(ctx *gin.Context) {
return
}
err = uc.userService.UserModifyPassword(ctx, req)
if err == nil {
uc.actionService.ActionRecordDel(ctx, schema.ActionRecordTypeLogin, ctx.ClientIP())
}
handler.HandleResponse(ctx, err, nil)
}
+1
View File
@@ -4,6 +4,7 @@ import "time"
const (
TagRelStatusAvailable = 1
TagRelStatusHide = 2
TagRelStatusDeleted = 10
)
+140 -24
View File
@@ -1,38 +1,23 @@
package migrations
import (
"encoding/json"
"fmt"
"github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/segmentfault/pacman/log"
"xorm.io/xorm"
)
func addGravatarBaseURL(x *xorm.Engine) error {
usersSiteInfo := &entity.SiteInfo{
Type: constant.SiteTypeUsers,
}
exist, err := x.Get(usersSiteInfo)
if err != nil {
return fmt.Errorf("get config failed: %w", err)
}
if exist {
content := &schema.SiteUsersReq{}
_ = json.Unmarshal([]byte(usersSiteInfo.Content), content)
content.GravatarBaseURL = "https://www.gravatar.com/avatar/"
data, _ := json.Marshal(content)
usersSiteInfo.Content = string(data)
func updateCount(x *xorm.Engine) error {
// updateQuestionCount(x)
// updateTagCount(x)
// updateUserQuestionCount(x)
updateUserAnswerCount(x)
return nil
}
_, err = x.ID(usersSiteInfo.ID).Cols("content").Update(usersSiteInfo)
if err != nil {
return fmt.Errorf("update site info failed: %w", err)
}
}
//search all answers
func updateQuestionCount(x *xorm.Engine) error {
//question answer count
answers := make([]entity.Answer, 0)
err = x.Find(&answers, &entity.Answer{Status: entity.AnswerStatusAvailable})
if err != nil {
@@ -62,5 +47,136 @@ func addGravatarBaseURL(x *xorm.Engine) error {
}
}
}
return nil
}
// updateTagCount update tag count
func updateTagCount(x *xorm.Engine) error {
tagRelList := make([]entity.TagRel, 0)
err := x.Find(&tagRelList, &entity.TagRel{})
if err != nil {
return fmt.Errorf("get tag rel failed: %w", err)
}
questionIDs := make([]string, 0)
questionsAvailableMap := make(map[string]bool)
questionsHideMap := make(map[string]bool)
for _, item := range tagRelList {
questionIDs = append(questionIDs, item.ObjectID)
questionsAvailableMap[item.ObjectID] = false
questionsHideMap[item.ObjectID] = false
}
questionList := make([]entity.Question, 0)
err = x.In("id", questionIDs).In("question.status", []int{entity.QuestionStatusAvailable, entity.QuestionStatusClosed}).Find(&questionList, &entity.Question{})
if err != nil {
return fmt.Errorf("get questions failed: %w", err)
}
for _, question := range questionList {
_, ok := questionsAvailableMap[question.ID]
if ok {
questionsAvailableMap[question.ID] = true
if question.Show == entity.QuestionHide {
questionsHideMap[question.ID] = true
}
}
}
for id, ok := range questionsHideMap {
if ok {
if _, err = x.Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusHide}, &entity.TagRel{ObjectID: id}); err != nil {
log.Errorf("update %+v config failed: %s", id, err)
}
}
}
for id, ok := range questionsAvailableMap {
if !ok {
if _, err = x.Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusDeleted}, &entity.TagRel{ObjectID: id}); err != nil {
log.Errorf("update %+v config failed: %s", id, err)
}
}
}
//select tag count
newTagRelList := make([]entity.TagRel, 0)
err = x.Find(&newTagRelList, &entity.TagRel{Status: entity.TagRelStatusAvailable})
if err != nil {
return fmt.Errorf("get tag rel failed: %w", err)
}
tagCountMap := make(map[string]int)
for _, v := range newTagRelList {
_, ok := tagCountMap[v.TagID]
if !ok {
tagCountMap[v.TagID] = 1
} else {
tagCountMap[v.TagID]++
}
}
TagList := make([]entity.Tag, 0)
err = x.Find(&TagList, &entity.Tag{})
if err != nil {
return fmt.Errorf("get tag failed: %w", err)
}
for _, tag := range TagList {
_, ok := tagCountMap[tag.ID]
if ok {
tag.QuestionCount = tagCountMap[tag.ID]
if _, err = x.Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
log.Errorf("update %+v tag failed: %s", tag.ID, err)
return fmt.Errorf("update tag failed: %w", err)
}
} else {
tag.QuestionCount = 0
if _, err = x.Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
log.Errorf("update %+v tag failed: %s", tag.ID, err)
return fmt.Errorf("update tag failed: %w", err)
}
}
}
return nil
}
// updateUserQuestionCount update user question count
func updateUserQuestionCount(x *xorm.Engine) error {
questionList := make([]entity.Question, 0)
err := x.In("status", []int{entity.QuestionStatusAvailable, entity.QuestionStatusClosed}).Find(&questionList, &entity.Question{})
if err != nil {
return fmt.Errorf("get question failed: %w", err)
}
userQuestionCountMap := make(map[string]int)
for _, question := range questionList {
_, ok := userQuestionCountMap[question.UserID]
if !ok {
userQuestionCountMap[question.UserID] = 1
} else {
userQuestionCountMap[question.UserID]++
}
}
userList := make([]entity.User, 0)
err = x.Find(&userList, &entity.User{})
if err != nil {
return fmt.Errorf("get user failed: %w", err)
}
for _, user := range userList {
_, ok := userQuestionCountMap[user.ID]
if ok {
user.QuestionCount = userQuestionCountMap[user.ID]
if _, err = x.Cols("question_count").Update(user, &entity.User{ID: user.ID}); err != nil {
log.Errorf("update %+v user failed: %s", user.ID, err)
return fmt.Errorf("update user failed: %w", err)
}
} else {
user.QuestionCount = 0
if _, err = x.Cols("question_count").Update(user, &entity.User{ID: user.ID}); err != nil {
log.Errorf("update %+v user failed: %s", user.ID, err)
return fmt.Errorf("update user failed: %w", err)
}
}
}
return nil
}
// updateUserAnswerCount update user answer count
func updateUserAnswerCount(x *xorm.Engine) error {
return nil
}
+1 -1
View File
@@ -138,7 +138,7 @@ func (ur *UserRankRepo) UserRankPage(ctx context.Context, userID string, page, p
) {
rankPage = make([]*entity.Activity, 0)
session := ur.data.DB.Where(builder.Eq{"has_rank": 1}.And(builder.Eq{"cancelled": 0}))
session := ur.data.DB.Where(builder.Eq{"has_rank": 1}.And(builder.Eq{"cancelled": 0})).And(builder.Gt{"rank": 0})
session.Desc("created_at")
cond := &entity.Activity{UserID: userID}
+22 -1
View File
@@ -9,6 +9,7 @@ import (
tagcommon "github.com/answerdev/answer/internal/service/tag_common"
"github.com/answerdev/answer/internal/service/unique"
"github.com/answerdev/answer/pkg/uid"
"github.com/davecgh/go-spew/spew"
"github.com/segmentfault/pacman/errors"
)
@@ -52,6 +53,26 @@ func (tr *tagRelRepo) RemoveTagRelListByObjectID(ctx context.Context, objectID s
return
}
func (tr *tagRelRepo) HideTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
spew.Dump("====== HideTagRelListByObjectID")
objectID = uid.DeShortID(objectID)
_, err = tr.data.DB.Where("object_id = ?", objectID).Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusHide})
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
func (tr *tagRelRepo) ShowTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
spew.Dump("====== ShowTagRelListByObjectID")
objectID = uid.DeShortID(objectID)
_, err = tr.data.DB.Where("object_id = ?", objectID).Cols("status").Update(&entity.TagRel{Status: entity.TagRelStatusAvailable})
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// RemoveTagRelListByIDs delete tag list
func (tr *tagRelRepo) RemoveTagRelListByIDs(ctx context.Context, ids []int64) (err error) {
_, err = tr.data.DB.In("id", ids).Update(&entity.TagRel{Status: entity.TagRelStatusDeleted})
@@ -90,7 +111,7 @@ func (tr *tagRelRepo) GetObjectTagRelList(ctx context.Context, objectID string)
objectID = uid.DeShortID(objectID)
tagListList = make([]*entity.TagRel, 0)
session := tr.data.DB.Where("object_id = ?", objectID)
session.Where("status = ?", entity.TagRelStatusAvailable)
session.In("status", []int{entity.TagRelStatusAvailable, entity.TagRelStatusHide})
err = session.Find(&tagListList)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+9 -6
View File
@@ -222,9 +222,10 @@ const (
NoticeStatusOn = 1
NoticeStatusOff = 2
ActionRecordTypeLogin = "login"
ActionRecordTypeEmail = "e_mail"
ActionRecordTypeFindPass = "find_pass"
ActionRecordTypeLogin = "login"
ActionRecordTypeEmail = "e_mail"
ActionRecordTypeFindPass = "find_pass"
ActionRecordTypeModifyPass = "modify_pass"
)
var UserStatusShow = map[int]string{
@@ -276,10 +277,12 @@ func (u *UserRegisterReq) Check() (errFields []*validator.FormErrorField, err er
}
type UserModifyPasswordReq struct {
OldPass string `validate:"omitempty,gte=8,lte=32" json:"old_pass"`
Pass string `validate:"required,gte=8,lte=32" json:"pass"`
OldPass string `validate:"omitempty,gte=8,lte=32" json:"old_pass"`
Pass string `validate:"required,gte=8,lte=32" json:"pass"`
UserID string `json:"-"`
AccessToken string `json:"-"`
CaptchaID string `validate:"omitempty,gt=0,lte=500" json:"captcha_id"`
CaptchaCode string `validate:"omitempty,gt=0,lte=500" json:"captcha_code"`
}
func (u *UserModifyPasswordReq) Check() (errFields []*validator.FormErrorField, err error) {
@@ -376,7 +379,7 @@ type UserNoticeSetResp struct {
type ActionRecordReq struct {
// action
Action string `validate:"required,oneof=login e_mail find_pass" form:"action"`
Action string `validate:"required,oneof=login e_mail find_pass modify_pass" form:"action"`
IP string `json:"-"`
}
+33 -13
View File
@@ -1,14 +1,22 @@
package activity_type
import "github.com/answerdev/answer/internal/repo/config"
import (
"github.com/answerdev/answer/internal/repo/config"
)
const (
QuestionVoteUp = "question.vote_up"
QuestionVoteDown = "question.vote_down"
AnswerVoteUp = "answer.vote_up"
AnswerVoteDown = "answer.vote_down"
CommentVoteUp = "comment.vote_up"
CommentVoteDown = "comment.vote_down"
QuestionVoteUp = "question.vote_up"
QuestionVoteDown = "question.vote_down"
AnswerVoteUp = "answer.vote_up"
AnswerVoteDown = "answer.vote_down"
CommentVoteUp = "comment.vote_up"
CommentVoteDown = "comment.vote_down"
AnswerAccepted = "answer.accepted"
AnswerAccept = "answer.accept"
QuestionVotedUp = "question.voted_up"
QuestionVotedDown = "question.voted_down"
AnswerVotedUp = "answer.voted_up"
AnswerVotedDown = "answer.voted_down"
)
var (
@@ -19,14 +27,26 @@ var (
AnswerVoteDown,
CommentVoteUp,
CommentVoteDown,
AnswerAccepted,
AnswerAccept,
QuestionVotedUp,
QuestionVotedDown,
AnswerVotedUp,
AnswerVotedDown,
}
activityTypeFlagMapping = map[string]string{
QuestionVoteUp: "upvote",
QuestionVoteDown: "downvote",
AnswerVoteUp: "upvote",
AnswerVoteDown: "downvote",
CommentVoteUp: "upvote",
CommentVoteDown: "downvote",
QuestionVoteUp: "upvote",
QuestionVoteDown: "downvote",
AnswerVoteUp: "upvote",
AnswerVoteDown: "downvote",
CommentVoteUp: "upvote",
CommentVoteDown: "downvote",
AnswerAccepted: "accepted",
AnswerAccept: "accept",
QuestionVotedUp: "upvoted",
QuestionVotedDown: "downvoted",
AnswerVotedUp: "upvoted",
AnswerVotedDown: "downvoted",
}
)
+35
View File
@@ -349,8 +349,24 @@ func (qs *QuestionService) OperationQuestion(ctx context.Context, req *schema.Op
switch req.Operation {
case schema.QuestionOperationHide:
questionInfo.Show = entity.QuestionHide
err = qs.tagCommon.HideTagRelListByObjectID(ctx, req.ID)
if err != nil {
return err
}
err = qs.tagCommon.RefreshTagCountByQuestionID(ctx, req.ID)
if err != nil {
return err
}
case schema.QuestionOperationShow:
questionInfo.Show = entity.QuestionShow
err = qs.tagCommon.ShowTagRelListByObjectID(ctx, req.ID)
if err != nil {
return err
}
err = qs.tagCommon.RefreshTagCountByQuestionID(ctx, req.ID)
if err != nil {
return err
}
case schema.QuestionOperationPin:
questionInfo.Pin = entity.QuestionPin
case schema.QuestionOperationUnPin:
@@ -436,6 +452,25 @@ func (qs *QuestionService) RemoveQuestion(ctx context.Context, req *schema.Remov
}
}
//tag count
tagIDs := make([]string, 0)
Tags, tagerr := qs.tagCommon.GetObjectEntityTag(ctx, req.ID)
if tagerr != nil {
log.Error("GetObjectEntityTag error", tagerr)
return nil
}
for _, v := range Tags {
tagIDs = append(tagIDs, v.ID)
}
err = qs.tagCommon.RemoveTagRelListByObjectID(ctx, req.ID)
if err != nil {
log.Error("RemoveTagRelListByObjectID error", err.Error())
}
err = qs.tagCommon.RefreshTagQuestionCount(ctx, tagIDs)
if err != nil {
log.Error("efreshTagQuestionCount error", err.Error())
}
err = qs.answerActivityService.DeleteQuestion(ctx, questionInfo.ID, questionInfo.CreatedAt, questionInfo.VoteCount)
if err != nil {
log.Errorf("user DeleteQuestion rank rollback error %s", err.Error())
+32
View File
@@ -44,6 +44,9 @@ type TagRepo interface {
type TagRelRepo interface {
AddTagRelList(ctx context.Context, tagList []*entity.TagRel) (err error)
RemoveTagRelListByObjectID(ctx context.Context, objectID string) (err error)
ShowTagRelListByObjectID(ctx context.Context, objectID string) (err error)
HideTagRelListByObjectID(ctx context.Context, objectID string) (err error)
RemoveTagRelListByIDs(ctx context.Context, ids []int64) (err error)
EnableTagRelByIDs(ctx context.Context, ids []int64) (err error)
GetObjectTagRelWithoutStatus(ctx context.Context, objectId, tagID string) (tagRel *entity.TagRel, exist bool, err error)
@@ -653,6 +656,35 @@ func (ts *TagCommonService) RefreshTagQuestionCount(ctx context.Context, tagIDs
return nil
}
func (ts *TagCommonService) RefreshTagCountByQuestionID(ctx context.Context, questionID string) (err error) {
tagListList, err := ts.tagRelRepo.GetObjectTagRelList(ctx, questionID)
if err != nil {
return err
}
tagIDs := make([]string, 0)
for _, item := range tagListList {
tagIDs = append(tagIDs, item.TagID)
}
err = ts.RefreshTagQuestionCount(ctx, tagIDs)
if err != nil {
return err
}
return nil
}
// RemoveTagRelListByObjectID remove tag relation by object id
func (ts *TagCommonService) RemoveTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
return ts.tagRelRepo.RemoveTagRelListByObjectID(ctx, objectID)
}
func (ts *TagCommonService) HideTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
return ts.tagRelRepo.HideTagRelListByObjectID(ctx, objectID)
}
func (ts *TagCommonService) ShowTagRelListByObjectID(ctx context.Context, objectID string) (err error) {
return ts.tagRelRepo.ShowTagRelListByObjectID(ctx, objectID)
}
// CreateOrUpdateTagRelList if tag relation is exists update status, if not create it
func (ts *TagCommonService) CreateOrUpdateTagRelList(ctx context.Context, objectId string, tagIDs []string) (err error) {
addTagIDMapping := make(map[string]bool)