mirror of
https://github.com/tucnak/telebot
synced 2024-11-05 06:00:58 +00:00
layout: add inline query results support
This commit is contained in:
parent
3281935f9c
commit
5108157783
@ -24,3 +24,8 @@ func (dlt *DefaultLayout) Button(k string, args ...interface{}) *tele.Btn {
|
||||
func (dlt *DefaultLayout) Markup(k string, args ...interface{}) *tele.ReplyMarkup {
|
||||
return dlt.lt.MarkupLocale(dlt.locale, k, args...)
|
||||
}
|
||||
|
||||
// Result wraps localized layout function Result using your default locale.
|
||||
func (dlt *DefaultLayout) Result(k string, args ...interface{}) tele.Result {
|
||||
return dlt.lt.ResultLocale(dlt.locale, k, args...)
|
||||
}
|
||||
|
@ -43,3 +43,12 @@ markups:
|
||||
one_time_keyboard: true
|
||||
inline:
|
||||
- [ stop ]
|
||||
|
||||
results:
|
||||
article:
|
||||
type: article
|
||||
id: '{{ .ID }}'
|
||||
title: '{{ .Title }}'
|
||||
description: '{{ .Description }}'
|
||||
message_text: '{{ .Content }}'
|
||||
thumb_url: '{{ .PreviewURL }}'
|
169
layout/layout.go
169
layout/layout.go
@ -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
|
||||
}
|
||||
|
@ -28,6 +28,20 @@ func TestLayout(t *testing.T) {
|
||||
assert.Equal(t, float64(123), lt.Float("num"))
|
||||
assert.Equal(t, 10*time.Minute, lt.Duration("dur"))
|
||||
|
||||
assert.Equal(t, &tele.Btn{
|
||||
Unique: "pay",
|
||||
Text: "Pay",
|
||||
Data: "1|100.00|USD",
|
||||
}, lt.ButtonLocale("en", "pay", struct {
|
||||
UserID int
|
||||
Amount string
|
||||
Currency string
|
||||
}{
|
||||
UserID: 1,
|
||||
Amount: "100.00",
|
||||
Currency: "USD",
|
||||
}))
|
||||
|
||||
assert.Equal(t, &tele.ReplyMarkup{
|
||||
ReplyKeyboard: [][]tele.ReplyButton{
|
||||
{{Text: "Help"}},
|
||||
@ -46,17 +60,26 @@ func TestLayout(t *testing.T) {
|
||||
InlineKeyboard: [][]tele.InlineButton{{{Unique: "stop", Text: "Stop", Data: "1"}}},
|
||||
}, lt.MarkupLocale("en", "inline", 1))
|
||||
|
||||
assert.Equal(t, &tele.Btn{
|
||||
Unique: "pay",
|
||||
Text: "Pay",
|
||||
Data: "1|100.00|USD",
|
||||
}, lt.ButtonLocale("en", "pay", struct {
|
||||
UserID int
|
||||
Amount string
|
||||
Currency string
|
||||
assert.Equal(t, &tele.ArticleResult{
|
||||
ResultBase: tele.ResultBase{
|
||||
ID: "1853",
|
||||
Type: "article",
|
||||
},
|
||||
Title: "Some title",
|
||||
Description: "Some description",
|
||||
Text: "The text of the article",
|
||||
ThumbURL: "https://preview.picture",
|
||||
}, lt.ResultLocale("en", "article", struct {
|
||||
ID int
|
||||
Title string
|
||||
Description string
|
||||
Content string
|
||||
PreviewURL string
|
||||
}{
|
||||
UserID: 1,
|
||||
Amount: "100.00",
|
||||
Currency: "USD",
|
||||
ID: 1853,
|
||||
Title: "Some title",
|
||||
Description: "Some description",
|
||||
Content: "The text of the article",
|
||||
PreviewURL: "https://preview.picture",
|
||||
}))
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ type Settings struct {
|
||||
Token string
|
||||
Updates int
|
||||
|
||||
LocalesDir string `"locales_dir"`
|
||||
LocalesDir string `yaml:"locales_dir"`
|
||||
TokenEnv string `yaml:"token_env"`
|
||||
ParseMode string `yaml:"parse_mode"`
|
||||
|
||||
@ -31,6 +31,7 @@ func (lt *Layout) UnmarshalYAML(data []byte) error {
|
||||
Config map[string]interface{}
|
||||
Buttons yaml.MapSlice
|
||||
Markups yaml.MapSlice
|
||||
Results yaml.MapSlice
|
||||
Locales map[string]map[string]string
|
||||
}
|
||||
if err := yaml.Unmarshal(data, &aux); err != nil {
|
||||
@ -192,6 +193,29 @@ func (lt *Layout) UnmarshalYAML(data []byte) error {
|
||||
}
|
||||
}
|
||||
|
||||
lt.results = make(map[string]Result, len(aux.Results))
|
||||
for _, item := range aux.Results {
|
||||
k, v := item.Key.(string), item.Value
|
||||
|
||||
data, err := yaml.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmpl, err := template.New(k).Funcs(lt.funcs).Parse(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var result Result
|
||||
if err := yaml.Unmarshal(data, &result); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result.result = tmpl
|
||||
lt.results[k] = result
|
||||
}
|
||||
|
||||
if aux.Locales == nil {
|
||||
if aux.Settings.LocalesDir == "" {
|
||||
aux.Settings.LocalesDir = "locales"
|
||||
|
Loading…
Reference in New Issue
Block a user