summaryrefslogtreecommitdiff
path: root/internal/service/progress.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-17 15:08:16 +0300
committerPaul Buetow <paul@buetow.org>2026-05-17 15:08:16 +0300
commit29188f031ff4c83e28b021ac5ffbc780e9a92a22 (patch)
tree2301490c18b35f97f915ae4c575b045205d0e837 /internal/service/progress.go
parenta96f53c30341baf96ff2c791f7e5689de756ae9b (diff)
Add progress service completion methods
Diffstat (limited to 'internal/service/progress.go')
-rw-r--r--internal/service/progress.go88
1 files changed, 84 insertions, 4 deletions
diff --git a/internal/service/progress.go b/internal/service/progress.go
index ef248cf..4e79aa5 100644
--- a/internal/service/progress.go
+++ b/internal/service/progress.go
@@ -12,15 +12,17 @@ import (
// progressService is the concrete implementation of ProgressService.
type progressService struct {
- store repository.ProgressServiceStore
- clock clock.Clock
+ store repository.ProgressServiceStore
+ helper *accessHelper
+ clock clock.Clock
}
// NewProgressService creates a concrete ProgressService.
func NewProgressService(store repository.ProgressServiceStore, clk clock.Clock) *progressService {
return &progressService{
- store: store,
- clock: clk,
+ store: store,
+ helper: NewAccessHelper(store),
+ clock: clk,
}
}
@@ -82,3 +84,81 @@ func (s *progressService) UpdateProgress(ctx context.Context, sessionID string,
return nil
}
+
+func (s *progressService) MarkFinished(ctx context.Context, userID, mediaID int64) error {
+ if mediaID == 0 {
+ return errors.New("media_id required")
+ }
+
+ media, err := s.helper.verifyAccess(ctx, mediaID, userID)
+ if err != nil {
+ return err
+ }
+
+ if err := s.store.UpsertProgress(ctx, &model.PlaybackProgress{
+ UserID: userID,
+ MediaID: mediaID,
+ PositionSeconds: media.Duration,
+ Finished: true,
+ UpdatedAt: s.clock.Now(),
+ }); err != nil {
+ return fmt.Errorf("mark finished: %w", err)
+ }
+
+ return nil
+}
+
+func (s *progressService) MarkNotStarted(ctx context.Context, userID, mediaID int64) error {
+ if mediaID == 0 {
+ return errors.New("media_id required")
+ }
+
+ if _, err := s.helper.verifyAccess(ctx, mediaID, userID); err != nil {
+ return err
+ }
+
+ if err := s.store.DeleteProgress(ctx, userID, mediaID); err != nil {
+ return fmt.Errorf("delete progress: %w", err)
+ }
+ if err := s.store.DeleteAccumulatorByMedia(ctx, mediaID); err != nil {
+ return fmt.Errorf("delete accumulator: %w", err)
+ }
+
+ return nil
+}
+
+func (s *progressService) ListInProgress(ctx context.Context, userID int64) ([]model.Media, error) {
+ allowed, err := s.helper.allowedSetIDs(ctx, userID)
+ if err != nil {
+ return nil, err
+ }
+ if allowed != nil && len(allowed) == 0 {
+ return []model.Media{}, nil
+ }
+
+ return s.store.ListInProgressMedia(ctx, userID, repository.MediaFilter{
+ AllowedSetIDs: allowed,
+ })
+}
+
+func (h *accessHelper) allowedSetIDs(ctx context.Context, userID int64) ([]int64, error) {
+ user, err := h.store.GetUserByID(ctx, userID)
+ if err != nil {
+ return nil, fmt.Errorf("get user: %w", err)
+ }
+ if user != nil && user.IsAdmin {
+ return nil, nil
+ }
+
+ perms, err := h.store.ListPermissionsByUser(ctx, userID)
+ if err != nil {
+ return nil, fmt.Errorf("list permissions: %w", err)
+ }
+
+ allowed := make([]int64, 0, len(perms))
+ for _, p := range perms {
+ allowed = append(allowed, p.SetID)
+ }
+
+ return allowed, nil
+}