add transaction when add or update reactions and fix other issues
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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:"-"`
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user