Adds templates to birthday message
This commit is contained in:
parent
7a88cf62ac
commit
c7399eb9da
9 changed files with 64 additions and 11 deletions
15
README.md
15
README.md
|
@ -11,6 +11,19 @@ There is an [example configuration file](./example-config.yml) that
|
||||||
can be used as a base to create your own configuration, and there is a
|
can be used as a base to create your own configuration, and there is a
|
||||||
[birthdays example CSV file](./birthdays.csv) to load the data.
|
[birthdays example CSV file](./birthdays.csv) to load the data.
|
||||||
|
|
||||||
|
## Template file
|
||||||
|
|
||||||
|
The template can be configured using the `birthday_template` config
|
||||||
|
parameter to point to the template file. The template uses the Go
|
||||||
|
Template Format, and has the following properties available:
|
||||||
|
|
||||||
|
- `.Name`: the name of the person whose birthday we're notifying.
|
||||||
|
- `.Email`: the email of the person.
|
||||||
|
- `.Phone`: the phone of the person, as a string.
|
||||||
|
- `.YearOfBirth`: the year that the person was born, as number.
|
||||||
|
- `.MonthOfBirth`: the month that the person was born, as number.
|
||||||
|
- `.DayOfBirth`: the day that the person was born, as number.
|
||||||
|
|
||||||
## Run the bot
|
## Run the bot
|
||||||
|
|
||||||
To get help for the bot command, run:
|
To get help for the bot command, run:
|
||||||
|
@ -39,7 +52,7 @@ $ make run
|
||||||
- [X] Configure logger through config (levels and such)
|
- [X] Configure logger through config (levels and such)
|
||||||
- [X] Reduce logger verbosity (through levels)
|
- [X] Reduce logger verbosity (through levels)
|
||||||
- [ ] Add pictures to birthday notifications
|
- [ ] Add pictures to birthday notifications
|
||||||
- [ ] Create a configurable template to fill with each notification
|
- [X] Create a configurable template to fill with each notification
|
||||||
- [ ] Create different message systems to use with the bot
|
- [ ] Create different message systems to use with the bot
|
||||||
- [X] Telegram
|
- [X] Telegram
|
||||||
- [ ] Email
|
- [ ] Email
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
birthday_file: birthdays.csv
|
birthday_file: birthdays.csv
|
||||||
|
birthday_template: ./birthday_message.tmpl
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
level: debug
|
level: debug
|
||||||
|
|
|
@ -15,6 +15,17 @@ type Birthday struct {
|
||||||
DayOfBirth int
|
DayOfBirth int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Birthday) ToMap() map[string]any {
|
||||||
|
return map[string]any{
|
||||||
|
"Name": b.Name,
|
||||||
|
"Email": b.Email,
|
||||||
|
"Phone": b.Phone,
|
||||||
|
"YearOfBirth": b.YearOfBirth,
|
||||||
|
"MonthOfBirth": b.MonthOfBirth,
|
||||||
|
"DayOfBirth": b.DayOfBirth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewBirthdayFromRecord(record []string) (*Birthday, error) {
|
func NewBirthdayFromRecord(record []string) (*Birthday, error) {
|
||||||
if len(record) != 4 {
|
if len(record) != 4 {
|
||||||
return nil, fmt.Errorf("invalid length %d for record", len(record))
|
return nil, fmt.Errorf("invalid length %d for record", len(record))
|
||||||
|
|
|
@ -18,11 +18,11 @@ var (
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
BirthdayFile string `yaml:"birthday_file"`
|
BirthdayFile string `yaml:"birthday_file"`
|
||||||
|
BirthdayTemplate string `yaml:"birthday_template"`
|
||||||
Logger *LoggerConfig `yaml:"logger"`
|
Logger *LoggerConfig `yaml:"logger"`
|
||||||
TelegramNotifications *TelegramNotificationsConfig `yaml:"telegram_notifications"`
|
TelegramNotifications *TelegramNotificationsConfig `yaml:"telegram_notifications"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDo: to be implemented
|
|
||||||
func (c *Config) IsValid() error {
|
func (c *Config) IsValid() error {
|
||||||
if c.BirthdayFile == "" {
|
if c.BirthdayFile == "" {
|
||||||
return ErrConfigBirthdayFileEmpty
|
return ErrConfigBirthdayFileEmpty
|
||||||
|
|
|
@ -6,6 +6,7 @@ package mocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
|
template "text/template"
|
||||||
|
|
||||||
model "git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
model "git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
||||||
gomock "github.com/golang/mock/gomock"
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
@ -35,15 +36,15 @@ func (m *MockNotificationService) EXPECT() *MockNotificationServiceMockRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify mocks base method.
|
// Notify mocks base method.
|
||||||
func (m *MockNotificationService) Notify(arg0 *model.Birthday) error {
|
func (m *MockNotificationService) Notify(arg0 *model.Birthday, arg1 *template.Template) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "Notify", arg0)
|
ret := m.ctrl.Call(m, "Notify", arg0, arg1)
|
||||||
ret0, _ := ret[0].(error)
|
ret0, _ := ret[0].(error)
|
||||||
return ret0
|
return ret0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify indicates an expected call of Notify.
|
// Notify indicates an expected call of Notify.
|
||||||
func (mr *MockNotificationServiceMockRecorder) Notify(arg0 interface{}) *gomock.Call {
|
func (mr *MockNotificationServiceMockRecorder) Notify(arg0, arg1 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Notify", reflect.TypeOf((*MockNotificationService)(nil).Notify), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Notify", reflect.TypeOf((*MockNotificationService)(nil).Notify), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
package notification
|
package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type NotificationService interface {
|
type NotificationService interface {
|
||||||
Notify(*model.Birthday) error
|
Notify(*model.Birthday, *template.Template) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package notification
|
package notification
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
|
@ -35,9 +37,19 @@ func NewTelegramNotificationService(logger *log.Logger, config *model.TelegramNo
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tns *TelegramNotificationService) Notify(birthday *model.Birthday) error {
|
func (tns *TelegramNotificationService) Notify(birthday *model.Birthday, template *template.Template) error {
|
||||||
// ToDo: introduce templates here
|
var msgText string
|
||||||
msgText := fmt.Sprintf("It's %s's birthday! You can reach them out at %s or %s", birthday.Name, birthday.Email, birthday.Phone)
|
if template != nil {
|
||||||
|
var stringBuffer bytes.Buffer
|
||||||
|
if err := template.Execute(&stringBuffer, birthday.ToMap()); err != nil {
|
||||||
|
return fmt.Errorf("cannot execute template for birthday: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msgText = stringBuffer.String()
|
||||||
|
} else {
|
||||||
|
msgText = fmt.Sprintf("It's %s's birthday! You can reach them out at %s or %s", birthday.Name, birthday.Email, birthday.Phone)
|
||||||
|
}
|
||||||
|
|
||||||
chatID, err := strconv.Atoi(tns.config.ChannelID)
|
chatID, err := strconv.Atoi(tns.config.ChannelID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot parse ChannelID: %w", err)
|
return fmt.Errorf("cannot parse ChannelID: %w", err)
|
||||||
|
|
1
sample.tmpl
Normal file
1
sample.tmpl
Normal file
|
@ -0,0 +1 @@
|
||||||
|
¡Mañana es el cumpleaños de {{.Name}}! Puedes felicitarle o bien escribiendo a {{.Email}} o bien llamando al número {{.Phone}}
|
|
@ -3,6 +3,7 @@ package server
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
||||||
"git.ctrlz.es/mgdelacroix/birthdaybot/notification"
|
"git.ctrlz.es/mgdelacroix/birthdaybot/notification"
|
||||||
|
@ -22,6 +23,7 @@ type Server struct {
|
||||||
workers []Worker
|
workers []Worker
|
||||||
birthdays []*model.Birthday
|
birthdays []*model.Birthday
|
||||||
notificationServices []notification.NotificationService
|
notificationServices []notification.NotificationService
|
||||||
|
tmpl *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNotificationServices(logger *log.Logger, config *model.Config) ([]notification.NotificationService, error) {
|
func createNotificationServices(logger *log.Logger, config *model.Config) ([]notification.NotificationService, error) {
|
||||||
|
@ -84,6 +86,16 @@ func New(options ...Option) (*Server, error) {
|
||||||
srv.workers = []Worker{NewSimpleWorker(srv)}
|
srv.workers = []Worker{NewSimpleWorker(srv)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if srv.config.BirthdayTemplate != "" {
|
||||||
|
srv.Logger.Debug("parsing birthday template", "file", srv.config.BirthdayTemplate)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
srv.tmpl, err = template.ParseFiles(srv.config.BirthdayTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot parse template file %q: %w", srv.config.BirthdayTemplate, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return srv, nil
|
return srv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +118,7 @@ func (s *Server) Stop() {
|
||||||
func (s *Server) Notify(birthday *model.Birthday) error {
|
func (s *Server) Notify(birthday *model.Birthday) error {
|
||||||
errs := []error{}
|
errs := []error{}
|
||||||
for _, service := range s.notificationServices {
|
for _, service := range s.notificationServices {
|
||||||
err := service.Notify(birthday)
|
err := service.Notify(birthday, s.tmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue