Merge pull request #2098 from bradrydzewski/master

ability to serve website from disk
This commit is contained in:
Brad Rydzewski 2017-06-30 14:45:11 -04:00 committed by GitHub
commit 8c91205042
5 changed files with 224 additions and 12 deletions

View file

@ -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")
{

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="author" content="bradrydzewski">
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
<title></title>
<script>
window.ENV = {};
window.ENV.server = window.location.protocol+"//"+window.location.host;
{{ if .csrf }}window.ENV.csrf = "{{ .csrf }}"{{ end }}
{{ if .user }}
window.USER = {{ json .user }};
{{ end }}
</script>
<script src="/bower_components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono">
<link rel="import" href="/src/drone/drone-app.html">
<style>
html, body {
padding:0px;
margin:0px;
}
</style>
</head>
<body>
<drone-app></drone-app>
</body>
</html>

View file

@ -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 = `<!DOCTYPE html>
</html>
`
// files/index_polymer.html
var indexpolymer = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="author" content="bradrydzewski">
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes">
<title></title>
<script>
window.ENV = {};
window.ENV.server = window.location.protocol+"//"+window.location.host;
{{ if .csrf }}window.ENV.csrf = "{{ .csrf }}"{{ end }}
{{ if .user }}
window.USER = {{ json .user }};
{{ end }}
</script>
<script src="/bower_components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono">
<link rel="import" href="/src/drone/drone-app.html">
<style>
html, body {
padding:0px;
margin:0px;
}
</style>
</head>
<body>
<drone-app></drone-app>
</body>
</html>
`
// files/login.html
var login = `<!DOCTYPE html>
<html>

78
server/ui.go Normal file
View file

@ -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",
}
}

66
server/ui_local.go Normal file
View file

@ -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",
}
}