add transaction tag

This commit is contained in:
MaysWind
2020-12-05 23:56:04 +08:00
parent e5e159dfec
commit 15d6a93a71
13 changed files with 1101 additions and 0 deletions
+219
View File
@@ -0,0 +1,219 @@
package api
import (
"github.com/mayswind/lab/pkg/core"
"github.com/mayswind/lab/pkg/errs"
"github.com/mayswind/lab/pkg/log"
"github.com/mayswind/lab/pkg/models"
"github.com/mayswind/lab/pkg/services"
)
type TransactionTagsApi struct {
tags *services.TransactionTagService
}
var (
TransactionTags = &TransactionTagsApi{
tags: services.TransactionTags,
}
)
func (a *TransactionTagsApi) TagListHandler(c *core.Context) (interface{}, *errs.Error) {
uid := c.GetCurrentUid()
tags, err := a.tags.GetAllTagsByUid(uid)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.TagListHandler] failed to get tags for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.ErrOperationFailed
}
tagResps := make([]*models.TransactionTagInfoResponse, len(tags))
for i := 0; i < len(tags); i++ {
tagResps[i] = tags[i].ToTransactionTagInfoResponse()
}
return tagResps, nil
}
func (a *TransactionTagsApi) TagGetHandler(c *core.Context) (interface{}, *errs.Error) {
var tagGetReq models.TransactionTagGetRequest
err := c.ShouldBindQuery(&tagGetReq)
if err != nil {
log.WarnfWithRequestId(c, "[transaction_tags.TagGetHandler] parse request failed, because %s", err.Error())
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
}
uid := c.GetCurrentUid()
tag, err := a.tags.GetTagByTagId(uid, tagGetReq.Id)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.TagGetHandler] failed to get tag \"id:%d\" for user \"uid:%d\", because %s", tagGetReq.Id, uid, err.Error())
return nil, errs.ErrOperationFailed
}
tagResp := tag.ToTransactionTagInfoResponse()
return tagResp, nil
}
func (a *TransactionTagsApi) TagCreateHandler(c *core.Context) (interface{}, *errs.Error) {
var tagCreateReq models.TransactionTagCreateRequest
err := c.ShouldBindJSON(&tagCreateReq)
if err != nil {
log.WarnfWithRequestId(c, "[transaction_tags.TagCreateHandler] parse request failed, because %s", err.Error())
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
}
uid := c.GetCurrentUid()
maxOrderId, err := a.tags.GetMaxDisplayOrder(uid)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.TagCreateHandler] failed to get max display order for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.ErrOperationFailed
}
tag := a.createNewTagModel(uid, &tagCreateReq, maxOrderId+1)
err = a.tags.CreateTag(tag)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.TagCreateHandler] failed to create tag \"id:%d\" for user \"uid:%d\", because %s", tag.TagId, uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed)
}
log.InfofWithRequestId(c, "[transaction_tags.TagCreateHandler] user \"uid:%d\" has created a new tag \"id:%d\" successfully", uid, tag.TagId)
tagResp := tag.ToTransactionTagInfoResponse()
return tagResp, nil
}
func (a *TransactionTagsApi) TagModifyHandler(c *core.Context) (interface{}, *errs.Error) {
var tagModifyReq models.TransactionTagModifyRequest
err := c.ShouldBindJSON(&tagModifyReq)
if err != nil {
log.WarnfWithRequestId(c, "[transaction_tags.TagModifyHandler] parse request failed, because %s", err.Error())
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
}
uid := c.GetCurrentUid()
tag, err := a.tags.GetTagByTagId(uid, tagModifyReq.Id)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.TagModifyHandler] failed to get tag \"id:%d\" for user \"uid:%d\", because %s", tagModifyReq.Id, uid, err.Error())
return nil, errs.ErrOperationFailed
}
newTag := &models.TransactionTag{
TagId: tag.TagId,
Uid: uid,
Name: tagModifyReq.Name,
}
if newTag.Name == tag.Name {
return nil, errs.ErrNothingWillBeUpdated
}
err = a.tags.ModifyTag(newTag)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.TagModifyHandler] failed to update tag \"id:%d\" for user \"uid:%d\", because %s", tagModifyReq.Id, uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed)
}
log.InfofWithRequestId(c, "[transaction_tags.TagModifyHandler] user \"uid:%d\" has updated tag \"id:%d\" successfully", uid, tagModifyReq.Id)
tag.Name = newTag.Name
tagResp := tag.ToTransactionTagInfoResponse()
return tagResp, nil
}
func (a *TransactionTagsApi) TagHideHandler(c *core.Context) (interface{}, *errs.Error) {
var tagHideReq models.TransactionTagHideRequest
err := c.ShouldBindJSON(&tagHideReq)
if err != nil {
log.WarnfWithRequestId(c, "[transaction_tags.CategoryHideHandler] parse request failed, because %s", err.Error())
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
}
uid := c.GetCurrentUid()
err = a.tags.HideTag(uid, []int64{tagHideReq.Id}, tagHideReq.Hidden)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.CategoryHideHandler] failed to hide tag \"id:%d\" for user \"uid:%d\", because %s", tagHideReq.Id, uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed)
}
log.InfofWithRequestId(c, "[transaction_tags.CategoryHideHandler] user \"uid:%d\" has hidden category \"id:%d\"", uid, tagHideReq.Id)
return true, nil
}
func (a *TransactionTagsApi) TagMoveHandler(c *core.Context) (interface{}, *errs.Error) {
var tagMoveReq models.TransactionTagMoveRequest
err := c.ShouldBindJSON(&tagMoveReq)
if err != nil {
log.WarnfWithRequestId(c, "[transaction_tags.CategoryMoveHandler] parse request failed, because %s", err.Error())
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
}
uid := c.GetCurrentUid()
tags := make([]*models.TransactionTag, len(tagMoveReq.NewDisplayOrders))
for i := 0; i < len(tagMoveReq.NewDisplayOrders); i++ {
newDisplayOrder := tagMoveReq.NewDisplayOrders[i]
tag := &models.TransactionTag{
Uid: uid,
TagId: newDisplayOrder.Id,
DisplayOrder: newDisplayOrder.DisplayOrder,
}
tags[i] = tag
}
err = a.tags.ModifyTagDisplayOrders(uid, tags)
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.CategoryMoveHandler] failed to move tags for user \"uid:%d\", because %s", uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed)
}
log.InfofWithRequestId(c, "[transaction_tags.CategoryMoveHandler] user \"uid:%d\" has moved categories", uid)
return true, nil
}
func (a *TransactionTagsApi) TagDeleteHandler(c *core.Context) (interface{}, *errs.Error) {
var tagDeleteReq models.TransactionTagDeleteRequest
err := c.ShouldBindJSON(&tagDeleteReq)
if err != nil {
log.WarnfWithRequestId(c, "[transaction_tags.TagDeleteHandler] parse request failed, because %s", err.Error())
return nil, errs.NewIncompleteOrIncorrectSubmissionError(err)
}
uid := c.GetCurrentUid()
err = a.tags.DeleteTags(uid, []int64{tagDeleteReq.Id})
if err != nil {
log.ErrorfWithRequestId(c, "[transaction_tags.TagDeleteHandler] failed to delete tag \"id:%d\" for user \"uid:%d\", because %s", tagDeleteReq.Id, uid, err.Error())
return nil, errs.Or(err, errs.ErrOperationFailed)
}
log.InfofWithRequestId(c, "[transaction_tags.TagDeleteHandler] user \"uid:%d\" has deleted tag \"id:%d\"", uid, tagDeleteReq.Id)
return true, nil
}
func (a *TransactionTagsApi) createNewTagModel(uid int64, tagCreateReq *models.TransactionTagCreateRequest, order int) *models.TransactionTag {
return &models.TransactionTag{
Uid: uid,
Name: tagCreateReq.Name,
DisplayOrder: order,
}
}
+10
View File
@@ -0,0 +1,10 @@
package errs
import "net/http"
var (
ErrTransactionTagIdInvalid = NewNormalError(NORMAL_SUBCATEGORY_TAG, 0, http.StatusBadRequest, "transaction tag id is invalid")
ErrTransactionTagNotFound = NewNormalError(NORMAL_SUBCATEGORY_TAG, 1, http.StatusBadRequest, "transaction tag not found")
ErrTransactionTagNameIsEmpty = NewNormalError(NORMAL_SUBCATEGORY_TAG, 2, http.StatusBadRequest, "transaction tag name is empty")
ErrTransactionTagNameAlreadyExists = NewNormalError(NORMAL_SUBCATEGORY_TAG, 3, http.StatusBadRequest, "transaction tag name already exists")
)
+72
View File
@@ -0,0 +1,72 @@
package models
type TransactionTag struct {
TagId int64 `xorm:"PK"`
Uid int64 `xorm:"UNIQUE(IDX_tag_uid_name) NOT NULL"`
Name string `xorm:"UNIQUE(IDX_tag_uid_name) VARCHAR(32) NOT NULL"`
DisplayOrder int `xorm:"NOT NULL"`
Hidden bool `xorm:"NOT NULL"`
CreatedUnixTime int64
UpdatedUnixTime int64
}
type TransactionTagCreateRequest struct {
Name string `json:"name" binding:"required,notBlank,max=32"`
}
type TransactionTagGetRequest struct {
Id int64 `form:"id,string" binding:"required,min=1"`
}
type TransactionTagModifyRequest struct {
Id int64 `json:"id,string" binding:"required,min=1"`
Name string `json:"name" binding:"required,notBlank,max=32"`
}
type TransactionTagHideRequest struct {
Id int64 `json:"id,string" binding:"required,min=1"`
Hidden bool `json:"hidden"`
}
type TransactionTagMoveRequest struct {
NewDisplayOrders []*TransactionTagNewDisplayOrderRequest `json:"newDisplayOrders"`
}
type TransactionTagNewDisplayOrderRequest struct {
Id int64 `json:"id,string" binding:"required,min=1"`
DisplayOrder int `json:"displayOrder"`
}
type TransactionTagDeleteRequest struct {
Id int64 `json:"id,string" binding:"required,min=1"`
}
type TransactionTagInfoResponse struct {
Id int64 `json:"id,string"`
Name string `json:"name"`
DisplayOrder int `json:"displayOrder"`
Hidden bool `json:"hidden"`
}
func (c *TransactionTag) ToTransactionTagInfoResponse() *TransactionTagInfoResponse {
return &TransactionTagInfoResponse{
Id: c.TagId,
Name: c.Name,
DisplayOrder: c.DisplayOrder,
Hidden: c.Hidden,
}
}
type TransactionTagInfoResponseSlice []*TransactionTagInfoResponse
func (c TransactionTagInfoResponseSlice) Len() int {
return len(c)
}
func (c TransactionTagInfoResponseSlice) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
func (c TransactionTagInfoResponseSlice) Less(i, j int) bool {
return c[i].DisplayOrder < c[j].DisplayOrder
}
+207
View File
@@ -0,0 +1,207 @@
package services
import (
"github.com/mayswind/lab/pkg/datastore"
"github.com/mayswind/lab/pkg/errs"
"github.com/mayswind/lab/pkg/models"
"github.com/mayswind/lab/pkg/uuid"
"time"
"xorm.io/xorm"
)
type TransactionTagService struct {
ServiceUsingDB
ServiceUsingUuid
}
var (
TransactionTags = &TransactionTagService{
ServiceUsingDB: ServiceUsingDB{
container: datastore.Container,
},
ServiceUsingUuid: ServiceUsingUuid{
container: uuid.Container,
},
}
)
func (s *TransactionTagService) GetAllTagsByUid(uid int64) ([]*models.TransactionTag, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
var tags []*models.TransactionTag
err := s.UserDataDB(uid).Where("uid=?", uid).OrderBy("display_order asc").Find(&tags)
return tags, err
}
func (s *TransactionTagService) GetTagByTagId(uid int64, tagId int64) (*models.TransactionTag, error) {
if uid <= 0 {
return nil, errs.ErrUserIdInvalid
}
if tagId <= 0 {
return nil, errs.ErrTransactionTagIdInvalid
}
tag := &models.TransactionTag{}
has, err := s.UserDataDB(uid).Where("uid=? AND tag_id=?", uid, tagId).Get(tag)
if err != nil {
return nil, err
} else if !has {
return nil, errs.ErrTransactionTagNotFound
}
return tag, nil
}
func (s *TransactionTagService) GetMaxDisplayOrder(uid int64) (int, error) {
if uid <= 0 {
return 0, errs.ErrUserIdInvalid
}
tag := &models.TransactionTag{}
has, err := s.UserDataDB(uid).Cols("uid", "display_order").Where("uid=?", uid).OrderBy("display_order desc").Limit(1).Get(tag)
if err != nil {
return 0, err
}
if has {
return tag.DisplayOrder, nil
} else {
return 0, nil
}
}
func (s *TransactionTagService) CreateTag(tag *models.TransactionTag) error {
if tag.Uid <= 0 {
return errs.ErrUserIdInvalid
}
exists, err := s.ExistsTagName(tag.Uid, tag.Name)
if err != nil {
return err
} else if exists {
return errs.ErrTransactionTagNameAlreadyExists
}
tag.TagId = s.GenerateUuid(uuid.UUID_TYPE_TAG)
tag.CreatedUnixTime = time.Now().Unix()
tag.UpdatedUnixTime = time.Now().Unix()
return s.UserDataDB(tag.Uid).DoTransaction(func(sess *xorm.Session) error {
_, err := sess.Insert(tag)
return err
})
}
func (s *TransactionTagService) ModifyTag(tag *models.TransactionTag) error {
if tag.Uid <= 0 {
return errs.ErrUserIdInvalid
}
exists, err := s.ExistsTagName(tag.Uid, tag.Name)
if err != nil {
return err
} else if exists {
return errs.ErrTransactionTagNameAlreadyExists
}
tag.UpdatedUnixTime = time.Now().Unix()
return s.UserDataDB(tag.Uid).DoTransaction(func(sess *xorm.Session) error {
updatedRows, err := sess.Cols("name", "updated_unix_time").Where("tag_id=? AND uid=?", tag.TagId, tag.Uid).Update(tag)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrTransactionTagNotFound
}
return err
})
}
func (s *TransactionTagService) HideTag(uid int64, ids []int64, hidden bool) error {
if uid <= 0 {
return errs.ErrUserIdInvalid
}
now := time.Now().Unix()
updateModel := &models.TransactionTag{
Hidden: hidden,
UpdatedUnixTime: now,
}
return s.UserDataDB(uid).DoTransaction(func(sess *xorm.Session) error {
updatedRows, err := sess.Cols("hidden", "updated_unix_time").In("tag_id", ids).Where("uid=?", uid).Update(updateModel)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrTransactionTagNotFound
}
return err
})
}
func (s *TransactionTagService) ModifyTagDisplayOrders(uid int64, tags []*models.TransactionTag) error {
if uid <= 0 {
return errs.ErrUserIdInvalid
}
for i := 0; i < len(tags); i++ {
tags[i].UpdatedUnixTime = time.Now().Unix()
}
return s.UserDataDB(uid).DoTransaction(func(sess *xorm.Session) error {
for i := 0; i < len(tags); i++ {
tag := tags[i]
updatedRows, err := sess.Cols("display_order", "updated_unix_time").Where("tag_id=? AND uid=?", tag.TagId, uid).Update(tag)
if err != nil {
return err
} else if updatedRows < 1 {
return errs.ErrTransactionTagNotFound
}
}
return nil
})
}
func (s *TransactionTagService) DeleteTags(uid int64, ids []int64) error {
if uid <= 0 {
return errs.ErrUserIdInvalid
}
tag := &models.TransactionTag{}
return s.UserDataDB(uid).DoTransaction(func(sess *xorm.Session) error {
deletedRows, err := sess.In("tag_id", ids).Where("uid=?", uid).Delete(tag)
if err != nil {
return err
} else if deletedRows < 1 {
return errs.ErrTransactionTagNotFound
}
return err
})
}
func (s *TransactionTagService) ExistsTagName(uid int64, name string) (bool, error) {
if name == "" {
return false, errs.ErrTransactionTagNameIsEmpty
}
return s.UserDB().Cols("name").Where("uid=? AND name=?", uid, name).Exist(&models.TransactionTag{})
}