- Assign default circle to user when leaving a circle
- Support Pushover - Support Disable Signup - Migrate chatID to TargetID
This commit is contained in:
parent
850d472445
commit
adf5c0c0cd
20 changed files with 362 additions and 151 deletions
|
@ -80,18 +80,19 @@ func generateDueNotifications(chore *chModel.Chore, users []*cModel.UserCircleDe
|
|||
}
|
||||
}
|
||||
for _, user := range users {
|
||||
|
||||
notification := &nModel.Notification{
|
||||
ChoreID: chore.ID,
|
||||
IsSent: false,
|
||||
ScheduledFor: *chore.NextDueDate,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
TypeID: 1,
|
||||
TypeID: user.NotificationType,
|
||||
UserID: user.ID,
|
||||
TargetID: fmt.Sprint(user.ChatID),
|
||||
TargetID: user.TargetID,
|
||||
Text: fmt.Sprintf("📅 Reminder: *%s* is due today and assigned to %s.", chore.Name, assignee.DisplayName),
|
||||
}
|
||||
notifications = append(notifications, notification)
|
||||
if notification.IsValid() {
|
||||
notifications = append(notifications, notification)
|
||||
}
|
||||
}
|
||||
|
||||
return notifications
|
||||
|
@ -112,12 +113,14 @@ func generatePreDueNotifications(chore *chModel.Chore, users []*cModel.UserCircl
|
|||
IsSent: false,
|
||||
ScheduledFor: *chore.NextDueDate,
|
||||
CreatedAt: time.Now().UTC().Add(-time.Hour * 3),
|
||||
TypeID: 3,
|
||||
TypeID: user.NotificationType,
|
||||
UserID: user.ID,
|
||||
TargetID: fmt.Sprint(user.ChatID),
|
||||
TargetID: user.TargetID,
|
||||
Text: fmt.Sprintf("📢 Heads up! *%s* is due soon (on %s) and assigned to %s.", chore.Name, chore.NextDueDate.Format("January 2nd"), assignee.DisplayName),
|
||||
}
|
||||
notifications = append(notifications, notification)
|
||||
if notification.IsValid() {
|
||||
notifications = append(notifications, notification)
|
||||
}
|
||||
|
||||
}
|
||||
return notifications
|
||||
|
@ -141,12 +144,14 @@ func generateOverdueNotifications(chore *chModel.Chore, users []*cModel.UserCirc
|
|||
IsSent: false,
|
||||
ScheduledFor: scheduleTime,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
TypeID: 2,
|
||||
TypeID: user.NotificationType,
|
||||
UserID: user.ID,
|
||||
TargetID: fmt.Sprint(user.ChatID),
|
||||
TargetID: fmt.Sprint(user.TargetID),
|
||||
Text: fmt.Sprintf("🚨 *%s* is now %d hours overdue. Please complete it as soon as possible. (Assigned to %s)", chore.Name, hours, assignee.DisplayName),
|
||||
}
|
||||
notifications = append(notifications, notification)
|
||||
if notification.IsValid() {
|
||||
notifications = append(notifications, notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +165,7 @@ func generateCircleGroupNotifications(chore *chModel.Chore, mt *chModel.Notifica
|
|||
return notifications
|
||||
}
|
||||
if mt.DueDate {
|
||||
notifications = append(notifications, &nModel.Notification{
|
||||
notification := &nModel.Notification{
|
||||
ChoreID: chore.ID,
|
||||
IsSent: false,
|
||||
ScheduledFor: *chore.NextDueDate,
|
||||
|
@ -168,10 +173,14 @@ func generateCircleGroupNotifications(chore *chModel.Chore, mt *chModel.Notifica
|
|||
TypeID: 1,
|
||||
TargetID: fmt.Sprint(*mt.CircleGroupID),
|
||||
Text: fmt.Sprintf("📅 Reminder: *%s* is due today.", chore.Name),
|
||||
})
|
||||
}
|
||||
if notification.IsValid() {
|
||||
notifications = append(notifications, notification)
|
||||
}
|
||||
|
||||
}
|
||||
if mt.PreDue {
|
||||
notifications = append(notifications, &nModel.Notification{
|
||||
notification := &nModel.Notification{
|
||||
ChoreID: chore.ID,
|
||||
IsSent: false,
|
||||
ScheduledFor: *chore.NextDueDate,
|
||||
|
@ -179,12 +188,16 @@ func generateCircleGroupNotifications(chore *chModel.Chore, mt *chModel.Notifica
|
|||
TypeID: 3,
|
||||
TargetID: fmt.Sprint(*mt.CircleGroupID),
|
||||
Text: fmt.Sprintf("📢 Heads up! *%s* is due soon (on %s).", chore.Name, chore.NextDueDate.Format("January 2nd")),
|
||||
})
|
||||
}
|
||||
if notification.IsValid() {
|
||||
notifications = append(notifications, notification)
|
||||
}
|
||||
|
||||
}
|
||||
if mt.Nagging {
|
||||
for _, hours := range []int{24, 48, 72} {
|
||||
scheduleTime := chore.NextDueDate.Add(time.Hour * time.Duration(hours))
|
||||
notifications = append(notifications, &nModel.Notification{
|
||||
notification := &nModel.Notification{
|
||||
ChoreID: chore.ID,
|
||||
IsSent: false,
|
||||
ScheduledFor: scheduleTime,
|
||||
|
@ -192,7 +205,10 @@ func generateCircleGroupNotifications(chore *chModel.Chore, mt *chModel.Notifica
|
|||
TypeID: 2,
|
||||
TargetID: fmt.Sprint(*mt.CircleGroupID),
|
||||
Text: fmt.Sprintf("🚨 *%s* is now %d hours overdue. Please complete it as soon as possible.", chore.Name, hours),
|
||||
})
|
||||
}
|
||||
if notification.IsValid() {
|
||||
notifications = append(notifications, notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
37
internal/notifier/service/pushover/pushover.go
Normal file
37
internal/notifier/service/pushover/pushover.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package pushover
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"donetick.com/core/config"
|
||||
nModel "donetick.com/core/internal/notifier/model"
|
||||
"donetick.com/core/logging"
|
||||
"github.com/gregdel/pushover"
|
||||
)
|
||||
|
||||
type Pushover struct {
|
||||
pushover *pushover.Pushover
|
||||
}
|
||||
|
||||
func NewPushover(cfg *config.Config) *Pushover {
|
||||
|
||||
pushoverApp := pushover.New(cfg.Pushover.Token)
|
||||
|
||||
return &Pushover{
|
||||
pushover: pushoverApp,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pushover) SendNotification(c context.Context, notification *nModel.Notification) error {
|
||||
log := logging.FromContext(c)
|
||||
recipient := pushover.NewRecipient(notification.TargetID)
|
||||
message := pushover.NewMessageWithTitle(notification.Text, "Donetick")
|
||||
|
||||
_, err := p.pushover.SendMessage(message, recipient)
|
||||
if err != nil {
|
||||
log.Debug("Error sending pushover notification", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
95
internal/notifier/service/telegram/telegram.go
Normal file
95
internal/notifier/service/telegram/telegram.go
Normal file
|
@ -0,0 +1,95 @@
|
|||
package telegram
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"donetick.com/core/config"
|
||||
chModel "donetick.com/core/internal/chore/model"
|
||||
nModel "donetick.com/core/internal/notifier/model"
|
||||
uModel "donetick.com/core/internal/user/model"
|
||||
"donetick.com/core/logging"
|
||||
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
|
||||
)
|
||||
|
||||
type TelegramNotifier struct {
|
||||
bot *tgbotapi.BotAPI
|
||||
}
|
||||
|
||||
func NewTelegramNotifier(config *config.Config) *TelegramNotifier {
|
||||
bot, err := tgbotapi.NewBotAPI(config.Telegram.Token)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating bot: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
return &TelegramNotifier{
|
||||
bot: bot,
|
||||
}
|
||||
}
|
||||
|
||||
func (tn *TelegramNotifier) SendChoreCompletion(c context.Context, chore *chModel.Chore, user *uModel.User) {
|
||||
|
||||
log := logging.FromContext(c)
|
||||
if tn == nil {
|
||||
log.Error("Telegram bot is not initialized, Skipping sending message")
|
||||
return
|
||||
}
|
||||
var mt *chModel.NotificationMetadata
|
||||
if err := json.Unmarshal([]byte(*chore.NotificationMetadata), &mt); err != nil {
|
||||
log.Error("Error unmarshalling notification metadata", err)
|
||||
}
|
||||
|
||||
targets := []int64{}
|
||||
if user.ChatID != 0 {
|
||||
targets = append(targets, user.ChatID)
|
||||
}
|
||||
if mt.CircleGroup && mt.CircleGroupID != nil {
|
||||
// attempt to parse it:
|
||||
|
||||
if *mt.CircleGroupID != 0 {
|
||||
targets = append(targets, *mt.CircleGroupID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
text := fmt.Sprintf("🎉 *%s* is completed! is off the list, %s! 🌟 ", chore.Name, user.DisplayName)
|
||||
for _, target := range targets {
|
||||
msg := tgbotapi.NewMessage(target, text)
|
||||
|
||||
msg.ParseMode = "Markdown"
|
||||
_, err := tn.bot.Send(msg)
|
||||
if err != nil {
|
||||
log.Error("Error sending message to user: ", err)
|
||||
log.Debug("Error sending message, chore: ", chore.Name, " user: ", user.DisplayName, " chatID: ", user.ChatID, " user id: ", user.ID)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (tn *TelegramNotifier) SendNotification(c context.Context, notification *nModel.Notification) error {
|
||||
|
||||
log := logging.FromContext(c)
|
||||
if notification.TargetID == "" {
|
||||
log.Error("Notification target ID is empty")
|
||||
return errors.New("Notification target ID is empty")
|
||||
}
|
||||
chatID, err := strconv.ParseInt(notification.TargetID, 10, 64)
|
||||
if err != nil {
|
||||
log.Error("Error parsing chatID: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
msg := tgbotapi.NewMessage(chatID, notification.Text)
|
||||
msg.ParseMode = "Markdown"
|
||||
_, err = tn.bot.Send(msg)
|
||||
if err != nil {
|
||||
log.Error("Error sending message to user: ", err)
|
||||
log.Debug("Error sending message, notification: ", notification.Text, " chatID: ", chatID)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue