add transaction when add or update reactions and fix other issues

This commit is contained in:
hgaol
2024-05-08 00:24:51 +08:00
committed by LinkinStars
parent 255f985cd4
commit 7d2fd40097
4 changed files with 104 additions and 82 deletions
+3 -3
View File
@@ -67,9 +67,9 @@ func (mc *MetaController) AddOrUpdateReaction(ctx *gin.Context) {
// @Accept json
// @Produce json
// @Security ApiKeyAuth
// @Param data body schema.UpdateReactionReq true "reaction"
// @Success 200 {object} handler.RespBody
// @Router /answer/api/v1/meta/reaction [put]
// @Param object_id query string true "object_id"
// @Success 200 {object} handler.RespBody{data=schema.ReactionResp}
// @Router /answer/api/v1/meta/reaction [get]
func (mc *MetaController) GetReaction(ctx *gin.Context) {
req := &schema.GetReactionReq{}
if handler.BindAndCheck(ctx, req) {
+98
View File
@@ -21,13 +21,16 @@ package meta
import (
"context"
"encoding/json"
"github.com/apache/incubator-answer/internal/base/data"
"github.com/apache/incubator-answer/internal/base/reason"
"github.com/apache/incubator-answer/internal/entity"
"github.com/apache/incubator-answer/internal/schema"
"github.com/apache/incubator-answer/internal/service/meta"
"github.com/segmentfault/pacman/errors"
"xorm.io/builder"
"xorm.io/xorm"
)
// metaRepo meta repository
@@ -69,6 +72,101 @@ func (mr *metaRepo) UpdateMeta(ctx context.Context, meta *entity.Meta) (err erro
return
}
// AddOrUpdateMetaByObjectIdAndKey if exist record with same objectID and key, update it. Or create a new one
func (mr *metaRepo) AddOrUpdateMetaByObjectIdAndKey(ctx context.Context, req *schema.UpdateReactionReq) (schema.ReactSummaryMeta, error) {
result, err := mr.data.DB.Transaction(func(session *xorm.Session) (interface{}, error) {
session = session.Context(ctx)
// 1. acquire meta entity with target object id and key
metaEntity := &entity.Meta{}
exist, err := mr.data.DB.Context(ctx).Where(builder.Eq{"object_id": req.ObjectID}.And(builder.Eq{"`key`": entity.ObjectReactSummaryKey})).ForUpdate().Get(metaEntity)
if err != nil {
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
var reaction schema.ReactSummaryMeta
// if not exist, create new one
if !exist {
reaction = schema.ReactSummaryMeta{}
return nil, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
} else {
err = json.Unmarshal([]byte(metaEntity.Value), &reaction)
if err != nil {
return nil, err
}
}
// update reaction
mr.updateReaction(req, reaction)
// write back to meta repo
reactSumBytes, err := json.Marshal(reaction)
if err != nil {
return nil, err
}
metaObj := &entity.Meta{
ObjectID: req.ObjectID,
Key: entity.ObjectReactSummaryKey,
Value: string(reactSumBytes),
}
if exist {
_, err = session.Update(metaObj)
} else {
_, err = session.Insert(metaObj)
}
return reaction, err
})
if err != nil {
return nil, errors.InternalServer(reason.DatabaseError).WithError(err)
}
if ret, ok := result.(schema.ReactSummaryMeta); ok {
return ret, nil
} else {
return nil, errors.InternalServer(reason.UnknownError).WithMsg("Unable to cast to schema.ReactSummaryMeta.")
}
}
// updateReaction update reaction
func (mr *metaRepo) updateReaction(req *schema.UpdateReactionReq, reaction schema.ReactSummaryMeta) {
emojiUserIds, ok := reaction[req.Emoji]
if !ok {
emojiUserIds = make([]string, 0)
}
found := false
for _, item := range emojiUserIds {
if item == req.UserID {
found = true
break
}
}
removeItem := func(arr []string, target string) []string {
result := make([]string, 0, len(arr))
for _, item := range arr {
if item != target {
result = append(result, item)
}
}
return result
}
if req.Reaction == "activate" && !found {
emojiUserIds = append(emojiUserIds, req.UserID)
} else if req.Reaction == "deactivate" && found {
emojiUserIds = removeItem(emojiUserIds, req.UserID)
}
reaction[req.Emoji] = emojiUserIds
}
// GetMetaByObjectIdAndKey get meta one
func (mr *metaRepo) GetMetaByObjectIdAndKey(ctx context.Context, objectID, key string) (
meta *entity.Meta, exist bool, err error) {
+1 -1
View File
@@ -22,7 +22,7 @@ package schema
type UpdateReactionReq struct {
ObjectID string `validate:"required" form:"object_id" json:"object_id"` // object id
Emoji string `validate:"required" form:"emoji" json:"emoji"` // emoji
Type string `validate:"required" form:"type" json:"type"` // type
Reaction string `validate:"required" form:"reaction" json:"reaction"` // reaction
UserID string `json:"-"`
}
+2 -78
View File
@@ -36,6 +36,7 @@ type MetaRepo interface {
AddMeta(ctx context.Context, meta *entity.Meta) (err error)
RemoveMeta(ctx context.Context, id int) (err error)
UpdateMeta(ctx context.Context, meta *entity.Meta) (err error)
AddOrUpdateMetaByObjectIdAndKey(ctx context.Context, req *schema.UpdateReactionReq) (schema.ReactSummaryMeta, error)
GetMetaByObjectIdAndKey(ctx context.Context, objectId, key string) (meta *entity.Meta, exist bool, err error)
GetMetaList(ctx context.Context, meta *entity.Meta) (metas []*entity.Meta, err error)
}
@@ -123,41 +124,7 @@ func (ms *MetaService) GetReactionByObjectId(ctx context.Context, objectID strin
// AddOrUpdateReaction add or update reaction
func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.UpdateReactionReq) (resp schema.ReactionResp, err error) {
// get reaction for this object
reactionMeta, err := ms.GetMetaByObjectIdAndKey(ctx, req.ObjectID, entity.ObjectReactSummaryKey)
var reaction schema.ReactSummaryMeta
if err != nil {
var pacmanErr *myErrors.Error
if errors.As(err, &pacmanErr) && pacmanErr.Reason == reason.MetaObjectNotFound {
// create new reaction summary
reaction = schema.ReactSummaryMeta{}
} else {
return nil, err
}
} else {
// json unmarshal reactionMeta.Value to reaction
err = json.Unmarshal([]byte(reactionMeta.Value), &reaction)
if err != nil {
return nil, err
}
}
// update reaction
ms.updateReaction(req, reaction)
// write back to meta repo
reactSumBytes, err := json.Marshal(reaction)
if err != nil {
return nil, err
}
if reactionMeta == nil {
err = ms.AddMeta(ctx, req.ObjectID, entity.ObjectReactSummaryKey, string(reactSumBytes))
} else {
err = ms.UpdateMeta(ctx, reactionMeta.ID, entity.ObjectReactSummaryKey, string(reactSumBytes))
}
reaction, err := ms.metaRepo.AddOrUpdateMetaByObjectIdAndKey(ctx, req)
if err != nil {
return nil, err
}
@@ -170,49 +137,6 @@ func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req *schema.Upda
return resp, nil
}
// updateReaction update reaction
func (ms *MetaService) updateReaction(req *schema.UpdateReactionReq, reaction schema.ReactSummaryMeta) {
emojiUserIds, ok := reaction[req.Emoji]
if !ok {
emojiUserIds = make([]string, 0)
}
found := false
for _, item := range emojiUserIds {
if item == req.UserID {
found = true
break
}
}
removeItem := func(arr []string, target string) []string {
result := make([]string, 0, len(arr))
for _, item := range arr {
if item != target {
result = append(result, item)
}
}
return result
}
if req.Type == "activate" && !found {
emojiUserIds = append(emojiUserIds, req.UserID)
} else if req.Type == "deactivate" && found {
emojiUserIds = removeItem(emojiUserIds, req.UserID)
} else if req.Type == "toggle" {
if found {
emojiUserIds = removeItem(emojiUserIds, req.UserID)
} else {
emojiUserIds = append(emojiUserIds, req.UserID)
}
}
reaction[req.Emoji] = emojiUserIds
}
func (ms *MetaService) convertToReactionResp(ctx context.Context, reaction schema.ReactSummaryMeta) (schema.ReactionResp, error) {
resp := schema.ReactionResp{}
// traverse map and convert to username