Files
mattermost/utils/html.go

135 lines
3.2 KiB
Go
Raw Normal View History

// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
2016-02-08 07:26:10 -05:00
// See License.txt for license information.
package utils
import (
"bytes"
"html/template"
2017-11-20 11:57:45 -06:00
"io"
"reflect"
2017-11-20 11:57:45 -06:00
"sync/atomic"
2016-02-08 07:26:10 -05:00
l4g "github.com/alecthomas/log4go"
"github.com/fsnotify/fsnotify"
"github.com/nicksnyder/go-i18n/i18n"
2016-02-08 07:26:10 -05:00
)
2017-11-20 11:57:45 -06:00
type HTMLTemplateWatcher struct {
templates atomic.Value
stop chan struct{}
stopped chan struct{}
2016-02-08 07:26:10 -05:00
}
2017-11-20 11:57:45 -06:00
func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
templatesDir, _ := FindDir(directory)
l4g.Debug(T("api.api.init.parsing_templates.debug"), templatesDir)
2016-03-14 16:07:58 -07:00
2017-11-20 11:57:45 -06:00
ret := &HTMLTemplateWatcher{
stop: make(chan struct{}),
stopped: make(chan struct{}),
}
2016-03-14 16:07:58 -07:00
2017-11-20 11:57:45 -06:00
watcher, err := fsnotify.NewWatcher()
if err != nil {
return nil, err
2016-03-14 16:07:58 -07:00
}
2017-11-20 11:57:45 -06:00
if err = watcher.Add(templatesDir); err != nil {
return nil, err
2016-02-08 07:26:10 -05:00
}
2017-11-20 11:57:45 -06:00
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
return nil, err
} else {
ret.templates.Store(htmlTemplates)
2016-02-08 07:26:10 -05:00
}
go func() {
2017-11-20 11:57:45 -06:00
defer close(ret.stopped)
defer watcher.Close()
2016-02-08 07:26:10 -05:00
for {
select {
2017-11-20 11:57:45 -06:00
case <-ret.stop:
return
2016-02-08 07:26:10 -05:00
case event := <-watcher.Events:
if event.Op&fsnotify.Write == fsnotify.Write {
l4g.Info(T("web.reparse_templates.info"), event.Name)
2017-11-20 11:57:45 -06:00
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
2016-02-08 07:26:10 -05:00
l4g.Error(T("web.parsing_templates.error"), err)
2017-11-20 11:57:45 -06:00
} else {
ret.templates.Store(htmlTemplates)
2016-02-08 07:26:10 -05:00
}
}
case err := <-watcher.Errors:
l4g.Error(T("web.dir_fail.error"), err)
}
}
}()
2017-11-20 11:57:45 -06:00
return ret, nil
2016-02-08 07:26:10 -05:00
}
2017-11-20 11:57:45 -06:00
func (w *HTMLTemplateWatcher) Templates() *template.Template {
return w.templates.Load().(*template.Template)
2016-02-08 07:26:10 -05:00
}
2017-11-20 11:57:45 -06:00
func (w *HTMLTemplateWatcher) Close() {
close(w.stop)
<-w.stopped
}
2017-11-20 11:57:45 -06:00
type HTMLTemplate struct {
Templates *template.Template
TemplateName string
Props map[string]interface{}
Html map[string]template.HTML
}
2017-11-20 11:57:45 -06:00
func NewHTMLTemplate(templates *template.Template, templateName string) *HTMLTemplate {
return &HTMLTemplate{
Templates: templates,
TemplateName: templateName,
Props: make(map[string]interface{}),
Html: make(map[string]template.HTML),
}
2016-02-08 07:26:10 -05:00
}
func (t *HTMLTemplate) Render() string {
var text bytes.Buffer
2017-11-20 11:57:45 -06:00
t.RenderToWriter(&text)
2016-02-08 07:26:10 -05:00
return text.String()
}
2017-11-20 11:57:45 -06:00
func (t *HTMLTemplate) RenderToWriter(w io.Writer) error {
if err := t.Templates.ExecuteTemplate(w, t.TemplateName, t); err != nil {
2016-02-08 07:26:10 -05:00
l4g.Error(T("api.api.render.error"), t.TemplateName, err)
return err
}
2016-02-08 07:26:10 -05:00
return nil
}
func TranslateAsHtml(t i18n.TranslateFunc, translationID string, args map[string]interface{}) template.HTML {
return template.HTML(t(translationID, escapeForHtml(args)))
}
func escapeForHtml(arg interface{}) interface{} {
switch typedArg := arg.(type) {
case string:
return template.HTMLEscapeString(typedArg)
case *string:
return template.HTMLEscapeString(*typedArg)
case map[string]interface{}:
safeArg := make(map[string]interface{}, len(typedArg))
for key, value := range typedArg {
safeArg[key] = escapeForHtml(value)
}
return safeArg
default:
l4g.Warn("Unable to escape value for HTML template %v of type %v", arg, reflect.ValueOf(arg).Type())
return ""
}
}