- Added CertificateHandler for listing certificates. - Created health check handler for service metadata. - Introduced ImportHandler for handling Caddyfile imports. - Developed ProxyHostHandler for CRUD operations on proxy hosts. - Added RemoteServerHandler for managing remote servers. - Implemented UserHandler for initial setup and user management. - Created authentication middleware for secure API access. - Registered all handlers and routes in the main API router. - Added tests for proxy host and remote server handlers.
114 lines
2.8 KiB
Go
114 lines
2.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/Wikid82/CaddyProxyManagerPlus/backend/internal/models"
|
|
)
|
|
|
|
type UserHandler struct {
|
|
DB *gorm.DB
|
|
}
|
|
|
|
func NewUserHandler(db *gorm.DB) *UserHandler {
|
|
return &UserHandler{DB: db}
|
|
}
|
|
|
|
func (h *UserHandler) RegisterRoutes(r *gin.RouterGroup) {
|
|
r.GET("/setup", h.GetSetupStatus)
|
|
r.POST("/setup", h.Setup)
|
|
}
|
|
|
|
// GetSetupStatus checks if the application needs initial setup (i.e., no users exist).
|
|
func (h *UserHandler) GetSetupStatus(c *gin.Context) {
|
|
var count int64
|
|
if err := h.DB.Model(&models.User{}).Count(&count).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check setup status"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"setupRequired": count == 0,
|
|
})
|
|
}
|
|
|
|
type SetupRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Email string `json:"email" binding:"required,email"`
|
|
Password string `json:"password" binding:"required,min=8"`
|
|
}
|
|
|
|
// Setup creates the initial admin user and configures the ACME email.
|
|
func (h *UserHandler) Setup(c *gin.Context) {
|
|
// 1. Check if setup is allowed
|
|
var count int64
|
|
if err := h.DB.Model(&models.User{}).Count(&count).Error; err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to check setup status"})
|
|
return
|
|
}
|
|
|
|
if count > 0 {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "Setup already completed"})
|
|
return
|
|
}
|
|
|
|
// 2. Parse request
|
|
var req SetupRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// 3. Create User
|
|
user := models.User{
|
|
UUID: uuid.New().String(),
|
|
Name: req.Name,
|
|
Email: req.Email,
|
|
Role: "admin",
|
|
Enabled: true,
|
|
}
|
|
|
|
if err := user.SetPassword(req.Password); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to hash password"})
|
|
return
|
|
}
|
|
|
|
// 4. Create Setting for ACME Email
|
|
acmeEmailSetting := models.Setting{
|
|
Key: "caddy.acme_email",
|
|
Value: req.Email,
|
|
Type: "string",
|
|
Category: "caddy",
|
|
}
|
|
|
|
// Transaction to ensure both succeed
|
|
err := h.DB.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Create(&user).Error; err != nil {
|
|
return err
|
|
}
|
|
// Use Save to update if exists (though it shouldn't in fresh setup) or create
|
|
if err := tx.Where(models.Setting{Key: "caddy.acme_email"}).Assign(models.Setting{Value: req.Email}).FirstOrCreate(&acmeEmailSetting).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to complete setup: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, gin.H{
|
|
"message": "Setup completed successfully",
|
|
"user": gin.H{
|
|
"id": user.ID,
|
|
"email": user.Email,
|
|
"name": user.Name,
|
|
},
|
|
})
|
|
}
|