149 lines
3.2 KiB
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,
|
|
})
|
|
}
|