Added set current
This commit is contained in:
parent
0c4453500f
commit
7a3a732efb
@ -30,5 +30,33 @@ func NewRouter(svc service.EpisodeService) *gin.Engine {
|
||||
c.JSON(http.StatusOK, cur)
|
||||
})
|
||||
|
||||
type setCurrentReq struct {
|
||||
ID int64 `json:"id" binding:"required"`
|
||||
StartTime string `json:"start_time" binding:"required"` // HH:MM or HH:MM:SS
|
||||
}
|
||||
|
||||
r.POST("/current", func(c *gin.Context) {
|
||||
var req setCurrentReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"})
|
||||
return
|
||||
}
|
||||
cur, err := svc.SetCurrent(c.Request.Context(), req.ID, req.StartTime)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case service.ErrInvalidTime:
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
case repo.ErrNotFound:
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "id not found"})
|
||||
return
|
||||
default:
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "update failed"})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, cur)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ type Episode struct {
|
||||
|
||||
type EpisodeRepository interface {
|
||||
GetCurrent(ctx context.Context) (Episode, error)
|
||||
SetCurrent(ctx context.Context, id int64, startHHMMSS string) error
|
||||
}
|
||||
|
||||
type pgxEpisodeRepo struct {
|
||||
@ -58,3 +59,27 @@ LIMIT 1;
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (r *pgxEpisodeRepo) SetCurrent(ctx context.Context, id int64, startHHMMSS string) error {
|
||||
tx, err := r.pool.Begin(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = tx.Rollback(ctx) }()
|
||||
|
||||
// 1) clear any current episode flag
|
||||
if _, err := tx.Exec(ctx, `UPDATE current SET current_ep = false WHERE current_ep = true`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2) set start_time and current_ep for the id
|
||||
ct, err := tx.Exec(ctx, `UPDATE current SET start_time = $1::time, current_ep = true WHERE id = $2`, startHHMMSS, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ct.RowsAffected() == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
return tx.Commit(ctx)
|
||||
}
|
||||
|
||||
@ -2,13 +2,18 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"watch-party-backend/internal/repo"
|
||||
)
|
||||
|
||||
var ErrInvalidTime = errors.New("invalid start_time (expected HH:MM or HH:MM:SS)")
|
||||
|
||||
type EpisodeService interface {
|
||||
GetCurrent(ctx context.Context) (repo.Episode, error)
|
||||
SetCurrent(ctx context.Context, id int64, start string) (repo.Episode, error)
|
||||
}
|
||||
|
||||
type episodeService struct {
|
||||
@ -20,8 +25,38 @@ func NewEpisodeService(r repo.EpisodeRepository) EpisodeService {
|
||||
}
|
||||
|
||||
func (s *episodeService) GetCurrent(ctx context.Context) (repo.Episode, error) {
|
||||
// Add cross-cutting concerns here (timeouts, metrics, caching, etc.)
|
||||
c, cancel := context.WithTimeout(ctx, 3*time.Second)
|
||||
defer cancel()
|
||||
return s.repo.GetCurrent(c)
|
||||
}
|
||||
|
||||
func (s *episodeService) SetCurrent(ctx context.Context, id int64, start string) (repo.Episode, error) {
|
||||
// normalize and validate time as HH:MM:SS
|
||||
normalized, err := normalizeHHMMSS(start)
|
||||
if err != nil {
|
||||
return repo.Episode{}, ErrInvalidTime
|
||||
}
|
||||
|
||||
c, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// do the transaction
|
||||
if err := s.repo.SetCurrent(c, id, normalized); err != nil {
|
||||
return repo.Episode{}, err
|
||||
}
|
||||
// return the new current row
|
||||
return s.repo.GetCurrent(c)
|
||||
}
|
||||
|
||||
func normalizeHHMMSS(s string) (string, error) {
|
||||
s = strings.TrimSpace(s)
|
||||
if len(s) == 5 { // HH:MM → append seconds
|
||||
s += ":00"
|
||||
}
|
||||
// Strict parse/format to 24h
|
||||
t, err := time.Parse("15:04:05", s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return t.Format("15:04:05"), nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user