package main import ( "context" "flag" "fmt" "os" "time" "gitea.lab.audasmedia.com.au/sam/compass_teams_nhs/internal/brief" "gitea.lab.audasmedia.com.au/sam/compass_teams_nhs/internal/config" "gitea.lab.audasmedia.com.au/sam/compass_teams_nhs/internal/dashboard" "gitea.lab.audasmedia.com.au/sam/compass_teams_nhs/internal/store" ) // briefCommand is the `school brief` entry point: build and delete the stored // brief (the summary half of FR-10), list what is stored, and send it. Sending // through Apprise is Phase 7 and lives in `school notify` too. func briefCommand(args []string) { if len(args) == 0 { usage("school brief build --child NAME | school brief build --combined | school brief list") } switch args[0] { case "build": briefBuild(args[1:]) case "list": briefList() default: usage("school brief build --child NAME | school brief build --combined | school brief list") } } func briefBuild(args []string) { fs := flag.NewFlagSet("brief build", flag.ContinueOnError) var ( child string combined bool ) fs.StringVar(&child, "child", "", "child name (Harry or Finn)") fs.BoolVar(&combined, "combined", false, "build the combined brief for Jo and Sam") _ = fs.Parse(args) if child == "" && !combined { fmt.Fprintln(os.Stderr, "school brief build: --child NAME or --combined is required") os.Exit(2) } if err := runBriefBuild(child, combined); err != nil { fmt.Fprintln(os.Stderr, "school brief:", err) os.Exit(1) } } func runBriefBuild(child string, combined bool) error { ctx := context.Background() cfg, err := config.LoadDB() if err != nil { return err } st, err := store.Open(cfg.DBPath) if err != nil { return err } defer st.Close() if err := st.Migrate(ctx); err != nil { return err } if combined { children, err := st.ListChildren(ctx) if err != nil { return err } parts := make([]dashboard.Combined, 0, len(children)) for _, c := range children { items, err := st.ItemsForChild(ctx, c.ID) if err != nil { return err } parts = append(parts, dashboard.Combined{ Child: c.Name, Buckets: dashboard.Classify(items, time.Now(), cfg.Location), }) } text := dashboard.RenderCombined(parts, cfg.Location) recipient := brief.CombinedNames(children) id, err := st.CreateDraft(ctx, brief.ScopeCombined, recipient, text) if err != nil { return err } fmt.Printf("brief=%d scope=combined recipient=%s bytes=%d\n", id, recipient, len(text)) return nil } c, err := st.ChildByName(ctx, child) if err != nil { return err } if c == nil { return fmt.Errorf("unknown child %q", child) } items, err := st.ItemsForChild(ctx, c.ID) if err != nil { return err } text := dashboard.Render(c.Name, dashboard.Classify(items, time.Now(), cfg.Location), cfg.Location) id, err := st.CreateSummary(ctx, c.Name, text) if err != nil { return err } fmt.Printf("brief=%d recipient=%s bytes=%d\n", id, c.Name, len(text)) return nil } func briefList() { ctx := context.Background() cfg, err := config.LoadDB() if err != nil { fmt.Fprintln(os.Stderr, "school brief:", err) os.Exit(1) } st, err := store.Open(cfg.DBPath) if err != nil { fmt.Fprintln(os.Stderr, "school brief:", err) os.Exit(1) } defer st.Close() rows, err := st.RecentNotifications(ctx, 20) if err != nil { fmt.Fprintln(os.Stderr, "school brief:", err) os.Exit(1) } if len(rows) == 0 { fmt.Println("no briefs stored") return } for _, n := range rows { state := "draft" switch { case n.Channel != "" && n.OK && n.SentAt != nil: state = "sent " + n.SentAt.In(cfg.Location).Format("2006-01-02 15:04") case n.Channel != "" && n.OK: state = "sent" case n.Channel != "": state = "FAILED" } fmt.Printf("%d\t%s\t%s\t%s\t%s\n", n.ID, n.Scope, n.Recipient, state, firstLine(n.Text)) } } func firstLine(s string) string { for i, r := range s { if r == '\n' { return s[:i] } } return s } func usage(msg string) { fmt.Fprintln(os.Stderr, "usage:", msg) os.Exit(2) }