package telegram import ( "context" "fmt" "log/slog" ) type Service struct { repo Repository sender Sender logger *slog.Logger } func NewService(repo Repository, sender Sender, logger *slog.Logger) *Service { return &Service{repo: repo, sender: sender, logger: logger} } func (s *Service) Get(ctx context.Context) (*Settings, error) { return s.repo.Get(ctx) } // Update persists the settings. botToken == "" means "leave the currently // stored token untouched" -- the admin never has to re-type the secret just // to flip a checkbox, and the API never has to echo it back. func (s *Service) Update(ctx context.Context, enabled bool, botToken, chatID string, notifyNewOrder, notifyStatusChange bool) (*Settings, error) { settings := &Settings{ Enabled: enabled, BotToken: botToken, ChatID: chatID, NotifyNewOrder: notifyNewOrder, NotifyStatusChange: notifyStatusChange, } if err := s.repo.Update(ctx, settings); err != nil { return nil, err } return s.repo.Get(ctx) } func (s *Service) SendTestMessage(ctx context.Context) error { settings, err := s.repo.Get(ctx) if err != nil { return err } if settings.BotToken == "" || settings.ChatID == "" { return fmt.Errorf("bot token and chat id must be configured before testing") } return s.sender.Send(ctx, settings.BotToken, settings.ChatID, "Test notification: your Telegram integration is working.") } // NotifyNewOrder implements orders.OrderNotifier. It never returns an error // to the caller: a broken/misconfigured Telegram integration must not // prevent a customer's order from being created, so failures are only // logged. func (s *Service) NotifyNewOrder(ctx context.Context, summary string) { s.notify(ctx, func(st *Settings) bool { return st.NotifyNewOrder }, summary) } func (s *Service) NotifyOrderStatusChange(ctx context.Context, summary string) { s.notify(ctx, func(st *Settings) bool { return st.NotifyStatusChange }, summary) } func (s *Service) notify(ctx context.Context, shouldSend func(*Settings) bool, text string) { settings, err := s.repo.Get(ctx) if err != nil { s.logger.Error("telegram: failed to load settings", "error", err) return } if !settings.Enabled || !shouldSend(settings) { return } if err := s.sender.Send(ctx, settings.BotToken, settings.ChatID, text); err != nil { s.logger.Error("telegram: failed to send notification", "error", err) } }