sabisan/internal/app/handlers_admin_mutations.go

382 lines
13 KiB
Go
Raw Permalink Normal View History

2026-05-16 23:03:50 +00:00
package app
import (
"net/http"
"strconv"
"strings"
"archi_folio/internal/store"
)
func (s *Server) adminUpdateContent(w http.ResponseWriter, r *http.Request) {
if err := parseAdminForm(w, r, maxFormBytes); err != nil {
s.redirectAdmin(w, r, "main", "content form failed")
return
}
current, err := s.store.SiteContent(r.Context())
if err != nil {
s.redirectAdmin(w, r, "main", "content could not be loaded")
return
}
content := store.SiteContent{
2026-05-17 12:36:50 +00:00
HeroTitle: formValueOr(r, "hero_title", current.HeroTitle),
HeroSubtitle: formValueOr(r, "hero_subtitle", current.HeroSubtitle),
Positioning: formValueOr(r, "positioning", current.Positioning),
HeroCTALabel: formValueOr(r, "hero_cta_label", current.HeroCTALabel),
HeroCTAURL: formValueOr(r, "hero_cta_url", current.HeroCTAURL),
SecondaryCTALabel: formValueOr(r, "secondary_cta_label", current.SecondaryCTALabel),
SecondaryCTAURL: formValueOr(r, "secondary_cta_url", current.SecondaryCTAURL),
IntroTitle: formValueOr(r, "intro_title", current.IntroTitle),
IntroText: formValueOr(r, "intro_text", current.IntroText),
ServiceOneTitle: formValueOr(r, "service_one_title", current.ServiceOneTitle),
ServiceOneText: formValueOr(r, "service_one_text", current.ServiceOneText),
ServiceTwoTitle: formValueOr(r, "service_two_title", current.ServiceTwoTitle),
ServiceTwoText: formValueOr(r, "service_two_text", current.ServiceTwoText),
ServiceThreeTitle: formValueOr(r, "service_three_title", current.ServiceThreeTitle),
ServiceThreeText: formValueOr(r, "service_three_text", current.ServiceThreeText),
ProcessOneTitle: formValueOr(r, "process_one_title", current.ProcessOneTitle),
ProcessOneText: formValueOr(r, "process_one_text", current.ProcessOneText),
ProcessTwoTitle: formValueOr(r, "process_two_title", current.ProcessTwoTitle),
ProcessTwoText: formValueOr(r, "process_two_text", current.ProcessTwoText),
ProcessThreeTitle: formValueOr(r, "process_three_title", current.ProcessThreeTitle),
ProcessThreeText: formValueOr(r, "process_three_text", current.ProcessThreeText),
AboutName: formValueOr(r, "about_name", current.AboutName),
AboutRole: formValueOr(r, "about_role", current.AboutRole),
AboutBio: formValueOr(r, "about_bio", current.AboutBio),
StudioPhilosophy: formValueOr(r, "studio_philosophy", current.StudioPhilosophy),
StudioApproach: formValueOr(r, "studio_approach", current.StudioApproach),
StudioCredentials: formValueOr(r, "studio_credentials", current.StudioCredentials),
ServiceArea: formValueOr(r, "service_area", current.ServiceArea),
Email: current.Email,
Phone: current.Phone,
Location: current.Location,
HeroImage: formValueOr(r, "hero_image_current", current.HeroImage),
AboutImage: formValueOr(r, "about_image_current", current.AboutImage),
2026-05-16 23:03:50 +00:00
}
if err := validateContent(content); err != nil {
s.redirectAdmin(w, r, "main", err.Error())
return
}
if path, ok, err := s.saveUpload(r, "hero_image"); err != nil {
s.redirectAdmin(w, r, "main", "hero image "+err.Error())
return
} else if ok {
content.HeroImage = path
}
if path, ok, err := s.saveUpload(r, "about_image"); err != nil {
s.redirectAdmin(w, r, "main", "about image "+err.Error())
return
} else if ok {
content.AboutImage = path
}
if err := s.store.UpdateSiteContent(r.Context(), content); err != nil {
s.redirectAdmin(w, r, "main", "content could not be saved")
return
}
s.redirectAdmin(w, r, "main", "content saved")
}
func (s *Server) adminUpdateContactDetails(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
s.redirectAdmin(w, r, "contact-details", "contact details form failed")
return
}
content, err := s.store.SiteContent(r.Context())
if err != nil {
s.redirectAdmin(w, r, "contact-details", "contact details could not be loaded")
return
}
content.Email = strings.TrimSpace(r.FormValue("email"))
content.Phone = strings.TrimSpace(r.FormValue("phone"))
content.Location = strings.TrimSpace(r.FormValue("location"))
if err := validateContactDetails(content); err != nil {
s.redirectAdmin(w, r, "contact-details", err.Error())
return
}
if err := s.store.UpdateSiteContent(r.Context(), content); err != nil {
s.redirectAdmin(w, r, "contact-details", "contact details could not be saved")
return
}
s.redirectAdmin(w, r, "contact-details", "contact details saved")
}
func (s *Server) adminCreateProject(w http.ResponseWriter, r *http.Request) {
if err := parseAdminForm(w, r, maxFormBytes); err != nil {
s.redirectAdmin(w, r, "projects", "project form failed")
return
}
cover := "/static/placeholders/project-1.svg"
if path, ok, err := s.saveUpload(r, "cover_image"); err != nil {
s.redirectAdmin(w, r, "projects", "cover upload "+err.Error())
return
} else if ok {
cover = path
}
slug := strings.TrimSpace(r.FormValue("slug"))
if slug == "" {
slug = store.SlugFromTitle(r.FormValue("title"))
} else {
slug = store.SlugFromTitle(slug)
}
project := store.Project{
Slug: slug,
Title: strings.TrimSpace(r.FormValue("title")),
Location: strings.TrimSpace(r.FormValue("location")),
Year: strings.TrimSpace(r.FormValue("year")),
Category: strings.TrimSpace(r.FormValue("category")),
2026-05-17 12:36:50 +00:00
Summary: strings.TrimSpace(r.FormValue("summary")),
Scope: strings.TrimSpace(r.FormValue("scope")),
Status: strings.TrimSpace(r.FormValue("status")),
Position: formInt(r, "position"),
2026-05-16 23:03:50 +00:00
Description: strings.TrimSpace(r.FormValue("description")),
CoverImage: cover,
Featured: r.FormValue("featured") == "on",
}
if err := validateProject(project); err != nil {
s.redirectAdmin(w, r, "projects", err.Error())
return
}
id, err := s.store.CreateProject(r.Context(), project)
if err != nil {
s.redirectAdmin(w, r, "projects", "project could not be created")
return
}
_ = s.store.AddProjectImage(r.Context(), id, cover, r.FormValue("title"))
s.redirectAdmin(w, r, "projects", "project created")
}
func (s *Server) adminUpdateProject(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil {
http.NotFound(w, r)
return
}
if err := parseAdminForm(w, r, maxFormBytes); err != nil {
s.redirectAdmin(w, r, "projects", "project form failed")
return
}
cover := r.FormValue("cover_image_current")
if path, ok, err := s.saveUpload(r, "cover_image"); err != nil {
s.redirectAdmin(w, r, "projects", "cover upload "+err.Error())
return
} else if ok {
cover = path
}
slug := strings.TrimSpace(r.FormValue("slug"))
if slug == "" {
slug = store.SlugFromTitle(r.FormValue("title"))
} else {
slug = store.SlugFromTitle(slug)
}
project := store.Project{
ID: id,
Slug: slug,
Title: strings.TrimSpace(r.FormValue("title")),
Location: strings.TrimSpace(r.FormValue("location")),
Year: strings.TrimSpace(r.FormValue("year")),
Category: strings.TrimSpace(r.FormValue("category")),
2026-05-17 12:36:50 +00:00
Summary: strings.TrimSpace(r.FormValue("summary")),
Scope: strings.TrimSpace(r.FormValue("scope")),
Status: strings.TrimSpace(r.FormValue("status")),
Position: formInt(r, "position"),
2026-05-16 23:03:50 +00:00
Description: strings.TrimSpace(r.FormValue("description")),
CoverImage: cover,
Featured: r.FormValue("featured") == "on",
}
if err := validateProject(project); err != nil {
s.redirectAdmin(w, r, "projects", err.Error())
return
}
err = s.store.UpdateProject(r.Context(), project)
if err != nil {
s.redirectAdmin(w, r, "projects", "project could not be saved")
return
}
s.redirectAdmin(w, r, "projects", "project saved")
}
func (s *Server) adminDeleteProject(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err == nil {
err = s.store.DeleteProject(r.Context(), id)
}
if err != nil {
s.redirectAdmin(w, r, "projects", "project could not be deleted")
return
}
s.redirectAdmin(w, r, "projects", "project deleted")
}
func (s *Server) adminAddProjectImage(w http.ResponseWriter, r *http.Request) {
projectID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil {
http.NotFound(w, r)
return
}
if err := parseAdminForm(w, r, maxFormBytes); err != nil {
s.redirectAdmin(w, r, "projects", "image form failed")
return
}
path, ok, err := s.saveUpload(r, "image")
if err != nil || !ok {
if err != nil {
s.redirectAdmin(w, r, "projects", "image upload "+err.Error())
return
}
s.redirectAdmin(w, r, "projects", "image upload failed")
return
}
if err := s.store.AddProjectImage(r.Context(), projectID, path, r.FormValue("caption")); err != nil {
s.redirectAdmin(w, r, "projects", "image could not be added")
return
}
s.redirectAdmin(w, r, "projects", "image added")
}
func (s *Server) adminDeleteProjectImage(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err == nil {
err = s.store.DeleteProjectImage(r.Context(), id)
}
if err != nil {
s.redirectAdmin(w, r, "projects", "image could not be deleted")
return
}
s.redirectAdmin(w, r, "projects", "image deleted")
}
2026-05-17 12:36:50 +00:00
func (s *Server) adminCreateService(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
s.redirectAdmin(w, r, "services", "service form failed")
return
}
service := serviceFromForm(r, 0)
if err := validateService(service); err != nil {
s.redirectAdmin(w, r, "services", err.Error())
return
}
if err := s.store.CreateService(r.Context(), service); err != nil {
s.redirectAdmin(w, r, "services", "service could not be created")
return
}
s.redirectAdmin(w, r, "services", "service created")
}
func (s *Server) adminUpdateService(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil {
http.NotFound(w, r)
return
}
if err := r.ParseForm(); err != nil {
s.redirectAdmin(w, r, "services", "service form failed")
return
}
service := serviceFromForm(r, id)
if err := validateService(service); err != nil {
s.redirectAdmin(w, r, "services", err.Error())
return
}
if err := s.store.UpdateService(r.Context(), service); err != nil {
s.redirectAdmin(w, r, "services", "service could not be saved")
return
}
s.redirectAdmin(w, r, "services", "service saved")
}
func (s *Server) adminDeleteService(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err == nil {
err = s.store.DeleteService(r.Context(), id)
}
if err != nil {
s.redirectAdmin(w, r, "services", "service could not be deleted")
return
}
s.redirectAdmin(w, r, "services", "service deleted")
}
func (s *Server) adminCreateFAQ(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
s.redirectAdmin(w, r, "services", "FAQ form failed")
return
}
faq := faqFromForm(r, 0)
if err := validateFAQ(faq); err != nil {
s.redirectAdmin(w, r, "services", err.Error())
return
}
if err := s.store.CreateFAQ(r.Context(), faq); err != nil {
s.redirectAdmin(w, r, "services", "FAQ could not be created")
return
}
s.redirectAdmin(w, r, "services", "FAQ created")
}
func (s *Server) adminUpdateFAQ(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil {
http.NotFound(w, r)
return
}
if err := r.ParseForm(); err != nil {
s.redirectAdmin(w, r, "services", "FAQ form failed")
return
}
faq := faqFromForm(r, id)
if err := validateFAQ(faq); err != nil {
s.redirectAdmin(w, r, "services", err.Error())
return
}
if err := s.store.UpdateFAQ(r.Context(), faq); err != nil {
s.redirectAdmin(w, r, "services", "FAQ could not be saved")
return
}
s.redirectAdmin(w, r, "services", "FAQ saved")
}
func (s *Server) adminDeleteFAQ(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err == nil {
err = s.store.DeleteFAQ(r.Context(), id)
}
if err != nil {
s.redirectAdmin(w, r, "services", "FAQ could not be deleted")
return
}
s.redirectAdmin(w, r, "services", "FAQ deleted")
}
func serviceFromForm(r *http.Request, id int64) store.Service {
return store.Service{
ID: id,
Title: strings.TrimSpace(r.FormValue("title")),
Summary: strings.TrimSpace(r.FormValue("summary")),
Details: strings.TrimSpace(r.FormValue("details")),
Position: formInt(r, "position"),
Active: r.FormValue("active") == "on",
}
}
func faqFromForm(r *http.Request, id int64) store.FAQ {
return store.FAQ{
ID: id,
Question: strings.TrimSpace(r.FormValue("question")),
Answer: strings.TrimSpace(r.FormValue("answer")),
Position: formInt(r, "position"),
Active: r.FormValue("active") == "on",
}
}
func formInt(r *http.Request, name string) int {
value, _ := strconv.Atoi(strings.TrimSpace(r.FormValue(name)))
return value
}
func formValueOr(r *http.Request, name, fallback string) string {
if _, ok := r.Form[name]; !ok {
return fallback
}
return strings.TrimSpace(r.FormValue(name))
}