Add subtask model and repository, implement webhook notification handling

fix Issue with Scheduler
Support NotificationPlatformWebhook
support Discord as notification target
This commit is contained in:
Mo Tarbin 2025-03-05 19:52:10 -05:00
parent 8db572f1ec
commit 81acbd8eba
8 changed files with 136 additions and 11 deletions

View file

@ -37,6 +37,7 @@ const (
NotificationPlatformTelegram
NotificationPlatformPushover
NotificationPlatformWebhook
NotificationPlatformDiscord
)
type JSONB map[string]interface{}

View file

@ -5,6 +5,7 @@ import (
"donetick.com/core/internal/events"
nModel "donetick.com/core/internal/notifier/model"
"donetick.com/core/internal/notifier/service/discord"
pushover "donetick.com/core/internal/notifier/service/pushover"
telegram "donetick.com/core/internal/notifier/service/telegram"
@ -14,14 +15,16 @@ import (
type Notifier struct {
Telegram *telegram.TelegramNotifier
Pushover *pushover.Pushover
discord *discord.DiscordNotifier
eventsProducer *events.EventsProducer
}
func NewNotifier(t *telegram.TelegramNotifier, p *pushover.Pushover, ep *events.EventsProducer) *Notifier {
func NewNotifier(t *telegram.TelegramNotifier, p *pushover.Pushover, ep *events.EventsProducer, d *discord.DiscordNotifier) *Notifier {
return &Notifier{
Telegram: t,
Pushover: p,
eventsProducer: ep,
discord: d,
}
}
@ -41,6 +44,13 @@ func (n *Notifier) SendNotification(c context.Context, notification *nModel.Noti
return nil
}
err = n.Pushover.SendNotification(c, notification)
case nModel.NotificationPlatformDiscord:
if n.discord == nil {
log.Error("Discord is not initialized, Skipping sending message")
return nil
}
err = n.discord.SendNotification(c, notification)
case nModel.NotificationPlatformWebhook:
// TODO: Implement webhook notification
// currently we have eventProducer to send events always as a webhook

View file

@ -0,0 +1,84 @@
package discord
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"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"
)
type DiscordNotifier struct {
}
func NewDiscordNotifier(config *config.Config) *DiscordNotifier {
return &DiscordNotifier{}
}
func (dn *DiscordNotifier) SendChoreCompletion(c context.Context, chore *chModel.Chore, user *uModel.User) {
log := logging.FromContext(c)
if dn == nil {
log.Error("Discord notifier is not initialized, skipping message sending")
return
}
var mt *chModel.NotificationMetadata
if err := json.Unmarshal([]byte(*chore.NotificationMetadata), &mt); err != nil {
log.Error("Error unmarshalling notification metadata", err)
}
message := fmt.Sprintf("🎉 **%s** is completed! Great job, %s! 🌟", chore.Name, user.DisplayName)
err := dn.sendMessage(c, user.UserNotificationTargets.TargetID, message)
if err != nil {
log.Error("Error sending Discord message:", err)
}
}
func (dn *DiscordNotifier) SendNotification(c context.Context, notification *nModel.NotificationDetails) error {
if dn == nil {
return errors.New("Discord notifier is not initialized")
}
if notification.Text == "" {
return errors.New("unable to send notification, text is empty")
}
return dn.sendMessage(c, notification.TargetID, notification.Text)
}
func (dn *DiscordNotifier) sendMessage(c context.Context, webhookURL string, message string) error {
log := logging.FromContext(c)
if webhookURL == "" {
return errors.New("unable to send notification, webhook URL is empty")
}
payload := map[string]string{"content": message}
jsonData, err := json.Marshal(payload)
if err != nil {
log.Error("Error marshalling JSON:", err)
return err
}
resp, err := http.Post(webhookURL, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
log.Error("Error sending message to Discord:", err)
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK {
log.Error("Discord webhook returned unexpected status:", resp.Status)
return errors.New("failed to send Discord message")
}
return nil
}