Files
llink/go/internal/human/service.go
T
talksik 51c4c6c822 feat: send email notifications for missed messages
- New cron job in cluster
- Handle presence and other concerns
- Toggle in app to disable email notifications
- Handles other edge cases such as cooldown period
- Simple html email with simple message

Closes #117
2026-04-09 14:15:34 -07:00

92 lines
2.4 KiB
Go

package human
import (
"context"
"errors"
"time"
"github.com/flowy-live/llink/internal/utils"
"github.com/jackc/pgx/v5/pgxpool"
)
var ErrNotFound = errors.New("human not found")
type Service interface {
GetOrCreateByEmail(ctx context.Context, email string) (*Human, error)
// GetByEmail returns ErrNotFound if no human found
GetByEmail(ctx context.Context, email string) (*Human, error)
// GetByID returns ErrNotFound if no human found
GetByID(ctx context.Context, id string) (*Human, error)
// ListAll returns all humans
ListAll(ctx context.Context) ([]*Human, error)
// UpdateEmailNotificationsEnabled toggles email notification preference
UpdateEmailNotificationsEnabled(ctx context.Context, id string, enabled bool) error
// UpdateLastEmailNotificationSentAt records when the last notification email was sent
UpdateLastEmailNotificationSentAt(ctx context.Context, id string, t time.Time) error
}
type serviceImpl struct {
repo repository
}
func NewService(pool *pgxpool.Pool) Service {
return &serviceImpl{repo: newRepository(pool)}
}
func (s *serviceImpl) GetOrCreateByEmail(ctx context.Context, email string) (*Human, error) {
email, err := utils.NormalizeEmail(email)
if err != nil {
return nil, err
}
h, err := s.repo.getByEmail(ctx, email)
if err != nil {
if errors.Is(err, errNotFound) {
return s.repo.create(ctx, email)
}
return nil, err
}
return h, nil
}
func (s *serviceImpl) GetByEmail(ctx context.Context, email string) (*Human, error) {
email, err := utils.NormalizeEmail(email)
if err != nil {
return nil, err
}
h, err := s.repo.getByEmail(ctx, email)
if errors.Is(err, errNotFound) {
return nil, ErrNotFound
}
return h, err
}
func (s *serviceImpl) GetByID(ctx context.Context, id string) (*Human, error) {
h, err := s.repo.getByID(ctx, id)
if errors.Is(err, errNotFound) {
return nil, ErrNotFound
}
return h, err
}
func (s *serviceImpl) ListAll(ctx context.Context) ([]*Human, error) {
return s.repo.listAll(ctx)
}
func (s *serviceImpl) UpdateEmailNotificationsEnabled(ctx context.Context, id string, enabled bool) error {
err := s.repo.updateEmailNotificationsEnabled(ctx, id, enabled)
if errors.Is(err, errNotFound) {
return ErrNotFound
}
return err
}
func (s *serviceImpl) UpdateLastEmailNotificationSentAt(ctx context.Context, id string, t time.Time) error {
err := s.repo.updateLastEmailNotificationSentAt(ctx, id, t)
if errors.Is(err, errNotFound) {
return ErrNotFound
}
return err
}