tavern/web/view.go

240 lines
6.0 KiB
Go

package web
import (
"database/sql"
"encoding/hex"
"encoding/json"
"fmt"
"html/template"
"math"
"net/url"
"os"
"strings"
"time"
"github.com/foolin/goview"
"github.com/gofrs/uuid"
"github.com/ngerakines/tavern/templates"
)
var (
ohioLocal *time.Location
)
func TemplateFileHandler() goview.FileHandler {
return func(config goview.Config, tplFile string) (content string, err error) {
shortLocation := config.Root + string(os.PathSeparator) + tplFile + config.Extension
data, err := templates.Asset(shortLocation)
if err != nil {
return "", fmt.Errorf("view engine unable to load %s: %w", shortLocation, err)
}
return string(data), nil
}
}
func tmplOptionalDate(value sql.NullTime, defaultValue string) string {
if value.Valid {
return tmplDate(value.Time)
}
return defaultValue
}
func tmplDate(value time.Time) string {
return value.In(ohioLocal).Format("02 Jan 2006") // " MST"
}
func tmplOptionalTime(value sql.NullTime, defaultValue string) string {
if value.Valid {
return tmplTime(value.Time)
}
return defaultValue
}
func tmplTime(value time.Time) string {
return value.In(ohioLocal).Format("3:04 PM") // " MST"
}
func tmplOptionalDateTime(value sql.NullTime, defaultValue string) string {
if value.Valid {
return tmplDateTime(value.Time)
}
return defaultValue
}
func tmplDateTime(value time.Time) string {
return value.In(ohioLocal).Format("02 Jan 2006 3:04 PM") // " MST"
}
func tmplShortUUID(id uuid.UUID) string {
return hex.EncodeToString(id.Bytes())
}
func tmplShort(input string, max int) string {
halfMax := int(math.Ceil(float64(max) / 2))
if l := len(input); l > max {
return fmt.Sprintf("%s...%s", input[0:halfMax], input[l-halfMax:])
}
return input
}
func tmplAnchor(url, label string) template.HTML {
return template.HTML(fmt.Sprintf(`<a href="%s">%s</a>`, url, label))
}
func tmplToHTML(input string) template.HTML {
return template.HTML(input)
}
func tmplStrong(args ...string) template.HTML {
if len(args) == 1 {
return template.HTML(fmt.Sprintf(`<strong>%s</strong>`, args[0]))
}
if len(args) == 2 {
return template.HTML(fmt.Sprintf(`<strong class="%s">%s</strong>`, args[0], args[1]))
}
return ""
}
func tmplPretty(v interface{}) string {
b, err := json.MarshalIndent(v, "", " ")
if err == nil {
return string(b)
}
return ""
}
func tmplUrlGen(siteBase string) func(parts ...interface{}) string {
return func(parts ...interface{}) string {
if len(parts) >= 1 {
if controller, ok := parts[0].(string); ok {
switch controller {
case "signin":
return fmt.Sprintf("%s/signin", siteBase)
case "signout":
return fmt.Sprintf("%s/signout", siteBase)
case "feed", "feed_recent":
return fmt.Sprintf("%s/feed", siteBase)
case "feed_mine":
return fmt.Sprintf("%s/feed/mine", siteBase)
case "feed_local":
return fmt.Sprintf("%s/feed/local", siteBase)
case "thread":
return fmt.Sprintf("%s/thread/%s", siteBase, parts[1])
case "network":
return fmt.Sprintf("%s/manage/network", siteBase)
case "network_follow":
return fmt.Sprintf("%s/manage/network/follow", siteBase)
case "network_unfollow":
return fmt.Sprintf("%s/manage/network/unfollow", siteBase)
case "network_accept":
return fmt.Sprintf("%s/manage/network/accept", siteBase)
case "network_reject":
return fmt.Sprintf("%s/manage/network/reject", siteBase)
case "group":
return fmt.Sprintf("%s/groups/%s", siteBase, parts[1])
case "group_manage":
return fmt.Sprintf("%s/groups/%s/manage", siteBase, parts[1])
case "group_directory":
return fmt.Sprintf("%s/directory/groups", siteBase)
case "groups":
return fmt.Sprintf("%s/manage/groups", siteBase)
case "groups_create":
return fmt.Sprintf("%s/manage/groups/create", siteBase)
case "groups_accept":
return fmt.Sprintf("%s/manage/groups/accept", siteBase)
case "groups_reject":
return fmt.Sprintf("%s/manage/groups/reject", siteBase)
case "groups_follow":
return fmt.Sprintf("%s/manage/groups/follow", siteBase)
case "groups_unfollow":
return fmt.Sprintf("%s/manage/groups/unfollow", siteBase)
case "profile":
return fmt.Sprintf("%s/users/%s", siteBase, parts[1])
case "notes":
return fmt.Sprintf("%s/dashboard/notes", siteBase)
case "compose":
return fmt.Sprintf("%s/compose", siteBase)
case "compose_create_note":
return fmt.Sprintf("%s/compose/create/note", siteBase)
case "utilities":
return fmt.Sprintf("%s/utilities", siteBase)
case "utilities_webfinger":
return fmt.Sprintf("%s/utilities/webfinger", siteBase)
case "utilities_crawl":
return fmt.Sprintf("%s/utilities/crawl", siteBase)
case "configure":
return fmt.Sprintf("%s/configure", siteBase)
case "configure_user":
return fmt.Sprintf("%s/configure/user", siteBase)
case "tag":
return fmt.Sprintf("%s/tag/%s", siteBase, parts[1])
case "about":
return fmt.Sprintf("%s/about", siteBase)
case "terms":
return fmt.Sprintf("%s/terms", siteBase)
case "usage":
return fmt.Sprintf("%s/usage", siteBase)
}
}
}
return fmt.Sprintf("%s/", siteBase)
}
}
func tmplWrapMaybe(input string) string {
if strings.HasPrefix(input, "<") {
return input
}
return fmt.Sprintf("<p>%s</p>", input)
}
func tmplDict(values ...interface{}) (map[string]interface{}, error) {
if len(values)%2 != 0 {
return nil, fmt.Errorf("invalid dict call")
}
dict := make(map[string]interface{}, len(values)/2)
for i := 0; i < len(values); i += 2 {
key, ok := values[i].(string)
if !ok {
return nil, fmt.Errorf("dict keys must be strings")
}
dict[key] = values[i+1]
}
return dict, nil
}
func tmplLookupStr(values map[string]string, key string) string {
if value, ok := values[key]; ok {
return value
}
return key
}
func tmplLookupBool(values map[string]bool, key string, defaultValue bool) bool {
if value, ok := values[key]; ok {
return value
}
return defaultValue
}
func tmplUrlEncode(input string) string {
return url.QueryEscape(input)
}