247 lines
6.5 KiB
Go
247 lines
6.5 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/imc-vibe/backend/internal/api/handlers"
|
|
"github.com/imc-vibe/backend/internal/auth"
|
|
"github.com/imc-vibe/backend/internal/config"
|
|
"github.com/imc-vibe/backend/internal/db"
|
|
)
|
|
|
|
type Router struct {
|
|
authHandler *handlers.AuthHandler
|
|
domainHandler *handlers.DomainHandler
|
|
userHandler *handlers.UserHandler
|
|
aliasHandler *handlers.AliasHandler
|
|
statsHandler *handlers.StatsHandler
|
|
queueHandler *handlers.QueueHandler
|
|
logsHandler *handlers.LogsHandler
|
|
jwtManager *auth.JWTManager
|
|
db *db.DB
|
|
}
|
|
|
|
func New(database *db.DB, cfg *config.Config) *Router {
|
|
jwtManager := auth.NewJWTManager(cfg.JWTSecret, "imc-vibe")
|
|
|
|
return &Router{
|
|
authHandler: handlers.NewAuthHandler(database, jwtManager),
|
|
domainHandler: handlers.NewDomainHandler(database),
|
|
userHandler: handlers.NewUserHandler(database),
|
|
aliasHandler: handlers.NewAliasHandler(database),
|
|
statsHandler: handlers.NewStatsHandler(database),
|
|
queueHandler: handlers.NewQueueHandler(),
|
|
logsHandler: handlers.NewLogsHandler(),
|
|
jwtManager: jwtManager,
|
|
db: database,
|
|
}
|
|
}
|
|
|
|
func (r *Router) Handler() http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
path := req.URL.Path
|
|
|
|
// Only handle /api/* routes
|
|
if !strings.HasPrefix(path, "/api/") {
|
|
http.NotFound(w, req)
|
|
return
|
|
}
|
|
|
|
// Public routes - no auth required
|
|
switch path {
|
|
case "/api/auth/login":
|
|
r.authHandler.Login(w, req)
|
|
return
|
|
case "/api/auth/forgot":
|
|
r.authHandler.ForgotPassword(w, req)
|
|
return
|
|
case "/api/auth/logout":
|
|
r.authHandler.Logout(w, req)
|
|
return
|
|
}
|
|
|
|
// Protected routes - auth required
|
|
req = r.validateAuth(req)
|
|
if req == nil {
|
|
http.Error(w, `{"error":"not authenticated"}`, http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
switch {
|
|
case path == "/api/auth/me":
|
|
r.authHandler.Me(w, req)
|
|
case path == "/api/auth/change-password":
|
|
r.authHandler.ChangePassword(w, req)
|
|
case path == "/api/stats":
|
|
r.statsHandler.Get(w, req)
|
|
case strings.HasPrefix(path, "/api/domains/"):
|
|
if strings.Contains(strings.TrimPrefix(path, "/api/domains/"), "/users") {
|
|
r.handleDomainUsers(w, req)
|
|
} else if strings.Contains(strings.TrimPrefix(path, "/api/domains/"), "/aliases") {
|
|
r.handleDomainAliases(w, req)
|
|
} else {
|
|
r.handleDomains(w, req)
|
|
}
|
|
case strings.HasPrefix(path, "/api/domains"):
|
|
r.handleDomains(w, req)
|
|
case strings.HasPrefix(path, "/api/queue"):
|
|
r.handleQueue(w, req)
|
|
case path == "/api/logs":
|
|
r.logsHandler.List(w, req)
|
|
default:
|
|
http.NotFound(w, req)
|
|
}
|
|
})
|
|
}
|
|
|
|
func (r *Router) validateAuth(req *http.Request) *http.Request {
|
|
authHeader := req.Header.Get("Authorization")
|
|
if authHeader == "" {
|
|
return nil
|
|
}
|
|
|
|
parts := strings.SplitN(authHeader, " ", 2)
|
|
if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
|
|
return nil
|
|
}
|
|
|
|
claims, err := r.jwtManager.ValidateToken(parts[1])
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
authCtx := &auth.Context{
|
|
UserID: claims.UserID,
|
|
Username: claims.Username,
|
|
Role: auth.Role(claims.Role),
|
|
}
|
|
|
|
ctx := context.WithValue(req.Context(), handlers.AuthContextKey, authCtx)
|
|
return req.WithContext(ctx)
|
|
}
|
|
|
|
func (r *Router) handleDomains(w http.ResponseWriter, req *http.Request) {
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if len(req.URL.Path) > len("/api/domains/") {
|
|
r.domainHandler.Get(w, req)
|
|
} else {
|
|
r.domainHandler.List(w, req)
|
|
}
|
|
case http.MethodPost:
|
|
r.domainHandler.Create(w, req)
|
|
case http.MethodDelete:
|
|
r.domainHandler.Delete(w, req)
|
|
default:
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
}
|
|
|
|
func (r *Router) handleDomainUsers(w http.ResponseWriter, req *http.Request) {
|
|
path := req.URL.Path
|
|
parts := strings.Split(strings.TrimPrefix(path, "/api/domains/"), "/")
|
|
if len(parts) < 2 || parts[1] != "users" {
|
|
http.NotFound(w, req)
|
|
return
|
|
}
|
|
|
|
domainName := parts[0]
|
|
var idStr string
|
|
if len(parts) >= 3 {
|
|
idStr = parts[2]
|
|
}
|
|
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
if idStr != "" {
|
|
req.URL.Path = "/api/domains/" + domainName + "/users/" + idStr
|
|
r.userHandler.Get(w, req)
|
|
} else {
|
|
req.URL.Path = "/api/domains/" + domainName + "/users"
|
|
r.userHandler.List(w, req)
|
|
}
|
|
case http.MethodPost:
|
|
req.URL.Path = "/api/domains/" + domainName + "/users"
|
|
r.userHandler.Create(w, req)
|
|
case http.MethodPut:
|
|
if idStr != "" {
|
|
req.URL.Path = "/api/domains/" + domainName + "/users/" + idStr
|
|
r.userHandler.Update(w, req)
|
|
} else {
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
case http.MethodDelete:
|
|
if idStr != "" {
|
|
req.URL.Path = "/api/domains/" + domainName + "/users/" + idStr
|
|
r.userHandler.Delete(w, req)
|
|
} else {
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
default:
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
}
|
|
|
|
func (r *Router) handleDomainAliases(w http.ResponseWriter, req *http.Request) {
|
|
path := req.URL.Path
|
|
parts := strings.Split(strings.TrimPrefix(path, "/api/domains/"), "/")
|
|
if len(parts) < 2 || parts[1] != "aliases" {
|
|
http.NotFound(w, req)
|
|
return
|
|
}
|
|
|
|
domainName := parts[0]
|
|
var idStr string
|
|
if len(parts) >= 3 {
|
|
idStr = parts[2]
|
|
}
|
|
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
req.URL.Path = "/api/domains/" + domainName + "/aliases"
|
|
r.aliasHandler.List(w, req)
|
|
case http.MethodPost:
|
|
req.URL.Path = "/api/domains/" + domainName + "/aliases"
|
|
r.aliasHandler.Create(w, req)
|
|
case http.MethodDelete:
|
|
if idStr != "" {
|
|
req.URL.Path = "/api/domains/" + domainName + "/aliases/" + idStr
|
|
r.aliasHandler.Delete(w, req)
|
|
} else {
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
default:
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
}
|
|
|
|
func (r *Router) handleQueue(w http.ResponseWriter, req *http.Request) {
|
|
path := req.URL.Path
|
|
id := ""
|
|
if len(path) > len("/api/queue/") {
|
|
id = path[len("/api/queue/"):]
|
|
}
|
|
|
|
switch req.Method {
|
|
case http.MethodGet:
|
|
r.queueHandler.List(w, req)
|
|
case http.MethodPost:
|
|
if id != "" {
|
|
req.URL.Path = "/api/queue/" + id
|
|
r.queueHandler.Requeue(w, req)
|
|
} else {
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
case http.MethodDelete:
|
|
if id != "" {
|
|
req.URL.Path = "/api/queue/" + id
|
|
r.queueHandler.Delete(w, req)
|
|
} else {
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
default:
|
|
http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
|
|
}
|
|
}
|