diff --git a/main.go b/main.go index 3453251..4c4760c 100644 --- a/main.go +++ b/main.go @@ -65,6 +65,8 @@ func newHandler(cfg Config) http.HandlerFunc { mux := http.NewServeMux() mux.Handle("POST /api/v1/events/slack", http.HandlerFunc(newHandlerPostAPIV1EventsSlack(cfg))) + mux.Handle("GET /api/v1/eventnames", http.HandlerFunc(newHandlerGetAPIV1EventNames(cfg))) + mux.Handle("GET /api/v1/events", http.HandlerFunc(newHandlerGetAPIV1Events(cfg))) mux.Handle("GET /api/v1/messages", http.HandlerFunc(newHandlerGetAPIV1Messages(cfg))) mux.Handle("GET /api/v1/threads", http.HandlerFunc(newHandlerGetAPIV1Threads(cfg))) mux.Handle("GET /api/v1/threads/{thread}", http.HandlerFunc(newHandlerGetAPIV1ThreadsThread(cfg))) @@ -80,6 +82,50 @@ func newHandler(cfg Config) http.HandlerFunc { } } +func newHandlerGetAPIV1EventNames(cfg Config) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !basicAuth(cfg, w, r) { + return + } + + since, err := parseSince(r.URL.Query().Get("since")) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + eventNames, err := cfg.storage.EventNamesSince(r.Context(), since) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + encodeResponse(w, r, map[string]any{"eventNames": eventNames}) + } +} + +func newHandlerGetAPIV1Events(cfg Config) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !basicAuth(cfg, w, r) { + return + } + + since, err := parseSince(r.URL.Query().Get("since")) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + events, err := cfg.storage.EventsSince(r.Context(), since) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + encodeResponse(w, r, map[string]any{"events": events}) + } +} + func newHandlerGetAPIV1Messages(cfg Config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if !basicAuth(cfg, w, r) { diff --git a/main_test.go b/main_test.go index 8ce7e4a..9d3c67f 100644 --- a/main_test.go +++ b/main_test.go @@ -104,6 +104,52 @@ func TestRun(t *testing.T) { } }) + t.Run("GET /api/v1/eventnames", func(t *testing.T) { + resp, err := http.Get(fmt.Sprintf("%s/api/v1/eventnames", u)) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + t.Fatalf("(%d) %s", resp.StatusCode, b) + } + var result struct { + EventNames []string + } + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + t.Fatal(err) + } else if result.EventNames[0] != "[Oregon-1] Wal Receive Count Alert" { + t.Fatal(result.EventNames) + } else { + t.Logf("%+v", result) + } + }) + + t.Run("GET /api/v1/events", func(t *testing.T) { + resp, err := http.Get(fmt.Sprintf("%s/api/v1/events", u)) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + b, _ := io.ReadAll(resp.Body) + t.Fatalf("(%d) %s", resp.StatusCode, b) + } + var result struct { + Events []string + } + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + t.Fatal(err) + } else if result.Events[0] != "11067" { + t.Fatal(result.Events) + } else { + t.Logf("%+v", result) + } + }) + t.Run("GET /api/v1/threads", func(t *testing.T) { resp, err := http.Get(fmt.Sprintf("%s/api/v1/threads", u)) if err != nil { diff --git a/storage.go b/storage.go index 34ca605..af9dc2b 100644 --- a/storage.go +++ b/storage.go @@ -25,6 +25,40 @@ func (s Storage) MessagesSince(ctx context.Context, t time.Time) ([]Message, err }) } +func (s Storage) EventNamesSince(ctx context.Context, t time.Time) ([]string, error) { + messages, err := s.MessagesSince(ctx, t) + if err != nil { + return nil, err + } + names := map[string]struct{}{} + for _, m := range messages { + names[m.EventName] = struct{}{} + } + result := make([]string, 0, len(names)) + for k := range names { + result = append(result, k) + } + sort.Strings(result) + return result, nil +} + +func (s Storage) EventsSince(ctx context.Context, t time.Time) ([]string, error) { + messages, err := s.MessagesSince(ctx, t) + if err != nil { + return nil, err + } + events := map[string]struct{}{} + for _, m := range messages { + events[m.Event] = struct{}{} + } + result := make([]string, 0, len(events)) + for k := range events { + result = append(result, k) + } + sort.Strings(result) + return result, nil +} + func (s Storage) Threads(ctx context.Context) ([]string, error) { return s.ThreadsSince(ctx, time.Unix(0, 0)) }