oef/renderer/funcmap.go

464 lines
10 KiB
Go

package renderer
import (
"fmt"
"html/template"
"io/ioutil"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"time"
"git.andreafazzi.eu/andrea/oef/errors"
"git.andreafazzi.eu/andrea/oef/i18n"
"github.com/dchest/captcha"
jwt "github.com/dgrijalva/jwt-go"
"github.com/jinzhu/inflection"
yml "gopkg.in/yaml.v2"
"github.com/microcosm-cc/bluemonday"
"gopkg.in/russross/blackfriday.v2"
)
const (
MaxTextLength = 20
)
var (
funcMap = template.FuncMap{
"env": env,
"genCaptcha": genCaptcha,
"markdown": markdown,
"version": version,
"toInt": toInt,
"isResponseIn": isResponseIn,
"query": query,
"convertDate": convertDate,
"convertTime": convertTime,
"prettyDate": prettyDate,
"prettyTime": prettyTime,
"prettyDateTime": prettyDateTime,
"zeroTime": zeroTime,
"seconds": seconds,
"modelPath": modelPath,
"dict": dict,
"yaml": yaml,
"create": create,
"update": update,
"delete": delete,
"show": show,
"all": all,
"execute": execute,
"isSlice": isSlice,
"toSlice": toSlice,
"string": callString,
"incr": incr,
"mod2": mod2,
"toLower": toLower,
"anchor": anchor,
"alertLink": alertLink,
"html": html,
"field": field,
"modelName": modelName,
"active": active,
"pluralize": pluralize,
"lower": lower,
"trim": trim,
"username": username,
"isAdmin": isAdmin,
"isSchool": isSchool,
"modelId": modelId,
"isParticipant": isParticipant,
"isSubscriber": isSubscriber,
"attr": attr,
}
)
func env(key string) string {
return os.Getenv(key)
}
func genCaptcha() string {
return captcha.New()
}
func markdown(text string) string {
sanitized := strings.Replace(text, "\r\n", "\n", -1)
unsafe := blackfriday.Run([]byte(sanitized))
return string(bluemonday.UGCPolicy().SanitizeBytes(unsafe))
}
func version() string {
version, err := ioutil.ReadFile("./VERSION")
if err != nil {
return ""
}
return strings.TrimSpace(string(version))
}
func toInt(value float64) int {
return int(value)
}
func isResponseIn(id uint, answersIDs string) (bool, error) {
if answersIDs != "" {
ids := make([]uint, 0)
srIDs := strings.Split(answersIDs, " ")
for _, srID := range srIDs {
id, err := strconv.Atoi(srID)
if err != nil {
return false, err
}
ids = append(ids, uint(id))
}
for _, v := range ids {
if v == id {
return true, nil
}
}
}
return false, nil
}
func username(claims jwt.MapClaims) string {
return claims["username"].(string)
}
func modelId(claims jwt.MapClaims) (uint, error) {
id, err := strconv.Atoi(claims["model_id"].(string))
if err != nil {
return 0, err
}
return uint(id), nil
}
func getRole(claims jwt.MapClaims) (string, error) {
role, ok := claims["role"]
if !ok {
return "", errors.NotAuthorized
}
return role.(string), nil
}
func isAdmin(claims jwt.MapClaims) (bool, error) {
role, err := getRole(claims)
if err != nil {
return false, err
}
return role == "administrator", nil
}
func isParticipant(claims jwt.MapClaims) (bool, error) {
role, err := getRole(claims)
if err != nil {
return false, err
}
return role == "participant", nil
}
func isSchool(claims jwt.MapClaims) (bool, error) {
role, err := getRole(claims)
if err != nil {
return false, err
}
return role == "school", nil
}
func isSubscriber(claims jwt.MapClaims) (bool, error) {
role, err := getRole(claims)
if err != nil {
return false, err
}
return role == "subscriber", nil
}
func trim(text string) string {
if len(text) > MaxTextLength {
return text[0:MaxTextLength] + "…"
}
return text
}
func modelName(value interface{}) string {
t := reflect.TypeOf(value)
switch t.Kind() {
case reflect.Ptr:
return t.Elem().Name()
case reflect.Slice:
return strings.Replace(t.Elem().String(), "*orm.", "", -1)
default:
return t.Name()
}
}
func lower(text string) string {
return strings.ToLower(text)
}
func pluralize(text string) string {
return inflection.Plural(text)
}
func active(value string, options url.Values) string {
if len(options["tpl_content"]) > 0 {
model := strings.Title(inflection.Singular(strings.Split(options["tpl_content"][0], "_")[0]))
if value == model {
return "active"
}
}
return ""
}
func field(name string, value interface{}) interface{} {
if value != nil {
s := reflect.ValueOf(value).Elem()
return s.FieldByName(name).Interface()
} else {
return nil
}
}
func html(content string) template.HTML {
return template.HTML(content)
}
func attr(attr string) template.HTMLAttr {
return template.HTMLAttr(attr)
}
func anchor(text, url string) template.HTML {
return template.HTML(fmt.Sprintf("<a href=\"%s\">%s</a>", url, text))
}
func alertLink(text, url string) template.HTML {
return template.HTML(fmt.Sprintf("<a class=\"alert-link\" href=\"%s\">%s</a>", url, text))
}
func toLower(text string) string {
return strings.ToLower(text)
}
func mod2(value int) bool {
return value%2 == 0
}
func incr(value int) int {
return value + 1
}
func callString(value interface{}) string {
if value != nil {
switch reflect.ValueOf(value).Kind() {
case reflect.String:
return value.(string)
case reflect.Bool:
if value.(bool) {
return i18n.Text["answerCorrect"]["it"]
}
return "false"
default:
return reflect.ValueOf(value).MethodByName("String").Interface().(func() string)()
}
} else {
return ""
}
}
func isSlice(value interface{}) bool {
return reflect.TypeOf(value).Kind() == reflect.Slice
}
func yaml(content string) (interface{}, error) {
var result interface{}
err := yml.Unmarshal([]byte(content), &result)
if err != nil {
return nil, err
}
return result, nil
}
func dict(values ...interface{}) (map[string]interface{}, error) {
if len(values)%2 != 0 {
return nil, fmt.Errorf("Invalid dict call, numbers of arguments is %d but should be a multiple of two", len(values))
}
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("%s", "dict keys must be strings")
}
dict[key] = values[i+1]
}
return dict, nil
}
func toSlice(values ...string) interface{} {
var result []string
result = append(result, values...)
return result
}
func getType(myvar interface{}) (res string) {
t := reflect.TypeOf(myvar)
for t.Kind() == reflect.Ptr {
t = t.Elem()
res += "*"
}
return res + t.Name()
}
func query(values ...string) template.URL {
var (
urlValues url.Values
format bool
)
urlValues = make(url.Values)
for i := 0; i < len(values); i += 2 {
if values[i] == "format" {
format = true
}
urlValues.Add(values[i], values[i+1])
}
if !format {
urlValues.Set("format", "html")
}
return template.URL(urlValues.Encode())
}
func convertDate(value interface{}) string {
t, ok := value.(time.Time)
if !ok {
return ""
}
return fmt.Sprintf("%d-%02d-%02d", t.Year(), t.Month(), t.Day())
}
func prettyDate(value interface{}) string {
t, ok := value.(time.Time)
if !ok {
return ""
}
if zeroTime(&t) {
return i18n.Text["alwaysActiveContest"]["it"]
}
return fmt.Sprintf("%02d/%02d/%d", t.Day(), t.Month(), t.Year())
}
func prettyDateTime(value interface{}) string {
t, ok := value.(time.Time)
if !ok {
return ""
}
return fmt.Sprintf(i18n.Formats["dateTime"]["it"], t.Day(), t.Month(), t.Year(), t.Hour(), t.Minute())
}
func convertTime(value interface{}) string {
t, ok := value.(time.Time)
if !ok {
return ""
}
return fmt.Sprintf("%02d:%02d", t.Hour(), t.Minute())
}
func prettyTime(value interface{}) string {
return convertTime(value)
}
func zeroTime(t *time.Time) bool {
return *t == time.Time{}
}
func seconds(d time.Duration) int {
return int(d.Seconds())
}
func modelPath(model string, action string, id uint) string {
var q template.URL
action = strings.ToLower(action)
plural := inflection.Plural(strings.ToLower(model))
if action != "" {
switch action {
case "show":
q = query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_%s", plural, action))
return fmt.Sprintf("/%s/%d?%s", plural, id, q)
case "update":
q = query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_add_update", plural), "update", "true")
return fmt.Sprintf("/%s/%d/%s?%s", plural, id, action, q)
case "create":
q = query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_add_update", plural))
return fmt.Sprintf("/%s/%s/?%s", plural, action, q)
case "delete":
q = query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_%s", plural, action))
return fmt.Sprintf("/%s/%d/%s?%s", plural, id, action, q)
}
}
q = query("tpl_layout", "base", "tpl_content", plural)
return fmt.Sprintf("/%s?%s", plural, q)
}
func all(model string) string {
plural := inflection.Plural(strings.ToLower(model))
q := query("tpl_layout", "base", "tpl_content", plural)
return fmt.Sprintf("/%s?%s", plural, q)
}
func create(model string) string {
action := "create"
plural := inflection.Plural(strings.ToLower(model))
q := query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_add_update", plural))
return fmt.Sprintf("/%s/%s/?%s", plural, action, q)
}
func show(model string, id uint, format ...string) string {
action := "show"
plural := inflection.Plural(strings.ToLower(model))
args := []string{"tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_%s", plural, action)}
if len(format) > 0 {
args = append(args, []string{"format", format[0]}...)
}
// q := query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_%s", plural, action))
q := query(args...)
return fmt.Sprintf("/%s/%d?%s", plural, id, q)
}
func execute(model string, id uint) string {
action := "execute"
plural := inflection.Plural(strings.ToLower(model))
q := query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_%s", plural, action))
return fmt.Sprintf("/%s/%d/%s?%s", plural, id, action, q)
}
func update(model string, id uint) string {
action := "update"
plural := inflection.Plural(strings.ToLower(model))
q := query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_add_update", plural), "update", "true")
return fmt.Sprintf("/%s/%d/%s?%s", plural, id, action, q)
}
func delete(model string, id uint) string {
action := "delete"
plural := inflection.Plural(strings.ToLower(model))
q := query("tpl_layout", "base", "tpl_content", fmt.Sprintf("%s_%s", plural, action))
return fmt.Sprintf("/%s/%d/%s?%s", plural, id, action, q)
}