落地输入合规、探索题库、报告日/时辰刷新、账号头像、OEJTS 量表,并补齐 H5 埋点与 Admin 漏斗;同步 ESS 工件、切至自建 Git、清理 GitHub Actions。 Co-authored-by: Cursor <cursoragent@cursor.com>
68 lines
1.6 KiB
Go
68 lines
1.6 KiB
Go
package companion
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5"
|
|
|
|
core "github.com/yuxingu/digital-psychology/apps/api/internal/companion"
|
|
"github.com/yuxingu/digital-psychology/apps/api/internal/model"
|
|
"github.com/yuxingu/digital-psychology/apps/api/internal/repository"
|
|
"github.com/yuxingu/digital-psychology/apps/api/internal/textsafe"
|
|
)
|
|
|
|
// Service exposes solar terms and moods.
|
|
type Service struct {
|
|
Moods *repository.MoodRepo
|
|
}
|
|
|
|
// TodaySolar returns today's tip.
|
|
func (s *Service) TodaySolar() core.SolarTerm {
|
|
return core.TodaySolar(time.Now())
|
|
}
|
|
|
|
// SaveMoodInput for POST /moods.
|
|
type SaveMoodInput struct {
|
|
Score *int
|
|
Note *string
|
|
Day *time.Time
|
|
}
|
|
|
|
// SaveMood upserts mood for a day (default today).
|
|
func (s *Service) SaveMood(ctx context.Context, userID uuid.UUID, in SaveMoodInput) (*model.Mood, error) {
|
|
if in.Score != nil && (*in.Score < 1 || *in.Score > 5) {
|
|
return nil, errors.New("score must be 1-5")
|
|
}
|
|
if in.Note != nil {
|
|
n, err := textsafe.Check(textsafe.Note, *in.Note)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if n == "" {
|
|
in.Note = nil
|
|
} else {
|
|
in.Note = &n
|
|
}
|
|
}
|
|
day := time.Now()
|
|
if in.Day != nil {
|
|
day = *in.Day
|
|
}
|
|
return s.Moods.UpsertToday(ctx, userID, day, in.Score, in.Note)
|
|
}
|
|
|
|
// GetTodayMood returns today's mood or nil when none.
|
|
func (s *Service) GetTodayMood(ctx context.Context, userID uuid.UUID) (*model.Mood, error) {
|
|
m, err := s.Moods.GetToday(ctx, userID, time.Now())
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
return m, nil
|
|
}
|