package handler import ( "encoding/json" "errors" "net/http" "strconv" "github.com/panelhosting/panel/internal/auth" "github.com/panelhosting/panel/internal/middleware" "github.com/panelhosting/panel/internal/sitesvc" ) type SiteHandler struct { svc *sitesvc.Service } func NewSiteHandler(svc *sitesvc.Service) *SiteHandler { return &SiteHandler{svc: svc} } type createSiteRequest struct { Name string `json:"name"` Domain string `json:"domain"` PHPVersion string `json:"php_version"` SSLEmail string `json:"ssl_email"` ServerID int64 `json:"server_id,omitempty"` IssueSSL *bool `json:"issue_ssl"` } type reissueSSLRequest struct { SSLEmail string `json:"ssl_email"` } func (h *SiteHandler) List(w http.ResponseWriter, r *http.Request) { user, ok := middleware.UserFromContext(r.Context()) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } sites, err := h.svc.List(r.Context(), user, middleware.IsAdmin(user)) if err != nil { writeError(w, http.StatusInternalServerError, "failed to list sites") return } writeJSON(w, http.StatusOK, map[string]any{"sites": sites}) } func (h *SiteHandler) Create(w http.ResponseWriter, r *http.Request) { user, ok := middleware.UserFromContext(r.Context()) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } var req createSiteRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid json") return } issueSSL := true if req.IssueSSL != nil { issueSSL = *req.IssueSSL } site, err := h.svc.Create(r.Context(), sitesvc.CreateInput{ Name: req.Name, Domain: req.Domain, PHPVersion: req.PHPVersion, SSLEmail: req.SSLEmail, ServerID: req.ServerID, OwnerID: user.ID, IsAdmin: middleware.IsAdmin(user), IssueSSL: issueSSL, }) if err != nil { switch { case errors.Is(err, sitesvc.ErrInvalidSiteName), errors.Is(err, sitesvc.ErrInvalidDomain), errors.Is(err, sitesvc.ErrInvalidPHPVersion), errors.Is(err, sitesvc.ErrInvalidSSLEmail), errors.Is(err, sitesvc.ErrSSLEmailRequired): writeError(w, http.StatusBadRequest, err.Error()) default: writeError(w, http.StatusInternalServerError, "failed to create site: "+err.Error()) } return } writeJSON(w, http.StatusCreated, map[string]any{"site": site}) } func (h *SiteHandler) PHPVersions(w http.ResponseWriter, r *http.Request) { versions, err := h.svc.ListPHPVersions(r.Context()) if err != nil { writeError(w, http.StatusInternalServerError, "failed to list php versions") return } writeJSON(w, http.StatusOK, map[string]any{"versions": versions}) } func (h *SiteHandler) ReissueSSL(w http.ResponseWriter, r *http.Request) { _, ok := middleware.UserFromContext(r.Context()) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } siteID, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { writeError(w, http.StatusBadRequest, "invalid site id") return } var req reissueSSLRequest _ = json.NewDecoder(r.Body).Decode(&req) if req.SSLEmail != "" { if err := auth.ValidateEmail(req.SSLEmail); err != nil { writeError(w, http.StatusBadRequest, "invalid ssl email") return } } h.svc.ReissueSSLAsync(siteID, req.SSLEmail) writeJSON(w, http.StatusOK, map[string]string{"message": "ssl issuance started"}) }