111 lines
3.3 KiB
Go
111 lines
3.3 KiB
Go
package editor
|
|
|
|
import (
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// Search engines: the consoles' verification codes and the IndexNow key, as
|
|
// verify: and indexnow: in site.yaml (only those blocks rewritten).
|
|
|
|
func (s *Server) apiSearch(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
|
|
}
|
|
c := loaded.Config
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"verify": c.Verify, "indexnow": c.IndexNow.Key, "siteURL": c.URL, "sitemap": strings.TrimRight(c.URL, "/") + "/sitemap.xml",
|
|
"commit": commit, "branch": branch, "canWrite": acc.Write,
|
|
})
|
|
}
|
|
|
|
type searchRequest struct {
|
|
Branch string `json:"branch"`
|
|
BaseCommit string `json:"baseCommit"`
|
|
Verify map[string]string `json:"verify"`
|
|
IndexNow string `json:"indexnow"`
|
|
}
|
|
|
|
var (
|
|
keyRe = regexp.MustCompile(`^[A-Za-z0-9-]{8,128}$`)
|
|
codeRe = regexp.MustCompile(`^[A-Za-z0-9_.=+/-]{4,200}$`)
|
|
)
|
|
|
|
func (s *Server) searchSave(w http.ResponseWriter, r *http.Request, sess *Session, f *ForgeConfig, st *SiteConfig) {
|
|
var req searchRequest
|
|
if !decode(w, r, &req) {
|
|
return
|
|
}
|
|
if req.Branch == "" {
|
|
req.Branch = st.Branch
|
|
}
|
|
verify := map[string]any{}
|
|
for _, k := range []string{"google", "bing", "yandex"} {
|
|
v := strings.TrimSpace(req.Verify[k])
|
|
// Pasted the whole tag? Take the code out of it.
|
|
if m := regexp.MustCompile(`content="([^"]+)"`).FindStringSubmatch(v); m != nil {
|
|
v = m[1]
|
|
}
|
|
if v == "" {
|
|
continue
|
|
}
|
|
if !codeRe.MatchString(v) {
|
|
apiError(w, http.StatusUnprocessableEntity, "The "+k+" code doesn't look like a verification code.")
|
|
return
|
|
}
|
|
verify[k] = v
|
|
}
|
|
key := strings.TrimSpace(req.IndexNow)
|
|
if key != "" && !keyRe.MatchString(key) {
|
|
apiError(w, http.StatusUnprocessableEntity, "The IndexNow key should be 8 to 128 letters, digits or dashes.")
|
|
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 in map[string]any
|
|
if key != "" {
|
|
in = map[string]any{"key": key}
|
|
}
|
|
out, err := setTopLevel(string(raw), "verify", verify)
|
|
if err == nil {
|
|
out, err = setTopLevel(out, "indexnow", in)
|
|
}
|
|
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, "search-engines.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 search engine settings")
|
|
if err != nil {
|
|
s.writeError(w, r, err)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"branch": target, "commit": commit, "created": create})
|
|
}
|