2020-04-29 17:44:29 -07:00
|
|
|
package gctemplates
|
2013-02-02 15:01:01 -08:00
|
|
|
|
2013-04-20 01:21:40 -07:00
|
|
|
import (
|
|
|
|
"fmt"
|
2017-10-29 00:59:42 -07:00
|
|
|
"html"
|
2020-04-29 17:44:29 -07:00
|
|
|
"html/template"
|
2018-08-09 00:04:45 -07:00
|
|
|
"reflect"
|
2014-06-15 02:15:51 -07:00
|
|
|
"strconv"
|
2013-06-07 07:15:42 -07:00
|
|
|
"strings"
|
2020-04-29 17:44:29 -07:00
|
|
|
"time"
|
2019-02-16 19:18:00 -08:00
|
|
|
|
2020-04-29 17:44:29 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/config"
|
|
|
|
"github.com/gochan-org/gochan/pkg/gcsql"
|
|
|
|
"github.com/gochan-org/gochan/pkg/gcutil"
|
2019-02-16 19:18:00 -08:00
|
|
|
x_html "golang.org/x/net/html"
|
2013-04-20 01:21:40 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
var funcMap = template.FuncMap{
|
2018-10-07 12:20:10 -07:00
|
|
|
// Arithmetic functions
|
2015-12-24 23:26:13 -08:00
|
|
|
"add": func(a, b int) int {
|
2013-06-05 14:01:27 -07:00
|
|
|
return a + b
|
|
|
|
},
|
2015-12-24 23:26:13 -08:00
|
|
|
"subtract": func(a, b int) int {
|
2013-06-05 14:01:27 -07:00
|
|
|
return a - b
|
|
|
|
},
|
2018-10-07 12:20:10 -07:00
|
|
|
|
|
|
|
// Comparison functions (some copied from text/template for compatibility)
|
|
|
|
"ge": func(a int, b int) bool {
|
|
|
|
return a >= b
|
|
|
|
},
|
|
|
|
"gt": func(a int, b int) bool {
|
|
|
|
return a > b
|
|
|
|
},
|
|
|
|
"le": func(a int, b int) bool {
|
|
|
|
return a <= b
|
2013-06-05 14:01:27 -07:00
|
|
|
},
|
2018-10-07 12:20:10 -07:00
|
|
|
"lt": func(a int, b int) bool {
|
|
|
|
return a < b
|
|
|
|
},
|
|
|
|
"intEq": func(a, b int) bool {
|
|
|
|
return a == b
|
|
|
|
},
|
|
|
|
"isNil": func(i interface{}) bool {
|
|
|
|
return i == nil
|
|
|
|
},
|
|
|
|
|
|
|
|
// Array functions
|
2019-11-29 15:08:18 -08:00
|
|
|
"getSlice": func(arr []interface{}, start, length int) []interface{} {
|
|
|
|
if start < 0 {
|
|
|
|
start = 0
|
|
|
|
}
|
|
|
|
if length > len(arr) {
|
|
|
|
length = len(arr)
|
|
|
|
}
|
|
|
|
return arr[start:length]
|
2013-06-05 14:01:27 -07:00
|
|
|
},
|
2018-10-07 12:20:10 -07:00
|
|
|
"len": func(arr []interface{}) int {
|
|
|
|
return len(arr)
|
2014-06-16 19:20:36 -07:00
|
|
|
},
|
2018-10-07 12:20:10 -07:00
|
|
|
|
|
|
|
// String functions
|
2020-04-29 17:44:29 -07:00
|
|
|
// "arrToString": arrToString,
|
2018-10-07 12:20:10 -07:00
|
|
|
"intToString": strconv.Itoa,
|
|
|
|
"escapeString": func(a string) string {
|
|
|
|
return html.EscapeString(a)
|
2015-12-28 13:24:34 -08:00
|
|
|
},
|
2019-12-06 20:03:37 -08:00
|
|
|
"formatFilesize": func(sizeInt int) string {
|
|
|
|
size := float32(sizeInt)
|
2018-10-07 12:20:10 -07:00
|
|
|
if size < 1000 {
|
2019-12-06 20:03:37 -08:00
|
|
|
return fmt.Sprintf("%d B", sizeInt)
|
2018-10-07 12:20:10 -07:00
|
|
|
} else if size <= 100000 {
|
|
|
|
return fmt.Sprintf("%0.1f KB", size/1024)
|
|
|
|
} else if size <= 100000000 {
|
|
|
|
return fmt.Sprintf("%0.2f MB", size/1024/1024)
|
2018-04-06 01:03:57 -07:00
|
|
|
}
|
2018-10-07 12:20:10 -07:00
|
|
|
return fmt.Sprintf("%0.2f GB", size/1024/1024/1024)
|
2015-12-24 23:26:13 -08:00
|
|
|
},
|
2020-04-29 17:44:29 -07:00
|
|
|
"formatTimestamp": func(t time.Time) string {
|
|
|
|
return t.Format(config.Config.DateTimeFormat)
|
|
|
|
},
|
2018-06-09 23:40:20 -07:00
|
|
|
"stringAppend": func(strings ...string) string {
|
|
|
|
var appended string
|
|
|
|
for _, str := range strings {
|
|
|
|
appended += str
|
|
|
|
}
|
|
|
|
return appended
|
2013-05-29 13:43:12 -07:00
|
|
|
},
|
2019-12-06 20:03:37 -08:00
|
|
|
"truncateMessage": func(msg string, limit int, maxLines int) string {
|
2014-06-20 02:18:00 -07:00
|
|
|
var truncated bool
|
2015-12-24 23:26:13 -08:00
|
|
|
split := strings.SplitN(msg, "<br />", -1)
|
2014-06-20 02:18:00 -07:00
|
|
|
|
2019-12-06 20:03:37 -08:00
|
|
|
if len(split) > maxLines {
|
|
|
|
split = split[:maxLines]
|
2015-12-24 23:26:13 -08:00
|
|
|
msg = strings.Join(split, "<br />")
|
2014-06-20 02:18:00 -07:00
|
|
|
truncated = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(msg) < limit {
|
|
|
|
if truncated {
|
|
|
|
msg = msg + "..."
|
|
|
|
}
|
|
|
|
return msg
|
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
msg = msg[:limit]
|
|
|
|
truncated = true
|
2014-06-20 02:18:00 -07:00
|
|
|
|
|
|
|
if truncated {
|
|
|
|
msg = msg + "..."
|
2014-06-15 02:15:51 -07:00
|
|
|
}
|
2014-06-20 02:18:00 -07:00
|
|
|
return msg
|
2014-06-15 02:15:51 -07:00
|
|
|
},
|
2020-05-24 21:59:39 +02:00
|
|
|
"truncateHTMLMessage": truncateHTML,
|
2020-05-24 18:56:24 +02:00
|
|
|
"stripHTML": func(htmlStr template.HTML) string {
|
|
|
|
dom := x_html.NewTokenizer(strings.NewReader(string(htmlStr)))
|
2019-02-16 19:18:00 -08:00
|
|
|
for tokenType := dom.Next(); tokenType != x_html.ErrorToken; {
|
|
|
|
if tokenType != x_html.TextToken {
|
|
|
|
tokenType = dom.Next()
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
txtContent := strings.TrimSpace(x_html.UnescapeString(string(dom.Text())))
|
|
|
|
if len(txtContent) > 0 {
|
|
|
|
return x_html.EscapeString(txtContent)
|
|
|
|
}
|
|
|
|
tokenType = dom.Next()
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
},
|
2017-10-29 00:59:42 -07:00
|
|
|
"truncateString": func(msg string, limit int, ellipsis bool) string {
|
|
|
|
if len(msg) > limit {
|
|
|
|
if ellipsis {
|
|
|
|
return msg[:limit] + "..."
|
|
|
|
}
|
2018-06-09 23:40:20 -07:00
|
|
|
return msg[:limit]
|
2017-10-29 00:59:42 -07:00
|
|
|
}
|
2018-06-09 23:40:20 -07:00
|
|
|
return msg
|
2017-10-29 00:59:42 -07:00
|
|
|
},
|
2018-10-07 12:20:10 -07:00
|
|
|
|
|
|
|
// Imageboard functions
|
2020-05-22 17:35:59 +02:00
|
|
|
"bannedForever": func(banInfo *gcsql.BanInfo) bool {
|
|
|
|
return banInfo.BannedForever()
|
|
|
|
},
|
|
|
|
"isBanned": func(banInfo *gcsql.BanInfo, board string) bool {
|
|
|
|
return banInfo.IsBanned(board)
|
|
|
|
},
|
2018-10-22 22:02:06 -07:00
|
|
|
"getCatalogThumbnail": func(img string) string {
|
2020-04-29 17:44:29 -07:00
|
|
|
return gcutil.GetThumbnailPath("catalog", img)
|
2018-10-22 22:02:06 -07:00
|
|
|
},
|
2019-12-06 20:03:37 -08:00
|
|
|
"getThreadID": func(postInterface interface{}) (thread int) {
|
2020-04-29 17:44:29 -07:00
|
|
|
post, ok := postInterface.(gcsql.Post)
|
2018-11-22 23:47:51 -08:00
|
|
|
if !ok {
|
|
|
|
thread = 0
|
|
|
|
} else if post.ParentID == 0 {
|
2013-07-29 02:18:53 -07:00
|
|
|
thread = post.ID
|
|
|
|
} else {
|
|
|
|
thread = post.ParentID
|
|
|
|
}
|
|
|
|
return
|
|
|
|
},
|
2019-12-06 20:03:37 -08:00
|
|
|
"getPostURL": func(postInterface interface{}, typeOf string, withDomain bool) (postURL string) {
|
2019-02-16 19:18:00 -08:00
|
|
|
if withDomain {
|
2020-04-29 17:44:29 -07:00
|
|
|
postURL = config.Config.SiteDomain
|
2019-02-16 19:18:00 -08:00
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
postURL += config.Config.SiteWebfolder
|
2019-02-16 19:18:00 -08:00
|
|
|
|
|
|
|
if typeOf == "recent" {
|
2020-04-29 17:44:29 -07:00
|
|
|
post, ok := postInterface.(*gcsql.RecentPost)
|
2019-02-16 19:18:00 -08:00
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
postURL = post.GetURL(withDomain)
|
|
|
|
} else {
|
2020-04-29 17:44:29 -07:00
|
|
|
post, ok := postInterface.(*gcsql.Post)
|
2019-02-16 19:18:00 -08:00
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
postURL = post.GetURL(withDomain)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
},
|
2018-10-22 22:02:06 -07:00
|
|
|
"getThreadThumbnail": func(img string) string {
|
2020-04-29 17:44:29 -07:00
|
|
|
return gcutil.GetThumbnailPath("thread", img)
|
2013-07-04 02:39:23 -07:00
|
|
|
},
|
2018-01-28 15:01:59 -08:00
|
|
|
"getUploadType": func(name string) string {
|
2020-04-29 17:44:29 -07:00
|
|
|
extension := gcutil.GetFileExtension(name)
|
2018-01-28 15:01:59 -08:00
|
|
|
var uploadType string
|
|
|
|
switch extension {
|
|
|
|
case "":
|
2020-03-30 09:14:43 -07:00
|
|
|
fallthrough
|
2018-01-28 15:01:59 -08:00
|
|
|
case "deleted":
|
|
|
|
uploadType = ""
|
|
|
|
case "webm":
|
2020-03-30 09:14:43 -07:00
|
|
|
fallthrough
|
2018-01-28 15:01:59 -08:00
|
|
|
case "jpg":
|
2020-03-30 09:14:43 -07:00
|
|
|
fallthrough
|
|
|
|
case "jpeg":
|
|
|
|
fallthrough
|
2018-01-28 15:01:59 -08:00
|
|
|
case "gif":
|
|
|
|
uploadType = "jpg"
|
|
|
|
case "png":
|
|
|
|
uploadType = "png"
|
|
|
|
}
|
|
|
|
return uploadType
|
|
|
|
},
|
2018-10-22 22:02:06 -07:00
|
|
|
"imageToThumbnailPath": func(thumbType string, img string) string {
|
2018-01-28 15:01:59 -08:00
|
|
|
filetype := strings.ToLower(img[strings.LastIndex(img, ".")+1:])
|
|
|
|
if filetype == "gif" || filetype == "webm" {
|
2013-07-04 02:39:23 -07:00
|
|
|
filetype = "jpg"
|
|
|
|
}
|
2013-06-07 07:15:42 -07:00
|
|
|
index := strings.LastIndex(img, ".")
|
2016-01-06 01:32:57 -08:00
|
|
|
if index < 0 || index > len(img) {
|
|
|
|
return ""
|
|
|
|
}
|
2018-10-22 22:02:06 -07:00
|
|
|
thumbSuffix := "t." + filetype
|
|
|
|
if thumbType == "catalog" {
|
|
|
|
thumbSuffix = "c." + filetype
|
|
|
|
}
|
|
|
|
return img[0:index] + thumbSuffix
|
2014-06-08 08:26:28 -07:00
|
|
|
},
|
2020-04-29 17:44:29 -07:00
|
|
|
"numReplies": func(boardid, threadid int) int {
|
|
|
|
num, err := gcsql.GetReplyCount(threadid)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return num
|
|
|
|
},
|
2019-01-03 11:51:59 -08:00
|
|
|
"getBoardDir": func(id int) string {
|
2020-04-29 17:44:29 -07:00
|
|
|
var board gcsql.Board
|
2020-04-20 17:42:48 +02:00
|
|
|
if err := board.PopulateData(id); err != nil {
|
2019-01-03 11:51:59 -08:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return board.Dir
|
|
|
|
},
|
2018-10-07 12:20:10 -07:00
|
|
|
|
|
|
|
// Template convenience functions
|
|
|
|
"makeLoop": func(n int, offset int) []int {
|
|
|
|
loopArr := make([]int, n)
|
|
|
|
for i := range loopArr {
|
|
|
|
loopArr[i] = i + offset
|
|
|
|
}
|
|
|
|
return loopArr
|
|
|
|
},
|
2018-08-09 00:04:45 -07:00
|
|
|
"generateConfigTable": func() string {
|
2020-04-29 17:44:29 -07:00
|
|
|
configType := reflect.TypeOf(config.Config)
|
|
|
|
tableOut := `<table style="border-collapse: collapse;" id="config"><tr><th>Field name</th><th>Value</th><th>Type</th><th>Description</th></tr>`
|
2018-08-09 00:04:45 -07:00
|
|
|
numFields := configType.NumField()
|
|
|
|
for f := 17; f < numFields-2; f++ {
|
|
|
|
// starting at Lockdown because the earlier fields can't be safely edited from a web interface
|
|
|
|
field := configType.Field(f)
|
|
|
|
if field.Tag.Get("critical") != "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
name := field.Name
|
|
|
|
tableOut += "<tr><th>" + name + "</th><td>"
|
2020-04-29 17:44:29 -07:00
|
|
|
f := reflect.Indirect(reflect.ValueOf(config.Config)).FieldByName(name)
|
2018-08-09 00:04:45 -07:00
|
|
|
|
|
|
|
kind := f.Kind()
|
|
|
|
switch kind {
|
|
|
|
case reflect.Int:
|
2020-04-29 17:44:29 -07:00
|
|
|
tableOut += `<input name="` + name + `" type="number" value="` + html.EscapeString(fmt.Sprintf("%v", f)) + `" class="config-text"/>`
|
2018-08-09 00:04:45 -07:00
|
|
|
case reflect.String:
|
2020-04-29 17:44:29 -07:00
|
|
|
tableOut += `<input name="` + name + `" type="text" value="` + html.EscapeString(fmt.Sprintf("%v", f)) + `" class="config-text"/>`
|
2018-08-09 00:04:45 -07:00
|
|
|
case reflect.Bool:
|
|
|
|
checked := ""
|
|
|
|
if f.Bool() {
|
|
|
|
checked = "checked"
|
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
tableOut += `<input name="` + name + `" type="checkbox" ` + checked + " />"
|
2018-08-09 00:04:45 -07:00
|
|
|
case reflect.Slice:
|
2020-04-29 17:44:29 -07:00
|
|
|
tableOut += `<textarea name="` + name + `" rows="4" cols="28">`
|
2018-08-09 00:04:45 -07:00
|
|
|
arrLength := f.Len()
|
|
|
|
for s := 0; s < arrLength; s++ {
|
|
|
|
newLine := "\n"
|
|
|
|
if s == arrLength-1 {
|
|
|
|
newLine = ""
|
|
|
|
}
|
|
|
|
tableOut += html.EscapeString(f.Slice(s, s+1).Index(0).String()) + newLine
|
|
|
|
}
|
|
|
|
tableOut += "</textarea>"
|
|
|
|
default:
|
|
|
|
tableOut += fmt.Sprintf("%v", kind)
|
|
|
|
}
|
|
|
|
tableOut += "</td><td>" + kind.String() + "</td><td>"
|
|
|
|
defaultTag := field.Tag.Get("default")
|
|
|
|
var defaultTagHTML string
|
|
|
|
if defaultTag != "" {
|
|
|
|
defaultTagHTML = " <b>Default: " + defaultTag + "</b>"
|
|
|
|
}
|
|
|
|
tableOut += field.Tag.Get("description") + defaultTagHTML + "</td>"
|
2020-04-29 17:44:29 -07:00
|
|
|
tableOut += "</tr>"
|
2018-08-09 00:04:45 -07:00
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
tableOut += "</table>"
|
2018-08-09 00:04:45 -07:00
|
|
|
return tableOut
|
|
|
|
},
|
2018-10-07 12:20:10 -07:00
|
|
|
"isStyleDefault": func(style string) bool {
|
2020-04-29 17:44:29 -07:00
|
|
|
return style == config.Config.DefaultStyle
|
2018-10-05 15:21:36 -07:00
|
|
|
},
|
2018-11-26 15:29:26 -08:00
|
|
|
"version": func() string {
|
2020-04-29 17:44:29 -07:00
|
|
|
return config.Config.Version.String()
|
2018-11-22 23:47:51 -08:00
|
|
|
},
|
2013-04-20 01:21:40 -07:00
|
|
|
}
|