162 lines
5.1 KiB
Go
162 lines
5.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"go.uber.org/zap"
|
|
|
|
apperrors "veza-backend-api/internal/errors"
|
|
"veza-backend-api/internal/services"
|
|
)
|
|
|
|
// QueueSessionHandler handles collaborative queue session HTTP requests (v0.203 Lot D1)
|
|
type QueueSessionHandler struct {
|
|
svc *services.QueueSessionService
|
|
logger *zap.Logger
|
|
}
|
|
|
|
// NewQueueSessionHandler creates a new QueueSessionHandler
|
|
func NewQueueSessionHandler(svc *services.QueueSessionService, logger *zap.Logger) *QueueSessionHandler {
|
|
return &QueueSessionHandler{svc: svc, logger: logger}
|
|
}
|
|
|
|
// CreateSession creates a new shared queue session
|
|
func (h *QueueSessionHandler) CreateSession(c *gin.Context) {
|
|
userID, ok := GetUserIDUUID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
session, err := h.svc.CreateSession(c.Request.Context(), userID)
|
|
if err != nil {
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to create session", err))
|
|
return
|
|
}
|
|
RespondSuccess(c, http.StatusCreated, gin.H{
|
|
"session": session,
|
|
"share_token": session.ShareToken,
|
|
"share_url": "/queue?session=" + session.ShareToken,
|
|
})
|
|
}
|
|
|
|
// GetSession returns a session's queue (auth optional for joining via link)
|
|
func (h *QueueSessionHandler) GetSession(c *gin.Context) {
|
|
token := c.Param("token")
|
|
if token == "" {
|
|
RespondWithAppError(c, apperrors.NewValidationError("token is required"))
|
|
return
|
|
}
|
|
session, items, err := h.svc.GetSessionByToken(c.Request.Context(), token)
|
|
if err != nil {
|
|
if errors.Is(err, services.ErrQueueSessionNotFound) {
|
|
RespondWithAppError(c, apperrors.NewNotFoundError("session not found"))
|
|
return
|
|
}
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get session", err))
|
|
return
|
|
}
|
|
// Map items to response with tracks
|
|
type itemResp struct {
|
|
ID string `json:"id"`
|
|
Position int `json:"position"`
|
|
AddedAt string `json:"added_at"`
|
|
Track interface{} `json:"track,omitempty"`
|
|
}
|
|
respItems := make([]itemResp, 0, len(items))
|
|
for _, it := range items {
|
|
r := itemResp{
|
|
ID: it.ID.String(),
|
|
Position: it.Position,
|
|
AddedAt: it.AddedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
}
|
|
if it.Track.ID != uuid.Nil {
|
|
r.Track = it.Track
|
|
}
|
|
respItems = append(respItems, r)
|
|
}
|
|
RespondSuccess(c, http.StatusOK, gin.H{
|
|
"session": session,
|
|
"items": respItems,
|
|
})
|
|
}
|
|
|
|
// DeleteSession deletes a session (creator only)
|
|
func (h *QueueSessionHandler) DeleteSession(c *gin.Context) {
|
|
userID, ok := GetUserIDUUID(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
token := c.Param("token")
|
|
if token == "" {
|
|
RespondWithAppError(c, apperrors.NewValidationError("token is required"))
|
|
return
|
|
}
|
|
if err := h.svc.DeleteSession(c.Request.Context(), token, userID); err != nil {
|
|
if errors.Is(err, services.ErrQueueSessionNotFound) {
|
|
RespondWithAppError(c, apperrors.NewNotFoundError("session not found"))
|
|
return
|
|
}
|
|
if errors.Is(err, services.ErrQueueSessionForbidden) {
|
|
RespondWithAppError(c, apperrors.NewForbiddenError("only the creator can delete this session"))
|
|
return
|
|
}
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to delete session", err))
|
|
return
|
|
}
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "session deleted"})
|
|
}
|
|
|
|
// AddToSessionRequest represents the request body
|
|
type AddToSessionRequest struct {
|
|
TrackID uuid.UUID `json:"track_id" binding:"required"`
|
|
}
|
|
|
|
// AddToSession adds a track to a session's queue
|
|
func (h *QueueSessionHandler) AddToSession(c *gin.Context) {
|
|
token := c.Param("token")
|
|
if token == "" {
|
|
RespondWithAppError(c, apperrors.NewValidationError("token is required"))
|
|
return
|
|
}
|
|
var req AddToSessionRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
RespondWithAppError(c, apperrors.NewValidationError("track_id is required"))
|
|
return
|
|
}
|
|
if err := h.svc.AddToSession(c.Request.Context(), token, req.TrackID); err != nil {
|
|
if errors.Is(err, services.ErrQueueSessionNotFound) {
|
|
RespondWithAppError(c, apperrors.NewNotFoundError("session not found"))
|
|
return
|
|
}
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to add to session", err))
|
|
return
|
|
}
|
|
// Return updated session
|
|
session, items, _ := h.svc.GetSessionByToken(c.Request.Context(), token)
|
|
RespondSuccess(c, http.StatusCreated, gin.H{"session": session, "items": items})
|
|
}
|
|
|
|
// RemoveFromSession removes an item from a session's queue
|
|
func (h *QueueSessionHandler) RemoveFromSession(c *gin.Context) {
|
|
token := c.Param("token")
|
|
if token == "" {
|
|
RespondWithAppError(c, apperrors.NewValidationError("token is required"))
|
|
return
|
|
}
|
|
itemID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
RespondWithAppError(c, apperrors.NewValidationError("invalid item ID"))
|
|
return
|
|
}
|
|
if err := h.svc.RemoveFromSession(c.Request.Context(), token, itemID); err != nil {
|
|
if errors.Is(err, services.ErrQueueSessionNotFound) {
|
|
RespondWithAppError(c, apperrors.NewNotFoundError("session or item not found"))
|
|
return
|
|
}
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to remove from session", err))
|
|
return
|
|
}
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "item removed"})
|
|
}
|