template.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright 2017 Frédéric Guilloe. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package template
  5. import (
  6. "bytes"
  7. "html/template"
  8. "io"
  9. "log"
  10. "net/url"
  11. "strings"
  12. "time"
  13. "github.com/miniflux/miniflux2/config"
  14. "github.com/miniflux/miniflux2/errors"
  15. "github.com/miniflux/miniflux2/locale"
  16. "github.com/miniflux/miniflux2/server/route"
  17. "github.com/miniflux/miniflux2/server/template/helper"
  18. "github.com/miniflux/miniflux2/server/ui/filter"
  19. "github.com/gorilla/mux"
  20. )
  21. // Engine handles the templating system.
  22. type Engine struct {
  23. templates map[string]*template.Template
  24. router *mux.Router
  25. translator *locale.Translator
  26. currentLocale *locale.Language
  27. cfg *config.Config
  28. }
  29. func (e *Engine) parseAll() {
  30. funcMap := template.FuncMap{
  31. "baseURL": func() string {
  32. return e.cfg.Get("BASE_URL", config.DefaultBaseURL)
  33. },
  34. "hasOAuth2Provider": func(provider string) bool {
  35. return e.cfg.Get("OAUTH2_PROVIDER", "") == provider
  36. },
  37. "route": func(name string, args ...interface{}) string {
  38. return route.GetRoute(e.router, name, args...)
  39. },
  40. "noescape": func(str string) template.HTML {
  41. return template.HTML(str)
  42. },
  43. "proxyFilter": func(data string) string {
  44. return filter.ImageProxyFilter(e.router, data)
  45. },
  46. "domain": func(websiteURL string) string {
  47. parsedURL, err := url.Parse(websiteURL)
  48. if err != nil {
  49. return websiteURL
  50. }
  51. return parsedURL.Host
  52. },
  53. "hasPrefix": func(str, prefix string) bool {
  54. return strings.HasPrefix(str, prefix)
  55. },
  56. "contains": func(str, substr string) bool {
  57. return strings.Contains(str, substr)
  58. },
  59. "isodate": func(ts time.Time) string {
  60. return ts.Format("2006-01-02 15:04:05")
  61. },
  62. "elapsed": func(ts time.Time) string {
  63. return helper.GetElapsedTime(e.currentLocale, ts)
  64. },
  65. "t": func(key interface{}, args ...interface{}) string {
  66. switch key.(type) {
  67. case string:
  68. return e.currentLocale.Get(key.(string), args...)
  69. case errors.LocalizedError:
  70. err := key.(errors.LocalizedError)
  71. return err.Localize(e.currentLocale)
  72. case error:
  73. return key.(error).Error()
  74. default:
  75. return ""
  76. }
  77. },
  78. "plural": func(key string, n int, args ...interface{}) string {
  79. return e.currentLocale.Plural(key, n, args...)
  80. },
  81. }
  82. commonTemplates := ""
  83. for _, content := range templateCommonMap {
  84. commonTemplates += content
  85. }
  86. for name, content := range templateViewsMap {
  87. log.Println("Parsing template:", name)
  88. e.templates[name] = template.Must(template.New("main").Funcs(funcMap).Parse(commonTemplates + content))
  89. }
  90. }
  91. // SetLanguage change the language for template processing.
  92. func (e *Engine) SetLanguage(language string) {
  93. e.currentLocale = e.translator.GetLanguage(language)
  94. }
  95. // Execute process a template.
  96. func (e *Engine) Execute(w io.Writer, name string, data interface{}) {
  97. tpl, ok := e.templates[name]
  98. if !ok {
  99. log.Fatalf("The template %s does not exists.\n", name)
  100. }
  101. var b bytes.Buffer
  102. err := tpl.ExecuteTemplate(&b, "base", data)
  103. if err != nil {
  104. log.Fatalf("Unable to render template: %v\n", err)
  105. }
  106. b.WriteTo(w)
  107. }
  108. // NewEngine returns a new template Engine.
  109. func NewEngine(cfg *config.Config, router *mux.Router, translator *locale.Translator) *Engine {
  110. tpl := &Engine{
  111. templates: make(map[string]*template.Template),
  112. router: router,
  113. translator: translator,
  114. cfg: cfg,
  115. }
  116. tpl.parseAll()
  117. return tpl
  118. }