Slug-based RSS URLs and success flash messages
Build and Deploy / build-and-deploy (push) Successful in 45s

- Add podcast_slug to users with global uniqueness check
- RSS available at /rss/{slug} (path-based) with legacy ?slug= fallback
- Slug field in dashboard settings with validation (lowercase, hyphens)
- JS flash messages for success/error after form submissions
- Remove unused imports
This commit is contained in:
2026-07-08 09:29:00 -04:00
parent d70ed1943f
commit b179f57628
7 changed files with 111 additions and 29 deletions
+25 -3
View File
@@ -4,10 +4,13 @@ import (
"net/http"
"os"
"path/filepath"
"regexp"
"podstalk/store"
)
var slugRe = regexp.MustCompile(`^[a-z0-9]+(-[a-z0-9]+)*$`)
type SettingsHandler struct {
Store *store.Store
UploadDir string
@@ -36,6 +39,26 @@ func (h *SettingsHandler) ServeSettings(w http.ResponseWriter, r *http.Request)
title = user.PodcastTitle
}
slug := r.FormValue("podcast_slug")
if slug == "" {
slug = user.PodcastSlug
}
if slug != "" {
if !slugRe.MatchString(slug) {
http.Redirect(w, r, "/?error=slug+must+be+lowercase+letters+numbers+and+hyphens", http.StatusSeeOther)
return
}
taken, err := h.Store.SlugTaken(slug, userID)
if err != nil {
http.Redirect(w, r, "/?error=internal+error", http.StatusSeeOther)
return
}
if taken {
http.Redirect(w, r, "/?error=slug+already+taken", http.StatusSeeOther)
return
}
}
author := r.FormValue("podcast_author")
if author == "" {
author = user.PodcastAuthor
@@ -48,7 +71,6 @@ func (h *SettingsHandler) ServeSettings(w http.ResponseWriter, r *http.Request)
if err == nil {
defer file.Close()
// Remove old image
if image != "" {
os.Remove(filepath.Join(h.UploadDir, image))
}
@@ -68,6 +90,6 @@ func (h *SettingsHandler) ServeSettings(w http.ResponseWriter, r *http.Request)
}
}
h.Store.UpdateUserPodcast(userID, title, image, author)
http.Redirect(w, r, "/", http.StatusSeeOther)
h.Store.UpdateUserPodcast(userID, title, slug, image, author)
http.Redirect(w, r, "/?success=podcast+settings+saved", http.StatusSeeOther)
}