198 lines
7.3 KiB
Go
198 lines
7.3 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/redis/go-redis/v9"
|
|
"go.uber.org/zap"
|
|
|
|
trackcore "veza-backend-api/internal/core/track"
|
|
"veza-backend-api/internal/handlers"
|
|
"veza-backend-api/internal/repositories"
|
|
"veza-backend-api/internal/services"
|
|
)
|
|
|
|
// setupUserRoutes configure les routes utilisateur
|
|
func (r *APIRouter) setupUserRoutes(router *gin.RouterGroup) {
|
|
userRepo := repositories.NewGormUserRepository(r.db.GormDB)
|
|
userService := services.NewUserServiceWithDB(userRepo, r.db.GormDB)
|
|
profileHandler := handlers.NewProfileHandler(userService, r.logger)
|
|
if r.config != nil && r.config.PermissionService != nil {
|
|
profileHandler.SetPermissionService(r.config.PermissionService)
|
|
}
|
|
socialService := services.NewSocialService(r.db, r.logger)
|
|
profileHandler.SetSocialService(socialService)
|
|
if r.notificationService == nil {
|
|
r.notificationService = services.NewNotificationService(r.db, r.logger)
|
|
if r.pushService != nil {
|
|
r.notificationService.SetPushService(r.pushService)
|
|
}
|
|
}
|
|
profileHandler.SetNotificationService(r.notificationService)
|
|
|
|
users := router.Group("/users")
|
|
{
|
|
users.GET("", profileHandler.ListUsers)
|
|
users.GET("/:id", profileHandler.GetProfile)
|
|
users.GET("/by-username/:username", profileHandler.GetProfileByUsername)
|
|
users.GET("/search", profileHandler.SearchUsers)
|
|
|
|
if r.config.AuthMiddleware != nil {
|
|
protected := users.Group("")
|
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
|
r.applyCSRFProtection(protected)
|
|
|
|
settingsHandler := handlers.NewSettingsHandler(userService, r.logger)
|
|
protected.GET("/settings", settingsHandler.GetSettings)
|
|
protected.PUT("/settings", settingsHandler.UpdateSettings)
|
|
|
|
userOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
|
|
userIDStr := c.Param("id")
|
|
return uuid.Parse(userIDStr)
|
|
}
|
|
protected.PUT("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("user", userOwnerResolver), profileHandler.UpdateProfile)
|
|
protected.DELETE("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("user", userOwnerResolver), profileHandler.DeleteUser)
|
|
|
|
protected.GET("/:id/completion", profileHandler.GetProfileCompletion)
|
|
|
|
presenceService := services.NewPresenceService(r.db.GormDB, r.logger)
|
|
presenceHandler := handlers.NewPresenceHandler(presenceService, r.logger)
|
|
protected.PUT("/me/presence", presenceHandler.UpdatePresence)
|
|
protected.GET("/:id/presence", presenceHandler.GetPresence)
|
|
|
|
protected.POST("/:id/follow", profileHandler.FollowUser)
|
|
protected.DELETE("/:id/follow", profileHandler.UnfollowUser)
|
|
|
|
protected.POST("/:id/block", profileHandler.BlockUser)
|
|
protected.DELETE("/:id/block", profileHandler.UnblockUser)
|
|
|
|
roleService := services.NewRoleService(r.db.GormDB)
|
|
roleHandler := handlers.NewRoleHandler(roleService, r.logger)
|
|
protected.POST("/:id/roles", roleHandler.AssignRole)
|
|
protected.DELETE("/:id/roles/:roleId", roleHandler.RevokeRole)
|
|
|
|
avatarUploadDir := r.config.UploadDir
|
|
if avatarUploadDir == "" {
|
|
avatarUploadDir = "uploads/avatars"
|
|
}
|
|
imageService := services.NewImageService(avatarUploadDir)
|
|
avatarHandler := handlers.NewAvatarHandler(imageService, userService)
|
|
protected.POST("/:id/avatar", avatarHandler.UploadAvatar)
|
|
protected.DELETE("/:id/avatar", avatarHandler.DeleteAvatar)
|
|
|
|
uploadDir := r.config.UploadDir
|
|
if uploadDir == "" {
|
|
uploadDir = "uploads/tracks"
|
|
}
|
|
likeService := services.NewTrackLikeService(r.db.GormDB, r.logger)
|
|
trackService := trackcore.NewTrackServiceWithDB(r.db, r.logger, uploadDir)
|
|
if r.config.CacheService != nil {
|
|
trackService.SetCacheService(r.config.CacheService)
|
|
}
|
|
streamService := services.NewStreamServiceWithAPIKey(r.config.StreamServerURL, r.config.StreamServerInternalAPIKey, r.logger)
|
|
trackService.SetStreamService(streamService) // INT-02: Enable HLS pipeline for regular uploads
|
|
trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
|
|
var redisClient *redis.Client
|
|
if r.config != nil {
|
|
redisClient = r.config.RedisClient
|
|
}
|
|
chunksDir := uploadDir + "/chunks"
|
|
chunkService := services.NewTrackChunkService(chunksDir, redisClient, r.logger)
|
|
trackHandlerForLikes := trackcore.NewTrackHandler(
|
|
trackService,
|
|
trackUploadService,
|
|
chunkService,
|
|
likeService,
|
|
streamService,
|
|
)
|
|
protected.GET("/:id/likes", trackHandlerForLikes.GetUserLikedTracks)
|
|
|
|
dataExportService := services.NewDataExportService(r.db.GormDB, r.logger)
|
|
exportHandler := func(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID not found"})
|
|
return
|
|
}
|
|
|
|
userUUID, ok := userID.(uuid.UUID)
|
|
if !ok {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
|
return
|
|
}
|
|
|
|
jsonData, err := dataExportService.ExportUserDataAsJSON(c.Request.Context(), userUUID)
|
|
if err != nil {
|
|
r.logger.Error("Failed to export user data", zap.Error(err), zap.String("user_id", userUUID.String()))
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to export user data"})
|
|
return
|
|
}
|
|
|
|
filename := "veza-data-export-" + time.Now().Format("2006-01-02T15-04-05") + ".json"
|
|
c.Header("Content-Type", "application/json")
|
|
c.Header("Content-Disposition", `attachment; filename="`+filename+`"`)
|
|
c.Header("Content-Length", strconv.Itoa(len(jsonData)))
|
|
|
|
c.Data(http.StatusOK, "application/json", jsonData)
|
|
}
|
|
protected.GET("/me/export", exportHandler)
|
|
|
|
// DELETE /me: Account deletion (v0.803 SEC2-05)
|
|
protected.DELETE("/me", handlers.DeleteAccountHandler(
|
|
r.db.GormDB,
|
|
r.config.SessionService,
|
|
r.config.AuditService,
|
|
r.config.S3StorageService,
|
|
r.logger,
|
|
))
|
|
|
|
// POST /me/privacy/opt-out: CCPA Do Not Sell (v0.803 SEC2-06)
|
|
protected.POST("/me/privacy/opt-out", handlers.PrivacyOptOut(r.db.GormDB))
|
|
|
|
// POST /me/export: async GDPR export (ZIP to S3, notification when ready)
|
|
gdprExportService := services.NewGDPRExportService(
|
|
r.db.GormDB, dataExportService, r.config.S3StorageService, r.notificationService, r.logger,
|
|
)
|
|
protected.POST("/me/export", func(c *gin.Context) {
|
|
userID, exists := c.Get("user_id")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID not found"})
|
|
return
|
|
}
|
|
userUUID, ok := userID.(uuid.UUID)
|
|
if !ok {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
|
|
return
|
|
}
|
|
gdprExportService.ExportUserDataAsync(c.Request.Context(), userUUID)
|
|
c.JSON(http.StatusAccepted, gin.H{"message": "Export started, you will be notified when ready"})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// setupRoleRoutes configure les routes de gestion des rôles
|
|
func (r *APIRouter) setupRoleRoutes(router *gin.RouterGroup) {
|
|
roleService := services.NewRoleService(r.db.GormDB)
|
|
roleHandler := handlers.NewRoleHandler(roleService, r.logger)
|
|
|
|
roles := router.Group("/roles")
|
|
{
|
|
if r.config.AuthMiddleware != nil {
|
|
protected := roles.Group("")
|
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
|
r.applyCSRFProtection(protected)
|
|
{
|
|
protected.GET("", roleHandler.GetRoles)
|
|
protected.GET("/:id", roleHandler.GetRole)
|
|
protected.POST("", roleHandler.CreateRole)
|
|
protected.PUT("/:id", roleHandler.UpdateRole)
|
|
protected.DELETE("/:id", roleHandler.DeleteRole)
|
|
}
|
|
}
|
|
}
|
|
}
|