| | package api
|
| |
|
| | import (
|
| | "encoding/base64"
|
| | "errors"
|
| | "fmt"
|
| | "net/http"
|
| | "strings"
|
| | "time"
|
| |
|
| | "github.com/gin-gonic/gin"
|
| | "go.uber.org/fx"
|
| |
|
| | "github.com/looplj/axonhub/internal/build"
|
| | "github.com/looplj/axonhub/internal/log"
|
| | "github.com/looplj/axonhub/internal/server/assets"
|
| | "github.com/looplj/axonhub/internal/server/biz"
|
| | )
|
| |
|
| | type SystemHandlersParams struct {
|
| | fx.In
|
| |
|
| | SystemService *biz.SystemService
|
| | }
|
| |
|
| | func NewSystemHandlers(params SystemHandlersParams) *SystemHandlers {
|
| | return &SystemHandlers{
|
| | SystemService: params.SystemService,
|
| | }
|
| | }
|
| |
|
| | type SystemHandlers struct {
|
| | SystemService *biz.SystemService
|
| | }
|
| |
|
| |
|
| | type SystemStatusResponse struct {
|
| | IsInitialized bool `json:"isInitialized"`
|
| | }
|
| |
|
| |
|
| | type HealthResponse struct {
|
| | Status string `json:"status"`
|
| | Timestamp time.Time `json:"timestamp"`
|
| | Version string `json:"version"`
|
| | Build build.Info `json:"build"`
|
| | Uptime string `json:"uptime"`
|
| | }
|
| |
|
| |
|
| | type InitializeSystemRequest struct {
|
| | OwnerEmail string `json:"ownerEmail" binding:"required,email"`
|
| | OwnerPassword string `json:"ownerPassword" binding:"required,min=6"`
|
| | OwnerFirstName string `json:"ownerFirstName" binding:"required"`
|
| | OwnerLastName string `json:"ownerLastName" binding:"required"`
|
| | BrandName string `json:"brandName" binding:"required"`
|
| | }
|
| |
|
| |
|
| | type InitializeSystemResponse struct {
|
| | Success bool `json:"success"`
|
| | Message string `json:"message"`
|
| | }
|
| |
|
| |
|
| | func (h *SystemHandlers) GetSystemStatus(c *gin.Context) {
|
| | isInitialized, err := h.SystemService.IsInitialized(c.Request.Context())
|
| | if err != nil {
|
| | JSONError(c, http.StatusInternalServerError, errors.New("Failed to check system status"))
|
| | return
|
| | }
|
| |
|
| | c.JSON(http.StatusOK, SystemStatusResponse{
|
| | IsInitialized: isInitialized,
|
| | })
|
| | }
|
| |
|
| |
|
| | func (h *SystemHandlers) Health(c *gin.Context) {
|
| | buildInfo := build.GetBuildInfo()
|
| |
|
| | c.JSON(http.StatusOK, HealthResponse{
|
| | Status: "healthy",
|
| | Timestamp: time.Now(),
|
| | Version: build.Version,
|
| | Build: buildInfo,
|
| | Uptime: buildInfo.Uptime,
|
| | })
|
| | }
|
| |
|
| |
|
| | func (h *SystemHandlers) InitializeSystem(c *gin.Context) {
|
| | var req InitializeSystemRequest
|
| |
|
| | err := c.ShouldBindJSON(&req)
|
| | if err != nil {
|
| | c.JSON(http.StatusBadRequest, InitializeSystemResponse{
|
| | Success: false,
|
| | Message: "Invalid request format",
|
| | })
|
| |
|
| | return
|
| | }
|
| |
|
| |
|
| | isInitialized, err := h.SystemService.IsInitialized(c.Request.Context())
|
| | if err != nil {
|
| | JSONError(c, http.StatusInternalServerError, errors.New("Failed to check initialization status"))
|
| | return
|
| | }
|
| |
|
| | if isInitialized {
|
| | c.JSON(http.StatusBadRequest, InitializeSystemResponse{
|
| | Success: false,
|
| | Message: "System is already initialized",
|
| | })
|
| |
|
| | return
|
| | }
|
| |
|
| |
|
| | err = h.SystemService.Initialize(c.Request.Context(), &biz.InitializeSystemParams{
|
| | OwnerEmail: req.OwnerEmail,
|
| | OwnerPassword: req.OwnerPassword,
|
| | OwnerFirstName: req.OwnerFirstName,
|
| | OwnerLastName: req.OwnerLastName,
|
| | BrandName: req.BrandName,
|
| | })
|
| | if err != nil {
|
| | c.JSON(http.StatusInternalServerError, InitializeSystemResponse{
|
| | Success: false,
|
| | Message: fmt.Sprintf("Failed to initialize system: %v", err),
|
| | })
|
| |
|
| | return
|
| | }
|
| |
|
| | c.JSON(http.StatusOK, InitializeSystemResponse{
|
| | Success: true,
|
| | Message: "System initialized successfully",
|
| | })
|
| | }
|
| |
|
| |
|
| | func (h *SystemHandlers) GetFavicon(c *gin.Context) {
|
| | ctx := c.Request.Context()
|
| |
|
| | brandLogo, err := h.SystemService.BrandLogo(ctx)
|
| | if err != nil {
|
| | log.Error(ctx, "Failed to get brand logo", log.Cause(err))
|
| | }
|
| |
|
| |
|
| | if brandLogo == "" {
|
| | defaultFaviconData, err := assets.Favicon.ReadFile("favicon.ico")
|
| | if err != nil {
|
| | JSONError(c, http.StatusInternalServerError, errors.New("Failed to read default favicon"))
|
| | return
|
| | }
|
| |
|
| | c.Header("Content-Type", "image/x-icon")
|
| | c.Header("Cache-Control", "public, max-age=3600")
|
| | c.Data(http.StatusOK, "image/x-icon", defaultFaviconData)
|
| |
|
| | return
|
| | }
|
| |
|
| |
|
| |
|
| | if !strings.HasPrefix(brandLogo, "data:") {
|
| | JSONError(c, http.StatusBadRequest, errors.New("Invalid brand logo format"))
|
| | return
|
| | }
|
| |
|
| |
|
| | parts := strings.Split(brandLogo, ",")
|
| | if len(parts) != 2 {
|
| | JSONError(c, http.StatusBadRequest, errors.New("Invalid brand logo format"))
|
| | return
|
| | }
|
| |
|
| |
|
| | headerPart := parts[0]
|
| | mimeStart := strings.Index(headerPart, ":")
|
| |
|
| | mimeEnd := strings.Index(headerPart, ";")
|
| | if mimeStart == -1 || mimeEnd == -1 {
|
| | JSONError(c, http.StatusBadRequest, errors.New("Invalid brand logo format"))
|
| | return
|
| | }
|
| |
|
| | mimeType := headerPart[mimeStart+1 : mimeEnd]
|
| |
|
| |
|
| | imageData, err := base64.StdEncoding.DecodeString(parts[1])
|
| | if err != nil {
|
| | JSONError(c, http.StatusBadRequest, errors.New("Failed to decode brand logo"))
|
| | return
|
| | }
|
| |
|
| |
|
| | c.Header("Content-Type", mimeType)
|
| | c.Header("Cache-Control", "public, max-age=3600")
|
| | c.Header("Content-Length", fmt.Sprintf("%d", len(imageData)))
|
| |
|
| |
|
| | c.Data(http.StatusOK, mimeType, imageData)
|
| | }
|
| |
|