Archived
1
0
Fork 0
This repository has been archived on 2024-12-18. You can view files and clone it, but cannot push or open issues or pull requests.
restockbot/notifier_telegram.go
Julien Riou 305b3eeb76
Enable replies on Twitter and Telegram
By default, when a product is available, a notification is sent. When that same
product is not available, a reply is sent to the original message. With tons of
notifications, replies might be seen as flooding. This commit adds an option to
explicitly enable replies on Twitter and Telegram notifiers. By default, reply
messages are disabled.

Signed-off-by: Julien Riou <julien@riou.xyz>
2021-04-01 13:14:00 +02:00

138 lines
4.1 KiB
Go

package main
import (
"fmt"
"time"
telegram "github.com/go-telegram-bot-api/telegram-bot-api/v5"
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
)
// TelegramMessage to store relationship between a Product and a Telegram notification
type TelegramMessage struct {
gorm.Model
MessageID int `gorm:"not null;unique"`
ProductURL string
Product Product `gorm:"foreignKey:ProductURL"`
}
// TelegramNotifier to manage notifications to Twitter
type TelegramNotifier struct {
db *gorm.DB
bot *telegram.BotAPI
chatID int64
channelName string
enableReplies bool
}
// NewTelegramNotifier to create a Notifier with Telegram capabilities
func NewTelegramNotifier(config *TelegramConfig, db *gorm.DB) (*TelegramNotifier, error) {
// create table
err := db.AutoMigrate(&TelegramMessage{})
if err != nil {
return nil, err
}
// create client
bot, err := telegram.NewBotAPI(config.Token)
if err != nil {
return nil, err
}
log.Debugf("connected to telegram as %s", bot.Self.UserName)
return &TelegramNotifier{
db: db,
bot: bot,
chatID: config.ChatID,
channelName: config.ChannelName,
enableReplies: config.EnableReplies,
}, nil
}
// NotifyWhenAvailable create a Telegram message for announcing that a product is available
// implements the Notifier interface
func (n *TelegramNotifier) NotifyWhenAvailable(shopName string, productName string, productPrice float64, productCurrency string, productURL string) error {
// TODO: check if message exists in the database to avoid flood
// send message to telegram
formattedPrice := formatPrice(productPrice, productCurrency)
rawMessage := `*Name:* %s
*Retailer:* %s
*Price:* %s
*URL*: [go to website](%s)
*Date/Time:* %s`
message := fmt.Sprintf(rawMessage, productName, shopName, formattedPrice, productURL, time.Now().UTC().Format("2006-01-02 15:04:05 (-0700)"))
messageID, err := n.sendMessage(message, 0)
if err != nil {
return err
}
// save telegram message to database
m := TelegramMessage{MessageID: messageID, ProductURL: productURL}
trx := n.db.Create(&m)
if trx.Error != nil {
return fmt.Errorf("failed to save telegram message %d to database: %s", m.MessageID, trx.Error)
}
log.Debugf("telegram message %d saved to database", m.MessageID)
return nil
}
// NotifyWhenNotAvailable create a Telegram message replying to the NotifyWhenAvailable message to say it's gone
// implements the Notifier interface
func (n *TelegramNotifier) NotifyWhenNotAvailable(productURL string, duration time.Duration) error {
// find message in the database
var m TelegramMessage
trx := n.db.Where(TelegramMessage{ProductURL: productURL}).First(&m)
if trx.Error != nil {
return fmt.Errorf("failed to find telegram message in database for product with url %s: %s", productURL, trx.Error)
}
if m.MessageID == 0 {
log.Warnf("telegram message for product with url %s not found, skipping close notification", productURL)
return nil
}
if n.enableReplies {
// format message
text := fmt.Sprintf("And it's gone (%s)", duration)
// send reply on telegram
_, err := n.sendMessage(text, m.MessageID)
if err != nil {
return fmt.Errorf("failed to reply on telegram: %s", err)
}
log.Infof("reply to telegram message %d sent", m.MessageID)
}
// remove message from database
trx = n.db.Unscoped().Delete(&m)
if trx.Error != nil {
return fmt.Errorf("failed to remove message %d from database: %s", m.MessageID, trx.Error)
}
log.Debugf("telegram message removed from database")
return nil
}
func (n *TelegramNotifier) sendMessage(text string, reply int) (int, error) {
log.Debugf("sending message %s to telegram", text)
var request telegram.MessageConfig
if n.chatID != 0 {
request = telegram.NewMessage(n.chatID, text)
} else {
request = telegram.NewMessageToChannel(n.channelName, text)
}
request.DisableWebPagePreview = true
request.ParseMode = telegram.ModeMarkdown
if reply != 0 {
request.ReplyToMessageID = reply
}
response, err := n.bot.Send(request)
if err != nil {
return 0, err
}
log.Infof("message %d sent to telegram", response.MessageID)
return response.MessageID, nil
}