templates.go (5158B)
1 package template 2 3 import ( 4 "dkforest/pkg/global" 5 "dkforest/pkg/web/clientFrontends" 6 hutils "dkforest/pkg/web/handlers/utils" 7 "fmt" 8 "html/template" 9 "io" 10 "path/filepath" 11 "strings" 12 "time" 13 14 "dkforest/bindata" 15 "dkforest/pkg/config" 16 "dkforest/pkg/database" 17 "dkforest/pkg/utils" 18 "github.com/labstack/echo" 19 "github.com/nicksnyder/go-i18n/v2/i18n" 20 ) 21 22 // Templates ... 23 type Templates struct { 24 Templates map[string]*template.Template 25 funcMap FuncMap 26 e *echo.Echo 27 } 28 29 // NewTemplateBuilder ... 30 func NewTemplateBuilder(e *echo.Echo) *Templates { 31 t := new(Templates) 32 t.funcMap = make(FuncMap) 33 t.e = e 34 return t 35 } 36 37 // AddFn ... 38 func (t *Templates) AddFn(name string, fn any) { 39 t.funcMap[name] = fn 40 } 41 42 type templateDataStruct struct { 43 Bundle *i18n.Bundle 44 AcceptLanguage string 45 Lang string 46 Data any 47 VERSION string 48 SHA string 49 VersionHTML template.HTML 50 ShaHTML template.HTML 51 LogoASCII template.HTML 52 NullUsername string 53 DB *database.DkfDB 54 CSRF string 55 Master bool 56 Development bool 57 BaseKeywords string 58 TmplName string 59 AuthUser *database.User 60 InboxCount int64 61 WallpaperImg string 62 IsAprilFool2023 bool 63 GitURL string 64 Reverse func(string, ...any) string 65 } 66 67 // Render render a template 68 func (t *Templates) Render(w io.Writer, name string, data any, c echo.Context) error { 69 tmpl := t.Templates[name] 70 71 db := c.Get("database").(*database.DkfDB) 72 clientFE := c.Get("clientFE").(clientFrontends.ClientFrontend) 73 74 d := templateDataStruct{} 75 d.TmplName = name 76 d.Data = data 77 d.VERSION = config.Global.AppVersion.Get().Original() 78 if config.Development.IsTrue() { 79 d.VERSION += utils.FormatInt64(time.Now().Unix()) 80 } 81 d.Reverse = c.Echo().Reverse // {{ call .Reverse "name" }} || {{ call .Reverse "name" "params" }} 82 d.Bundle = c.Get("bundle").(*i18n.Bundle) 83 //d.SHA = config.Global.Sha() 84 d.VersionHTML = template.HTML(fmt.Sprintf("<!-- VERSION: %s -->", config.Global.AppVersion.Get().Original())) 85 d.ShaHTML = template.HTML(fmt.Sprintf("<!-- SHA: %s -->", config.Global.Sha.Get())) 86 d.NullUsername = config.NullUsername 87 d.CSRF, _ = c.Get("csrf").(string) 88 d.DB = db 89 d.AcceptLanguage = c.Get("accept-language").(string) 90 d.Lang = c.Get("lang").(string) 91 d.BaseKeywords = strings.Join(getBaseKeywords(), ", ") 92 d.Development = config.Development.Load() 93 d.AuthUser = c.Get("authUser").(*database.User) 94 switch clientFE { 95 case clientFrontends.TorClientFE: 96 d.GitURL = config.DkfGitOnion 97 case clientFrontends.I2PClientFE: 98 d.GitURL = config.I2pGitOnion 99 } 100 101 d.WallpaperImg = "/public/img/login_bg.jpg" 102 year, month, day := time.Now().UTC().Date() 103 d.IsAprilFool2023 = year == 2023 && month == time.April && day == 1 104 if strings.HasPrefix(c.QueryParam("redirect"), "/poker") { 105 d.WallpaperImg = "/public/img/login_bg_poker.jpg" 106 } else if month == time.October { 107 d.WallpaperImg = "/public/img/halloween_bg.jpg" 108 } else if month == time.December { 109 d.WallpaperImg = "/public/img/xmas.jpg" 110 } else if month == time.January { 111 d.WallpaperImg = "/public/img/login_bg_1.jpg" 112 } else if d.IsAprilFool2023 { 113 d.WallpaperImg = "/public/img/login_bg_2.jpg" 114 } 115 116 if d.AuthUser != nil { 117 var sessionToken string 118 if authCookie, err := c.Cookie(hutils.AuthCookieName); err == nil { 119 sessionToken = authCookie.Value 120 } 121 d.InboxCount = global.GetUserNotificationCount(db, d.AuthUser.ID, sessionToken) 122 } 123 124 return tmpl.ExecuteTemplate(w, "base", d) 125 } 126 127 // Keywords use for html meta tag, for SEO 128 func getBaseKeywords() []string { 129 return []string{} 130 } 131 132 // BuildTemplates build all templates 133 func (t *Templates) BuildTemplates() { 134 t.Templates = make(map[string]*template.Template) 135 136 bases := []string{ 137 "views/pages/captcha-tmpl.gohtml", 138 "views/pages/pagination.gohtml", 139 "views/pages/anti-prefill.gohtml"} 140 buildTemplatesHelper("views/pages", t.Templates, "", bases, t.funcMap) 141 } 142 143 func buildTemplatesHelper(root string, tmpls map[string]*template.Template, prefix string, bases []string, fnsMap FuncMap) { 144 if _, err := bindata.AssetInfo(root + prefix + "/index.gohtml"); err == nil { 145 bases = append(bases, root+prefix+"/index.gohtml") 146 } 147 viewsPages, _ := bindata.AssetDir(root + prefix) 148 for _, page := range viewsPages { 149 // Recursively process folders 150 ext := filepath.Ext(page) 151 if !strings.HasSuffix(page, ".gohtml") { 152 buildTemplatesHelper(root, tmpls, prefix+"/"+page, bases, fnsMap) 153 continue 154 } 155 // Create template 156 page = strings.TrimSuffix(page, ".gohtml") 157 tmpl := New("_", bindata.Asset).Funcs(fnsMap) 158 parseBases(tmpl, bases) 159 tmpl = Must(tmpl.Parse(root + prefix + "/" + page + ext)) 160 // Add to templates collection 161 tmplName := buildTemplateName(prefix, page) 162 tmpls[tmplName] = tmpl.Tmpl 163 } 164 } 165 166 func buildTemplateName(prefix, page string) string { 167 tmplName := strings.TrimPrefix(prefix, "/") 168 tmplName = strings.Join(strings.Split(tmplName, "/"), ".") + "." + page 169 tmplName = strings.TrimPrefix(tmplName, ".") 170 return tmplName 171 } 172 173 func parseBases(tmpl *Template, bases []string) { 174 for _, b := range bases { 175 tmpl = Must(tmpl.Parse(b)) 176 } 177 }