refactor(api): extract route setup functions into dedicated files
This commit is contained in:
parent
04c25aa24f
commit
037692887f
12 changed files with 1020 additions and 1069 deletions
File diff suppressed because it is too large
Load diff
33
veza-backend-api/internal/api/routes_analytics.go
Normal file
33
veza-backend-api/internal/api/routes_analytics.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
"veza-backend-api/internal/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupAnalyticsRoutes configure les routes pour les analytics
|
||||||
|
func (r *APIRouter) setupAnalyticsRoutes(router *gin.RouterGroup) {
|
||||||
|
if r.db == nil || r.db.GormDB == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
analyticsService := services.NewAnalyticsService(r.db.GormDB, r.logger)
|
||||||
|
analyticsHandler := handlers.NewAnalyticsHandler(analyticsService, r.logger)
|
||||||
|
|
||||||
|
if r.config != nil && r.config.JobWorker != nil {
|
||||||
|
analyticsHandler.SetJobWorker(r.config.JobWorker)
|
||||||
|
}
|
||||||
|
|
||||||
|
analytics := router.Group("/analytics")
|
||||||
|
if r.config != nil && r.config.AuthMiddleware != nil {
|
||||||
|
analytics.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(analytics)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
analytics.GET("", analyticsHandler.GetAnalytics)
|
||||||
|
analytics.POST("/events", analyticsHandler.RecordEvent)
|
||||||
|
analytics.GET("/tracks/:id", analyticsHandler.GetTrackAnalyticsDashboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
368
veza-backend-api/internal/api/routes_core.go
Normal file
368
veza-backend-api/internal/api/routes_core.go
Normal file
|
|
@ -0,0 +1,368 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
trackcore "veza-backend-api/internal/core/track"
|
||||||
|
"veza-backend-api/internal/config"
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
"veza-backend-api/internal/middleware"
|
||||||
|
"veza-backend-api/internal/models"
|
||||||
|
"veza-backend-api/internal/repositories"
|
||||||
|
"veza-backend-api/internal/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupValidateRoutes configures the validation endpoint
|
||||||
|
func (r *APIRouter) setupValidateRoutes(router *gin.RouterGroup) {
|
||||||
|
validateHandler := handlers.NewValidateHandler(r.logger)
|
||||||
|
router.POST("/validate", validateHandler.Validate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupInternalRoutes configure les routes internal (legacy and modern)
|
||||||
|
func (r *APIRouter) setupInternalRoutes(router *gin.Engine) {
|
||||||
|
uploadDir := r.config.UploadDir
|
||||||
|
if uploadDir == "" {
|
||||||
|
uploadDir = "uploads/tracks"
|
||||||
|
}
|
||||||
|
chunksDir := uploadDir + "/chunks"
|
||||||
|
|
||||||
|
trackService := trackcore.NewTrackService(r.db.GormDB, r.logger, uploadDir)
|
||||||
|
if r.config.CacheService != nil {
|
||||||
|
trackService.SetCacheService(r.config.CacheService)
|
||||||
|
}
|
||||||
|
trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
|
||||||
|
var redisClient *redis.Client
|
||||||
|
if r.config != nil {
|
||||||
|
redisClient = r.config.RedisClient
|
||||||
|
}
|
||||||
|
chunkService := services.NewTrackChunkService(chunksDir, redisClient, r.logger)
|
||||||
|
likeService := services.NewTrackLikeService(r.db.GormDB, r.logger)
|
||||||
|
streamService := services.NewStreamServiceWithAPIKey(r.config.StreamServerURL, r.config.StreamServerInternalAPIKey, r.logger)
|
||||||
|
|
||||||
|
trackHandler := trackcore.NewTrackHandler(
|
||||||
|
trackService,
|
||||||
|
trackUploadService,
|
||||||
|
chunkService,
|
||||||
|
likeService,
|
||||||
|
streamService,
|
||||||
|
)
|
||||||
|
|
||||||
|
expectedKey := ""
|
||||||
|
if r.config != nil {
|
||||||
|
expectedKey = r.config.StreamServerInternalAPIKey
|
||||||
|
}
|
||||||
|
streamCallbackAuth := middleware.StreamCallbackAuth(expectedKey, r.logger)
|
||||||
|
|
||||||
|
internalDeprecated := router.Group("/internal")
|
||||||
|
internalDeprecated.Use(middleware.DeprecationWarning(r.logger))
|
||||||
|
internalDeprecated.Use(streamCallbackAuth)
|
||||||
|
{
|
||||||
|
internalDeprecated.POST("/tracks/:id/stream-ready", trackHandler.HandleStreamCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1Internal := router.Group("/api/v1/internal")
|
||||||
|
v1Internal.Use(streamCallbackAuth)
|
||||||
|
{
|
||||||
|
v1Internal.POST("/tracks/:id/stream-ready", trackHandler.HandleStreamCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupCorePublicRoutes configure les routes publiques core (health, metrics, upload info)
|
||||||
|
func (r *APIRouter) setupCorePublicRoutes(router *gin.Engine) {
|
||||||
|
var healthCheckHandler gin.HandlerFunc
|
||||||
|
var livenessHandler gin.HandlerFunc
|
||||||
|
var readinessHandler gin.HandlerFunc
|
||||||
|
|
||||||
|
if r.db != nil && r.db.GormDB != nil {
|
||||||
|
var redisClient interface{}
|
||||||
|
if r.config != nil {
|
||||||
|
redisClient = r.config.RedisClient
|
||||||
|
}
|
||||||
|
var rabbitMQEventBus interface{}
|
||||||
|
if r.config != nil {
|
||||||
|
rabbitMQEventBus = r.config.RabbitMQEventBus
|
||||||
|
}
|
||||||
|
var env string
|
||||||
|
if r.config != nil {
|
||||||
|
env = r.config.Env
|
||||||
|
}
|
||||||
|
var s3Service interface{}
|
||||||
|
var jobWorker interface{}
|
||||||
|
var emailSender interface{}
|
||||||
|
if r.config != nil {
|
||||||
|
s3Service = r.config.S3StorageService
|
||||||
|
jobWorker = r.config.JobWorker
|
||||||
|
emailSender = r.config.EmailSender
|
||||||
|
}
|
||||||
|
healthHandler := handlers.NewHealthHandlerWithServices(
|
||||||
|
r.db.GormDB,
|
||||||
|
r.logger,
|
||||||
|
redisClient,
|
||||||
|
rabbitMQEventBus,
|
||||||
|
env,
|
||||||
|
s3Service,
|
||||||
|
jobWorker,
|
||||||
|
emailSender,
|
||||||
|
)
|
||||||
|
healthCheckHandler = healthHandler.Check
|
||||||
|
livenessHandler = healthHandler.Liveness
|
||||||
|
readinessHandler = healthHandler.Readiness
|
||||||
|
} else {
|
||||||
|
healthCheckHandler = handlers.SimpleHealthCheck
|
||||||
|
livenessHandler = handlers.SimpleHealthCheck
|
||||||
|
readinessHandler = handlers.SimpleHealthCheck
|
||||||
|
}
|
||||||
|
|
||||||
|
deprecationMW := middleware.DeprecationWarning(r.logger)
|
||||||
|
healthMonitoringMW := middleware.HealthCheckMonitoring(r.logger, r.monitoringService)
|
||||||
|
|
||||||
|
router.GET("/health", deprecationMW, healthMonitoringMW, healthCheckHandler)
|
||||||
|
router.GET("/healthz", deprecationMW, healthMonitoringMW, livenessHandler)
|
||||||
|
router.GET("/readyz", deprecationMW, healthMonitoringMW, readinessHandler)
|
||||||
|
router.GET("/metrics", deprecationMW, handlers.PrometheusMetrics())
|
||||||
|
if r.config != nil && r.config.ErrorMetrics != nil {
|
||||||
|
router.GET("/metrics/aggregated", deprecationMW, handlers.AggregatedMetrics(r.config.ErrorMetrics))
|
||||||
|
}
|
||||||
|
router.GET("/system/metrics", deprecationMW, handlers.SystemMetrics)
|
||||||
|
|
||||||
|
v1Public := router.Group("/api/v1")
|
||||||
|
{
|
||||||
|
v1Public.GET("/health", healthCheckHandler)
|
||||||
|
v1Public.GET("/healthz", livenessHandler)
|
||||||
|
v1Public.GET("/readyz", readinessHandler)
|
||||||
|
|
||||||
|
if r.db != nil && r.db.GormDB != nil {
|
||||||
|
var redisClient interface{}
|
||||||
|
if r.config != nil {
|
||||||
|
redisClient = r.config.RedisClient
|
||||||
|
}
|
||||||
|
chatServerURL := ""
|
||||||
|
streamServerURL := ""
|
||||||
|
if r.config != nil {
|
||||||
|
chatServerURL = r.config.ChatServerURL
|
||||||
|
streamServerURL = r.config.StreamServerURL
|
||||||
|
}
|
||||||
|
getEnv := func(key, defaultValue string) string {
|
||||||
|
if value := os.Getenv(key); value != "" {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
version := getEnv("APP_VERSION", "v1.0.0")
|
||||||
|
gitCommit := getEnv("GIT_COMMIT", "unknown")
|
||||||
|
buildTime := getEnv("BUILD_TIME", "")
|
||||||
|
environment := ""
|
||||||
|
if r.config != nil {
|
||||||
|
environment = r.config.Env
|
||||||
|
}
|
||||||
|
statusHandler := handlers.NewStatusHandler(
|
||||||
|
r.db.GormDB,
|
||||||
|
r.logger,
|
||||||
|
redisClient,
|
||||||
|
chatServerURL,
|
||||||
|
streamServerURL,
|
||||||
|
version,
|
||||||
|
gitCommit,
|
||||||
|
buildTime,
|
||||||
|
environment,
|
||||||
|
)
|
||||||
|
v1Public.GET("/status", statusHandler.GetStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1Public.GET("/metrics", handlers.PrometheusMetrics())
|
||||||
|
if r.config != nil && r.config.ErrorMetrics != nil {
|
||||||
|
v1Public.GET("/metrics/aggregated", handlers.AggregatedMetrics(r.config.ErrorMetrics))
|
||||||
|
}
|
||||||
|
v1Public.GET("/system/metrics", handlers.SystemMetrics)
|
||||||
|
|
||||||
|
if r.db != nil && r.db.GormDB != nil {
|
||||||
|
uploadConfig := getUploadConfigWithEnv()
|
||||||
|
uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
|
||||||
|
if err != nil {
|
||||||
|
r.logger.Warn("Upload validator created with ClamAV unavailable - uploads will be rejected", zap.Error(err))
|
||||||
|
uploadConfig.ClamAVEnabled = false
|
||||||
|
uploadValidator, _ = services.NewUploadValidator(uploadConfig, r.logger)
|
||||||
|
}
|
||||||
|
auditService := services.NewAuditService(r.db, r.logger)
|
||||||
|
trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
|
||||||
|
uploadHandler := handlers.NewUploadHandler(uploadValidator, auditService, trackUploadService, r.logger, r.config.MaxConcurrentUploads)
|
||||||
|
v1Public.GET("/upload/limits", uploadHandler.GetUploadLimits())
|
||||||
|
v1Public.GET("/upload/validate-type", uploadHandler.ValidateFileType())
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.config != nil {
|
||||||
|
frontendLogHandler, err := handlers.NewFrontendLogHandler(r.config, r.logger)
|
||||||
|
if err != nil {
|
||||||
|
r.logger.Warn("Failed to create frontend log handler, frontend logs will not be stored", zap.Error(err))
|
||||||
|
} else {
|
||||||
|
v1Public.POST("/logs/frontend", frontendLogHandler.ReceiveLog)
|
||||||
|
r.logger.Info("Frontend logging endpoint enabled", zap.String("endpoint", "/api/v1/logs/frontend"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setupCoreProtectedRoutes configure les routes protégées core (sessions, uploads, audit, admin, conversations)
|
||||||
|
func (r *APIRouter) setupCoreProtectedRoutes(v1 *gin.RouterGroup) {
|
||||||
|
if r.db == nil || r.db.GormDB == nil || r.config == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
csrfMiddleware := middleware.NewCSRFMiddleware(r.config.RedisClient, r.logger)
|
||||||
|
csrfMiddleware.SetEnvironment(r.config.Env)
|
||||||
|
csrfHandler := handlers.NewCSRFHandler(csrfMiddleware, r.logger)
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
v1.GET("/csrf-token", r.config.AuthMiddleware.OptionalAuth(), csrfHandler.GetCSRFToken())
|
||||||
|
} else {
|
||||||
|
v1.GET("/csrf-token", csrfHandler.GetCSRFToken())
|
||||||
|
}
|
||||||
|
|
||||||
|
protected := v1.Group("/")
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionService := services.NewSessionService(r.db, r.logger)
|
||||||
|
|
||||||
|
if r.config.RedisClient != nil {
|
||||||
|
protected.Use(csrfMiddleware.Middleware())
|
||||||
|
r.logger.Info("CSRF protection enabled for core protected routes",
|
||||||
|
zap.String("environment", r.config.Env),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if r.config.Env == config.EnvProduction {
|
||||||
|
r.logger.Fatal("CSRF protection requires Redis but Redis is unavailable in production. This is a security requirement.")
|
||||||
|
panic("CSRF protection requires Redis in production environment. Redis is unavailable.")
|
||||||
|
}
|
||||||
|
r.logger.Warn("Redis not available - CSRF protection disabled (non-production environment)",
|
||||||
|
zap.String("environment", r.config.Env),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadConfig := getUploadConfigWithEnv()
|
||||||
|
uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
|
||||||
|
if err != nil {
|
||||||
|
r.logger.Warn("Upload validator created with ClamAV unavailable - uploads will be rejected", zap.Error(err))
|
||||||
|
uploadConfig.ClamAVEnabled = false
|
||||||
|
uploadValidator, _ = services.NewUploadValidator(uploadConfig, r.logger)
|
||||||
|
}
|
||||||
|
auditService := services.NewAuditService(r.db, r.logger)
|
||||||
|
trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
|
||||||
|
|
||||||
|
sessionHandler := handlers.NewSessionHandler(sessionService, auditService, r.logger)
|
||||||
|
uploadHandler := handlers.NewUploadHandler(uploadValidator, auditService, trackUploadService, r.logger, r.config.MaxConcurrentUploads)
|
||||||
|
auditHandler := handlers.NewAuditHandler(auditService, r.logger)
|
||||||
|
|
||||||
|
sessions := protected.Group("/sessions")
|
||||||
|
{
|
||||||
|
sessions.POST("/logout", sessionHandler.Logout())
|
||||||
|
sessions.POST("/logout-all", sessionHandler.LogoutAll())
|
||||||
|
sessions.GET("", sessionHandler.GetSessions())
|
||||||
|
sessions.GET("/", sessionHandler.GetSessions())
|
||||||
|
sessions.DELETE("/:session_id", sessionHandler.RevokeSession())
|
||||||
|
sessions.GET("/stats", sessionHandler.GetSessionStats())
|
||||||
|
sessions.POST("/refresh", sessionHandler.RefreshSession())
|
||||||
|
}
|
||||||
|
|
||||||
|
uploads := protected.Group("/uploads")
|
||||||
|
{
|
||||||
|
if r.config.RedisClient != nil {
|
||||||
|
uploads.Use(middleware.UploadRateLimit(r.config.RedisClient))
|
||||||
|
}
|
||||||
|
uploads.POST("/", uploadHandler.UploadFile())
|
||||||
|
uploads.POST("/batch", uploadHandler.BatchUpload())
|
||||||
|
uploads.GET("/:id/status", uploadHandler.GetUploadStatus())
|
||||||
|
uploads.GET("/:id/progress", uploadHandler.UploadProgress())
|
||||||
|
uploads.DELETE("/:id", uploadHandler.DeleteUpload())
|
||||||
|
uploads.GET("/stats", uploadHandler.GetUploadStats())
|
||||||
|
}
|
||||||
|
|
||||||
|
audit := protected.Group("/audit")
|
||||||
|
{
|
||||||
|
audit.GET("/logs", auditHandler.SearchLogs())
|
||||||
|
audit.GET("/stats", auditHandler.GetStats())
|
||||||
|
audit.GET("/activity", auditHandler.GetUserActivity())
|
||||||
|
audit.GET("/suspicious", auditHandler.DetectSuspiciousActivity())
|
||||||
|
audit.GET("/ip/:ip", auditHandler.GetIPActivity())
|
||||||
|
audit.GET("/logs/:id", auditHandler.GetAuditLog())
|
||||||
|
audit.POST("/cleanup", auditHandler.CleanupOldLogs())
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadDir := r.config.UploadDir
|
||||||
|
if uploadDir == "" {
|
||||||
|
uploadDir = "uploads/tracks"
|
||||||
|
}
|
||||||
|
trackServiceForDashboard := trackcore.NewTrackService(r.db.GormDB, r.logger, uploadDir)
|
||||||
|
if r.config.CacheService != nil {
|
||||||
|
trackServiceForDashboard.SetCacheService(r.config.CacheService)
|
||||||
|
}
|
||||||
|
|
||||||
|
trackListFunc := func(ctx context.Context, params handlers.TrackListParamsForDashboard) ([]*models.Track, int64, error) {
|
||||||
|
return trackServiceForDashboard.ListTracks(ctx, trackcore.TrackListParams{
|
||||||
|
Page: params.Page,
|
||||||
|
Limit: params.Limit,
|
||||||
|
UserID: params.UserID,
|
||||||
|
Genre: params.Genre,
|
||||||
|
Format: params.Format,
|
||||||
|
SortBy: params.SortBy,
|
||||||
|
SortOrder: params.SortOrder,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboardHandler := handlers.NewDashboardHandler(auditService, trackListFunc, r.logger)
|
||||||
|
protected.GET("/dashboard", dashboardHandler.GetDashboard())
|
||||||
|
|
||||||
|
roomRepo := repositories.NewRoomRepository(r.db.GormDB)
|
||||||
|
messageRepo := repositories.NewChatMessageRepository(r.db.GormDB)
|
||||||
|
roomService := services.NewRoomService(roomRepo, messageRepo, r.logger)
|
||||||
|
roomHandler := handlers.NewRoomHandler(roomService, r.logger)
|
||||||
|
|
||||||
|
conversations := protected.Group("/conversations")
|
||||||
|
{
|
||||||
|
conversations.GET("", roomHandler.GetUserRooms)
|
||||||
|
conversations.POST("", roomHandler.CreateRoom)
|
||||||
|
conversations.GET("/:id", roomHandler.GetRoom)
|
||||||
|
conversations.PUT("/:id", roomHandler.UpdateRoom)
|
||||||
|
conversations.DELETE("/:id", roomHandler.DeleteRoom)
|
||||||
|
conversations.POST("/:id/members", roomHandler.AddMember)
|
||||||
|
conversations.POST("/:id/participants", roomHandler.AddParticipant)
|
||||||
|
conversations.DELETE("/:id/participants/:userId", roomHandler.RemoveParticipant)
|
||||||
|
conversations.GET("/:id/history", roomHandler.GetRoomHistory)
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationService := services.NewNotificationService(r.db, r.logger)
|
||||||
|
handlers.NewNotificationHandlers(notificationService)
|
||||||
|
notifications := protected.Group("/notifications")
|
||||||
|
{
|
||||||
|
notifications.GET("", handlers.NotificationHandlersInstance.GetNotifications)
|
||||||
|
notifications.GET("/unread-count", handlers.NotificationHandlersInstance.GetUnreadCount)
|
||||||
|
notifications.POST("/:id/read", handlers.NotificationHandlersInstance.MarkAsRead)
|
||||||
|
notifications.POST("/read-all", handlers.NotificationHandlersInstance.MarkAllAsRead)
|
||||||
|
notifications.DELETE("/:id", handlers.NotificationHandlersInstance.DeleteNotification)
|
||||||
|
notifications.DELETE("", handlers.NotificationHandlersInstance.DeleteAllNotifications)
|
||||||
|
}
|
||||||
|
|
||||||
|
admin := v1.Group("/admin")
|
||||||
|
{
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
admin.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
admin.Use(r.config.AuthMiddleware.RequireAdmin())
|
||||||
|
}
|
||||||
|
|
||||||
|
admin.GET("/audit/logs", auditHandler.SearchLogs())
|
||||||
|
admin.GET("/audit/stats", auditHandler.GetStats())
|
||||||
|
admin.GET("/audit/suspicious", auditHandler.DetectSuspiciousActivity())
|
||||||
|
|
||||||
|
admin.Any("/debug/pprof/*path", gin.WrapH(http.DefaultServeMux))
|
||||||
|
|
||||||
|
if r.authService != nil {
|
||||||
|
admin.POST("/auth/unlock-account", handlers.UnlockAccount(r.authService, r.logger))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
veza-backend-api/internal/api/routes_education.go
Normal file
19
veza-backend-api/internal/api/routes_education.go
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
eduApi "veza-backend-api/internal/api/education"
|
||||||
|
eduCore "veza-backend-api/internal/core/education"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupEducationRoutes configure les routes d'éducation (cours, tutoriels)
|
||||||
|
func (r *APIRouter) setupEducationRoutes(router *gin.RouterGroup) {
|
||||||
|
if r.config == nil || r.config.AuthMiddleware == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
courseManager := eduCore.NewCourseManager(r.logger)
|
||||||
|
tutorialManager := eduCore.NewTutorialManager(r.logger)
|
||||||
|
eduHandler := eduApi.NewHandler(courseManager, tutorialManager, r.logger)
|
||||||
|
eduApi.SetupRoutes(router, eduHandler, r.config.JWTSecret, r.config.AuthMiddleware)
|
||||||
|
}
|
||||||
30
veza-backend-api/internal/api/routes_gear.go
Normal file
30
veza-backend-api/internal/api/routes_gear.go
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
"veza-backend-api/internal/repositories"
|
||||||
|
"veza-backend-api/internal/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupGearRoutes configure les routes d'inventaire gear/équipement
|
||||||
|
func (r *APIRouter) setupGearRoutes(router *gin.RouterGroup) {
|
||||||
|
if r.config == nil || r.config.AuthMiddleware == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gearRepo := repositories.NewGearRepository(r.db.GormDB)
|
||||||
|
gearService := services.NewGearService(gearRepo, r.logger)
|
||||||
|
gearHandler := handlers.NewGearHandler(gearService, r.logger)
|
||||||
|
|
||||||
|
inventory := router.Group("/inventory")
|
||||||
|
inventory.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(inventory)
|
||||||
|
{
|
||||||
|
inventory.GET("/gear", gearHandler.ListGear)
|
||||||
|
inventory.POST("/gear", gearHandler.CreateGear)
|
||||||
|
inventory.GET("/gear/:id", gearHandler.GetGear)
|
||||||
|
inventory.PUT("/gear/:id", gearHandler.UpdateGear)
|
||||||
|
inventory.DELETE("/gear/:id", gearHandler.DeleteGear)
|
||||||
|
}
|
||||||
|
}
|
||||||
29
veza-backend-api/internal/api/routes_live.go
Normal file
29
veza-backend-api/internal/api/routes_live.go
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
"veza-backend-api/internal/repositories"
|
||||||
|
"veza-backend-api/internal/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupLiveRoutes configure les routes live streams
|
||||||
|
func (r *APIRouter) setupLiveRoutes(router *gin.RouterGroup) {
|
||||||
|
liveStreamRepo := repositories.NewLiveStreamRepository(r.db.GormDB)
|
||||||
|
liveStreamService := services.NewLiveStreamService(liveStreamRepo)
|
||||||
|
liveStreamHandler := handlers.NewLiveStreamHandler(liveStreamService, r.logger)
|
||||||
|
|
||||||
|
live := router.Group("/live")
|
||||||
|
{
|
||||||
|
live.GET("/streams", liveStreamHandler.ListLiveStreams)
|
||||||
|
live.GET("/streams/:id", liveStreamHandler.GetLiveStream)
|
||||||
|
|
||||||
|
if r.config != nil && r.config.AuthMiddleware != nil {
|
||||||
|
protected := live.Group("")
|
||||||
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(protected)
|
||||||
|
protected.POST("/streams", liveStreamHandler.CreateLiveStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
veza-backend-api/internal/api/routes_marketplace.go
Normal file
72
veza-backend-api/internal/api/routes_marketplace.go
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"veza-backend-api/internal/core/marketplace"
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
"veza-backend-api/internal/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupMarketplaceRoutes configure les routes de la marketplace
|
||||||
|
func (r *APIRouter) setupMarketplaceRoutes(router *gin.RouterGroup) {
|
||||||
|
uploadDir := r.config.UploadDir
|
||||||
|
if uploadDir == "" {
|
||||||
|
uploadDir = "uploads/tracks"
|
||||||
|
}
|
||||||
|
|
||||||
|
storageService := services.NewTrackStorageService(uploadDir, false, r.logger)
|
||||||
|
marketService := marketplace.NewService(r.db.GormDB, r.logger, storageService)
|
||||||
|
marketHandler := handlers.NewMarketplaceHandler(marketService, r.logger)
|
||||||
|
|
||||||
|
group := router.Group("/marketplace")
|
||||||
|
group.GET("/products", marketHandler.ListProducts)
|
||||||
|
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
protected := group.Group("")
|
||||||
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(protected)
|
||||||
|
|
||||||
|
createGroup := protected.Group("")
|
||||||
|
createGroup.Use(r.config.AuthMiddleware.RequireContentCreatorRole())
|
||||||
|
createGroup.POST("/products", marketHandler.CreateProduct)
|
||||||
|
|
||||||
|
productOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
|
||||||
|
productIDStr := c.Param("id")
|
||||||
|
productID, err := uuid.Parse(productIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
product, err := marketService.GetProduct(c.Request.Context(), productID)
|
||||||
|
if err != nil {
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
return product.SellerID, nil
|
||||||
|
}
|
||||||
|
protected.PUT("/products/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("product", productOwnerResolver), marketHandler.UpdateProduct)
|
||||||
|
|
||||||
|
protected.GET("/orders", marketHandler.ListOrders)
|
||||||
|
protected.GET("/orders/:id", marketHandler.GetOrder)
|
||||||
|
protected.POST("/orders", marketHandler.CreateOrder)
|
||||||
|
protected.GET("/download/:product_id", marketHandler.GetDownloadURL)
|
||||||
|
|
||||||
|
marketplaceExtHandler := handlers.NewMarketplaceExtHandler(marketService, r.logger)
|
||||||
|
protected.GET("/wishlist", marketplaceExtHandler.GetWishlist)
|
||||||
|
protected.POST("/wishlist", marketplaceExtHandler.AddToWishlist)
|
||||||
|
protected.DELETE("/wishlist/:productId", marketplaceExtHandler.RemoveFromWishlist)
|
||||||
|
}
|
||||||
|
|
||||||
|
commerce := router.Group("/commerce")
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
cartProtected := commerce.Group("")
|
||||||
|
cartProtected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(cartProtected)
|
||||||
|
|
||||||
|
marketplaceExtHandler := handlers.NewMarketplaceExtHandler(marketService, r.logger)
|
||||||
|
cartProtected.GET("/cart", marketplaceExtHandler.GetCart)
|
||||||
|
cartProtected.POST("/cart/items", marketplaceExtHandler.AddToCart)
|
||||||
|
cartProtected.DELETE("/cart/items/:id", marketplaceExtHandler.RemoveFromCart)
|
||||||
|
cartProtected.POST("/cart/checkout", marketplaceExtHandler.Checkout)
|
||||||
|
}
|
||||||
|
}
|
||||||
80
veza-backend-api/internal/api/routes_playlists.go
Normal file
80
veza-backend-api/internal/api/routes_playlists.go
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
"veza-backend-api/internal/repositories"
|
||||||
|
"veza-backend-api/internal/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupPlaylistRoutes configure les routes pour les playlists
|
||||||
|
func (r *APIRouter) setupPlaylistRoutes(router *gin.RouterGroup) {
|
||||||
|
playlistRepo := repositories.NewPlaylistRepository(r.db.GormDB)
|
||||||
|
playlistTrackRepo := repositories.NewPlaylistTrackRepository(r.db.GormDB)
|
||||||
|
playlistCollaboratorRepo := repositories.NewPlaylistCollaboratorRepository(r.db.GormDB)
|
||||||
|
userRepo := repositories.NewGormUserRepository(r.db.GormDB)
|
||||||
|
|
||||||
|
playlistService := services.NewPlaylistService(
|
||||||
|
playlistRepo,
|
||||||
|
playlistTrackRepo,
|
||||||
|
playlistCollaboratorRepo,
|
||||||
|
userRepo,
|
||||||
|
r.logger,
|
||||||
|
)
|
||||||
|
|
||||||
|
playlistShareService := services.NewPlaylistShareService(r.db.GormDB)
|
||||||
|
playlistService.SetPlaylistShareService(playlistShareService)
|
||||||
|
|
||||||
|
playlistFollowService := services.NewPlaylistFollowService(r.db.GormDB, r.logger)
|
||||||
|
playlistService.SetPlaylistFollowService(playlistFollowService)
|
||||||
|
|
||||||
|
playlistHandler := handlers.NewPlaylistHandler(playlistService, r.db.GormDB, r.logger)
|
||||||
|
playlistHandler.SetPlaylistFollowService(playlistFollowService)
|
||||||
|
|
||||||
|
playlists := router.Group("/playlists")
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
playlists.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(playlists)
|
||||||
|
{
|
||||||
|
playlists.GET("", playlistHandler.GetPlaylists)
|
||||||
|
playlists.POST("", playlistHandler.CreatePlaylist)
|
||||||
|
playlists.GET("/search", playlistHandler.SearchPlaylists)
|
||||||
|
playlists.GET("/recommendations", playlistHandler.GetRecommendations)
|
||||||
|
playlists.GET("/:id", playlistHandler.GetPlaylist)
|
||||||
|
|
||||||
|
playlistOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
|
||||||
|
playlistIDStr := c.Param("id")
|
||||||
|
playlistID, err := uuid.Parse(playlistIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
playlist, err := playlistRepo.GetByID(c.Request.Context(), playlistID)
|
||||||
|
if err != nil {
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
return playlist.UserID, nil
|
||||||
|
}
|
||||||
|
playlists.PUT("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.UpdatePlaylist)
|
||||||
|
playlists.DELETE("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.DeletePlaylist)
|
||||||
|
|
||||||
|
playlists.POST("/:id/tracks", playlistHandler.AddTrack)
|
||||||
|
playlists.DELETE("/:id/tracks/:track_id", playlistHandler.RemoveTrack)
|
||||||
|
playlists.PUT("/:id/tracks/reorder", playlistHandler.ReorderTracks)
|
||||||
|
|
||||||
|
playlists.POST("/:id/collaborators", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.AddCollaborator)
|
||||||
|
playlists.GET("/:id/collaborators", playlistHandler.GetCollaborators)
|
||||||
|
playlists.PUT("/:id/collaborators/:userId", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.UpdateCollaboratorPermission)
|
||||||
|
playlists.DELETE("/:id/collaborators/:userId", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.RemoveCollaborator)
|
||||||
|
|
||||||
|
playlists.POST("/:id/share", r.config.AuthMiddleware.RequireOwnershipOrAdmin("playlist", playlistOwnerResolver), playlistHandler.CreateShareLink)
|
||||||
|
|
||||||
|
exportHandler := handlers.NewPlaylistExportHandler(playlistService)
|
||||||
|
playlists.GET("/:id/export/json", exportHandler.ExportPlaylistJSON)
|
||||||
|
playlists.GET("/:id/export/csv", exportHandler.ExportPlaylistCSV)
|
||||||
|
|
||||||
|
playlists.POST("/:id/duplicate", playlistHandler.DuplicatePlaylist)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
veza-backend-api/internal/api/routes_social.go
Normal file
37
veza-backend-api/internal/api/routes_social.go
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
socialcore "veza-backend-api/internal/core/social"
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupSocialRoutes configure les routes sociales
|
||||||
|
func (r *APIRouter) setupSocialRoutes(router *gin.RouterGroup) {
|
||||||
|
socialService := socialcore.NewService(r.db.GormDB, r.logger)
|
||||||
|
socialHandler := handlers.NewSocialHandler(socialService, r.logger)
|
||||||
|
groupHandler := handlers.NewGroupHandler(socialService, r.logger)
|
||||||
|
|
||||||
|
social := router.Group("/social")
|
||||||
|
{
|
||||||
|
social.GET("/feed", socialHandler.GetFeed)
|
||||||
|
social.GET("/posts/user/:user_id", socialHandler.GetPostsByUser)
|
||||||
|
social.GET("/groups", groupHandler.ListGroups)
|
||||||
|
social.GET("/groups/:id", groupHandler.GetGroup)
|
||||||
|
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
protected := social.Group("")
|
||||||
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(protected)
|
||||||
|
|
||||||
|
protected.POST("/posts", socialHandler.CreatePost)
|
||||||
|
protected.POST("/like", socialHandler.ToggleLike)
|
||||||
|
protected.POST("/comments", socialHandler.AddComment)
|
||||||
|
|
||||||
|
protected.POST("/groups", groupHandler.CreateGroup)
|
||||||
|
protected.POST("/groups/:id/join", groupHandler.JoinGroup)
|
||||||
|
protected.DELETE("/groups/:id/leave", groupHandler.LeaveGroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
156
veza-backend-api/internal/api/routes_tracks.go
Normal file
156
veza-backend-api/internal/api/routes_tracks.go
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupTrackRoutes configure les routes de gestion des tracks
|
||||||
|
func (r *APIRouter) setupTrackRoutes(router *gin.RouterGroup) {
|
||||||
|
uploadDir := r.config.UploadDir
|
||||||
|
if uploadDir == "" {
|
||||||
|
uploadDir = "uploads/tracks"
|
||||||
|
}
|
||||||
|
chunksDir := uploadDir + "/chunks"
|
||||||
|
|
||||||
|
trackService := trackcore.NewTrackService(r.db.GormDB, r.logger, uploadDir)
|
||||||
|
if r.config.CacheService != nil {
|
||||||
|
trackService.SetCacheService(r.config.CacheService)
|
||||||
|
}
|
||||||
|
trackUploadService := services.NewTrackUploadService(r.db.GormDB, r.logger)
|
||||||
|
var redisClient *redis.Client
|
||||||
|
if r.config != nil {
|
||||||
|
redisClient = r.config.RedisClient
|
||||||
|
}
|
||||||
|
chunkService := services.NewTrackChunkService(chunksDir, redisClient, r.logger)
|
||||||
|
likeService := services.NewTrackLikeService(r.db.GormDB, r.logger)
|
||||||
|
streamService := services.NewStreamServiceWithAPIKey(r.config.StreamServerURL, r.config.StreamServerInternalAPIKey, r.logger)
|
||||||
|
|
||||||
|
trackHandler := trackcore.NewTrackHandler(
|
||||||
|
trackService,
|
||||||
|
trackUploadService,
|
||||||
|
chunkService,
|
||||||
|
likeService,
|
||||||
|
streamService,
|
||||||
|
)
|
||||||
|
if r.config != nil && r.config.PermissionService != nil {
|
||||||
|
trackHandler.SetPermissionService(r.config.PermissionService)
|
||||||
|
}
|
||||||
|
uploadConfig := getUploadConfigWithEnv()
|
||||||
|
uploadValidator, err := services.NewUploadValidator(uploadConfig, r.logger)
|
||||||
|
if err != nil {
|
||||||
|
r.logger.Warn("Upload validator created with ClamAV unavailable - uploads will be rejected", zap.Error(err))
|
||||||
|
uploadConfig.ClamAVEnabled = false
|
||||||
|
uploadValidator, _ = services.NewUploadValidator(uploadConfig, r.logger)
|
||||||
|
}
|
||||||
|
trackHandler.SetUploadValidator(uploadValidator)
|
||||||
|
|
||||||
|
trackSearchService := services.NewTrackSearchService(r.db.GormDB)
|
||||||
|
trackHandler.SetSearchService(trackSearchService)
|
||||||
|
|
||||||
|
trackVersionService := services.NewTrackVersionService(r.db.GormDB, r.logger, uploadDir)
|
||||||
|
trackHandler.SetVersionService(trackVersionService)
|
||||||
|
|
||||||
|
playbackAnalyticsService := services.NewPlaybackAnalyticsService(r.db.GormDB, r.logger)
|
||||||
|
trackHandler.SetPlaybackAnalyticsService(playbackAnalyticsService)
|
||||||
|
|
||||||
|
tracks := router.Group("/tracks")
|
||||||
|
{
|
||||||
|
tracks.GET("", trackHandler.ListTracks)
|
||||||
|
tracks.GET("/search", trackHandler.SearchTracks)
|
||||||
|
tracks.GET("/:id", trackHandler.GetTrack)
|
||||||
|
tracks.GET("/:id/stats", trackHandler.GetTrackStats)
|
||||||
|
tracks.GET("/:id/history", trackHandler.GetTrackHistory)
|
||||||
|
tracks.GET("/:id/download", trackHandler.DownloadTrack)
|
||||||
|
tracks.GET("/shared/:token", trackHandler.GetSharedTrack)
|
||||||
|
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
protected := tracks.Group("")
|
||||||
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(protected)
|
||||||
|
|
||||||
|
uploadGroup := protected.Group("")
|
||||||
|
uploadGroup.Use(r.config.AuthMiddleware.RequireContentCreatorRole())
|
||||||
|
uploadGroup.POST("", trackHandler.UploadTrack)
|
||||||
|
|
||||||
|
trackOwnerResolver := func(c *gin.Context) (uuid.UUID, error) {
|
||||||
|
trackIDStr := c.Param("id")
|
||||||
|
trackID, err := uuid.Parse(trackIDStr)
|
||||||
|
if err != nil {
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
track, err := trackService.GetTrackByID(c.Request.Context(), trackID)
|
||||||
|
if err != nil {
|
||||||
|
return uuid.Nil, err
|
||||||
|
}
|
||||||
|
return track.UserID, nil
|
||||||
|
}
|
||||||
|
protected.PUT("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("track", trackOwnerResolver), trackHandler.UpdateTrack)
|
||||||
|
protected.DELETE("/:id", r.config.AuthMiddleware.RequireOwnershipOrAdmin("track", trackOwnerResolver), trackHandler.DeleteTrack)
|
||||||
|
|
||||||
|
protected.GET("/:id/status", trackHandler.GetUploadStatus)
|
||||||
|
protected.POST("/initiate", trackHandler.InitiateChunkedUpload)
|
||||||
|
protected.POST("/chunk", trackHandler.UploadChunk)
|
||||||
|
protected.POST("/complete", trackHandler.CompleteChunkedUpload)
|
||||||
|
protected.GET("/quota/:id", trackHandler.GetUploadQuota)
|
||||||
|
protected.GET("/resume/:uploadId", trackHandler.ResumeUpload)
|
||||||
|
|
||||||
|
protected.POST("/batch/delete", trackHandler.BatchDeleteTracks)
|
||||||
|
protected.POST("/batch/update", trackHandler.BatchUpdateTracks)
|
||||||
|
|
||||||
|
protected.POST("/:id/like", trackHandler.LikeTrack)
|
||||||
|
protected.DELETE("/:id/like", trackHandler.UnlikeTrack)
|
||||||
|
protected.GET("/:id/likes", trackHandler.GetTrackLikes)
|
||||||
|
|
||||||
|
protected.POST("/:id/share", trackHandler.CreateShare)
|
||||||
|
protected.DELETE("/share/:id", trackHandler.RevokeShare)
|
||||||
|
|
||||||
|
protected.POST("/:id/versions/:versionId/restore", trackHandler.RestoreVersion)
|
||||||
|
|
||||||
|
protected.POST("/:id/play", trackHandler.RecordPlay)
|
||||||
|
|
||||||
|
hlsOutputDir := r.config.UploadDir
|
||||||
|
if hlsOutputDir == "" {
|
||||||
|
hlsOutputDir = "uploads/tracks"
|
||||||
|
}
|
||||||
|
hlsService := services.NewHLSService(r.db.GormDB, hlsOutputDir, r.logger)
|
||||||
|
hlsHandler := handlers.NewHLSHandler(hlsService)
|
||||||
|
tracks.GET("/:id/hls/info", hlsHandler.GetStreamInfo)
|
||||||
|
tracks.GET("/:id/hls/status", hlsHandler.GetStreamStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commentService := services.NewCommentService(r.db.GormDB, r.logger)
|
||||||
|
commentHandler := handlers.NewCommentHandler(commentService, r.logger)
|
||||||
|
|
||||||
|
comments := router.Group("/tracks")
|
||||||
|
{
|
||||||
|
comments.GET("/:id/comments", commentHandler.GetComments)
|
||||||
|
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
protected := comments.Group("")
|
||||||
|
protected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(protected)
|
||||||
|
{
|
||||||
|
protected.POST("/:id/comments", commentHandler.CreateComment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commentsProtected := router.Group("/comments")
|
||||||
|
{
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
commentsProtected.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(commentsProtected)
|
||||||
|
{
|
||||||
|
commentsProtected.DELETE("/:id", commentHandler.DeleteComment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
151
veza-backend-api/internal/api/routes_users.go
Normal file
151
veza-backend-api/internal/api/routes_users.go
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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.NewTrackService(r.db.GormDB, r.logger, uploadDir)
|
||||||
|
if r.config.CacheService != nil {
|
||||||
|
trackService.SetCacheService(r.config.CacheService)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
streamService := services.NewStreamServiceWithAPIKey(r.config.StreamServerURL, r.config.StreamServerInternalAPIKey, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
veza-backend-api/internal/api/routes_webhooks.go
Normal file
43
veza-backend-api/internal/api/routes_webhooks.go
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"veza-backend-api/internal/handlers"
|
||||||
|
"veza-backend-api/internal/services"
|
||||||
|
"veza-backend-api/internal/workers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// setupWebhookRoutes configure les routes pour les webhooks
|
||||||
|
func (r *APIRouter) setupWebhookRoutes(router *gin.RouterGroup) {
|
||||||
|
webhookService := services.NewWebhookService(r.db.GormDB, r.logger, r.config.JWTSecret)
|
||||||
|
|
||||||
|
webhookWorker := workers.NewWebhookWorker(
|
||||||
|
r.db.GormDB,
|
||||||
|
webhookService,
|
||||||
|
r.logger,
|
||||||
|
100,
|
||||||
|
5,
|
||||||
|
3,
|
||||||
|
)
|
||||||
|
|
||||||
|
go webhookWorker.Start(context.Background())
|
||||||
|
|
||||||
|
webhookHandler := handlers.NewWebhookHandler(webhookService, webhookWorker, r.logger)
|
||||||
|
|
||||||
|
webhooks := router.Group("/webhooks")
|
||||||
|
if r.config.AuthMiddleware != nil {
|
||||||
|
webhooks.Use(r.config.AuthMiddleware.RequireAuth())
|
||||||
|
r.applyCSRFProtection(webhooks)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
webhooks.POST("", webhookHandler.RegisterWebhook())
|
||||||
|
webhooks.GET("", webhookHandler.ListWebhooks())
|
||||||
|
webhooks.DELETE("/:id", webhookHandler.DeleteWebhook())
|
||||||
|
webhooks.GET("/stats", webhookHandler.GetWebhookStats())
|
||||||
|
webhooks.POST("/:id/test", webhookHandler.TestWebhook())
|
||||||
|
webhooks.POST("/:id/regenerate-key", webhookHandler.RegenerateAPIKey())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue