From aa15dc793bd973d5351fc4a51ce59ad65e28c07b Mon Sep 17 00:00:00 2001 From: Sergey <83376337+freak12techno@users.noreply.github.com> Date: Sun, 12 May 2024 02:21:03 +0300 Subject: [PATCH] feat: move templates manager to class (#85) * feat: move templates manager to class * chore: fixed linting * chore: added tests for templates manager * chore: fixed linting --- pkg/reporters/telegram/add_mute.go | 13 ++- pkg/reporters/telegram/help.go | 13 ++- pkg/reporters/telegram/list_mutes.go | 12 ++- pkg/reporters/telegram/list_proposals.go | 12 ++- pkg/reporters/telegram/params.go | 17 +--- pkg/reporters/telegram/tally.go | 17 +--- pkg/reporters/telegram/telegram.go | 88 ++++-------------- pkg/templates/manager.go | 5 ++ pkg/templates/telegram.go | 88 ++++++++++++++++++ pkg/templates/telegram_test.go | 108 +++++++++++++++++++++++ templates/telegram/help.html | 2 +- 11 files changed, 247 insertions(+), 128 deletions(-) create mode 100644 pkg/templates/manager.go create mode 100644 pkg/templates/telegram.go create mode 100644 pkg/templates/telegram_test.go diff --git a/pkg/reporters/telegram/add_mute.go b/pkg/reporters/telegram/add_mute.go index d097178..f453158 100644 --- a/pkg/reporters/telegram/add_mute.go +++ b/pkg/reporters/telegram/add_mute.go @@ -1,8 +1,6 @@ package telegram import ( - "bytes" - tele "gopkg.in/telebot.v3" ) @@ -19,12 +17,11 @@ func (reporter *Reporter) HandleAddMute(c tele.Context) error { reporter.MutesManager.AddMute(mute) - template, _ := reporter.GetTemplate("mute_added") - var buffer bytes.Buffer - if err := template.Execute(&buffer, mute); err != nil { - reporter.Logger.Error().Err(err).Msg("Error rendering mute_added template") - return err + templateRendered, renderErr := reporter.TemplatesManager.Render("mute_added", mute) + if renderErr != nil { + reporter.Logger.Error().Err(renderErr).Msg("Error rendering template") + return reporter.BotReply(c, "Error rendering template") } - return reporter.BotReply(c, buffer.String()) + return reporter.BotReply(c, templateRendered) } diff --git a/pkg/reporters/telegram/help.go b/pkg/reporters/telegram/help.go index 394f520..a11023b 100644 --- a/pkg/reporters/telegram/help.go +++ b/pkg/reporters/telegram/help.go @@ -1,8 +1,6 @@ package telegram import ( - "bytes" - tele "gopkg.in/telebot.v3" ) @@ -12,12 +10,11 @@ func (reporter *Reporter) HandleHelp(c tele.Context) error { Str("text", c.Text()). Msg("Got help query") - template, _ := reporter.GetTemplate("help") - var buffer bytes.Buffer - if err := template.Execute(&buffer, reporter.Version); err != nil { - reporter.Logger.Error().Err(err).Msg("Error rendering help template") - return err + template, err := reporter.TemplatesManager.Render("help", reporter.Version) + if err != nil { + reporter.Logger.Error().Err(err).Msg("Error rendering template") + return reporter.BotReply(c, "Error rendering template") } - return reporter.BotReply(c, buffer.String()) + return reporter.BotReply(c, template) } diff --git a/pkg/reporters/telegram/list_mutes.go b/pkg/reporters/telegram/list_mutes.go index 54e1f21..467c79a 100644 --- a/pkg/reporters/telegram/list_mutes.go +++ b/pkg/reporters/telegram/list_mutes.go @@ -1,7 +1,6 @@ package telegram import ( - "bytes" mutes "main/pkg/mutes" "main/pkg/utils" @@ -18,12 +17,11 @@ func (reporter *Reporter) HandleListMutes(c tele.Context) error { return !m.IsExpired() }) - template, _ := reporter.GetTemplate("mutes") - var buffer bytes.Buffer - if err := template.Execute(&buffer, filteredMutes); err != nil { - reporter.Logger.Error().Err(err).Msg("Error rendering votes template") - return err + template, err := reporter.TemplatesManager.Render("mutes", filteredMutes) + if err != nil { + reporter.Logger.Error().Err(err).Msg("Error rendering template") + return reporter.BotReply(c, "Error rendering template") } - return reporter.BotReply(c, buffer.String()) + return reporter.BotReply(c, template) } diff --git a/pkg/reporters/telegram/list_proposals.go b/pkg/reporters/telegram/list_proposals.go index 8c8a47a..1674641 100644 --- a/pkg/reporters/telegram/list_proposals.go +++ b/pkg/reporters/telegram/list_proposals.go @@ -1,7 +1,6 @@ package telegram import ( - "bytes" statePkg "main/pkg/state" tele "gopkg.in/telebot.v3" @@ -16,12 +15,11 @@ func (reporter *Reporter) HandleProposals(c tele.Context) error { state := reporter.StateGenerator.GetState(statePkg.NewState()) renderedState := state.ToRenderedState() - template, _ := reporter.GetTemplate("proposals") - var buffer bytes.Buffer - if err := template.Execute(&buffer, renderedState); err != nil { - reporter.Logger.Error().Err(err).Msg("Error rendering proposals template") - return err + template, err := reporter.TemplatesManager.Render("proposals", renderedState) + if err != nil { + reporter.Logger.Error().Err(err).Msg("Error rendering template") + return reporter.BotReply(c, "Error rendering template") } - return reporter.BotReply(c, buffer.String()) + return reporter.BotReply(c, template) } diff --git a/pkg/reporters/telegram/params.go b/pkg/reporters/telegram/params.go index 9f415ee..966cb2f 100644 --- a/pkg/reporters/telegram/params.go +++ b/pkg/reporters/telegram/params.go @@ -1,7 +1,6 @@ package telegram import ( - "bytes" "fmt" tele "gopkg.in/telebot.v3" @@ -18,19 +17,11 @@ func (reporter *Reporter) HandleParams(c tele.Context) error { return reporter.BotReply(c, fmt.Sprintf("Error getting chain params: %s", err)) } - template, err := reporter.GetTemplate("params") + template, err := reporter.TemplatesManager.Render("params", params) if err != nil { - reporter.Logger.Error(). - Err(err). - Msg("Error rendering params template") - return reporter.BotReply(c, "Error rendering params template") + reporter.Logger.Error().Err(err).Msg("Error rendering template") + return reporter.BotReply(c, "Error rendering template") } - var buffer bytes.Buffer - if err := template.Execute(&buffer, params); err != nil { - reporter.Logger.Error().Err(err).Msg("Error rendering params template") - return err - } - - return reporter.BotReply(c, buffer.String()) + return reporter.BotReply(c, template) } diff --git a/pkg/reporters/telegram/tally.go b/pkg/reporters/telegram/tally.go index 38e19a1..3c46521 100644 --- a/pkg/reporters/telegram/tally.go +++ b/pkg/reporters/telegram/tally.go @@ -1,7 +1,6 @@ package telegram import ( - "bytes" "fmt" tele "gopkg.in/telebot.v3" @@ -22,19 +21,11 @@ func (reporter *Reporter) HandleTally(c tele.Context) error { return reporter.BotReply(c, fmt.Sprintf("Error getting tallies info: %s", err)) } - template, err := reporter.GetTemplate("tally") + template, err := reporter.TemplatesManager.Render("tally", tallies) if err != nil { - reporter.Logger.Error(). - Err(err). - Msg("Error rendering tallies template") - return reporter.BotReply(c, "Error rendering tallies template") + reporter.Logger.Error().Err(err).Msg("Error rendering template") + return reporter.BotReply(c, "Error rendering template") } - var buffer bytes.Buffer - if err := template.Execute(&buffer, tallies); err != nil { - reporter.Logger.Error().Err(err).Msg("Error rendering votes template") - return err - } - - return reporter.BotReply(c, buffer.String()) + return reporter.BotReply(c, template) } diff --git a/pkg/reporters/telegram/telegram.go b/pkg/reporters/telegram/telegram.go index b81d100..ddfa405 100644 --- a/pkg/reporters/telegram/telegram.go +++ b/pkg/reporters/telegram/telegram.go @@ -1,38 +1,34 @@ package telegram import ( - "bytes" "fmt" - "html/template" "main/pkg/data" mutes "main/pkg/mutes" "main/pkg/report/entry" "main/pkg/state" - "main/pkg/utils" + "main/pkg/templates" "strings" "time" "main/pkg/reporters" "main/pkg/types" - "main/templates" "github.com/rs/zerolog" tele "gopkg.in/telebot.v3" ) type Reporter struct { - TelegramToken string - TelegramChat int64 - MutesManager *mutes.Manager - StateGenerator *state.Generator - DataManager *data.Manager + TelegramToken string + TelegramChat int64 + MutesManager *mutes.Manager + StateGenerator *state.Generator + DataManager *data.Manager + TemplatesManager templates.Manager TelegramBot *tele.Bot Logger zerolog.Logger - Templates map[string]*template.Template - Version string - Timezone *time.Location + Version string } const ( @@ -49,15 +45,14 @@ func NewTelegramReporter( timezone *time.Location, ) *Reporter { return &Reporter{ - TelegramToken: config.TelegramToken, - TelegramChat: config.TelegramChat, - MutesManager: mutesManager, - StateGenerator: stateGenerator, - DataManager: dataManager, - Logger: logger.With().Str("component", "telegram_reporter").Logger(), - Templates: make(map[string]*template.Template, 0), - Version: version, - Timezone: timezone, + TelegramToken: config.TelegramToken, + TelegramChat: config.TelegramChat, + MutesManager: mutesManager, + StateGenerator: stateGenerator, + DataManager: dataManager, + Logger: logger.With().Str("component", "telegram_reporter").Logger(), + TemplatesManager: templates.NewTelegramTemplatesManager(logger, timezone), + Version: version, } } @@ -95,45 +90,8 @@ func (reporter *Reporter) Enabled() bool { return reporter.TelegramToken != "" && reporter.TelegramChat != 0 } -func (reporter *Reporter) GetTemplate(tmlpType string) (*template.Template, error) { - if cachedTemplate, ok := reporter.Templates[tmlpType]; ok { - reporter.Logger.Trace().Str("type", tmlpType).Msg("Using cached template") - return cachedTemplate, nil - } - - reporter.Logger.Trace().Str("type", tmlpType).Msg("Loading template") - - filename := tmlpType + ".html" - - t, err := template.New(filename).Funcs(template.FuncMap{ - "SerializeLink": reporter.SerializeLink, - "SerializeDate": reporter.SerializeDate, - "FormatDuration": utils.FormatDuration, - }).ParseFS(templates.TemplatesFs, "telegram/"+filename) - if err != nil { - return nil, err - } - - reporter.Templates[tmlpType] = t - - return t, nil -} - func (reporter *Reporter) SerializeReportEntry(e entry.ReportEntry) (string, error) { - parsedTemplate, err := reporter.GetTemplate(e.Name()) - if err != nil { - reporter.Logger.Error().Err(err).Str("type", e.Name()).Msg("Error loading template") - return "", err - } - - var buffer bytes.Buffer - err = parsedTemplate.Execute(&buffer, e) - if err != nil { - reporter.Logger.Error().Err(err).Str("type", e.Name()).Msg("Error rendering template") - return "", err - } - - return buffer.String(), nil + return reporter.TemplatesManager.Render(e.Name(), e) } func (reporter *Reporter) SendReport(report reporters.Report) error { @@ -247,15 +205,3 @@ func ParseMuteOptions(query string, c tele.Context) (*mutes.Mute, string) { return mute, "" } - -func (reporter *Reporter) SerializeLink(link types.Link) template.HTML { - if link.Href != "" { - return template.HTML(fmt.Sprintf("%s", link.Href, link.Name)) - } - - return template.HTML(link.Name) -} - -func (reporter *Reporter) SerializeDate(date time.Time) string { - return date.In(reporter.Timezone).Format(time.RFC1123) -} diff --git a/pkg/templates/manager.go b/pkg/templates/manager.go new file mode 100644 index 0000000..1952026 --- /dev/null +++ b/pkg/templates/manager.go @@ -0,0 +1,5 @@ +package templates + +type Manager interface { + Render(templateName string, data interface{}) (string, error) +} diff --git a/pkg/templates/telegram.go b/pkg/templates/telegram.go new file mode 100644 index 0000000..594b0a0 --- /dev/null +++ b/pkg/templates/telegram.go @@ -0,0 +1,88 @@ +package templates + +import ( + "bytes" + "fmt" + "html/template" + "main/pkg/types" + "main/pkg/utils" + "main/templates" + "time" + + "github.com/rs/zerolog" +) + +type TelegramTemplatesManager struct { + Templates map[string]*template.Template + Logger zerolog.Logger + Timezone *time.Location +} + +func NewTelegramTemplatesManager( + logger *zerolog.Logger, + timezone *time.Location, +) *TelegramTemplatesManager { + return &TelegramTemplatesManager{ + Templates: map[string]*template.Template{}, + Logger: logger.With().Str("component", "telegram_templates_manager").Logger(), + Timezone: timezone, + } +} + +func (m *TelegramTemplatesManager) Render(templateName string, data interface{}) (string, error) { + templateToRender, err := m.GetTemplate(templateName) + if err != nil { + m.Logger.Error(). + Err(err). + Str("name", templateName). + Msg("Error getting template") + return "", err + } + + var buffer bytes.Buffer + if err := templateToRender.Execute(&buffer, data); err != nil { + m.Logger.Error(). + Err(err). + Str("name", templateName). + Msg("Error rendering template") + return "", err + } + + return buffer.String(), nil +} + +func (m *TelegramTemplatesManager) GetTemplate(templateName string) (*template.Template, error) { + if cachedTemplate, ok := m.Templates[templateName]; ok { + m.Logger.Trace().Str("type", templateName).Msg("Using cached template") + return cachedTemplate, nil + } + + m.Logger.Trace().Str("type", templateName).Msg("Loading template") + + filename := templateName + ".html" + + t, err := template.New(filename).Funcs(template.FuncMap{ + "SerializeLink": m.SerializeLink, + "SerializeDate": m.SerializeDate, + "FormatDuration": utils.FormatDuration, + }).ParseFS(templates.TemplatesFs, "telegram/"+filename) + if err != nil { + return nil, err + } + + m.Templates[templateName] = t + + return t, nil +} + +func (m *TelegramTemplatesManager) SerializeLink(link types.Link) template.HTML { + if link.Href != "" { + return template.HTML(fmt.Sprintf("%s", link.Href, link.Name)) + } + + return template.HTML(link.Name) +} + +func (m *TelegramTemplatesManager) SerializeDate(date time.Time) string { + return date.In(m.Timezone).Format(time.RFC1123) +} diff --git a/pkg/templates/telegram_test.go b/pkg/templates/telegram_test.go new file mode 100644 index 0000000..62e8de5 --- /dev/null +++ b/pkg/templates/telegram_test.go @@ -0,0 +1,108 @@ +package templates + +import ( + templatePkg "html/template" + loggerPkg "main/pkg/logger" + "main/pkg/types" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/stretchr/testify/assert" +) + +func TestTelegramGetTemplateNotExisting(t *testing.T) { + t.Parallel() + + logger := loggerPkg.GetNopLogger() + timezone, _ := time.LoadLocation("Europe/Moscow") + manager := NewTelegramTemplatesManager(logger, timezone) + + template, err := manager.GetTemplate("not-existing") + require.Error(t, err) + assert.Nil(t, template) +} + +func TestTelegramGetTemplateExistingAndCached(t *testing.T) { + t.Parallel() + + logger := loggerPkg.GetNopLogger() + timezone, _ := time.LoadLocation("Europe/Moscow") + manager := NewTelegramTemplatesManager(logger, timezone) + + template, err := manager.GetTemplate("help") + require.NoError(t, err) + assert.NotNil(t, template) + + // this time it should be loaded from cache + template2, err2 := manager.GetTemplate("help") + require.NoError(t, err2) + assert.NotNil(t, template2) +} + +func TestTelegramRenderTemplateError(t *testing.T) { + t.Parallel() + + logger := loggerPkg.GetNopLogger() + timezone, _ := time.LoadLocation("Europe/Moscow") + manager := NewTelegramTemplatesManager(logger, timezone) + + template, err := manager.Render("not-existing", nil) + require.Error(t, err) + assert.Empty(t, template) +} + +func TestTelegramRenderTemplateRenderError(t *testing.T) { + t.Parallel() + + logger := loggerPkg.GetNopLogger() + timezone, _ := time.LoadLocation("Europe/Moscow") + manager := NewTelegramTemplatesManager(logger, timezone) + + value := map[string]interface{}{} + + template, err := manager.Render("voted", value) + require.Error(t, err) + assert.Empty(t, template) +} + +func TestTelegramRenderTemplateRenderSuccess(t *testing.T) { + t.Parallel() + + logger := loggerPkg.GetNopLogger() + timezone, _ := time.LoadLocation("Europe/Moscow") + manager := NewTelegramTemplatesManager(logger, timezone) + + template, err := manager.Render("help", "1.0.0") + require.NoError(t, err) + assert.NotEmpty(t, template) +} + +func TestTelegramRenderSerializeLink(t *testing.T) { + t.Parallel() + + logger := loggerPkg.GetNopLogger() + timezone, _ := time.LoadLocation("Europe/Moscow") + manager := NewTelegramTemplatesManager(logger, timezone) + + assert.Equal(t, templatePkg.HTML("test"), manager.SerializeLink(types.Link{Name: "test"})) + assert.Equal( + t, + templatePkg.HTML("test"), + manager.SerializeLink(types.Link{Name: "test", Href: "href"}), + ) +} + +func TestTelegramRenderSerializeDate(t *testing.T) { + t.Parallel() + + logger := loggerPkg.GetNopLogger() + timezone, _ := time.LoadLocation("Europe/Moscow") + manager := NewTelegramTemplatesManager(logger, timezone) + + dateStr := manager.SerializeDate( + time.Date(2000, 1, 1, 0, 0, 0, 0, timezone), + ) + assert.Equal(t, "Sat, 01 Jan 2000 00:00:00 MSK", dateStr) +} diff --git a/templates/telegram/help.html b/templates/telegram/help.html index 041d3c1..6f1ddd9 100644 --- a/templates/telegram/help.html +++ b/templates/telegram/help.html @@ -6,5 +6,5 @@ - /proposals_mutes - display the active proposals mutes list - /help - display this command -Created by 🐹 QuokkaStake with ❤️. +Created by 🐹 Quokka Stake with ❤️. If you like what we're doing, consider staking with us!