115 lines
3.6 KiB
Go
115 lines
3.6 KiB
Go
package editor
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"git.coffeylabs.org/coffey-labs/hotdog-cms/internal/site"
|
|
)
|
|
|
|
// The analytics wizard and the privacy settings: analytics: and privacy: in
|
|
// site.yaml, written as two blocks, the rest of the file left as it was.
|
|
// Statistics wait for consent unless the person chooses otherwise, and that
|
|
// choice is spelled out in the file.
|
|
|
|
func (s *Server) apiPrivacy(w http.ResponseWriter, r *http.Request, sess *Session, f *ForgeConfig, id string) {
|
|
st, acc, err := s.siteByID(r.Context(), sess, f, id)
|
|
if s.signedOut(w, r, err) {
|
|
return
|
|
}
|
|
if err != nil || st == nil {
|
|
apiError(w, http.StatusNotFound, "No such site, or you can't open it.")
|
|
return
|
|
}
|
|
branch := r.URL.Query().Get("branch")
|
|
if branch == "" {
|
|
branch = st.Branch
|
|
}
|
|
loaded, _, commit, err := s.ws.checkout(sess, f.Kind, st, s.cloneURL(st), branch)
|
|
if loaded == nil {
|
|
apiError(w, http.StatusBadGateway, "Couldn't load the site: "+trimErr(err))
|
|
return
|
|
}
|
|
p := loaded.Config.Privacy
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"analytics": loaded.Config.Analytics,
|
|
"privacy": map[string]string{"controller": p.Controller, "contact": p.Contact, "updated": p.Updated},
|
|
"commit": commit, "branch": branch, "canWrite": acc.Write,
|
|
})
|
|
}
|
|
|
|
type privacyRequest struct {
|
|
Branch string `json:"branch"`
|
|
BaseCommit string `json:"baseCommit"`
|
|
Analytics *site.AnalyticsConfig `json:"analytics"`
|
|
Privacy map[string]string `json:"privacy"`
|
|
}
|
|
|
|
var emailish = regexp.MustCompile(`^[^@\s]+@[^@\s]+\.[^@\s]+$`)
|
|
|
|
func (s *Server) privacySave(w http.ResponseWriter, r *http.Request, sess *Session, f *ForgeConfig, st *SiteConfig) {
|
|
var req privacyRequest
|
|
if !decode(w, r, &req) {
|
|
return
|
|
}
|
|
if req.Branch == "" {
|
|
req.Branch = st.Branch
|
|
}
|
|
if err := req.Analytics.Validate(); err != nil {
|
|
apiError(w, http.StatusUnprocessableEntity, "Analytics: "+err.Error())
|
|
return
|
|
}
|
|
if c := strings.TrimSpace(req.Privacy["contact"]); c != "" && !emailish.MatchString(c) {
|
|
apiError(w, http.StatusUnprocessableEntity, fmt.Sprintf("%q doesn't look like an email address.", c))
|
|
return
|
|
}
|
|
_, siteDir, _, err := s.ws.checkout(sess, f.Kind, st, s.cloneURL(st), req.Branch)
|
|
if siteDir == "" {
|
|
s.writeError(w, r, err)
|
|
return
|
|
}
|
|
raw, err := readIn(siteDir, "site.yaml")
|
|
if err != nil {
|
|
apiError(w, http.StatusBadGateway, "Couldn't read site.yaml.")
|
|
return
|
|
}
|
|
var an map[string]any
|
|
if a := req.Analytics; a != nil {
|
|
an = map[string]any{"provider": a.Provider}
|
|
for k, v := range map[string]string{"domain": a.Domain, "src": a.Src, "url": a.URL, "site_id": a.SiteID, "id": a.ID} {
|
|
if v = strings.TrimSpace(v); v != "" {
|
|
an[k] = v
|
|
}
|
|
}
|
|
if !a.IsGated() {
|
|
an["gated"] = false // counting without asking: a choice, written down
|
|
}
|
|
}
|
|
pv := map[string]any{}
|
|
for _, k := range []string{"controller", "contact", "updated"} {
|
|
if v := strings.TrimSpace(req.Privacy[k]); v != "" {
|
|
pv[k] = v
|
|
}
|
|
}
|
|
out, err := setTopLevel(string(raw), "analytics", an)
|
|
if err == nil {
|
|
out, err = setTopLevel(out, "privacy", pv)
|
|
}
|
|
if err != nil {
|
|
apiError(w, http.StatusUnprocessableEntity, err.Error())
|
|
return
|
|
}
|
|
target, create := req.Branch, false
|
|
if req.Branch == st.Branch {
|
|
target, create = s.draftName(r, sess, f, st, "privacy.md"), true
|
|
}
|
|
commit, err := s.ws.save(sess, f.Kind, st, s.cloneURL(st), req.Branch, target, create, req.BaseCommit, map[string][]byte{repoFile(st, "site.yaml"): []byte(out)}, "Update analytics and privacy settings")
|
|
if err != nil {
|
|
s.writeError(w, r, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"branch": target, "commit": commit, "created": create})
|
|
}
|