2016-12-06 20:58:31 +03:00
// +build bindata
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package templates
import (
2017-03-01 04:45:21 +03:00
"bytes"
"fmt"
2016-12-06 20:58:31 +03:00
"html/template"
2017-03-01 04:45:21 +03:00
"io"
2016-12-06 20:58:31 +03:00
"io/ioutil"
2021-01-05 16:05:40 +03:00
"os"
2016-12-06 20:58:31 +03:00
"path"
2021-01-05 16:05:40 +03:00
"path/filepath"
2016-12-06 20:58:31 +03:00
"strings"
2019-11-07 16:34:28 +03:00
texttmpl "text/template"
2016-12-06 20:58:31 +03:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2020-11-28 05:42:08 +03:00
"code.gitea.io/gitea/modules/util"
2019-08-23 19:40:30 +03:00
"gitea.com/macaron/macaron"
2016-12-06 20:58:31 +03:00
)
var (
2019-11-07 16:34:28 +03:00
subjectTemplates = texttmpl . New ( "" )
bodyTemplates = template . New ( "" )
2016-12-06 20:58:31 +03:00
)
2017-03-01 04:45:21 +03:00
type templateFileSystem struct {
files [ ] macaron . TemplateFile
}
func ( templates templateFileSystem ) ListFiles ( ) [ ] macaron . TemplateFile {
return templates . files
}
func ( templates templateFileSystem ) Get ( name string ) ( io . Reader , error ) {
for i := range templates . files {
if templates . files [ i ] . Name ( ) + templates . files [ i ] . Ext ( ) == name {
return bytes . NewReader ( templates . files [ i ] . Data ( ) ) , nil
}
}
return nil , fmt . Errorf ( "file '%s' not found" , name )
}
2021-01-05 16:05:40 +03:00
// GetAsset get a special asset, only for chi
func GetAsset ( name string ) ( [ ] byte , error ) {
bs , err := ioutil . ReadFile ( filepath . Join ( setting . CustomPath , name ) )
if err != nil && ! os . IsNotExist ( err ) {
return nil , err
} else if err == nil {
return bs , nil
}
return Asset ( strings . TrimPrefix ( name , "templates/" ) )
}
// GetAssetNames only for chi
func GetAssetNames ( ) [ ] string {
realFS := Assets . ( vfsgen۰ FS )
var tmpls = make ( [ ] string , 0 , len ( realFS ) )
for k := range realFS {
tmpls = append ( tmpls , "templates/" + k [ 1 : ] )
}
customDir := path . Join ( setting . CustomPath , "templates" )
customTmpls := getDirAssetNames ( customDir )
return append ( tmpls , customTmpls ... )
}
2018-07-28 03:19:01 +03:00
func NewTemplateFileSystem ( ) templateFileSystem {
2017-03-01 04:45:21 +03:00
fs := templateFileSystem { }
fs . files = make ( [ ] macaron . TemplateFile , 0 , 10 )
for _ , assetPath := range AssetNames ( ) {
if strings . HasPrefix ( assetPath , "mail/" ) {
continue
}
if ! strings . HasSuffix ( assetPath , ".tmpl" ) {
continue
}
content , err := Asset ( assetPath )
if err != nil {
log . Warn ( "Failed to read embedded %s template. %v" , assetPath , err )
continue
}
fs . files = append ( fs . files , macaron . NewTplFile (
strings . TrimSuffix (
assetPath ,
".tmpl" ,
) ,
content ,
".tmpl" ,
) )
}
customDir := path . Join ( setting . CustomPath , "templates" )
2020-11-28 05:42:08 +03:00
isDir , err := util . IsDir ( customDir )
if err != nil {
log . Warn ( "Unable to check if templates dir %s is a directory. Error: %v" , customDir , err )
}
if isDir {
2020-12-22 02:40:57 +03:00
files , err := util . StatDir ( customDir )
2017-03-01 04:45:21 +03:00
if err != nil {
log . Warn ( "Failed to read %s templates dir. %v" , customDir , err )
} else {
for _ , filePath := range files {
if strings . HasPrefix ( filePath , "mail/" ) {
continue
}
if ! strings . HasSuffix ( filePath , ".tmpl" ) {
continue
}
content , err := ioutil . ReadFile ( path . Join ( customDir , filePath ) )
if err != nil {
log . Warn ( "Failed to read custom %s template. %v" , filePath , err )
continue
}
fs . files = append ( fs . files , macaron . NewTplFile (
strings . TrimSuffix (
filePath ,
".tmpl" ,
) ,
content ,
".tmpl" ,
) )
}
}
}
2018-07-28 03:19:01 +03:00
return fs
}
// HTMLRenderer implements the macaron handler for serving HTML templates.
func HTMLRenderer ( ) macaron . Handler {
return macaron . Renderer ( macaron . RenderOptions {
Funcs : NewFuncMap ( ) ,
2018-08-08 14:15:48 +03:00
TemplateFileSystem : NewTemplateFileSystem ( ) ,
2018-07-28 03:19:01 +03:00
} )
}
// JSONRenderer implements the macaron handler for serving JSON templates.
func JSONRenderer ( ) macaron . Handler {
2016-12-06 20:58:31 +03:00
return macaron . Renderer ( macaron . RenderOptions {
2017-03-01 04:45:21 +03:00
Funcs : NewFuncMap ( ) ,
2018-08-08 14:15:48 +03:00
TemplateFileSystem : NewTemplateFileSystem ( ) ,
2018-07-28 03:19:01 +03:00
HTMLContentType : "application/json" ,
2016-12-06 20:58:31 +03:00
} )
}
// Mailer provides the templates required for sending notification mails.
2019-11-07 16:34:28 +03:00
func Mailer ( ) ( * texttmpl . Template , * template . Template ) {
for _ , funcs := range NewTextFuncMap ( ) {
subjectTemplates . Funcs ( funcs )
}
2016-12-06 20:58:31 +03:00
for _ , funcs := range NewFuncMap ( ) {
2019-11-07 16:34:28 +03:00
bodyTemplates . Funcs ( funcs )
2016-12-06 20:58:31 +03:00
}
for _ , assetPath := range AssetNames ( ) {
if ! strings . HasPrefix ( assetPath , "mail/" ) {
continue
}
if ! strings . HasSuffix ( assetPath , ".tmpl" ) {
continue
}
content , err := Asset ( assetPath )
if err != nil {
log . Warn ( "Failed to read embedded %s template. %v" , assetPath , err )
continue
}
2019-11-07 16:34:28 +03:00
buildSubjectBodyTemplate ( subjectTemplates ,
bodyTemplates ,
2016-12-06 20:58:31 +03:00
strings . TrimPrefix (
strings . TrimSuffix (
assetPath ,
".tmpl" ,
) ,
"mail/" ,
) ,
2019-11-07 16:34:28 +03:00
content )
2016-12-06 20:58:31 +03:00
}
customDir := path . Join ( setting . CustomPath , "templates" , "mail" )
2020-11-28 05:42:08 +03:00
isDir , err := util . IsDir ( customDir )
if err != nil {
log . Warn ( "Failed to check if custom directory %s is a directory. %v" , err )
}
if isDir {
2020-12-22 02:40:57 +03:00
files , err := util . StatDir ( customDir )
2016-12-06 20:58:31 +03:00
if err != nil {
log . Warn ( "Failed to read %s templates dir. %v" , customDir , err )
} else {
for _ , filePath := range files {
if ! strings . HasSuffix ( filePath , ".tmpl" ) {
continue
}
content , err := ioutil . ReadFile ( path . Join ( customDir , filePath ) )
if err != nil {
log . Warn ( "Failed to read custom %s template. %v" , filePath , err )
continue
}
2019-11-07 16:34:28 +03:00
buildSubjectBodyTemplate ( subjectTemplates ,
bodyTemplates ,
2016-12-06 20:58:31 +03:00
strings . TrimSuffix (
filePath ,
".tmpl" ,
) ,
2019-11-07 16:34:28 +03:00
content )
2016-12-06 20:58:31 +03:00
}
}
}
2019-11-07 16:34:28 +03:00
return subjectTemplates , bodyTemplates
2016-12-06 20:58:31 +03:00
}
2019-06-03 00:43:47 +03:00
func Asset ( name string ) ( [ ] byte , error ) {
f , err := Assets . Open ( "/" + name )
if err != nil {
return nil , err
}
defer f . Close ( )
return ioutil . ReadAll ( f )
}
func AssetNames ( ) [ ] string {
realFS := Assets . ( vfsgen۰ FS )
var results = make ( [ ] string , 0 , len ( realFS ) )
for k := range realFS {
results = append ( results , k [ 1 : ] )
}
return results
}
2020-02-02 05:17:44 +03:00
func AssetIsDir ( name string ) ( bool , error ) {
if f , err := Assets . Open ( "/" + name ) ; err != nil {
return false , err
} else {
defer f . Close ( )
if fi , err := f . Stat ( ) ; err != nil {
return false , err
} else {
return fi . IsDir ( ) , nil
}
}
}