veza/veza-backend-api/internal/middleware/playlist_permission.go

114 lines
3.8 KiB
Go

package middleware
import (
"context"
"veza-backend-api/internal/models"
"veza-backend-api/internal/response"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// PlaylistPermissionChecker définit l'interface pour vérifier les permissions de playlist
// T0484: Interface pour permettre le mocking dans les tests
// MIGRATION UUID: Utilise maintenant uuid.UUID au lieu de int64
type PlaylistPermissionChecker interface {
CheckPermission(ctx context.Context, playlistID, userID uuid.UUID, requiredPermission models.PlaylistPermission) (bool, error)
}
// CheckPlaylistPermission crée un middleware qui vérifie si un utilisateur a une permission spécifique sur une playlist
// T0484: Create Playlist Permission Middleware
// Le middleware vérifie:
// - Si l'utilisateur est le propriétaire (a toutes les permissions)
// - Si l'utilisateur est collaborateur avec la permission requise
// - Si la playlist est publique et la permission est "read"
func CheckPlaylistPermission(playlistService PlaylistPermissionChecker, requiredPermission models.PlaylistPermission) gin.HandlerFunc {
return func(c *gin.Context) {
// Récupérer user_id du contexte (doit être défini par AuthMiddleware)
userIDInterface, exists := c.Get("user_id")
if !exists {
response.Unauthorized(c, "unauthorized")
c.Abort()
return
}
// Extraire user_id comme uuid.UUID (défini par AuthMiddleware)
// MIGRATION UUID: Support uuid.UUID directement, plus de conversion en int64
var userID uuid.UUID
switch v := userIDInterface.(type) {
case uuid.UUID:
userID = v
case string:
// Support legacy: si c'est une string, essayer de la parser en UUID
parsed, err := uuid.Parse(v)
if err != nil {
response.Unauthorized(c, "invalid user id format")
c.Abort()
return
}
userID = parsed
default:
response.Unauthorized(c, "invalid user id type")
c.Abort()
return
}
// Extraire playlistID depuis les paramètres de la route
// MIGRATION UUID: Parse playlistID comme UUID au lieu de int64
playlistIDStr := c.Param("id")
if playlistIDStr == "" {
response.BadRequest(c, "playlist id is required")
c.Abort()
return
}
playlistID, err := uuid.Parse(playlistIDStr)
if err != nil {
response.BadRequest(c, "invalid playlist id format (expected UUID)")
c.Abort()
return
}
// Vérifier la permission via le service
hasPermission, err := playlistService.CheckPermission(c.Request.Context(), playlistID, userID, requiredPermission)
if err != nil {
// Si la playlist n'existe pas, retourner 404
if err.Error() == "playlist not found" {
response.NotFound(c, "playlist not found")
c.Abort()
return
}
response.InternalServerError(c, "failed to check permission")
c.Abort()
return
}
if !hasPermission {
response.Forbidden(c, "forbidden")
c.Abort()
return
}
// Permission accordée, continuer
c.Next()
}
}
// RequirePlaylistOwner crée un middleware qui exige que l'utilisateur soit le propriétaire de la playlist
// T0484: Helper pour vérifier l'ownership
func RequirePlaylistOwner(playlistService PlaylistPermissionChecker) gin.HandlerFunc {
return CheckPlaylistPermission(playlistService, models.PlaylistPermissionAdmin)
}
// RequirePlaylistWrite crée un middleware qui exige que l'utilisateur ait la permission write ou admin
// T0484: Helper pour vérifier la permission d'écriture
func RequirePlaylistWrite(playlistService PlaylistPermissionChecker) gin.HandlerFunc {
return CheckPlaylistPermission(playlistService, models.PlaylistPermissionWrite)
}
// RequirePlaylistRead crée un middleware qui exige que l'utilisateur ait la permission read, write ou admin
// T0484: Helper pour vérifier la permission de lecture
func RequirePlaylistRead(playlistService PlaylistPermissionChecker) gin.HandlerFunc {
return CheckPlaylistPermission(playlistService, models.PlaylistPermissionRead)
}