2021-03-23 18:12:44 +01:00
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 )
2021-03-24 12:51:58 +01:00
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)" ) )
2021-03-23 18:12:44 +01:00
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
2021-03-24 12:51:58 +01:00
text := fmt . Sprintf ( "And it's gone (%s)" , duration )
2021-03-23 18:12:44 +01:00
// 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
2021-03-24 12:51:58 +01:00
request . ParseMode = telegram . ModeMarkdown
2021-03-23 18:12:44 +01:00
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
}