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 9ef7ac928e
Use markdown in Telegram
Signed-off-by: Julien Riou <julien@riou.xyz>
2021-03-24 12:51:58 +01:00

135 lines
4 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
timeout int
}
// 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,
}, 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
}
// 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
}