template.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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/mail"
  11. "net/url"
  12. "strings"
  13. "time"
  14. "github.com/miniflux/miniflux2/config"
  15. "github.com/miniflux/miniflux2/errors"
  16. "github.com/miniflux/miniflux2/locale"
  17. "github.com/miniflux/miniflux2/server/route"
  18. "github.com/miniflux/miniflux2/server/template/helper"
  19. "github.com/miniflux/miniflux2/server/ui/filter"
  20. "github.com/gorilla/mux"
  21. )
  22. // Engine handles the templating system.
  23. type Engine struct {
  24. templates map[string]*template.Template
  25. router *mux.Router
  26. translator *locale.Translator
  27. currentLocale *locale.Language
  28. cfg *config.Config
  29. }
  30. func (e *Engine) parseAll() {
  31. funcMap := template.FuncMap{
  32. "baseURL": func() string {
  33. return e.cfg.Get("BASE_URL", config.DefaultBaseURL)
  34. },
  35. "hasOAuth2Provider": func(provider string) bool {
  36. return e.cfg.Get("OAUTH2_PROVIDER", "") == provider
  37. },
  38. "hasKey": func(dict map[string]string, key string) bool {
  39. log.Println(dict)
  40. if value, found := dict[key]; found {
  41. return value != ""
  42. }
  43. return false
  44. },
  45. "route": func(name string, args ...interface{}) string {
  46. return route.GetRoute(e.router, name, args...)
  47. },
  48. "noescape": func(str string) template.HTML {
  49. return template.HTML(str)
  50. },
  51. "proxyFilter": func(data string) string {
  52. return filter.ImageProxyFilter(e.router, data)
  53. },
  54. "domain": func(websiteURL string) string {
  55. parsedURL, err := url.Parse(websiteURL)
  56. if err != nil {
  57. return websiteURL
  58. }
  59. return parsedURL.Host
  60. },
  61. "isEmail": func(str string) bool {
  62. _, err := mail.ParseAddress(str)
  63. if err != nil {
  64. return false
  65. }
  66. return true
  67. },
  68. "hasPrefix": func(str, prefix string) bool {
  69. return strings.HasPrefix(str, prefix)
  70. },
  71. "contains": func(str, substr string) bool {
  72. return strings.Contains(str, substr)
  73. },
  74. "isodate": func(ts time.Time) string {
  75. return ts.Format("2006-01-02 15:04:05")
  76. },
  77. "elapsed": func(ts time.Time) string {
  78. return helper.GetElapsedTime(e.currentLocale, ts)
  79. },
  80. "t": func(key interface{}, args ...interface{}) string {
  81. switch key.(type) {
  82. case string:
  83. return e.currentLocale.Get(key.(string), args...)
  84. case errors.LocalizedError:
  85. err := key.(errors.LocalizedError)
  86. return err.Localize(e.currentLocale)
  87. case error:
  88. return key.(error).Error()
  89. default:
  90. return ""
  91. }
  92. },
  93. "plural": func(key string, n int, args ...interface{}) string {
  94. return e.currentLocale.Plural(key, n, args...)
  95. },
  96. }
  97. commonTemplates := ""
  98. for _, content := range templateCommonMap {
  99. commonTemplates += content
  100. }
  101. for name, content := range templateViewsMap {
  102. log.Println("Parsing template:", name)
  103. e.templates[name] = template.Must(template.New("main").Funcs(funcMap).Parse(commonTemplates + content))
  104. }
  105. }
  106. // SetLanguage change the language for template processing.
  107. func (e *Engine) SetLanguage(language string) {
  108. e.currentLocale = e.translator.GetLanguage(language)
  109. }
  110. // Execute process a template.
  111. func (e *Engine) Execute(w io.Writer, name string, data interface{}) {
  112. tpl, ok := e.templates[name]
  113. if !ok {
  114. log.Fatalf("The template %s does not exists.\n", name)
  115. }
  116. var b bytes.Buffer
  117. err := tpl.ExecuteTemplate(&b, "base", data)
  118. if err != nil {
  119. log.Fatalf("Unable to render template: %v\n", err)
  120. }
  121. b.WriteTo(w)
  122. }
  123. // NewEngine returns a new template Engine.
  124. func NewEngine(cfg *config.Config, router *mux.Router, translator *locale.Translator) *Engine {
  125. tpl := &Engine{
  126. templates: make(map[string]*template.Template),
  127. router: router,
  128. translator: translator,
  129. cfg: cfg,
  130. }
  131. tpl.parseAll()
  132. return tpl
  133. }