5.0 KB
partials.go
package controllers
import (
"fmt"
"net/http"
"github.com/readysite/readysite/pkg/application"
"github.com/readysite/readysite/website/internal/access"
"github.com/readysite/readysite/website/internal/helpers"
"github.com/readysite/readysite/website/internal/content"
"github.com/readysite/readysite/website/models"
)
// Partials returns the partials controller.
func Partials() (string, *PartialsController) {
return "partials", &PartialsController{}
}
// PartialsController handles partial CRUD operations.
type PartialsController struct {
application.BaseController
}
// Setup registers routes.
func (c *PartialsController) Setup(app *application.App) {
c.BaseController.Setup(app)
}
// Handle implements Controller interface with value receiver for request isolation.
func (c PartialsController) Handle(r *http.Request) application.Controller {
c.Request = r
return &c
}
// Partial returns the current partial from path parameter.
func (c *PartialsController) Partial() *models.Partial {
if c.Request == nil {
return nil
}
id := c.PathValue("id")
if id == "" {
return nil
}
partial, err := models.Partials.Get(id)
if err != nil {
return nil
}
return partial
}
// Partials returns all partials.
func (c *PartialsController) Partials() []*models.Partial {
partials, _ := models.Partials.Search("ORDER BY Name")
return partials
}
// Create creates a new partial.
func (c *PartialsController) Create(w http.ResponseWriter, r *http.Request) {
slug := r.FormValue("slug")
name := r.FormValue("name")
description := r.FormValue("description")
html := r.FormValue("html")
// Validate slug if provided
if slug != "" {
if err := content.ValidateSlug(slug); err != nil {
c.RenderError(w, r, err)
return
}
// Check if slug is already used
if existing, _ := models.Partials.Get(slug); existing != nil {
c.RenderError(w, r, fmt.Errorf("A partial with this ID already exists"))
return
}
}
// Validate partial input fields
if err := content.ValidateName(name); err != nil {
c.RenderError(w, r, err)
return
}
if err := content.ValidateDescription(description); err != nil {
c.RenderError(w, r, err)
return
}
if err := content.ValidateHTML(html); err != nil {
c.RenderError(w, r, err)
return
}
partial := &models.Partial{
Name: name,
Description: description,
HTML: html,
Published: r.FormValue("published") == "on" || r.FormValue("published") == "true",
}
// Use slug as ID if provided
if slug != "" {
partial.ID = slug
}
id, err := models.Partials.Insert(partial)
if err != nil {
c.RenderError(w, r, fmt.Errorf("Failed to create partial: %w", err))
return
}
// Audit log
userID := ""
if user := access.GetUserFromJWT(r); user != nil {
userID = user.ID
}
helpers.AuditCreate(r, userID, "partial", id, partial.Name)
w.Header().Set("HX-Trigger", `{"showToast":"Partial created"}`)
c.Redirect(w, r, "/admin/partial/"+id)
}
// Update updates an existing partial.
func (c *PartialsController) Update(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
name := r.FormValue("name")
description := r.FormValue("description")
html := r.FormValue("html")
// Validate partial input fields
if err := content.ValidateName(name); err != nil {
c.RenderError(w, r, err)
return
}
if err := content.ValidateDescription(description); err != nil {
c.RenderError(w, r, err)
return
}
if err := content.ValidateHTML(html); err != nil {
c.RenderError(w, r, err)
return
}
partial, err := models.Partials.Get(id)
if err != nil {
c.RenderError(w, r, fmt.Errorf("Partial not found"))
return
}
// Check for concurrent edit conflict using UpdatedAt
expectedVersion := r.FormValue("version")
if expectedVersion != "" && partial.UpdatedAt.Format("2006-01-02T15:04:05") != expectedVersion {
c.RenderError(w, r, fmt.Errorf("This partial was modified by another user. Please reload and try again."))
return
}
partial.Name = name
partial.Description = description
partial.HTML = html
partial.Published = r.FormValue("published") == "on" || r.FormValue("published") == "true"
if err := models.Partials.Update(partial); err != nil {
c.RenderError(w, r, fmt.Errorf("Failed to update partial: %w", err))
return
}
// Audit log
userID := ""
if user := access.GetUserFromJWT(r); user != nil {
userID = user.ID
}
helpers.AuditUpdate(r, userID, "partial", id, partial.Name, nil)
w.Header().Set("HX-Trigger", `{"showToast":"Partial saved"}`)
c.Refresh(w, r)
}
// Delete deletes a partial.
func (c *PartialsController) Delete(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
partial, err := models.Partials.Get(id)
if err != nil {
c.RenderError(w, r, fmt.Errorf("Partial not found"))
return
}
if err := models.Partials.Delete(partial); err != nil {
c.RenderError(w, r, fmt.Errorf("Failed to delete partial: %w", err))
return
}
// Audit log
userID := ""
if user := access.GetUserFromJWT(r); user != nil {
userID = user.ID
}
helpers.AuditDelete(r, userID, "partial", id, partial.Name)
c.Redirect(w, r, "/admin/partials")
}