spoc-bot-vr/.report.go

149 lines
3.2 KiB
Go

package main
import (
"context"
_ "embed"
"encoding/json"
"errors"
"io"
"slices"
"sort"
"text/template"
"time"
)
//go:embed report.tmpl
var reportTMPL string
func ReportSince(ctx context.Context, w io.Writer, s Storage, t time.Time) error {
tmpl := template.New("report").Funcs(map[string]any{
"time": func(foo string, args ...any) (any, error) {
switch foo {
case "Unix":
seconds, _ := args[0].(uint64)
return time.Unix(int64(seconds), 0), nil
case "Time.Format":
t, _ := args[1].(time.Time)
return t.Format(args[0].(string)), nil
}
return nil, errors.New("not impl")
},
"json": func(foo string, args ...any) (any, error) {
switch foo {
case "Marshal":
b, err := json.Marshal(args[0])
return string(b), err
}
return nil, errors.New("not impl")
},
})
tmpl, err := tmpl.Parse(reportTMPL)
if err != nil {
return err
}
messages, err := s.MessagesSince(ctx, t)
if err != nil {
return err
}
eventNames, err := s.EventNamesSince(ctx, t)
if err != nil {
return err
}
eventIDs, err := s.EventsSince(ctx, t)
if err != nil {
return err
}
type aThread struct {
Thread string
Messages []Message
First Message
Last Message
}
type anEvent struct {
Event string
Threads []aThread
First Message
Last Message
}
type someEvents struct {
Events []anEvent
}
return tmpl.Execute(w, map[string]any{
"since": t.Format("2006-01-02"),
"events": func() someEvents {
events := make([]anEvent, len(eventIDs))
for i, event := range eventIDs {
events[i] = func() anEvent {
threadNames := []string{}
for _, m := range messages {
if m.Event == event {
threadNames = append(threadNames, m.Thread)
}
}
slices.Sort(threadNames)
slices.Compact(threadNames)
threads := make([]aThread, len(threadNames))
for i, thread := range threadNames {
threads[i] = func() aThread {
someMessages := []Message{}
for _, m := range messages {
if m.Thread == thread {
someMessages = append(someMessages, m)
}
}
sort.Slice(someMessages, func(i, j int) bool {
return someMessages[i].TS < someMessages[j].TS
})
return aThread{
Thread: thread,
Messages: someMessages,
First: func() Message {
if len(someMessages) == 0 {
return Message{}
}
return someMessages[0]
}(),
Last: func() Message {
if len(someMessages) == 0 {
return Message{}
}
return someMessages[len(someMessages)-1]
}(),
}
}()
}
sort.Slice(threads, func(i, j int) bool {
return threads[i].First.TS < threads[j].First.TS
})
return anEvent{
Event: event,
Threads: threads,
First: func() Message {
if len(threads) == 0 {
return Message{}
}
return threads[0].First
}(),
Last: func() Message {
if len(threads) == 0 {
return Message{}
}
return threads[len(threads)-1].Last
}(),
}
}()
}
return someEvents{
Events: events,
}
}(),
"messages": messages,
"eventNames": eventNames,
})
}