Initial commit
This commit is contained in:
commit
2422e3108f
37 changed files with 12691 additions and 0 deletions
79
views/funcs.go
Normal file
79
views/funcs.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var funcs = template.FuncMap{
|
||||
"asset": assetURLFn,
|
||||
"url": relURLFn,
|
||||
"lower": lower,
|
||||
"upper": upper,
|
||||
"date": dateFn,
|
||||
"humanDate": readableDateFn,
|
||||
"t": translateFn,
|
||||
}
|
||||
|
||||
func lower(input string) string {
|
||||
return strings.ToLower(input)
|
||||
}
|
||||
|
||||
func upper(input string) string {
|
||||
return strings.ToUpper(input)
|
||||
}
|
||||
|
||||
func assetURLFn(input string) string {
|
||||
url := "/static/" //os.Getenv("ASSET_URL")
|
||||
return fmt.Sprintf("%s%s", url, input)
|
||||
}
|
||||
|
||||
func relURLFn(input string) string {
|
||||
url := "/" //os.Getenv("ASSET_URL")
|
||||
return fmt.Sprintf("%s%s", url, input)
|
||||
}
|
||||
|
||||
func dateFn(format string, input interface{}) string {
|
||||
var t time.Time
|
||||
switch date := input.(type) {
|
||||
default:
|
||||
t = time.Now()
|
||||
case time.Time:
|
||||
t = date
|
||||
}
|
||||
|
||||
return t.Format(format)
|
||||
}
|
||||
|
||||
func translateFn(language string, text string) string {
|
||||
return text
|
||||
}
|
||||
|
||||
func readableDateFn(t time.Time) string {
|
||||
if time.Now().Before(t) {
|
||||
return "in the future"
|
||||
}
|
||||
diff := time.Now().Sub(t)
|
||||
day := 24 * time.Hour
|
||||
month := 30 * day
|
||||
year := 12 * month
|
||||
|
||||
switch {
|
||||
case diff < time.Second:
|
||||
return "just now"
|
||||
case diff < 5*time.Minute:
|
||||
return "a few minutes ago"
|
||||
case diff < time.Hour:
|
||||
return fmt.Sprintf("%d minutes ago", diff/time.Minute)
|
||||
case diff < day:
|
||||
return fmt.Sprintf("%d hours ago", diff/time.Hour)
|
||||
case diff < month:
|
||||
return fmt.Sprintf("%d days ago", diff/day)
|
||||
case diff < year:
|
||||
return fmt.Sprintf("%d months ago", diff/month)
|
||||
default:
|
||||
return fmt.Sprintf("%d years ago", diff/year)
|
||||
}
|
||||
}
|
92
views/templates.go
Normal file
92
views/templates.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
|
||||
"git.klink.asia/paul/certman/assets"
|
||||
)
|
||||
|
||||
// map of all parsed templates, by template name
|
||||
var templates map[string]*template.Template
|
||||
|
||||
// LoadTemplates initializes the templates map, parsing all defined templates.
|
||||
func LoadTemplates() {
|
||||
templates = map[string]*template.Template{
|
||||
"401": newTemplate("layouts/application.gohtml", "errors/401.gohtml"),
|
||||
"403": newTemplate("layouts/application.gohtml", "errors/403.gohtml"),
|
||||
"404": newTemplate("layouts/application.gohtml", "errors/404.gohtml"),
|
||||
"500": newTemplate("layouts/application.gohtml", "errors/500.gohtml"),
|
||||
|
||||
"login": newTemplate("layouts/auth.gohtml", "views/login.gohtml"),
|
||||
|
||||
"client_list": newTemplate("layouts/application.gohtml", "views/client_list.gohtml"),
|
||||
|
||||
"config.ovpn": newTemplate("files/config.ovpn"),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// newTemplate returns a new template from the assets
|
||||
func newTemplate(filenames ...string) *template.Template {
|
||||
f := []string{}
|
||||
prefix := "/templates"
|
||||
|
||||
for _, filename := range filenames {
|
||||
f = append(f, filepath.Join(prefix, filename))
|
||||
}
|
||||
|
||||
baseTemplate := template.New("base").Funcs(funcs)
|
||||
tmpl, err := parseAssets(baseTemplate, assets.Assets, f...)
|
||||
if err != nil {
|
||||
log.Fatalf("could not parse template: %s", err.Error())
|
||||
}
|
||||
|
||||
return tmpl
|
||||
|
||||
}
|
||||
|
||||
// parseAssets is a helper function to generate a template from multiple
|
||||
// assets. If the argument template is nil, it is created from the first
|
||||
// parameter that is passed (first file).
|
||||
func parseAssets(t *template.Template, fs http.FileSystem, assets ...string) (*template.Template, error) {
|
||||
if len(assets) == 0 {
|
||||
// Not really a problem, but be consistent.
|
||||
return nil, fmt.Errorf("no templates supplied in call to parseAssets")
|
||||
}
|
||||
|
||||
for _, filename := range assets {
|
||||
f, err := fs.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(f)
|
||||
s := buf.String()
|
||||
|
||||
name := filepath.Base(filename)
|
||||
// First template becomes return value if not already defined,
|
||||
// and we use that one for subsequent New calls to associate
|
||||
// all the templates together.
|
||||
var tmpl *template.Template
|
||||
if t == nil {
|
||||
t = template.New(name)
|
||||
}
|
||||
if name == t.Name() {
|
||||
tmpl = t
|
||||
} else {
|
||||
tmpl = t.New(name)
|
||||
}
|
||||
_, err = tmpl.Parse(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
}
|
110
views/views.go
Normal file
110
views/views.go
Normal file
|
@ -0,0 +1,110 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"git.klink.asia/paul/certman/services"
|
||||
|
||||
"github.com/gorilla/csrf"
|
||||
)
|
||||
|
||||
type View struct {
|
||||
Vars map[string]interface{}
|
||||
Request *http.Request
|
||||
SessionStore *services.Sessions
|
||||
}
|
||||
|
||||
func New(req *http.Request) *View {
|
||||
return &View{
|
||||
Request: req,
|
||||
Vars: map[string]interface{}{
|
||||
"CSRF_TOKEN": csrf.Token(req),
|
||||
"csrfField": csrf.TemplateField(req),
|
||||
"Meta": map[string]interface{}{
|
||||
"Path": req.URL.Path,
|
||||
"Env": "develop",
|
||||
},
|
||||
"flashes": []services.Flash{},
|
||||
"username": "",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewWithSession(req *http.Request, sessionStore *services.Sessions) *View {
|
||||
return &View{
|
||||
Request: req,
|
||||
SessionStore: sessionStore,
|
||||
Vars: map[string]interface{}{
|
||||
"CSRF_TOKEN": csrf.Token(req),
|
||||
"csrfField": csrf.TemplateField(req),
|
||||
"Meta": map[string]interface{}{
|
||||
"Path": req.URL.Path,
|
||||
"Env": "develop",
|
||||
},
|
||||
"flashes": []services.Flash{},
|
||||
"username": sessionStore.GetUsername(req),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (view View) Render(w http.ResponseWriter, name string) {
|
||||
var err error
|
||||
|
||||
t, err := GetTemplate(name)
|
||||
if err != nil {
|
||||
log.Printf("the template '%s' does not exist.", name)
|
||||
view.RenderError(w, 404)
|
||||
return
|
||||
}
|
||||
|
||||
if view.SessionStore != nil {
|
||||
// add flashes to template
|
||||
view.Vars["flashes"] = view.SessionStore.Flashes(w, view.Request)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
t.Execute(w, view.Vars)
|
||||
|
||||
}
|
||||
|
||||
func (view View) RenderError(w http.ResponseWriter, status int) {
|
||||
var name string
|
||||
|
||||
switch status {
|
||||
case http.StatusUnauthorized:
|
||||
name = "401"
|
||||
case http.StatusForbidden:
|
||||
name = "403"
|
||||
case http.StatusNotFound:
|
||||
name = "404"
|
||||
default:
|
||||
name = "500"
|
||||
}
|
||||
|
||||
t, err := GetTemplate(name)
|
||||
if err != nil {
|
||||
log.Printf("the error template '%s' does not exist.", name)
|
||||
fmt.Fprintf(w, "Error page for status '%d' could not be rendered.", status)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(status)
|
||||
t.Execute(w, view.Vars)
|
||||
|
||||
}
|
||||
|
||||
// GetTemplate returns a parsed template. The template ,ap needs to be
|
||||
// Initialized by calling `LoadTemplates()` first.
|
||||
func GetTemplate(name string) (*template.Template, error) {
|
||||
if tmpl, ok := templates[name]; ok {
|
||||
return tmpl, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("Template not found")
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue