repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

commit
13c145a
parent
cfd74b9
author
Eric Bower
date
2022-08-01 20:02:02 +0000 UTC
refactor: abstract api functions into shared

I also updated the custom domain logic to apply to all services.

Each service has its own special TXT string, e.g. `_prose`, `_lists`,
`_pastes` which is based on `cfg.Space`.
7 files changed,  +169, -259
M lists/api.go
+21, -95
  1@@ -4,7 +4,6 @@ import (
  2 	"bytes"
  3 	"fmt"
  4 	"html/template"
  5-	"io/ioutil"
  6 	"net/http"
  7 	"net/url"
  8 	"strconv"
  9@@ -19,10 +18,6 @@ import (
 10 	"golang.org/x/exp/slices"
 11 )
 12 
 13-type PageData struct {
 14-	Site shared.SitePageData
 15-}
 16-
 17 type PostItemData struct {
 18 	URL            template.URL
 19 	BlogURL        template.URL
 20@@ -74,50 +69,6 @@ type TransparencyPageData struct {
 21 	Analytics *db.Analytics
 22 }
 23 
 24-func isRequestTrackable(r *http.Request) bool {
 25-	return true
 26-}
 27-
 28-func renderTemplate(cfg *shared.ConfigSite, templates []string) (*template.Template, error) {
 29-	files := make([]string, len(templates))
 30-	copy(files, templates)
 31-	files = append(
 32-		files,
 33-		cfg.StaticPath("html/footer.partial.tmpl"),
 34-		cfg.StaticPath("html/marketing-footer.partial.tmpl"),
 35-		cfg.StaticPath("html/base.layout.tmpl"),
 36-	)
 37-
 38-	ts, err := template.ParseFiles(files...)
 39-	if err != nil {
 40-		return nil, err
 41-	}
 42-	return ts, nil
 43-}
 44-
 45-func createPageHandler(fname string) http.HandlerFunc {
 46-	return func(w http.ResponseWriter, r *http.Request) {
 47-		logger := shared.GetLogger(r)
 48-		cfg := shared.GetCfg(r)
 49-		ts, err := renderTemplate(cfg, []string{cfg.StaticPath(fname)})
 50-
 51-		if err != nil {
 52-			logger.Error(err)
 53-			http.Error(w, err.Error(), http.StatusInternalServerError)
 54-			return
 55-		}
 56-
 57-		data := PageData{
 58-			Site: *cfg.GetSiteData(),
 59-		}
 60-		err = ts.Execute(w, data)
 61-		if err != nil {
 62-			logger.Error(err)
 63-			http.Error(w, err.Error(), http.StatusInternalServerError)
 64-		}
 65-	}
 66-}
 67-
 68 type HeaderTxt struct {
 69 	Title    string
 70 	Bio      string
 71@@ -131,18 +82,12 @@ type ReadmeTxt struct {
 72 	Items    []*pkg.ListItem
 73 }
 74 
 75-func GetUsernameFromRequest(r *http.Request) string {
 76-	subdomain := shared.GetSubdomain(r)
 77-	cfg := shared.GetCfg(r)
 78-
 79-	if !cfg.IsSubdomains() || subdomain == "" {
 80-		return shared.GetField(r, 0)
 81-	}
 82-	return subdomain
 83+func isRequestTrackable(r *http.Request) bool {
 84+	return true
 85 }
 86 
 87 func blogHandler(w http.ResponseWriter, r *http.Request) {
 88-	username := GetUsernameFromRequest(r)
 89+	username := shared.GetUsernameFromRequest(r)
 90 	dbpool := shared.GetDB(r)
 91 	logger := shared.GetLogger(r)
 92 	cfg := shared.GetCfg(r)
 93@@ -166,7 +111,7 @@ func blogHandler(w http.ResponseWriter, r *http.Request) {
 94 	onSubdomain := cfg.IsSubdomains() && strings.Contains(hostDomain, appDomain)
 95 	withUserName := (!onSubdomain && hostDomain == appDomain) || !cfg.IsCustomdomains()
 96 
 97-	ts, err := renderTemplate(cfg, []string{
 98+	ts, err := shared.RenderTemplate(cfg, []string{
 99 		cfg.StaticPath("html/blog.page.tmpl"),
100 		cfg.StaticPath("html/list.partial.tmpl"),
101 	})
102@@ -251,7 +196,7 @@ func GetBlogName(username string) string {
103 }
104 
105 func postHandler(w http.ResponseWriter, r *http.Request) {
106-	username := GetUsernameFromRequest(r)
107+	username := shared.GetUsernameFromRequest(r)
108 	subdomain := shared.GetSubdomain(r)
109 	cfg := shared.GetCfg(r)
110 
111@@ -339,7 +284,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
112 		}
113 	}
114 
115-	ts, err := renderTemplate(cfg, []string{
116+	ts, err := shared.RenderTemplate(cfg, []string{
117 		cfg.StaticPath("html/post.page.tmpl"),
118 		cfg.StaticPath("html/list.partial.tmpl"),
119 	})
120@@ -402,7 +347,7 @@ func readHandler(w http.ResponseWriter, r *http.Request) {
121 		return
122 	}
123 
124-	ts, err := renderTemplate(cfg, []string{
125+	ts, err := shared.RenderTemplate(cfg, []string{
126 		cfg.StaticPath("html/read.page.tmpl"),
127 	})
128 
129@@ -448,7 +393,7 @@ func readHandler(w http.ResponseWriter, r *http.Request) {
130 }
131 
132 func rssBlogHandler(w http.ResponseWriter, r *http.Request) {
133-	username := GetUsernameFromRequest(r)
134+	username := shared.GetUsernameFromRequest(r)
135 	dbpool := shared.GetDB(r)
136 	logger := shared.GetLogger(r)
137 	cfg := shared.GetCfg(r)
138@@ -619,47 +564,28 @@ func rssHandler(w http.ResponseWriter, r *http.Request) {
139 	}
140 }
141 
142-func serveFile(file string, contentType string) http.HandlerFunc {
143-	return func(w http.ResponseWriter, r *http.Request) {
144-		logger := shared.GetLogger(r)
145-		cfg := shared.GetCfg(r)
146-
147-		contents, err := ioutil.ReadFile(cfg.StaticPath(fmt.Sprintf("public/%s", file)))
148-		if err != nil {
149-			logger.Error(err)
150-			http.Error(w, "file not found", 404)
151-		}
152-
153-		w.Header().Add("Content-Type", contentType)
154-
155-		_, err = w.Write(contents)
156-		if err != nil {
157-			logger.Error(err)
158-		}
159-	}
160-}
161-
162 func createStaticRoutes() []shared.Route {
163 	return []shared.Route{
164-		shared.NewRoute("GET", "/main.css", serveFile("main.css", "text/css")),
165-		shared.NewRoute("GET", "/card.png", serveFile("card.png", "image/png")),
166-		shared.NewRoute("GET", "/favicon-16x16.png", serveFile("favicon-16x16.png", "image/png")),
167-		shared.NewRoute("GET", "/favicon-32x32.png", serveFile("favicon-32x32.png", "image/png")),
168-		shared.NewRoute("GET", "/apple-touch-icon.png", serveFile("apple-touch-icon.png", "image/png")),
169-		shared.NewRoute("GET", "/favicon.ico", serveFile("favicon.ico", "image/x-icon")),
170-		shared.NewRoute("GET", "/robots.txt", serveFile("robots.txt", "text/plain")),
171+		shared.NewRoute("GET", "/main.css", shared.ServeFile("main.css", "text/css")),
172+		shared.NewRoute("GET", "/card.png", shared.ServeFile("card.png", "image/png")),
173+		shared.NewRoute("GET", "/favicon-16x16.png", shared.ServeFile("favicon-16x16.png", "image/png")),
174+		shared.NewRoute("GET", "/favicon-32x32.png", shared.ServeFile("favicon-32x32.png", "image/png")),
175+		shared.NewRoute("GET", "/apple-touch-icon.png", shared.ServeFile("apple-touch-icon.png", "image/png")),
176+		shared.NewRoute("GET", "/favicon.ico", shared.ServeFile("favicon.ico", "image/x-icon")),
177+		shared.NewRoute("GET", "/robots.txt", shared.ServeFile("robots.txt", "text/plain")),
178 	}
179 }
180 
181 func createMainRoutes(staticRoutes []shared.Route) []shared.Route {
182 	routes := []shared.Route{
183-		shared.NewRoute("GET", "/", createPageHandler("html/marketing.page.tmpl")),
184-		shared.NewRoute("GET", "/spec", createPageHandler("html/spec.page.tmpl")),
185-		shared.NewRoute("GET", "/ops", createPageHandler("html/ops.page.tmpl")),
186-		shared.NewRoute("GET", "/privacy", createPageHandler("html/privacy.page.tmpl")),
187-		shared.NewRoute("GET", "/help", createPageHandler("html/help.page.tmpl")),
188+		shared.NewRoute("GET", "/", shared.CreatePageHandler("html/marketing.page.tmpl")),
189+		shared.NewRoute("GET", "/spec", shared.CreatePageHandler("html/spec.page.tmpl")),
190+		shared.NewRoute("GET", "/ops", shared.CreatePageHandler("html/ops.page.tmpl")),
191+		shared.NewRoute("GET", "/privacy", shared.CreatePageHandler("html/privacy.page.tmpl")),
192+		shared.NewRoute("GET", "/help", shared.CreatePageHandler("html/help.page.tmpl")),
193 		shared.NewRoute("GET", "/transparency", transparencyHandler),
194 		shared.NewRoute("GET", "/read", readHandler),
195+		shared.NewRoute("GET", "/check", shared.CheckHandler),
196 	}
197 
198 	routes = append(
M lists/gemini/gemini.go
+1, -1
1@@ -53,7 +53,7 @@ func createPageHandler(fname string) gemini.HandlerFunc {
2 			return
3 		}
4 
5-		data := lists.PageData{
6+		data := shared.PageData{
7 			Site: *cfg.GetSiteData(),
8 		}
9 		err = ts.Execute(w, data)
M pastes/api.go
+11, -60
  1@@ -61,46 +61,6 @@ type TransparencyPageData struct {
  2 	Analytics *db.Analytics
  3 }
  4 
  5-func renderTemplate(cfg *shared.ConfigSite, templates []string) (*template.Template, error) {
  6-	files := make([]string, len(templates))
  7-	copy(files, templates)
  8-	files = append(
  9-		files,
 10-		cfg.StaticPath("html/footer.partial.tmpl"),
 11-		cfg.StaticPath("html/marketing-footer.partial.tmpl"),
 12-		cfg.StaticPath("html/base.layout.tmpl"),
 13-	)
 14-
 15-	ts, err := template.ParseFiles(files...)
 16-	if err != nil {
 17-		return nil, err
 18-	}
 19-	return ts, nil
 20-}
 21-
 22-func createPageHandler(fname string) http.HandlerFunc {
 23-	return func(w http.ResponseWriter, r *http.Request) {
 24-		logger := shared.GetLogger(r)
 25-		cfg := shared.GetCfg(r)
 26-		ts, err := renderTemplate(cfg, []string{cfg.StaticPath(fname)})
 27-
 28-		if err != nil {
 29-			logger.Error(err)
 30-			http.Error(w, err.Error(), http.StatusInternalServerError)
 31-			return
 32-		}
 33-
 34-		data := PageData{
 35-			Site: *cfg.GetSiteData(),
 36-		}
 37-		err = ts.Execute(w, data)
 38-		if err != nil {
 39-			logger.Error(err)
 40-			http.Error(w, err.Error(), http.StatusInternalServerError)
 41-		}
 42-	}
 43-}
 44-
 45 type Link struct {
 46 	URL  string
 47 	Text string
 48@@ -113,18 +73,8 @@ type HeaderTxt struct {
 49 	HasLinks bool
 50 }
 51 
 52-func GetUsernameFromRequest(r *http.Request) string {
 53-	subdomain := shared.GetSubdomain(r)
 54-	cfg := shared.GetCfg(r)
 55-
 56-	if !cfg.IsSubdomains() || subdomain == "" {
 57-		return shared.GetField(r, 0)
 58-	}
 59-	return subdomain
 60-}
 61-
 62 func blogHandler(w http.ResponseWriter, r *http.Request) {
 63-	username := GetUsernameFromRequest(r)
 64+	username := shared.GetUsernameFromRequest(r)
 65 	dbpool := shared.GetDB(r)
 66 	logger := shared.GetLogger(r)
 67 	cfg := shared.GetCfg(r)
 68@@ -148,7 +98,7 @@ func blogHandler(w http.ResponseWriter, r *http.Request) {
 69 	onSubdomain := cfg.IsSubdomains() && strings.Contains(hostDomain, appDomain)
 70 	withUserName := (!onSubdomain && hostDomain == appDomain) || !cfg.IsCustomdomains()
 71 
 72-	ts, err := renderTemplate(cfg, []string{
 73+	ts, err := shared.RenderTemplate(cfg, []string{
 74 		cfg.StaticPath("html/blog.page.tmpl"),
 75 	})
 76 
 77@@ -207,7 +157,7 @@ func GetBlogName(username string) string {
 78 }
 79 
 80 func postHandler(w http.ResponseWriter, r *http.Request) {
 81-	username := GetUsernameFromRequest(r)
 82+	username := shared.GetUsernameFromRequest(r)
 83 	subdomain := shared.GetSubdomain(r)
 84 	cfg := shared.GetCfg(r)
 85 
 86@@ -268,7 +218,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
 87 		}
 88 	}
 89 
 90-	ts, err := renderTemplate(cfg, []string{
 91+	ts, err := shared.RenderTemplate(cfg, []string{
 92 		cfg.StaticPath("html/post.page.tmpl"),
 93 	})
 94 
 95@@ -284,7 +234,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
 96 }
 97 
 98 func postHandlerRaw(w http.ResponseWriter, r *http.Request) {
 99-	username := GetUsernameFromRequest(r)
100+	username := shared.GetUsernameFromRequest(r)
101 	subdomain := shared.GetSubdomain(r)
102 	cfg := shared.GetCfg(r)
103 
104@@ -388,12 +338,13 @@ func createStaticRoutes() []shared.Route {
105 
106 func createMainRoutes(staticRoutes []shared.Route) []shared.Route {
107 	routes := []shared.Route{
108-		shared.NewRoute("GET", "/", createPageHandler("html/marketing.page.tmpl")),
109-		shared.NewRoute("GET", "/spec", createPageHandler("html/spec.page.tmpl")),
110-		shared.NewRoute("GET", "/ops", createPageHandler("html/ops.page.tmpl")),
111-		shared.NewRoute("GET", "/privacy", createPageHandler("html/privacy.page.tmpl")),
112-		shared.NewRoute("GET", "/help", createPageHandler("html/help.page.tmpl")),
113+		shared.NewRoute("GET", "/", shared.CreatePageHandler("html/marketing.page.tmpl")),
114+		shared.NewRoute("GET", "/spec", shared.CreatePageHandler("html/spec.page.tmpl")),
115+		shared.NewRoute("GET", "/ops", shared.CreatePageHandler("html/ops.page.tmpl")),
116+		shared.NewRoute("GET", "/privacy", shared.CreatePageHandler("html/privacy.page.tmpl")),
117+		shared.NewRoute("GET", "/help", shared.CreatePageHandler("html/help.page.tmpl")),
118 		shared.NewRoute("GET", "/transparency", transparencyHandler),
119+		shared.NewRoute("GET", "/check", shared.CheckHandler),
120 	}
121 
122 	routes = append(
M prose/api.go
+27, -100
  1@@ -77,50 +77,6 @@ type TransparencyPageData struct {
  2 	Analytics *db.Analytics
  3 }
  4 
  5-func isRequestTrackable(r *http.Request) bool {
  6-	return true
  7-}
  8-
  9-func renderTemplate(cfg *shared.ConfigSite, templates []string) (*template.Template, error) {
 10-	files := make([]string, len(templates))
 11-	copy(files, templates)
 12-	files = append(
 13-		files,
 14-		cfg.StaticPath("html/footer.partial.tmpl"),
 15-		cfg.StaticPath("html/marketing-footer.partial.tmpl"),
 16-		cfg.StaticPath("html/base.layout.tmpl"),
 17-	)
 18-
 19-	ts, err := template.ParseFiles(files...)
 20-	if err != nil {
 21-		return nil, err
 22-	}
 23-	return ts, nil
 24-}
 25-
 26-func createPageHandler(fname string) http.HandlerFunc {
 27-	return func(w http.ResponseWriter, r *http.Request) {
 28-		logger := shared.GetLogger(r)
 29-		cfg := shared.GetCfg(r)
 30-		ts, err := renderTemplate(cfg, []string{cfg.StaticPath(fname)})
 31-
 32-		if err != nil {
 33-			logger.Error(err)
 34-			http.Error(w, err.Error(), http.StatusInternalServerError)
 35-			return
 36-		}
 37-
 38-		data := PageData{
 39-			Site: *cfg.GetSiteData(),
 40-		}
 41-		err = ts.Execute(w, data)
 42-		if err != nil {
 43-			logger.Error(err)
 44-			http.Error(w, err.Error(), http.StatusInternalServerError)
 45-		}
 46-	}
 47-}
 48-
 49 type Link struct {
 50 	URL  string
 51 	Text string
 52@@ -138,18 +94,24 @@ type ReadmeTxt struct {
 53 	Contents template.HTML
 54 }
 55 
 56-func GetUsernameFromRequest(r *http.Request) string {
 57-	subdomain := shared.GetSubdomain(r)
 58-	cfg := shared.GetCfg(r)
 59-
 60-	if !cfg.IsSubdomains() || subdomain == "" {
 61-		return shared.GetField(r, 0)
 62+func GetPostTitle(post *db.Post) string {
 63+	if post.Description == "" {
 64+		return post.Title
 65 	}
 66-	return subdomain
 67+
 68+	return fmt.Sprintf("%s: %s", post.Title, post.Description)
 69+}
 70+
 71+func GetBlogName(username string) string {
 72+	return fmt.Sprintf("%s's blog", username)
 73+}
 74+
 75+func isRequestTrackable(r *http.Request) bool {
 76+	return true
 77 }
 78 
 79 func blogStyleHandler(w http.ResponseWriter, r *http.Request) {
 80-	username := GetUsernameFromRequest(r)
 81+	username := shared.GetUsernameFromRequest(r)
 82 	dbpool := shared.GetDB(r)
 83 	logger := shared.GetLogger(r)
 84 	cfg := shared.GetCfg(r)
 85@@ -177,7 +139,7 @@ func blogStyleHandler(w http.ResponseWriter, r *http.Request) {
 86 }
 87 
 88 func blogHandler(w http.ResponseWriter, r *http.Request) {
 89-	username := GetUsernameFromRequest(r)
 90+	username := shared.GetUsernameFromRequest(r)
 91 	dbpool := shared.GetDB(r)
 92 	logger := shared.GetLogger(r)
 93 	cfg := shared.GetCfg(r)
 94@@ -201,7 +163,7 @@ func blogHandler(w http.ResponseWriter, r *http.Request) {
 95 	onSubdomain := cfg.IsSubdomains() && strings.Contains(hostDomain, appDomain)
 96 	withUserName := (!onSubdomain && hostDomain == appDomain) || !cfg.IsCustomdomains()
 97 
 98-	ts, err := renderTemplate(cfg, []string{
 99+	ts, err := shared.RenderTemplate(cfg, []string{
100 		cfg.StaticPath("html/blog.page.tmpl"),
101 	})
102 
103@@ -270,20 +232,8 @@ func blogHandler(w http.ResponseWriter, r *http.Request) {
104 	}
105 }
106 
107-func GetPostTitle(post *db.Post) string {
108-	if post.Description == "" {
109-		return post.Title
110-	}
111-
112-	return fmt.Sprintf("%s: %s", post.Title, post.Description)
113-}
114-
115-func GetBlogName(username string) string {
116-	return fmt.Sprintf("%s's blog", username)
117-}
118-
119 func postRawHandler(w http.ResponseWriter, r *http.Request) {
120-	username := GetUsernameFromRequest(r)
121+	username := shared.GetUsernameFromRequest(r)
122 	subdomain := shared.GetSubdomain(r)
123 	cfg := shared.GetCfg(r)
124 
125@@ -321,7 +271,7 @@ func postRawHandler(w http.ResponseWriter, r *http.Request) {
126 }
127 
128 func postHandler(w http.ResponseWriter, r *http.Request) {
129-	username := GetUsernameFromRequest(r)
130+	username := shared.GetUsernameFromRequest(r)
131 	subdomain := shared.GetSubdomain(r)
132 	cfg := shared.GetCfg(r)
133 
134@@ -417,7 +367,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) {
135 		logger.Infof("post not found %s/%s", username, slug)
136 	}
137 
138-	ts, err := renderTemplate(cfg, []string{
139+	ts, err := shared.RenderTemplate(cfg, []string{
140 		cfg.StaticPath("html/post.page.tmpl"),
141 	})
142 
143@@ -466,29 +416,6 @@ func transparencyHandler(w http.ResponseWriter, r *http.Request) {
144 	}
145 }
146 
147-func checkHandler(w http.ResponseWriter, r *http.Request) {
148-	dbpool := shared.GetDB(r)
149-	cfg := shared.GetCfg(r)
150-
151-	if cfg.IsCustomdomains() {
152-		hostDomain := r.URL.Query().Get("domain")
153-		appDomain := strings.Split(cfg.ConfigCms.Domain, ":")[0]
154-
155-		if !strings.Contains(hostDomain, appDomain) {
156-			subdomain := shared.GetCustomDomain(hostDomain)
157-			if subdomain != "" {
158-				u, err := dbpool.FindUserForName(subdomain)
159-				if u != nil && err == nil {
160-					w.WriteHeader(http.StatusOK)
161-					return
162-				}
163-			}
164-		}
165-	}
166-
167-	w.WriteHeader(http.StatusNotFound)
168-}
169-
170 func readHandler(w http.ResponseWriter, r *http.Request) {
171 	dbpool := shared.GetDB(r)
172 	logger := shared.GetLogger(r)
173@@ -502,7 +429,7 @@ func readHandler(w http.ResponseWriter, r *http.Request) {
174 		return
175 	}
176 
177-	ts, err := renderTemplate(cfg, []string{
178+	ts, err := shared.RenderTemplate(cfg, []string{
179 		cfg.StaticPath("html/read.page.tmpl"),
180 	})
181 
182@@ -549,7 +476,7 @@ func readHandler(w http.ResponseWriter, r *http.Request) {
183 }
184 
185 func rssBlogHandler(w http.ResponseWriter, r *http.Request) {
186-	username := GetUsernameFromRequest(r)
187+	username := shared.GetUsernameFromRequest(r)
188 	dbpool := shared.GetDB(r)
189 	logger := shared.GetLogger(r)
190 	cfg := shared.GetCfg(r)
191@@ -778,14 +705,14 @@ func createStaticRoutes() []shared.Route {
192 
193 func createMainRoutes(staticRoutes []shared.Route) []shared.Route {
194 	routes := []shared.Route{
195-		shared.NewRoute("GET", "/", createPageHandler("html/marketing.page.tmpl")),
196-		shared.NewRoute("GET", "/spec", createPageHandler("html/spec.page.tmpl")),
197-		shared.NewRoute("GET", "/ops", createPageHandler("html/ops.page.tmpl")),
198-		shared.NewRoute("GET", "/privacy", createPageHandler("html/privacy.page.tmpl")),
199-		shared.NewRoute("GET", "/help", createPageHandler("html/help.page.tmpl")),
200+		shared.NewRoute("GET", "/", shared.CreatePageHandler("html/marketing.page.tmpl")),
201+		shared.NewRoute("GET", "/spec", shared.CreatePageHandler("html/spec.page.tmpl")),
202+		shared.NewRoute("GET", "/ops", shared.CreatePageHandler("html/ops.page.tmpl")),
203+		shared.NewRoute("GET", "/privacy", shared.CreatePageHandler("html/privacy.page.tmpl")),
204+		shared.NewRoute("GET", "/help", shared.CreatePageHandler("html/help.page.tmpl")),
205 		shared.NewRoute("GET", "/transparency", transparencyHandler),
206 		shared.NewRoute("GET", "/read", readHandler),
207-		shared.NewRoute("GET", "/check", checkHandler),
208+		shared.NewRoute("GET", "/check", shared.CheckHandler),
209 	}
210 
211 	routes = append(
A shared/api.go
+102, -0
  1@@ -0,0 +1,102 @@
  2+package shared
  3+
  4+import (
  5+	"fmt"
  6+	"html/template"
  7+	"io/ioutil"
  8+	"net/http"
  9+	"strings"
 10+)
 11+
 12+func CheckHandler(w http.ResponseWriter, r *http.Request) {
 13+	dbpool := GetDB(r)
 14+	cfg := GetCfg(r)
 15+
 16+	if cfg.IsCustomdomains() {
 17+		hostDomain := r.URL.Query().Get("domain")
 18+		appDomain := strings.Split(cfg.ConfigCms.Domain, ":")[0]
 19+
 20+		if !strings.Contains(hostDomain, appDomain) {
 21+			subdomain := GetCustomDomain(hostDomain, cfg.Space)
 22+			if subdomain != "" {
 23+				u, err := dbpool.FindUserForName(subdomain)
 24+				if u != nil && err == nil {
 25+					w.WriteHeader(http.StatusOK)
 26+					return
 27+				}
 28+			}
 29+		}
 30+	}
 31+
 32+	w.WriteHeader(http.StatusNotFound)
 33+}
 34+
 35+func GetUsernameFromRequest(r *http.Request) string {
 36+	subdomain := GetSubdomain(r)
 37+	cfg := GetCfg(r)
 38+
 39+	if !cfg.IsSubdomains() || subdomain == "" {
 40+		return GetField(r, 0)
 41+	}
 42+	return subdomain
 43+}
 44+
 45+func ServeFile(file string, contentType string) http.HandlerFunc {
 46+	return func(w http.ResponseWriter, r *http.Request) {
 47+		logger := GetLogger(r)
 48+		cfg := GetCfg(r)
 49+
 50+		contents, err := ioutil.ReadFile(cfg.StaticPath(fmt.Sprintf("public/%s", file)))
 51+		if err != nil {
 52+			logger.Error(err)
 53+			http.Error(w, "file not found", 404)
 54+		}
 55+
 56+		w.Header().Add("Content-Type", contentType)
 57+
 58+		_, err = w.Write(contents)
 59+		if err != nil {
 60+			logger.Error(err)
 61+		}
 62+	}
 63+}
 64+
 65+func RenderTemplate(cfg *ConfigSite, templates []string) (*template.Template, error) {
 66+	files := make([]string, len(templates))
 67+	copy(files, templates)
 68+	files = append(
 69+		files,
 70+		cfg.StaticPath("html/footer.partial.tmpl"),
 71+		cfg.StaticPath("html/marketing-footer.partial.tmpl"),
 72+		cfg.StaticPath("html/base.layout.tmpl"),
 73+	)
 74+
 75+	ts, err := template.ParseFiles(files...)
 76+	if err != nil {
 77+		return nil, err
 78+	}
 79+	return ts, nil
 80+}
 81+
 82+func CreatePageHandler(fname string) http.HandlerFunc {
 83+	return func(w http.ResponseWriter, r *http.Request) {
 84+		logger := GetLogger(r)
 85+		cfg := GetCfg(r)
 86+		ts, err := RenderTemplate(cfg, []string{cfg.StaticPath(fname)})
 87+
 88+		if err != nil {
 89+			logger.Error(err)
 90+			http.Error(w, err.Error(), http.StatusInternalServerError)
 91+			return
 92+		}
 93+
 94+		data := PageData{
 95+			Site: *cfg.GetSiteData(),
 96+		}
 97+		err = ts.Execute(w, data)
 98+		if err != nil {
 99+			logger.Error(err)
100+			http.Error(w, err.Error(), http.StatusInternalServerError)
101+		}
102+	}
103+}
M shared/config.go
+4, -0
 1@@ -17,6 +17,10 @@ type SitePageData struct {
 2 	Email   string
 3 }
 4 
 5+type PageData struct {
 6+	Site SitePageData
 7+}
 8+
 9 type ConfigSite struct {
10 	config.ConfigCms
11 	config.ConfigURL
M shared/router.go
+3, -3
 1@@ -45,7 +45,7 @@ func CreateServe(routes []Route, subdomainRoutes []Route, cfg *ConfigSite, dbpoo
 2 						curRoutes = subdomainRoutes
 3 					}
 4 				} else {
 5-					subdomain = GetCustomDomain(hostDomain)
 6+					subdomain = GetCustomDomain(hostDomain, cfg.Space)
 7 					if subdomain != "" {
 8 						curRoutes = subdomainRoutes
 9 					}
10@@ -105,8 +105,8 @@ func GetSubdomain(r *http.Request) string {
11 	return r.Context().Value(ctxSubdomainKey{}).(string)
12 }
13 
14-func GetCustomDomain(host string) string {
15-	records, err := net.LookupTXT(fmt.Sprintf("_prose.%s", host))
16+func GetCustomDomain(host string, space string) string {
17+	records, err := net.LookupTXT(fmt.Sprintf("_%s.%s", host, space))
18 	if err != nil {
19 		return ""
20 	}