|
@@ -1,7 +1,7 @@
|
|
/*
|
|
/*
|
|
The Kurz Web UI exposes HTTP routes for browsers, route names to access them, and types for the requests.
|
|
The Kurz Web UI exposes HTTP routes for browsers, route names to access them, and types for the requests.
|
|
|
|
|
|
-These routes are exposed by running SetupRoutes(listenAddress), which is enough to
|
|
|
|
|
|
+These routes are exposed by running SetupUI(listenAddress), which is enough to
|
|
configure the Kurz domain API. Be sure to also configure the domain SPI to have
|
|
configure the Kurz domain API. Be sure to also configure the domain SPI to have
|
|
a complete application.
|
|
a complete application.
|
|
*/
|
|
*/
|
|
@@ -9,13 +9,14 @@ package web
|
|
|
|
|
|
import (
|
|
import (
|
|
"errors"
|
|
"errors"
|
|
- "fmt"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/gorilla/mux"
|
|
"html/template"
|
|
"html/template"
|
|
|
|
+ "log"
|
|
"net/http"
|
|
"net/http"
|
|
"net/url"
|
|
"net/url"
|
|
"path"
|
|
"path"
|
|
"path/filepath"
|
|
"path/filepath"
|
|
|
|
+ "strconv"
|
|
)
|
|
)
|
|
|
|
|
|
// Route names.
|
|
// Route names.
|
|
@@ -46,17 +47,28 @@ type Globals struct {
|
|
var globals Globals
|
|
var globals Globals
|
|
var tmpl *template.Template
|
|
var tmpl *template.Template
|
|
|
|
|
|
-// SetupRoutes() configures Web UI routes on the passed mux.Router.
|
|
|
|
-func SetupRoutes(router *mux.Router, configSiteBaseURL, configAssetsBaseURL, configAssetsPath string) {
|
|
|
|
- const assetsPrefix = "/public"
|
|
|
|
|
|
+// SetupUI() configures Web UI routes on the passed mux.Router.
|
|
|
|
+func SetupUI(router *mux.Router, configAssetsPath string) {
|
|
|
|
+ // Set up asset routes first, for them to have priority over possibly matching short URLs.
|
|
|
|
+ setupAssetRoutes(configAssetsPath, router)
|
|
|
|
+ setupControllerRoutes(router)
|
|
|
|
+ setupTemplates(configAssetsPath)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func setupAssetRoutes(configAssetsPath string, router *mux.Router) {
|
|
absAssetsDir, err := filepath.Abs(configAssetsPath)
|
|
absAssetsDir, err := filepath.Abs(configAssetsPath)
|
|
if err != nil {
|
|
if err != nil {
|
|
panic(err)
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
+ log.Printf("Serving assets from %s\n", absAssetsDir)
|
|
fs := http.FileServer(http.Dir(absAssetsDir))
|
|
fs := http.FileServer(http.Dir(absAssetsDir))
|
|
- router.PathPrefix(assetsPrefix).Handler(http.StripPrefix(assetsPrefix, fs))
|
|
|
|
router.Handle("/favicon.ico", fs)
|
|
router.Handle("/favicon.ico", fs)
|
|
|
|
+ for _, prefix := range []string{"css", "js", "images"} {
|
|
|
|
+ router.PathPrefix("/" + prefix).Handler(fs)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
|
|
+func setupControllerRoutes(router *mux.Router) {
|
|
// BUG(fgm): improve Accept header matchers once https://github.com/golang/go/issues/19307 is completed.
|
|
// BUG(fgm): improve Accept header matchers once https://github.com/golang/go/issues/19307 is completed.
|
|
router.HandleFunc("/{short}", func(w http.ResponseWriter, r *http.Request) {
|
|
router.HandleFunc("/{short}", func(w http.ResponseWriter, r *http.Request) {
|
|
handleGetShort(w, r, router)
|
|
handleGetShort(w, r, router)
|
|
@@ -71,7 +83,9 @@ func SetupRoutes(router *mux.Router, configSiteBaseURL, configAssetsBaseURL, con
|
|
router.HandleFunc("/", handleGetRoot).
|
|
router.HandleFunc("/", handleGetRoot).
|
|
Methods("GET", "HEAD").
|
|
Methods("GET", "HEAD").
|
|
Name(RouteGetRoot)
|
|
Name(RouteGetRoot)
|
|
|
|
+}
|
|
|
|
|
|
|
|
+func setupTemplates(configAssetsPath string) {
|
|
base, _ := filepath.Abs(configAssetsPath + "/../templates/")
|
|
base, _ := filepath.Abs(configAssetsPath + "/../templates/")
|
|
layout := base + "/layout"
|
|
layout := base + "/layout"
|
|
funcMap := template.FuncMap{
|
|
funcMap := template.FuncMap{
|
|
@@ -89,7 +103,7 @@ func SetupRoutes(router *mux.Router, configSiteBaseURL, configAssetsBaseURL, con
|
|
))
|
|
))
|
|
}
|
|
}
|
|
|
|
|
|
-func BuildGlobals(c map[string]interface{}) {
|
|
|
|
|
|
+func SetupGlobals(c map[string]interface{}) {
|
|
// Note: keys in viper are lower-cased.
|
|
// Note: keys in viper are lower-cased.
|
|
globals = Globals{
|
|
globals = Globals{
|
|
AssetsBaseURL: c["assetsbaseurl"].(string),
|
|
AssetsBaseURL: c["assetsbaseurl"].(string),
|
|
@@ -132,10 +146,10 @@ func URLForAsset(ns string, assetPath string) (string, error) {
|
|
panic(err)
|
|
panic(err)
|
|
}
|
|
}
|
|
// Handles "" cleanly, and doesn't use a "\" on windows, unlike filepath.Join.
|
|
// Handles "" cleanly, and doesn't use a "\" on windows, unlike filepath.Join.
|
|
- base.Path = path.Join(ns, assetPath)
|
|
|
|
|
|
+ base.Path = path.Join(base.Path, ns, assetPath)
|
|
|
|
|
|
// No need to url.QueryEscape() since this format is query-clean by construction.
|
|
// No need to url.QueryEscape() since this format is query-clean by construction.
|
|
- base.RawQuery = fmt.Sprintf("v=%d", version)
|
|
|
|
|
|
+ base.RawQuery = "v=" + strconv.Itoa(version)
|
|
|
|
|
|
res := base.String()
|
|
res := base.String()
|
|
return res, nil
|
|
return res, nil
|