package api import ( "github.com/mayswind/ezbookkeeping/pkg/core" "github.com/mayswind/ezbookkeeping/pkg/duplicatechecker" "github.com/mayswind/ezbookkeeping/pkg/errs" "github.com/mayswind/ezbookkeeping/pkg/log" "github.com/mayswind/ezbookkeeping/pkg/models" "github.com/mayswind/ezbookkeeping/pkg/services" "github.com/mayswind/ezbookkeeping/pkg/settings" "github.com/mayswind/ezbookkeeping/pkg/utils" ) // TransactionPicturesApi represents transaction pictures api type TransactionPicturesApi struct { ApiUsingConfig ApiUsingDuplicateChecker users *services.UserService pictures *services.TransactionPictureService } // Initialize a transaction api singleton instance var ( TransactionPictures = &TransactionPicturesApi{ ApiUsingConfig: ApiUsingConfig{ container: settings.Container, }, ApiUsingDuplicateChecker: ApiUsingDuplicateChecker{ container: duplicatechecker.Container, }, users: services.Users, pictures: services.TransactionPictures, } ) // TransactionPictureUploadHandler saves transaction picture by request parameters for current user func (a *TransactionPicturesApi) TransactionPictureUploadHandler(c *core.WebContext) (any, *errs.Error) { uid := c.GetCurrentUid() form, err := c.MultipartForm() if err != nil { log.Errorf(c, "[transaction_pictures.TransactionPictureUploadHandler] failed to get multi-part form data for user \"uid:%d\", because %s", uid, err.Error()) return nil, errs.ErrParameterInvalid } pictureFiles := form.File["picture"] if len(pictureFiles) < 1 { log.Warnf(c, "[transaction_pictures.TransactionPictureUploadHandler] there is no transaction picture in request for user \"uid:%d\"", uid) return nil, errs.ErrNoTransactionPicture } if pictureFiles[0].Size < 1 { log.Warnf(c, "[transaction_pictures.TransactionPictureUploadHandler] the size of transaction picture in request is zero for user \"uid:%d\"", uid) return nil, errs.ErrTransactionPictureIsEmpty } fileExtension := utils.GetFileNameExtension(pictureFiles[0].Filename) if utils.GetImageContentType(fileExtension) == "" { log.Warnf(c, "[transaction_pictures.TransactionPictureUploadHandler] the file extension \"%s\" of transaction picture in request is not supported for user \"uid:%d\"", fileExtension, uid) return nil, errs.ErrImageTypeNotSupported } pictureFile, err := pictureFiles[0].Open() if err != nil { log.Errorf(c, "[transaction_pictures.TransactionPictureUploadHandler] failed to get transaction picture file from request for user \"uid:%d\", because %s", uid, err.Error()) return nil, errs.ErrOperationFailed } pictureInfo := a.createNewPictureInfoModel(uid, fileExtension, c.ClientIP()) clientSessionIds := form.Value["clientSessionId"] clientSessionId := "" if len(clientSessionIds) > 0 { clientSessionId = clientSessionIds[0] } if a.CurrentConfig().EnableDuplicateSubmissionsCheck && clientSessionId != "" { found, remark := a.GetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_PICTURE, uid, clientSessionId) if found { log.Infof(c, "[transaction_pictures.TransactionPictureUploadHandler] another transaction picture \"id:%s\" has been uploaded for user \"uid:%d\"", remark, uid) pictureId, err := utils.StringToInt64(remark) if err == nil { pictureInfo, err = a.pictures.GetPictureInfoByPictureId(c, uid, pictureId) if err != nil { log.Errorf(c, "[transaction_pictures.TransactionPictureUploadHandler] failed to get existed transaction picture \"id:%d\" for user \"uid:%d\", because %s", pictureId, uid, err.Error()) return nil, errs.Or(err, errs.ErrOperationFailed) } pictureInfoResp := a.GetTransactionPictureInfoResponse(pictureInfo) return pictureInfoResp, nil } } } err = a.pictures.UploadPicture(c, pictureInfo, pictureFile) if err != nil { log.Errorf(c, "[transaction_pictures.TransactionPictureUploadHandler] failed to update transaction picture for user \"uid:%d\", because %s", uid, err.Error()) return nil, errs.Or(err, errs.ErrOperationFailed) } a.SetSubmissionRemark(duplicatechecker.DUPLICATE_CHECKER_TYPE_NEW_PICTURE, uid, clientSessionId, utils.Int64ToString(pictureInfo.PictureId)) pictureInfoResp := a.GetTransactionPictureInfoResponse(pictureInfo) return pictureInfoResp, nil } // TransactionPictureGetHandler returns transaction picture data for current user func (a *TransactionPicturesApi) TransactionPictureGetHandler(c *core.WebContext) ([]byte, string, *errs.Error) { fileName := c.Param("fileName") fileExtension := utils.GetFileNameExtension(fileName) contentType := utils.GetImageContentType(fileExtension) if contentType == "" { return nil, "", errs.ErrImageTypeNotSupported } fileBaseName := utils.GetFileNameWithoutExtension(fileName) pictureId, err := utils.StringToInt64(fileBaseName) if err != nil { return nil, "", errs.ErrTransactionPictureIdInvalid } uid := c.GetCurrentUid() pictureData, err := a.pictures.GetPictureByPictureId(c, uid, pictureId, fileExtension) if err != nil { if !errs.IsCustomError(err) { log.Errorf(c, "[transaction_pictures.TransactionPictureUploadHandler] failed to get transaction picture, because %s", err.Error()) } return nil, "", errs.Or(err, errs.ErrOperationFailed) } return pictureData, contentType, nil } // TransactionPictureRemoveUnusedHandler removes unused transaction picture by request parameters for current user func (a *TransactionPicturesApi) TransactionPictureRemoveUnusedHandler(c *core.WebContext) (any, *errs.Error) { var pictureDeleteReq models.TransactionPictureUnusedDeleteRequest err := c.ShouldBindJSON(&pictureDeleteReq) if err != nil { log.Warnf(c, "[transaction_pictures.TransactionPictureRemoveUnusedHandler] parse request failed, because %s", err.Error()) return nil, errs.NewIncompleteOrIncorrectSubmissionError(err) } uid := c.GetCurrentUid() err = a.pictures.RemoveUnusedTransactionPicture(c, uid, pictureDeleteReq.Id) if err != nil { log.Errorf(c, "[transaction_pictures.TransactionPictureRemoveUnusedHandler] failed to remove unused transaction picture for user \"uid:%d\", because %s", uid, err.Error()) return nil, errs.Or(err, errs.ErrOperationFailed) } return true, nil } func (a *TransactionPicturesApi) createNewPictureInfoModel(uid int64, fileExtension string, clientIp string) *models.TransactionPictureInfo { return &models.TransactionPictureInfo{ Uid: uid, TransactionId: models.TransactionPictureNewPictureTransactionId, PictureExtension: fileExtension, CreatedIp: clientIp, } }