package services import ( "io" "mime/multipart" "os" "time" "xorm.io/xorm" "github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/datastore" "github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/storage" "github.com/mayswind/ezbookkeeping/pkg/uuid" ) // TransactionPictureService represents transaction picture service type TransactionPictureService struct { ServiceUsingDB ServiceUsingUuid ServiceUsingStorage } // Initialize a transaction picture service singleton instance var ( TransactionPictures = &TransactionPictureService{ ServiceUsingDB: ServiceUsingDB{ container: datastore.Container, }, ServiceUsingUuid: ServiceUsingUuid{ container: uuid.Container, }, ServiceUsingStorage: ServiceUsingStorage{ container: storage.Container, }, } ) // GetTotalTransactionPicturesCountByUid returns total transaction pictures count of user func (s *TransactionPictureService) GetTotalTransactionPicturesCountByUid(c core.Context, uid int64) (int64, error) { if uid <= 0 { return 0, errs.ErrUserIdInvalid } count, err := s.UserDataDB(uid).NewSession(c).Where("uid=? AND deleted=?", uid, false).Count(&models.TransactionPictureInfo{}) return count, err } // GetPictureInfoByPictureId returns a transaction picture info model according to transaction picture id func (s *TransactionPictureService) GetPictureInfoByPictureId(c core.Context, uid int64, pictureId int64) (*models.TransactionPictureInfo, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } if pictureId <= 0 { return nil, errs.ErrTransactionPictureIdInvalid } pictureInfo := &models.TransactionPictureInfo{} has, err := s.UserDataDB(uid).NewSession(c).ID(pictureId).Where("uid=? AND deleted=?", uid, false).Get(pictureInfo) if err != nil { return nil, err } else if !has { return nil, errs.ErrTransactionPictureNotFound } return pictureInfo, nil } // GetNewPictureInfosByPictureIds returns new transaction picture info models according to transaction picture ids func (s *TransactionPictureService) GetNewPictureInfosByPictureIds(c core.Context, uid int64, pictureIds []int64) ([]*models.TransactionPictureInfo, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } if pictureIds == nil { return nil, errs.ErrTransactionPictureIdInvalid } var pictureInfos []*models.TransactionPictureInfo err := s.UserDataDB(uid).NewSession(c).Where("uid=? AND deleted=? AND transaction_id=?", uid, false, models.TransactionPictureNewPictureTransactionId).In("picture_id", pictureIds).OrderBy("picture_id asc").Find(&pictureInfos) if err != nil { return nil, err } return pictureInfos, nil } // GetPictureInfosByTransactionId returns transaction picture info models according to transaction id func (s *TransactionPictureService) GetPictureInfosByTransactionId(c core.Context, uid int64, transactionId int64) ([]*models.TransactionPictureInfo, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } if transactionId <= 0 { return nil, errs.ErrTransactionIdInvalid } var pictureInfos []*models.TransactionPictureInfo err := s.UserDataDB(uid).NewSession(c).Where("uid=? AND deleted=? AND transaction_id=?", uid, false, transactionId).OrderBy("picture_id asc").Find(&pictureInfos) if err != nil { return nil, err } return pictureInfos, nil } // GetPictureInfosByTransactionIds returns transaction picture info models according to transaction ids func (s *TransactionPictureService) GetPictureInfosByTransactionIds(c core.Context, uid int64, transactionIds []int64) (map[int64][]*models.TransactionPictureInfo, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } if transactionIds == nil { return nil, errs.ErrTransactionIdInvalid } var pictureInfos []*models.TransactionPictureInfo err := s.UserDataDB(uid).NewSession(c).Where("uid=? AND deleted=?", uid, false).In("transaction_id", transactionIds).OrderBy("picture_id asc").Find(&pictureInfos) if err != nil { return nil, err } pictureInfoMap := s.GetPictureInfoListMapByList(pictureInfos) return pictureInfoMap, err } // GetPictureByPictureId returns the transaction picture data according to transaction picture id func (s *TransactionPictureService) GetPictureByPictureId(c core.Context, uid int64, pictureId int64, fileExtension string) ([]byte, error) { if uid <= 0 { return nil, errs.ErrUserIdInvalid } if pictureId <= 0 { return nil, errs.ErrTransactionPictureIdInvalid } pictureInfo := &models.TransactionPictureInfo{} has, err := s.UserDataDB(uid).NewSession(c).ID(pictureId).Where("uid=? AND deleted=?", uid, false).Get(pictureInfo) if err != nil { return nil, err } else if !has { return nil, errs.ErrTransactionPictureNotFound } if pictureInfo.PictureExtension == "" { return nil, errs.ErrTransactionPictureNotFound } if pictureInfo.PictureExtension != fileExtension { return nil, errs.ErrTransactionPictureExtensionInvalid } pictureFile, err := s.ReadTransactionPicture(pictureInfo.Uid, pictureInfo.PictureId, pictureInfo.PictureExtension) if os.IsNotExist(err) { return nil, errs.ErrTransactionPictureNoExists } if err != nil { return nil, err } defer pictureFile.Close() pictureData, err := io.ReadAll(pictureFile) if err != nil { return nil, err } return pictureData, nil } // UploadPicture uploads the transaction picture for specified user func (s *TransactionPictureService) UploadPicture(c core.Context, pictureInfo *models.TransactionPictureInfo, pictureFile multipart.File) error { if pictureInfo.Uid <= 0 { return errs.ErrUserIdInvalid } defer pictureFile.Close() pictureInfo.PictureId = s.GenerateUuid(uuid.UUID_TYPE_USER) if pictureInfo.PictureId < 1 { return errs.ErrSystemIsBusy } pictureInfo.TransactionId = 0 pictureInfo.Deleted = false pictureInfo.CreatedUnixTime = time.Now().Unix() pictureInfo.UpdatedUnixTime = time.Now().Unix() err := s.SaveTransactionPicture(pictureInfo.Uid, pictureInfo.PictureId, pictureFile, pictureInfo.PictureExtension) if err != nil { return err } return s.UserDataDB(pictureInfo.Uid).DoTransaction(c, func(sess *xorm.Session) error { _, err := sess.Insert(pictureInfo) return err }) } // RemoveUnusedTransactionPicture removes the unused transaction picture of specified user func (s *TransactionPictureService) RemoveUnusedTransactionPicture(c core.Context, uid int64, pictureId int64) error { if uid <= 0 { return errs.ErrUserIdInvalid } if pictureId <= 0 { return errs.ErrTransactionPictureIdInvalid } now := time.Now().Unix() updateModel := &models.TransactionPictureInfo{ Deleted: true, DeletedUnixTime: now, } return s.UserDB().DoTransaction(c, func(sess *xorm.Session) error { deletedRows, err := sess.ID(pictureId).Cols("deleted", "deleted_unix_time").Where("uid=? AND deleted=? AND transaction_id=?", uid, false, models.TransactionPictureNewPictureTransactionId).Update(updateModel) if err != nil { return err } else if deletedRows < 1 { return errs.ErrTransactionPictureNotFound } return err }) } // GetPictureInfoMapByList returns a transaction picture info list map by a list func (s *TransactionPictureService) GetPictureInfoMapByList(pictureInfos []*models.TransactionPictureInfo) map[int64]*models.TransactionPictureInfo { pictureInfoMap := make(map[int64]*models.TransactionPictureInfo) for i := 0; i < len(pictureInfos); i++ { pictureInfo := pictureInfos[i] pictureInfoMap[pictureInfo.PictureId] = pictureInfo } return pictureInfoMap } // GetPictureInfoListMapByList returns a transaction picture info list map by a list func (s *TransactionPictureService) GetPictureInfoListMapByList(pictureInfos []*models.TransactionPictureInfo) map[int64][]*models.TransactionPictureInfo { pictureInfoMap := make(map[int64][]*models.TransactionPictureInfo) for i := 0; i < len(pictureInfos); i++ { pictureInfo := pictureInfos[i] pictureInfos, _ := pictureInfoMap[pictureInfo.TransactionId] pictureInfoMap[pictureInfo.TransactionId] = append(pictureInfos, pictureInfo) } return pictureInfoMap } // GetTransactionPictureIds returns transaction picture ids list func (s *TransactionPictureService) GetTransactionPictureIds(pictureInfos []*models.TransactionPictureInfo) []int64 { pictureIds := make([]int64, len(pictureInfos)) for i := 0; i < len(pictureInfos); i++ { pictureIds[i] = pictureInfos[i].PictureId } return pictureIds }