template.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package http
  2. import (
  3. "bytes"
  4. "embed"
  5. "html/template"
  6. "log"
  7. "os"
  8. "strings"
  9. "time"
  10. "github.com/spf13/pflag"
  11. "github.com/rclone/rclone/fs/config/flags"
  12. )
  13. // TemplateHelp returns a string that describes how to use a custom template
  14. func TemplateHelp(prefix string) string {
  15. help := `#### Template
  16. ` + "`--{{ .Prefix }}template`" + ` allows a user to specify a custom markup template for HTTP
  17. and WebDAV serve functions. The server exports the following markup
  18. to be used within the template to server pages:
  19. | Parameter | Description |
  20. | :---------- | :---------- |
  21. | .Name | The full path of a file/directory. |
  22. | .Title | Directory listing of .Name |
  23. | .Sort | The current sort used. This is changeable via ?sort= parameter |
  24. | | Sort Options: namedirfirst,name,size,time (default namedirfirst) |
  25. | .Order | The current ordering used. This is changeable via ?order= parameter |
  26. | | Order Options: asc,desc (default asc) |
  27. | .Query | Currently unused. |
  28. | .Breadcrumb | Allows for creating a relative navigation |
  29. |-- .Link | The relative to the root link of the Text. |
  30. |-- .Text | The Name of the directory. |
  31. | .Entries | Information about a specific file/directory. |
  32. |-- .URL | The 'url' of an entry. |
  33. |-- .Leaf | Currently same as 'URL' but intended to be 'just' the name. |
  34. |-- .IsDir | Boolean for if an entry is a directory or not. |
  35. |-- .Size | Size in Bytes of the entry. |
  36. |-- .ModTime | The UTC timestamp of an entry. |
  37. The server also makes the following functions available so that they can be used within the
  38. template. These functions help extend the options for dynamic rendering of HTML. They can
  39. be used to render HTML based on specific conditions.
  40. | Function | Description |
  41. | :---------- | :---------- |
  42. | afterEpoch | Returns the time since the epoch for the given time. |
  43. | contains | Checks whether a given substring is present or not in a given string. |
  44. | hasPrefix | Checks whether the given string begins with the specified prefix. |
  45. | hasSuffix | Checks whether the given string end with the specified suffix. |
  46. `
  47. tmpl, err := template.New("template help").Parse(help)
  48. if err != nil {
  49. log.Fatal("Fatal error parsing template", err)
  50. }
  51. data := struct {
  52. Prefix string
  53. }{
  54. Prefix: prefix,
  55. }
  56. buf := &bytes.Buffer{}
  57. err = tmpl.Execute(buf, data)
  58. if err != nil {
  59. log.Fatal("Fatal error executing template", err)
  60. }
  61. return buf.String()
  62. }
  63. // TemplateConfig for the templating functionality
  64. type TemplateConfig struct {
  65. Path string
  66. }
  67. // AddFlagsPrefix for the templating functionality
  68. func (cfg *TemplateConfig) AddFlagsPrefix(flagSet *pflag.FlagSet, prefix string) {
  69. flags.StringVarP(flagSet, &cfg.Path, prefix+"template", "", cfg.Path, "User-specified template", prefix)
  70. }
  71. // AddTemplateFlagsPrefix for the templating functionality
  72. func AddTemplateFlagsPrefix(flagSet *pflag.FlagSet, prefix string, cfg *TemplateConfig) {
  73. cfg.AddFlagsPrefix(flagSet, prefix)
  74. }
  75. // DefaultTemplateCfg returns a new config which can be customized by command line flags
  76. func DefaultTemplateCfg() TemplateConfig {
  77. return TemplateConfig{}
  78. }
  79. // AfterEpoch returns the time since the epoch for the given time
  80. func AfterEpoch(t time.Time) bool {
  81. return t.After(time.Time{})
  82. }
  83. // Assets holds the embedded filesystem for the default template
  84. //
  85. //go:embed templates
  86. var Assets embed.FS
  87. // GetTemplate returns the HTML template for serving directories via HTTP/WebDAV
  88. func GetTemplate(tmpl string) (*template.Template, error) {
  89. var readFile = os.ReadFile
  90. if tmpl == "" {
  91. tmpl = "templates/index.html"
  92. readFile = Assets.ReadFile
  93. }
  94. data, err := readFile(tmpl)
  95. if err != nil {
  96. return nil, err
  97. }
  98. funcMap := template.FuncMap{
  99. "afterEpoch": AfterEpoch,
  100. "contains": strings.Contains,
  101. "hasPrefix": strings.HasPrefix,
  102. "hasSuffix": strings.HasSuffix,
  103. }
  104. tpl, err := template.New("index").Funcs(funcMap).Parse(string(data))
  105. if err != nil {
  106. return nil, err
  107. }
  108. return tpl, nil
  109. }