From 7008e79c9c99e9613d0e210cdd58c1fcb1034c7e Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Fri, 30 Jun 2017 14:39:25 -0400 Subject: [PATCH] ability to server website from disk --- router/router.go | 20 +++--- server/template/files/index_polymer.html | 33 ++++++++++ server/template/template_gen.go | 39 ++++++++++++ server/ui.go | 78 ++++++++++++++++++++++++ server/ui_local.go | 66 ++++++++++++++++++++ 5 files changed, 224 insertions(+), 12 deletions(-) create mode 100644 server/template/files/index_polymer.html create mode 100644 server/ui.go create mode 100644 server/ui_local.go diff --git a/router/router.go b/router/router.go index a32615673..897ffb1a4 100644 --- a/router/router.go +++ b/router/router.go @@ -2,7 +2,6 @@ package router import ( "net/http" - "os" "github.com/gin-gonic/gin" @@ -13,8 +12,6 @@ import ( "github.com/drone/drone/server/debug" "github.com/drone/drone/server/metrics" "github.com/drone/drone/server/template" - - "github.com/drone/drone-ui/dist" ) // Load loads the router @@ -24,13 +21,11 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { e.Use(gin.Recovery()) e.SetHTMLTemplate(template.T) - if dir := os.Getenv("DRONE_STATIC_DIR"); dir == "" { - fs := http.FileServer(dist.AssetFS()) - e.GET("/static/*filepath", func(c *gin.Context) { - fs.ServeHTTP(c.Writer, c.Request) + ui := server.NewWebsite() + for _, path := range ui.Routes() { + e.GET(path, func(c *gin.Context) { + ui.File(c.Writer, c.Request) }) - } else { - e.Static("/static", dir) } e.Use(header.NoCache) @@ -40,10 +35,11 @@ func Load(middleware ...gin.HandlerFunc) http.Handler { e.Use(session.SetUser()) e.Use(token.Refresh) - e.GET("/login", server.ShowLogin) - e.GET("/login/form", server.ShowLoginForm) e.GET("/logout", server.GetLogout) - e.NoRoute(server.ShowIndex) + e.NoRoute(func(c *gin.Context) { + u := session.User(c) + ui.Page(c.Writer, c.Request, u) + }) user := e.Group("/api/user") { diff --git a/server/template/files/index_polymer.html b/server/template/files/index_polymer.html new file mode 100644 index 000000000..ce1fc9fe9 --- /dev/null +++ b/server/template/files/index_polymer.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/server/template/template_gen.go b/server/template/template_gen.go index 625f7bf49..459d97bd0 100644 --- a/server/template/template_gen.go +++ b/server/template/template_gen.go @@ -13,6 +13,9 @@ var files = []struct { }, { name: "index.html", data: index, + }, { + name: "index_polymer.html", + data: indexpolymer, }, { name: "login.html", data: login, @@ -83,6 +86,42 @@ var index = ` ` +// files/index_polymer.html +var indexpolymer = ` + + + + + + + + + + + + + + + + + + + + +` + // files/login.html var login = ` diff --git a/server/ui.go b/server/ui.go new file mode 100644 index 000000000..8ba5dbb99 --- /dev/null +++ b/server/ui.go @@ -0,0 +1,78 @@ +package server + +import ( + "net/http" + "os" + + "github.com/drone/drone-ui/dist" + "github.com/drone/drone/model" + "github.com/drone/drone/server/template" + "github.com/drone/drone/shared/token" +) + +// Website defines an interface to serve the user interface. +type Website interface { + Page(rw http.ResponseWriter, r *http.Request, u *model.User) + File(rw http.ResponseWriter, r *http.Request) + Routes() []string +} + +type website struct { + fs http.Handler +} + +// NewWebsite returns a new website loader. +func NewWebsite() Website { + path := os.Getenv("DRONE_WWW") + if path != "" { + return NewLocalWebsite(path) + } + return &website{ + fs: http.FileServer(dist.AssetFS()), + } +} + +// Page serves a page in the user interface. +func (w *website) Page(rw http.ResponseWriter, r *http.Request, u *model.User) { + rw.WriteHeader(200) + + path := r.URL.Path + switch path { + case "/login/form": + params := map[string]interface{}{} + template.T.ExecuteTemplate(rw, "login.html", params) + + case "/login": + if err := r.FormValue("error"); err != "" { + params := map[string]interface{}{"error": err} + template.T.ExecuteTemplate(rw, "error.html", params) + } else { + http.Redirect(rw, r, "/authorize", 303) + } + + default: + var csrf string + if u != nil { + csrf, _ = token.New( + token.CsrfToken, + u.Login, + ).Sign(u.Hash) + } + params := map[string]interface{}{ + "user": u, + "csrf": csrf, + } + template.T.ExecuteTemplate(rw, "index.html", params) + } +} + +// File serves a static file for the user interface. +func (w *website) File(rw http.ResponseWriter, r *http.Request) { + w.fs.ServeHTTP(rw, r) +} + +func (w *website) Routes() []string { + return []string{ + "/static/*filepath", + } +} diff --git a/server/ui_local.go b/server/ui_local.go new file mode 100644 index 000000000..9605523d3 --- /dev/null +++ b/server/ui_local.go @@ -0,0 +1,66 @@ +package server + +import ( + "net/http" + + "github.com/drone/drone/model" + "github.com/drone/drone/server/template" + "github.com/drone/drone/shared/token" +) + +type local struct { + dir string + fs http.Handler +} + +// NewLocalWebsite returns a new website loader. +func NewLocalWebsite(path string) Website { + return &local{ + dir: path, + fs: http.FileServer( + http.Dir(path), + ), + } +} + +// Page serves a page in the user interface. +func (w *local) Page(rw http.ResponseWriter, r *http.Request, u *model.User) { + rw.WriteHeader(200) + + path := r.URL.Path + switch path { + case "/login": + if err := r.FormValue("error"); err != "" { + // TODO login error + } else { + http.Redirect(rw, r, "/authorize", 303) + } + + default: + var csrf string + if u != nil { + csrf, _ = token.New( + token.CsrfToken, + u.Login, + ).Sign(u.Hash) + } + params := map[string]interface{}{ + "user": u, + "csrf": csrf, + } + + template.T.ExecuteTemplate(rw, "index_polymer.html", params) + } +} + +// File serves a static file for the user interface. +func (w *local) File(rw http.ResponseWriter, r *http.Request) { + w.fs.ServeHTTP(rw, r) +} + +func (w *local) Routes() []string { + return []string{ + "/src/*filepath", + "/bower_components/*filepath", + } +}