|
|
|
@ -2,6 +2,7 @@ package layout
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"log"
|
|
|
|
|
"sync"
|
|
|
|
@ -22,6 +23,7 @@ type (
|
|
|
|
|
|
|
|
|
|
buttons map[string]Button
|
|
|
|
|
markups map[string]Markup
|
|
|
|
|
results map[string]Result
|
|
|
|
|
locales map[string]*template.Template
|
|
|
|
|
|
|
|
|
|
*Config
|
|
|
|
@ -40,6 +42,22 @@ type (
|
|
|
|
|
RemoveKeyboard bool `yaml:"remove_keyboard,omitempty"`
|
|
|
|
|
Selective bool `yaml:"selective,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Result represents layout-specific result to be parsed.
|
|
|
|
|
Result struct {
|
|
|
|
|
result *template.Template
|
|
|
|
|
ResultBase `yaml:",inline"`
|
|
|
|
|
Markup string `yaml:"markup"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ResultBase represents layout-specific result's base to be parsed.
|
|
|
|
|
ResultBase struct {
|
|
|
|
|
tele.ResultBase `yaml:",inline"`
|
|
|
|
|
Content ResultContent `yaml:"content"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ResultContent represents any kind of InputMessageContent and implements it.
|
|
|
|
|
ResultContent map[string]interface{}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// New reads and parses the given layout file.
|
|
|
|
@ -157,7 +175,7 @@ func (lt *Layout) Text(c tele.Context, k string, args ...interface{}) string {
|
|
|
|
|
return lt.TextLocale(locale, k, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TextLocale returns a localized text processed with standard template engine.
|
|
|
|
|
// TextLocale returns a localized text processed with text/template engine.
|
|
|
|
|
// See Text for more details.
|
|
|
|
|
func (lt *Layout) TextLocale(locale, k string, args ...interface{}) string {
|
|
|
|
|
tmpl, ok := lt.locales[locale]
|
|
|
|
@ -227,7 +245,7 @@ func (lt *Layout) Button(c tele.Context, k string, args ...interface{}) *tele.Bt
|
|
|
|
|
return lt.ButtonLocale(locale, k, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ButtonLocale returns a localized button processed with standard template engine.
|
|
|
|
|
// ButtonLocale returns a localized button processed with text/template engine.
|
|
|
|
|
// See Button for more details.
|
|
|
|
|
func (lt *Layout) ButtonLocale(locale, k string, args ...interface{}) *tele.Btn {
|
|
|
|
|
btn, ok := lt.buttons[k]
|
|
|
|
@ -279,7 +297,8 @@ func (lt *Layout) ButtonLocale(locale, k string, args ...interface{}) *tele.Btn
|
|
|
|
|
// func onStart(c tele.Context) error {
|
|
|
|
|
// return c.Send(
|
|
|
|
|
// lt.Text(c, "start"),
|
|
|
|
|
// lt.Markup(c, "menu"))
|
|
|
|
|
// lt.Markup(c, "menu"),
|
|
|
|
|
// )
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
func (lt *Layout) Markup(c tele.Context, k string, args ...interface{}) *tele.ReplyMarkup {
|
|
|
|
@ -291,7 +310,7 @@ func (lt *Layout) Markup(c tele.Context, k string, args ...interface{}) *tele.Re
|
|
|
|
|
return lt.MarkupLocale(locale, k, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MarkupLocale returns a localized markup processed with standard template engine.
|
|
|
|
|
// MarkupLocale returns a localized markup processed with text/template engine.
|
|
|
|
|
// See Markup for more details.
|
|
|
|
|
func (lt *Layout) MarkupLocale(locale, k string, args ...interface{}) *tele.ReplyMarkup {
|
|
|
|
|
markup, ok := lt.markups[k]
|
|
|
|
@ -329,6 +348,143 @@ func (lt *Layout) MarkupLocale(locale, k string, args ...interface{}) *tele.Repl
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Result returns an inline result, which locale is dependent on the context.
|
|
|
|
|
// The given optional argument will be passed to the template engine.
|
|
|
|
|
//
|
|
|
|
|
// results:
|
|
|
|
|
// type: article
|
|
|
|
|
// id: '{{ .ID }}'
|
|
|
|
|
// title: '{{ .Title }}'
|
|
|
|
|
// description: '{{ .Description }}'
|
|
|
|
|
// message_text: '{{ .Content }}'
|
|
|
|
|
// thumb_url: '{{ .PreviewURL }}'
|
|
|
|
|
//
|
|
|
|
|
// Usage:
|
|
|
|
|
// func onQuery(c tele.Context) error {
|
|
|
|
|
// results := make(tele.Results, len(articles))
|
|
|
|
|
// for i, article := range articles {
|
|
|
|
|
// results[i] = lt.Result(c, "article", article)
|
|
|
|
|
// }
|
|
|
|
|
// return c.Answer(&tele.QueryResponse{
|
|
|
|
|
// Results: results,
|
|
|
|
|
// CacheTime: 100,
|
|
|
|
|
// })
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
func (lt *Layout) Result(c tele.Context, k string, args ...interface{}) tele.Result {
|
|
|
|
|
locale, ok := lt.Locale(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lt.ResultLocale(locale, k, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ResultLocale returns a localized result processed with text/template engine.
|
|
|
|
|
// See Result for more details.
|
|
|
|
|
func (lt *Layout) ResultLocale(locale, k string, args ...interface{}) tele.Result {
|
|
|
|
|
result, ok := lt.results[k]
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var arg interface{}
|
|
|
|
|
if len(args) > 0 {
|
|
|
|
|
arg = args[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := lt.template(result.result, locale).Execute(&buf, arg); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
data = buf.Bytes()
|
|
|
|
|
base ResultBase
|
|
|
|
|
r tele.Result
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if err := yaml.Unmarshal(data, &base); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch base.Type {
|
|
|
|
|
case "article":
|
|
|
|
|
r = &tele.ArticleResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "audio":
|
|
|
|
|
r = &tele.AudioResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "contact":
|
|
|
|
|
r = &tele.ContactResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "document":
|
|
|
|
|
r = &tele.DocumentResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "gif":
|
|
|
|
|
r = &tele.GifResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "location":
|
|
|
|
|
r = &tele.LocationResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := json.Unmarshal(data, &r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "mpeg4_gif":
|
|
|
|
|
r = &tele.Mpeg4GifResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "photo":
|
|
|
|
|
r = &tele.PhotoResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "venue":
|
|
|
|
|
r = &tele.VenueResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "video":
|
|
|
|
|
r = &tele.VideoResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "voice":
|
|
|
|
|
r = &tele.VoiceResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
case "sticker":
|
|
|
|
|
r = &tele.StickerResult{ResultBase: base.ResultBase}
|
|
|
|
|
if err := yaml.Unmarshal(data, r); err != nil {
|
|
|
|
|
log.Println("telebot/layout:", err)
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
log.Println("telebot/layout: unsupported inline result type")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if base.Content != nil {
|
|
|
|
|
r.SetContent(base.Content)
|
|
|
|
|
}
|
|
|
|
|
if result.Markup != "" {
|
|
|
|
|
markup := lt.MarkupLocale(locale, result.Markup)
|
|
|
|
|
r.SetReplyMarkup(markup.InlineKeyboard)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (lt *Layout) template(tmpl *template.Template, locale string) *template.Template {
|
|
|
|
|
funcs := make(template.FuncMap)
|
|
|
|
|
|
|
|
|
@ -339,3 +495,8 @@ func (lt *Layout) template(tmpl *template.Template, locale string) *template.Tem
|
|
|
|
|
|
|
|
|
|
return tmpl.Funcs(funcs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsInputMessageContent implements telebot.InputMessageContent.
|
|
|
|
|
func (ResultContent) IsInputMessageContent() bool {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|