package medias import ( "context" "database/sql" "path/filepath" "time" "backend/common/media_store" "backend/database/models/qvyun/public/table" "backend/pkg/path" "backend/pkg/pg" "backend/providers/storage" . "github.com/go-jet/jet/v2/postgres" "github.com/pkg/errors" "github.com/samber/lo" "github.com/sirupsen/logrus" ) // @provider:except type Service struct { db *sql.DB storageConfig *storage.Config log *logrus.Entry `inject:"false"` } func (svc *Service) Prepare() error { svc.log = logrus.WithField("module", "medias.service") return nil } // GetByID func (svc *Service) GetByID(ctx context.Context, tenantId, userId, id int64) (*ListItem, error) { log := svc.log.WithField("method", "GetByID") tbl := table.Medias stmt := tbl.SELECT(tbl.AllColumns).WHERE( tbl.ID.EQ(Int(id)).AND( tbl.TenantID.EQ(Int(tenantId)), ), ) log.Debug(stmt.Sql()) var media ListItem if err := stmt.QueryContext(ctx, svc.db, &media); err != nil { return nil, errors.Wrap(err, "query media by id") } // todo: resources var err error media.Bought, err = svc.HasUserBought(ctx, tenantId, userId, media.ID) if err != nil { return nil, errors.Wrap(err, "check user bought") } return &media, nil } // List func (svc *Service) List(ctx context.Context, tenantId, userId int64, filter *ListFilter) ([]ListItem, error) { log := svc.log.WithField("method", "List") boughtIDs, err := svc.GetUserBoughtMedias(ctx, tenantId, userId) if err != nil { return nil, errors.Wrap(err, "get user bought medias") } tbl := table.Medias stmt := tbl. SELECT(tbl.AllColumns). WHERE(tbl.TenantID.EQ(Int(tenantId))). ORDER_BY(tbl.ID.DESC()) if filter.Title != nil && *filter.Title != "" { stmt = stmt.WHERE(tbl.Title.LIKE(String("%" + *filter.Title + "%"))) } if filter.Bought != nil && *filter.Bought { if len(boughtIDs) > 0 { stmt = stmt. WHERE(tbl.ID.IN(lo.Map(boughtIDs, func(item int64, _ int) Expression { return Int(item) })...)) } } else { stmt = stmt.WHERE(tbl.Publish.EQ(Bool(true))) } if filter.OffsetID > 0 { if filter.Action == 0 { stmt = stmt.WHERE(tbl.ID.GT(Int(filter.OffsetID))) } if filter.Action == 1 { stmt = stmt.WHERE(tbl.ID.LT(Int(filter.OffsetID))) stmt = stmt.LIMIT(10) } } else { stmt = stmt.LIMIT(10) } log.Debug(stmt.DebugSql()) var dest []ListItem if err := stmt.QueryContext(ctx, svc.db, &dest); err != nil { return nil, errors.Wrap(err, "query medias") } items := lo.Map(dest, func(item ListItem, _ int) ListItem { if lo.Contains(boughtIDs, item.ID) { item.Bought = true } return item }) return items, nil } // GetUserBoughtMedias func (svc *Service) GetUserBoughtMedias(ctx context.Context, tenant int64, userID int64) ([]int64, error) { log := svc.log.WithField("method", "GetUserBoughtMedias") tbl := table.UserMedias stmt := tbl. SELECT(tbl.MediaID). WHERE( tbl.TenantID.EQ(Int(tenant)).AND( tbl.UserID.EQ(Int(userID)), ), ) log.Debug(stmt.Sql()) var mediaIDs []int64 if err := stmt.QueryContext(ctx, svc.db, &mediaIDs); err != nil { return nil, errors.Wrap(err, "query user bought medias") } return mediaIDs, nil } // HasUserBought func (svc *Service) HasUserBought(ctx context.Context, tenantId, userId, mediaId int64) (bool, error) { log := svc.log.WithField("method", "HasUserBought") tbl := table.UserMedias stmt := tbl. SELECT(tbl.MediaID). WHERE( tbl.TenantID.EQ(Int(tenantId)).AND( tbl.UserID.EQ(Int(userId)).AND( tbl.MediaID.EQ(Int(mediaId)), ), ), ) log.Debug(stmt.DebugSql()) var mediaID int64 if err := stmt.QueryContext(ctx, svc.db, &mediaID); err != nil { return false, errors.Wrap(err, "query user bought media") } return mediaID > 0, nil } // Upsert func (svc *Service) Upsert(ctx context.Context, tenantId int64, item media_store.VideoInfo) error { log := svc.log.WithField("method", "Upsert") resources := pg.MediaResources{} if path.DirExists(filepath.Join(svc.storageConfig.Path, item.Hash, pg.MediaTypeVideo.String())) { resources = append(resources, pg.MediaTypeVideo) } if path.DirExists(filepath.Join(svc.storageConfig.Path, item.Hash, pg.MediaTypeAudio.String())) { resources = append(resources, pg.MediaTypeAudio) } if path.DirExists(filepath.Join(svc.storageConfig.Path, item.Hash, pg.MediaTypePdf.String())) { resources = append(resources, pg.MediaTypePdf) } tbl := table.Medias stmt := tbl. INSERT(tbl.TenantID, tbl.Hash, tbl.Title, tbl.Price, tbl.Resources, tbl.Publish). VALUES(Int(tenantId), String(item.Hash), String(item.Name), Int(item.Price()), Json(resources.MustValue()), Bool(true)). ON_CONFLICT(tbl.Hash). DO_UPDATE( SET( tbl.Title.SET(String(item.Name)), tbl.Price.SET(Int(item.Price())), tbl.Resources.SET(Json(resources.MustValue())), tbl.Publish.SET(Bool(true)), tbl.UpdatedAt.SET(TimestampT(time.Now())), ), ) log.Debug(stmt.DebugSql()) if _, err := stmt.ExecContext(ctx, svc.db); err != nil { return errors.Wrapf(err, "upsert media: %s %s", item.Hash, item.Name) } return nil }