feat: registration_enabled admin setting — hides signup surfaces, gates the API
Release / build-and-push (push) Successful in 3m9s

One boolean (Security > Public Registration) switches the whole public
signup lifecycle: front page + login links, the logged-out sidebar's
Create-an-account (via a package-level templates hook so shared page
templates keep their signatures), GET /register -> 302 /login, and an
early 403 on POST /api/auth/register. First-user exception preserved:
zero admins keeps every route and link reachable for bootstrapping —
same 'users exist' reasoning as the setup gate. Admin user creation is
unaffected by design.

Live E2E verified: flag off hides all surfaces and blocks the POST
(403), flag on restores them (201); the admin UI renders the row
automatically.
This commit is contained in:
John O'Keefe
2026-10-03 23:54:07 -04:00
parent 6aaefe210a
commit b9f797789f
43 changed files with 627 additions and 519 deletions
+12 -12
View File
@@ -99,7 +99,7 @@ func Series(user User, seriesList []SeriesCardData, libData []LibraryData, curre
var templ_7745c5c3_Var2 templ.SafeURL
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs(fmt.Sprintf("/series?library_id=%s&page=%d", currentLibraryID, currentPage-1))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 50, Col: 93}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 50, Col: 93}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
@@ -125,7 +125,7 @@ func Series(user User, seriesList []SeriesCardData, libData []LibraryData, curre
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", currentPage))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 58, Col: 45}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 58, Col: 45}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@@ -138,7 +138,7 @@ func Series(user User, seriesList []SeriesCardData, libData []LibraryData, curre
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", totalPages))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 58, Col: 82}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 58, Col: 82}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@@ -156,7 +156,7 @@ func Series(user User, seriesList []SeriesCardData, libData []LibraryData, curre
var templ_7745c5c3_Var5 templ.SafeURL
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(fmt.Sprintf("/series?library_id=%s&page=%d", currentLibraryID, currentPage+1))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 62, Col: 93}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 62, Col: 93}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@@ -224,7 +224,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var7 templ.SafeURL
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs("/series/detail?name=" + url.QueryEscape(series.Name))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 79, Col: 64}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 79, Col: 64}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@@ -246,7 +246,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var8).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var9)
if templ_7745c5c3_Err != nil {
@@ -269,7 +269,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.ResolveAttributeValue(cover)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 84, Col: 17}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 84, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var11)
if templ_7745c5c3_Err != nil {
@@ -282,7 +282,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.ResolveAttributeValue(templ.CSSClasses(templ_7745c5c3_Var10).String())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 1, Col: 0}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 1, Col: 0}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var12)
if templ_7745c5c3_Err != nil {
@@ -295,7 +295,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.ResolveAttributeValue(series.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 86, Col: 23}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 86, Col: 23}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var13)
if templ_7745c5c3_Err != nil {
@@ -327,7 +327,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(series.Name)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 98, Col: 99}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 98, Col: 99}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
@@ -340,7 +340,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var15 string
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", series.BookCount))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 100, Col: 42}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 100, Col: 42}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
@@ -353,7 +353,7 @@ func SeriesCard(series SeriesCardData) templ.Component {
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", series.TotalInSeries))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `series.templ`, Line: 100, Col: 89}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/series.templ`, Line: 100, Col: 89}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {