template.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. "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/miniflux/miniflux2/url"
  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.Path(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. "proxyURL": func(link string) string {
  55. if url.IsHTTPS(link) {
  56. return link
  57. }
  58. return filter.Proxify(e.router, link)
  59. },
  60. "domain": func(websiteURL string) string {
  61. return url.Domain(websiteURL)
  62. },
  63. "isEmail": func(str string) bool {
  64. _, err := mail.ParseAddress(str)
  65. if err != nil {
  66. return false
  67. }
  68. return true
  69. },
  70. "hasPrefix": func(str, prefix string) bool {
  71. return strings.HasPrefix(str, prefix)
  72. },
  73. "contains": func(str, substr string) bool {
  74. return strings.Contains(str, substr)
  75. },
  76. "isodate": func(ts time.Time) string {
  77. return ts.Format("2006-01-02 15:04:05")
  78. },
  79. "elapsed": func(ts time.Time) string {
  80. return helper.GetElapsedTime(e.currentLocale, ts)
  81. },
  82. "t": func(key interface{}, args ...interface{}) string {
  83. switch key.(type) {
  84. case string:
  85. return e.currentLocale.Get(key.(string), args...)
  86. case errors.LocalizedError:
  87. err := key.(errors.LocalizedError)
  88. return err.Localize(e.currentLocale)
  89. case error:
  90. return key.(error).Error()
  91. default:
  92. return ""
  93. }
  94. },
  95. "plural": func(key string, n int, args ...interface{}) string {
  96. return e.currentLocale.Plural(key, n, args...)
  97. },
  98. }
  99. commonTemplates := ""
  100. for _, content := range templateCommonMap {
  101. commonTemplates += content
  102. }
  103. for name, content := range templateViewsMap {
  104. log.Println("Parsing template:", name)
  105. e.templates[name] = template.Must(template.New("main").Funcs(funcMap).Parse(commonTemplates + content))
  106. }
  107. }
  108. // SetLanguage change the language for template processing.
  109. func (e *Engine) SetLanguage(language string) {
  110. e.currentLocale = e.translator.GetLanguage(language)
  111. }
  112. // Execute process a template.
  113. func (e *Engine) Execute(w io.Writer, name string, data interface{}) {
  114. tpl, ok := e.templates[name]
  115. if !ok {
  116. log.Fatalf("The template %s does not exists.\n", name)
  117. }
  118. var b bytes.Buffer
  119. err := tpl.ExecuteTemplate(&b, "base", data)
  120. if err != nil {
  121. log.Fatalf("Unable to render template: %v\n", err)
  122. }
  123. b.WriteTo(w)
  124. }
  125. // NewEngine returns a new template Engine.
  126. func NewEngine(cfg *config.Config, router *mux.Router, translator *locale.Translator) *Engine {
  127. tpl := &Engine{
  128. templates: make(map[string]*template.Template),
  129. router: router,
  130. translator: translator,
  131. cfg: cfg,
  132. }
  133. tpl.parseAll()
  134. return tpl
  135. }