Add a customizable Contact page

This commit is contained in:
Matt Baer 2023-09-22 12:37:15 -04:00
parent 83f230ddaf
commit d48262a6df
6 changed files with 75 additions and 7 deletions

View File

@ -13,6 +13,7 @@ package writefreely
import ( import (
"database/sql" "database/sql"
"fmt" "fmt"
"html/template"
"net/http" "net/http"
"runtime" "runtime"
"strconv" "strconv"
@ -102,13 +103,16 @@ func NewAdminPage(app *App) *AdminPage {
return ap return ap
} }
func (c instanceContent) UpdatedFriendly() string { func (c instanceContent) UpdatedFriendly() template.HTML {
/* /*
// TODO: accept a locale in this method and use that for the format // TODO: accept a locale in this method and use that for the format
var loc monday.Locale = monday.LocaleEnUS var loc monday.Locale = monday.LocaleEnUS
return monday.Format(u.Created, monday.DateTimeFormatsByLocale[loc], loc) return monday.Format(u.Created, monday.DateTimeFormatsByLocale[loc], loc)
*/ */
return c.Updated.Format("January 2, 2006, 3:04 PM") if c.Updated.IsZero() {
return "<em>Never</em>"
}
return template.HTML(c.Updated.Format("January 2, 2006, 3:04 PM"))
} }
func handleViewAdminDash(app *App, u *User, w http.ResponseWriter, r *http.Request) error { func handleViewAdminDash(app *App, u *User, w http.ResponseWriter, r *http.Request) error {
@ -426,9 +430,9 @@ func handleViewAdminPages(app *App, u *User, w http.ResponseWriter, r *http.Requ
} }
// Add in default pages // Add in default pages
var hasAbout, hasPrivacy bool var hasAbout, hasContact, hasPrivacy bool
for i, c := range p.Pages { for i, c := range p.Pages {
if hasAbout && hasPrivacy { if hasAbout && hasContact && hasPrivacy {
break break
} }
if c.ID == "about" { if c.ID == "about" {
@ -436,6 +440,11 @@ func handleViewAdminPages(app *App, u *User, w http.ResponseWriter, r *http.Requ
if !c.Title.Valid { if !c.Title.Valid {
p.Pages[i].Title = defaultAboutTitle(app.cfg) p.Pages[i].Title = defaultAboutTitle(app.cfg)
} }
} else if c.ID == "contact" {
hasContact = true
if !c.Title.Valid {
p.Pages[i].Title = defaultContactTitle()
}
} else if c.ID == "privacy" { } else if c.ID == "privacy" {
hasPrivacy = true hasPrivacy = true
if !c.Title.Valid { if !c.Title.Valid {
@ -451,6 +460,13 @@ func handleViewAdminPages(app *App, u *User, w http.ResponseWriter, r *http.Requ
Updated: defaultPageUpdatedTime, Updated: defaultPageUpdatedTime,
}) })
} }
if !hasAbout {
p.Pages = append(p.Pages, &instanceContent{
ID: "contact",
Title: defaultContactTitle(),
Content: defaultContactPage(app),
})
}
if !hasPrivacy { if !hasPrivacy {
p.Pages = append(p.Pages, &instanceContent{ p.Pages = append(p.Pages, &instanceContent{
ID: "privacy", ID: "privacy",
@ -489,6 +505,8 @@ func handleViewAdminPage(app *App, u *User, w http.ResponseWriter, r *http.Reque
// Get pre-defined pages, or select slug // Get pre-defined pages, or select slug
if slug == "about" { if slug == "about" {
p.Content, err = getAboutPage(app) p.Content, err = getAboutPage(app)
} else if slug == "contact" {
p.Content, err = getContactPage(app)
} else if slug == "privacy" { } else if slug == "privacy" {
p.Content, err = getPrivacyPage(app) p.Content, err = getPrivacyPage(app)
} else if slug == "landing" { } else if slug == "landing" {
@ -523,7 +541,7 @@ func handleAdminUpdateSite(app *App, u *User, w http.ResponseWriter, r *http.Req
id := vars["page"] id := vars["page"]
// Validate // Validate
if id != "about" && id != "privacy" && id != "landing" && id != "reader" { if id != "about" && id != "contact" && id != "privacy" && id != "landing" && id != "reader" {
return impart.HTTPError{http.StatusNotFound, "No such page."} return impart.HTTPError{http.StatusNotFound, "No such page."}
} }

8
app.go
View File

@ -318,7 +318,7 @@ func handleTemplatedPage(app *App, w http.ResponseWriter, r *http.Request, t *te
}{ }{
StaticPage: pageForReq(app, r), StaticPage: pageForReq(app, r),
} }
if r.URL.Path == "/about" || r.URL.Path == "/privacy" { if r.URL.Path == "/about" || r.URL.Path == "/contact" || r.URL.Path == "/privacy" {
var c *instanceContent var c *instanceContent
var err error var err error
@ -329,6 +329,12 @@ func handleTemplatedPage(app *App, w http.ResponseWriter, r *http.Request, t *te
p.AboutStats = &InstanceStats{} p.AboutStats = &InstanceStats{}
p.AboutStats.NumPosts, _ = app.db.GetTotalPosts() p.AboutStats.NumPosts, _ = app.db.GetTotalPosts()
p.AboutStats.NumBlogs, _ = app.db.GetTotalCollections() p.AboutStats.NumBlogs, _ = app.db.GetTotalCollections()
} else if r.URL.Path == "/contact" {
c, err = getContactPage(app)
if c.Updated.IsZero() {
// Page was never set up, so return 404
return ErrPostNotFound
}
} else { } else {
c, err = getPrivacyPage(app) c, err = getPrivacyPage(app)
} }

View File

@ -40,6 +40,28 @@ func defaultAboutTitle(cfg *config.Config) sql.NullString {
return sql.NullString{String: "About " + cfg.App.SiteName, Valid: true} return sql.NullString{String: "About " + cfg.App.SiteName, Valid: true}
} }
func getContactPage(app *App) (*instanceContent, error) {
c, err := app.db.GetDynamicContent("contact")
if err != nil {
return nil, err
}
if c == nil {
c = &instanceContent{
ID: "contact",
Type: "page",
Content: defaultContactPage(app),
}
}
if !c.Title.Valid {
c.Title = defaultContactTitle()
}
return c, nil
}
func defaultContactTitle() sql.NullString {
return sql.NullString{String: "Contact Us", Valid: true}
}
func getPrivacyPage(app *App) (*instanceContent, error) { func getPrivacyPage(app *App) (*instanceContent, error) {
c, err := app.db.GetDynamicContent("privacy") c, err := app.db.GetDynamicContent("privacy")
if err != nil { if err != nil {
@ -70,6 +92,18 @@ func defaultAboutPage(cfg *config.Config) string {
return `_` + cfg.App.SiteName + `_ is a place for you to write and publish, powered by [WriteFreely](https://writefreely.org).` return `_` + cfg.App.SiteName + `_ is a place for you to write and publish, powered by [WriteFreely](https://writefreely.org).`
} }
func defaultContactPage(app *App) string {
c, err := app.db.GetCollectionByID(1)
if err != nil {
return ""
}
return `_` + app.cfg.App.SiteName + `_ is administered by: [**` + c.Alias + `**](/` + c.Alias + `/).
Contact them at this email address: _EMAIL GOES HERE_.
You can also reach them here...`
}
func defaultPrivacyPolicy(cfg *config.Config) string { func defaultPrivacyPolicy(cfg *config.Config) string {
return `[WriteFreely](https://writefreely.org), the software that powers this site, is built to enforce your right to privacy by default. return `[WriteFreely](https://writefreely.org), the software that powers this site, is built to enforce your right to privacy by default.

View File

@ -2,7 +2,7 @@
{{define "content"}} {{define "content"}}
<div class="content-container tight"> <div class="content-container tight">
<h1>Server error &#x1F635;</h1> <h1>Server error &#x1F635;</h1>
<p>There seems to be an issue with this server. Please contact the admin and let them know they'll need to fix it.</p> <p>There seems to be an issue with this server. Please <a href="/contact">contact the admin</a> and let them know they'll need to fix it.</p>
<p>&ndash; {{.SiteName}} &#x1F916;</p> <p>&ndash; {{.SiteName}} &#x1F916;</p>
</div> </div>
{{end}} {{end}}

8
pages/contact.tmpl Normal file
View File

@ -0,0 +1,8 @@
{{define "head"}}<title>{{.ContentTitle}} &mdash; {{.SiteName}}</title>
<meta name="description" content="{{.PlainContent}}">
{{end}}
{{define "content"}}<div class="content-container snug">
<h1>{{.ContentTitle}}</h1>
{{.Content}}
</div>
{{end}}

View File

@ -29,6 +29,8 @@ input[type=text] {
{{if eq .Content.ID "about"}} {{if eq .Content.ID "about"}}
<p class="page-desc content-desc">Describe what your instance is <a href="/about" target="page">about</a>.</p> <p class="page-desc content-desc">Describe what your instance is <a href="/about" target="page">about</a>.</p>
{{else if eq .Content.ID "contact"}}
<p class="page-desc content-desc">Tell your users and outside visitors how to <a href="/contact" target="page">contact</a> you.</p>
{{else if eq .Content.ID "privacy"}} {{else if eq .Content.ID "privacy"}}
<p class="page-desc content-desc">Outline your <a href="/privacy" target="page">privacy policy</a>.</p> <p class="page-desc content-desc">Outline your <a href="/privacy" target="page">privacy policy</a>.</p>
{{else if eq .Content.ID "reader"}} {{else if eq .Content.ID "reader"}}