diff options
author | Jan Dittberner <jandd@cacert.org> | 2018-03-29 21:26:12 +0200 |
---|---|---|
committer | Jan Dittberner <jandd@cacert.org> | 2018-03-29 21:26:12 +0200 |
commit | 94dcb5bd75faa4adaef9f56df197a42a5e978718 (patch) | |
tree | d4a11fae0058f92e7629d2c7719bdefc959ce32a | |
parent | 4dd5e0982050ae92a9a37cb62e606b2807a85c27 (diff) | |
download | cacert-boardvoting-94dcb5bd75faa4adaef9f56df197a42a5e978718.tar.gz cacert-boardvoting-94dcb5bd75faa4adaef9f56df197a42a5e978718.tar.xz cacert-boardvoting-94dcb5bd75faa4adaef9f56df197a42a5e978718.zip |
Use static assets for HTML templates
- implement custom http.Filesystem boardvoting.AssetFS
- replace "footer" and "header" with "footer.html" and "header.html"
- change renderTemplate to use Assets
- use boardvoting.GetAssetFS() with http.Fileserver
-rw-r--r-- | boardvoting.go | 36 | ||||
-rw-r--r-- | boardvoting/main.go | 140 | ||||
-rw-r--r-- | boardvoting/templates/create_motion_form.html | 4 | ||||
-rw-r--r-- | boardvoting/templates/denied.html | 6 | ||||
-rw-r--r-- | boardvoting/templates/direct_vote_form.html | 4 | ||||
-rw-r--r-- | boardvoting/templates/edit_motion_form.html | 4 | ||||
-rw-r--r-- | boardvoting/templates/footer.html | 2 | ||||
-rw-r--r-- | boardvoting/templates/header.html | 2 | ||||
-rw-r--r-- | boardvoting/templates/motion.html | 4 | ||||
-rw-r--r-- | boardvoting/templates/motion_fragments.html | 4 | ||||
-rw-r--r-- | boardvoting/templates/motions.html | 4 | ||||
-rw-r--r-- | boardvoting/templates/proxy_vote_form.html | 4 | ||||
-rw-r--r-- | boardvoting/templates/withdraw_motion_form.html | 4 |
13 files changed, 184 insertions, 34 deletions
diff --git a/boardvoting.go b/boardvoting.go index c1fa28f..a0d6359 100644 --- a/boardvoting.go +++ b/boardvoting.go @@ -10,7 +10,7 @@ import ( "encoding/pem" "flag" "fmt" - + "git.cacert.org/cacert-boardvoting/boardvoting" "github.com/Masterminds/sprig" "github.com/gorilla/sessions" _ "github.com/mattn/go-sqlite3" @@ -35,21 +35,31 @@ var log *logging.Logger const sessionCookieName = "votesession" -func getTemplateFilenames(templates []string) (result []string) { - result = make([]string, len(templates)) - for i := range templates { - result[i] = fmt.Sprintf("templates/%s", templates[i]) - } - return result -} - func renderTemplate(w http.ResponseWriter, templates []string, context interface{}) { funcMaps := sprig.FuncMap() funcMaps["nl2br"] = func(text string) template.HTML { return template.HTML(strings.Replace(template.HTMLEscapeString(text), "\n", "<br>", -1)) } - t := template.Must(template.New(templates[0]).Funcs(funcMaps).ParseFiles(getTemplateFilenames(templates)...)) - if err := t.Execute(w, context); err != nil { + + var baseTemplate *template.Template + + for count, t := range templates { + if assetBytes, err := boardvoting.Asset(fmt.Sprintf("templates/%s", t)); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } else { + if count == 0 { + if baseTemplate, err = template.New(t).Funcs(funcMaps).Parse(string(assetBytes)); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } else { + if _, err := baseTemplate.New(t).Funcs(funcMaps).Parse(string(assetBytes)); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + } + } + } + + if err := baseTemplate.Execute(w, context); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } @@ -733,7 +743,7 @@ func readConfig() { } func setupDbConfig(ctx context.Context) { - database, err := sql.Open("sqlite3", config.DatabaseFile) + database, err := sql.Open("sqlite3", config.DatabaseFile) if err != nil { log.Panicf("Opening database failed: %v", err) } @@ -777,7 +787,7 @@ func setupHandlers() { http.Handle("/newmotion/", motionsHandler{}) http.Handle("/proxy/", &decisionVoteHandler{}) http.Handle("/vote/", &decisionVoteHandler{}) - http.Handle("/static/", http.FileServer(http.Dir("."))) + http.Handle("/static/", http.FileServer(boardvoting.GetAssetFS())) http.Handle("/", http.RedirectHandler("/motions/", http.StatusMovedPermanently)) } diff --git a/boardvoting/main.go b/boardvoting/main.go index 5c8e6eb..7cc6005 100644 --- a/boardvoting/main.go +++ b/boardvoting/main.go @@ -1,3 +1,143 @@ package boardvoting //go:generate go-bindata -pkg $GOPACKAGE -o assets.go ./migrations/... ./static/... ./templates/... + +import ( + "bytes" + "errors" + "io" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strings" + "time" +) + +var defaultFileTimestamp = time.Now() + +type AssetFS struct { + Asset func(path string) ([]byte, error) + AssetDir func(path string) ([]string, error) + AssetInfo func(path string) (os.FileInfo, error) +} + +type FakeFile struct { + Path string + Dir bool + Len int64 + Timestamp time.Time +} + +func (f *FakeFile) Name() string { + _, name := filepath.Split(f.Path) + return name +} + +func (f *FakeFile) Size() int64 { return f.Len } + +func (f *FakeFile) Mode() os.FileMode { + mode := os.FileMode(0644) + if f.Dir { + return mode | os.ModeDir + } + return mode +} + +func (f *FakeFile) ModTime() time.Time { return f.Timestamp } +func (f *FakeFile) IsDir() bool { return f.Dir } +func (f *FakeFile) Sys() interface{} { return nil } + +type AssetFile struct { + *bytes.Reader + io.Closer + FakeFile +} + +func NewAssetFile(name string, content []byte, timestamp time.Time) *AssetFile { + if timestamp.IsZero() { + timestamp = defaultFileTimestamp + } + return &AssetFile{ + bytes.NewReader(content), + ioutil.NopCloser(nil), + FakeFile{name, false, int64(len(content)), timestamp}, + } +} + +func (f *AssetFile) Readdir(count int) ([]os.FileInfo, error) { + return nil, errors.New("not a directory") +} + +func (f *AssetFile) Size() int64 { + return f.FakeFile.Size() +} + +func (f *AssetFile) Stat() (os.FileInfo, error) { + return f, nil +} + +type AssetDirectory struct { + AssetFile + ChildrenRead int + Children []os.FileInfo +} + +func (f *AssetDirectory) Readdir(count int) ([]os.FileInfo, error) { + if count <= 0 { + return f.Children, nil + } + if f.ChildrenRead+count > len(f.Children) { + count = len(f.Children) - f.ChildrenRead + } + rv := f.Children[f.ChildrenRead : f.ChildrenRead+count] + f.ChildrenRead += count + return rv, nil +} + +func (f *AssetDirectory) Stat() (os.FileInfo, error) { + return f, nil +} + +func NewAssetDirectory(name string, children []string, fs *AssetFS) *AssetDirectory { + fileInfos := make([]os.FileInfo, 0, len(children)) + for _, child := range children { + _, err := fs.AssetDir(filepath.Join(name, child)) + fileInfos = append(fileInfos, &FakeFile{child, err == nil, 0, time.Time{}}) + } + return &AssetDirectory{ + AssetFile{ + bytes.NewReader(nil), + ioutil.NopCloser(nil), + FakeFile{name, true, 0, time.Time{}}, + }, + 0, + fileInfos} +} + +func (f *AssetFS) Open(name string) (http.File, error) { + if len(name) > 0 && name[0] == '/' { + name = name[1:] + } + if b, err := f.Asset(name); err == nil { + timestamp := defaultFileTimestamp + if f.AssetInfo != nil { + if info, err := f.AssetInfo(name); err == nil { + timestamp = info.ModTime() + } + } + return NewAssetFile(name, b, timestamp), nil + } + if children, err := f.AssetDir(name); err == nil { + return NewAssetDirectory(name, children, f), nil + } else { + if strings.Contains(err.Error(), "not found") { + return nil, os.ErrNotExist + } + return nil, err + } +} + +func GetAssetFS() *AssetFS { + return &AssetFS{Asset: Asset, AssetDir: AssetDir, AssetInfo: AssetInfo} +} diff --git a/boardvoting/templates/create_motion_form.html b/boardvoting/templates/create_motion_form.html index b3cbadb..5958aa7 100644 --- a/boardvoting/templates/create_motion_form.html +++ b/boardvoting/templates/create_motion_form.html @@ -1,4 +1,4 @@ -{{ template "header" . }} +{{ template "header.html" . }} <div class="column"> <div class="ui basic segment"> <div class="ui floated right secondary menu"> @@ -70,4 +70,4 @@ </form> </div> </div> -{{ template "footer" . }}
\ No newline at end of file +{{ template "footer.html" . }}
\ No newline at end of file diff --git a/boardvoting/templates/denied.html b/boardvoting/templates/denied.html index 398a36f..53bb364 100644 --- a/boardvoting/templates/denied.html +++ b/boardvoting/templates/denied.html @@ -1,7 +1,7 @@ -{{ template "header" . }} +{{ template "header.html" . }} <div class="column"> <div class="ui negative message"> - <div class="header">You are not authorized to act here!</div> + <div class="header.html">You are not authorized to act here!</div> <p>If you think this is in error, please contact the administrator.</p> <p>If you don't know who that is, it is definitely not an error ;)</p> {{ if .Emails }} @@ -14,4 +14,4 @@ {{ end }} </div> </div> -{{ template "footer" . }}
\ No newline at end of file +{{ template "footer.html" . }}
\ No newline at end of file diff --git a/boardvoting/templates/direct_vote_form.html b/boardvoting/templates/direct_vote_form.html index 861c68a..649c059 100644 --- a/boardvoting/templates/direct_vote_form.html +++ b/boardvoting/templates/direct_vote_form.html @@ -1,4 +1,4 @@ -{{ template "header" . }} +{{ template "header.html" . }} <div class="column"> <div class="ui basic segment"> <div class="ui floated right secondary menu"> @@ -24,4 +24,4 @@ {{ end }} </div> </form> -{{ template "footer" . }}
\ No newline at end of file +{{ template "footer.html" . }}
\ No newline at end of file diff --git a/boardvoting/templates/edit_motion_form.html b/boardvoting/templates/edit_motion_form.html index f686183..845442d 100644 --- a/boardvoting/templates/edit_motion_form.html +++ b/boardvoting/templates/edit_motion_form.html @@ -1,4 +1,4 @@ -{{ template "header" . }} +{{ template "header.html" . }} <div class="column"> <div class="ui floated right secondary menu"> <a href="/motions/" class="item" title="Show all votes">Back to @@ -69,4 +69,4 @@ </form> </div> </div> -{{ template "footer" . }}
\ No newline at end of file +{{ template "footer.html" . }}
\ No newline at end of file diff --git a/boardvoting/templates/footer.html b/boardvoting/templates/footer.html index f2bc089..fa873e5 100644 --- a/boardvoting/templates/footer.html +++ b/boardvoting/templates/footer.html @@ -1,4 +1,4 @@ -{{ define "footer" }} +{{ define "footer.html" }} </div> <script type="text/javascript"> $(document).ready(function() { diff --git a/boardvoting/templates/header.html b/boardvoting/templates/header.html index 8e0aedc..8215f71 100644 --- a/boardvoting/templates/header.html +++ b/boardvoting/templates/header.html @@ -1,4 +1,4 @@ -{{ define "header" -}} +{{ define "header.html" -}} <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/html"> <head> diff --git a/boardvoting/templates/motion.html b/boardvoting/templates/motion.html index 8fc7530..e78a955 100644 --- a/boardvoting/templates/motion.html +++ b/boardvoting/templates/motion.html @@ -1,4 +1,4 @@ -{{ template "header" . }} +{{ template "header.html" . }} {{ $voter := .Voter }} <div class="column"> <div class="ui basic segment"> @@ -16,4 +16,4 @@ </div> </div> {{ end}} -{{ template "footer" . }}
\ No newline at end of file +{{ template "footer.html" . }}
\ No newline at end of file diff --git a/boardvoting/templates/motion_fragments.html b/boardvoting/templates/motion_fragments.html index dbe59c2..96a1938 100644 --- a/boardvoting/templates/motion_fragments.html +++ b/boardvoting/templates/motion_fragments.html @@ -1,7 +1,7 @@ {{ define "motion_fragment" }} <span class="ui {{ template "status_class" .Status }} ribbon label">{{ .Status|toString|title }}</span> -<span class="header">{{ .Modified|date "2006-01-02 15:04:05 UTC" }}</span> -<h3 class="header"><a href="/motions/{{ .Tag }}">{{ .Tag }}: {{ .Title }}</a></h3> +<span class="header.html">{{ .Modified|date "2006-01-02 15:04:05 UTC" }}</span> +<h3 class="header.html"><a href="/motions/{{ .Tag }}">{{ .Tag }}: {{ .Title }}</a></h3> <p>{{ wrap 76 .Content | nl2br }}</p> <table class="ui small definition table"> <tbody> diff --git a/boardvoting/templates/motions.html b/boardvoting/templates/motions.html index 3f82092..625dc57 100644 --- a/boardvoting/templates/motions.html +++ b/boardvoting/templates/motions.html @@ -1,4 +1,4 @@ -{{ template "header" . }} +{{ template "header.html" . }} {{ $voter := .Voter }} <div class="column"> <div class="ui basic segment"> @@ -49,4 +49,4 @@ <p>There are no motions in the system yet.</p> {{ end }} {{ end }} -{{ template "footer" . }}
\ No newline at end of file +{{ template "footer.html" . }}
\ No newline at end of file diff --git a/boardvoting/templates/proxy_vote_form.html b/boardvoting/templates/proxy_vote_form.html index 3bfa9df..3a344c3 100644 --- a/boardvoting/templates/proxy_vote_form.html +++ b/boardvoting/templates/proxy_vote_form.html @@ -1,4 +1,4 @@ -{{ template "header" . }} +{{ template "header.html" . }} {{ $form := .Form }} <div class="column"> <div class="ui basic segment"> @@ -51,4 +51,4 @@ </form> </div> </div> -{{ template "footer" . }}
\ No newline at end of file +{{ template "footer.html" . }}
\ No newline at end of file diff --git a/boardvoting/templates/withdraw_motion_form.html b/boardvoting/templates/withdraw_motion_form.html index c5f0846..87ebb57 100644 --- a/boardvoting/templates/withdraw_motion_form.html +++ b/boardvoting/templates/withdraw_motion_form.html @@ -1,4 +1,4 @@ -{{ template "header" . }} +{{ template "header.html" . }} <div class="column"> <div class="ui basic segment"> <div class="ui floated right secondary menu"> @@ -18,4 +18,4 @@ <button class="ui primary left labeled icon button" type="submit"><i class="trash icon"></i> Withdraw</button> </div> </form> -{{ template "footer" . }} +{{ template "footer.html" . }} |