mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-17 08:14:25 +08:00
add transaction tag
This commit is contained in:
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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{})
|
||||
}
|
||||
Reference in New Issue
Block a user