town/cmd/review/main.go

195 lines
4.2 KiB
Go
Raw Normal View History

2023-02-14 04:48:12 +00:00
package main
import (
2023-02-16 05:08:31 +00:00
"encoding/json"
2023-02-14 04:48:12 +00:00
"fmt"
2023-02-14 07:33:53 +00:00
"math/rand"
2023-02-14 04:48:12 +00:00
"os"
2023-02-16 05:08:31 +00:00
"path"
2023-02-14 07:33:53 +00:00
"strings"
"time"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
2023-02-16 05:48:26 +00:00
const (
signupDir = "/town/signups"
acceptedDir = "/town/signups/accepted"
rejectedDir = "/town/signups/rejected"
)
2023-02-14 07:33:53 +00:00
func getTitle() string {
titles := []string{
"yo bum rush the show",
"can i kick it?",
"super nintendo sega genesis",
"birthdays was the worst days",
"where were you when we were getting high?",
"it's real time, real time, time to get real",
}
return titles[rand.Intn(len(titles))]
}
2023-02-16 05:08:31 +00:00
type townSignup struct {
2023-02-16 05:48:26 +00:00
When time.Time
DecisionTime time.Time
Decision string
Filename string
Answers map[string]string
}
func (s townSignup) Accept() error {
return s.review("accept")
2023-02-14 07:33:53 +00:00
}
2023-02-16 05:48:26 +00:00
func (s townSignup) Reject() error {
return s.review("reject")
}
2023-02-16 05:08:31 +00:00
2023-02-16 05:48:26 +00:00
func (s townSignup) review(decision string) error {
s.DecisionTime = time.Now()
s.Decision = "decision"
oldpath := path.Join(signupDir, s.Filename)
newpath := path.Join(acceptedDir, s.Filename)
if decision == "reject" {
newpath = path.Join(rejectedDir, s.Filename)
}
return os.Rename(oldpath, newpath)
}
func (s townSignup) Render() string {
out := fmt.Sprintf("[-:-:b]submitted:[-:-:-] %s\n", s.When.Format("2006-01-02 15:04"))
for k, v := range s.Answers {
2023-02-16 05:08:31 +00:00
out += fmt.Sprintf("[-:-:b]%s[-:-:-]\n", k)
out += strings.TrimSpace(v)
out += "\n\n"
}
return out
2023-02-14 07:33:53 +00:00
}
2023-02-16 05:08:31 +00:00
func getSignups() ([]townSignup, error) {
2023-02-14 07:33:53 +00:00
entries, err := os.ReadDir(signupDir)
if err != nil {
return nil, fmt.Errorf("failed to read '%s': %w", signupDir, err)
}
2023-02-16 05:08:31 +00:00
out := []townSignup{}
2023-02-14 07:33:53 +00:00
for _, entry := range entries {
if !strings.HasSuffix(entry.Name(), "json") {
continue
}
2023-02-16 05:08:31 +00:00
abs := path.Join(signupDir, entry.Name())
data, err := os.ReadFile(abs)
if err != nil {
return nil, fmt.Errorf("could not read signup file '%s': %w", abs, err)
}
fmt.Println(string(data))
var signup townSignup
err = json.Unmarshal(data, &signup)
if err != nil {
return nil, fmt.Errorf("could not unmarshal signup file '%s': %w", abs, err)
}
2023-02-16 05:48:26 +00:00
signup.Filename = entry.Name()
2023-02-16 05:08:31 +00:00
out = append(out, signup)
2023-02-14 07:33:53 +00:00
}
return out, nil
}
2023-02-14 04:48:12 +00:00
func _main() error {
2023-02-14 07:33:53 +00:00
rand.Seed(time.Now().Unix())
2023-02-16 05:08:31 +00:00
signups, err := getSignups()
2023-02-14 07:33:53 +00:00
if err != nil {
2023-02-16 05:08:31 +00:00
return fmt.Errorf("could not get signups: %w", err)
2023-02-14 07:33:53 +00:00
}
2023-02-16 05:08:31 +00:00
signupIx := 0
2023-02-14 07:33:53 +00:00
pages := tview.NewPages()
mainFlex := tview.NewFlex()
title := tview.NewTextView()
title.SetText(getTitle())
2023-02-16 05:08:31 +00:00
title.SetTextAlign(tview.AlignCenter)
2023-02-16 05:48:26 +00:00
title.SetTextColor(tcell.ColorPurple)
2023-02-16 05:08:31 +00:00
title.SetBackgroundColor(tcell.ColorBlack)
2023-02-14 07:33:53 +00:00
appView := tview.NewTextView()
2023-02-16 05:08:31 +00:00
appView.SetDynamicColors(true)
if len(signups) == 0 {
appView.SetText("no signups found.")
2023-02-14 07:33:53 +00:00
} else {
2023-02-16 05:08:31 +00:00
appView.SetText(signups[signupIx].Render())
2023-02-14 07:33:53 +00:00
}
legend := tview.NewTextView()
2023-02-16 05:48:26 +00:00
legend.SetText("s: skip r: random A: approve R: reject N: notate Q: quit")
legend.SetTextColor(tcell.ColorPurple)
legend.SetTextAlign(tview.AlignCenter)
legend.SetBackgroundColor(tcell.ColorBlack)
2023-02-14 07:33:53 +00:00
mainFlex.SetDirection(tview.FlexRow)
mainFlex.AddItem(title, 1, -1, false)
mainFlex.AddItem(appView, 0, 1, true)
mainFlex.AddItem(legend, 1, -1, false)
pages.AddPage("main", mainFlex, true, true)
// TODO page for textarea to notate
app := tview.NewApplication()
app.SetRoot(pages, true)
2023-02-16 05:48:26 +00:00
// TODO count of pending signups somewhere
2023-02-14 07:33:53 +00:00
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Rune() {
case 's':
2023-02-16 05:08:31 +00:00
signupIx++
if signupIx == len(signups) {
signupIx = 0
}
appView.SetText(signups[signupIx].Render())
2023-02-14 07:33:53 +00:00
case 'r':
2023-02-16 05:08:31 +00:00
signupIx = rand.Intn(len(signups))
appView.SetText(signups[signupIx].Render())
2023-02-14 07:33:53 +00:00
case 'A':
2023-02-16 05:48:26 +00:00
err := signups[signupIx].Accept()
if err != nil {
// TODO report in app
panic(fmt.Errorf("failed to approve '%s': %w", signups[signupIx].Filename, err))
}
// TODO remove from signups list
2023-02-14 07:33:53 +00:00
case 'R':
2023-02-16 05:48:26 +00:00
err = signups[signupIx].Reject()
if err != nil {
// TODO report in app
panic(fmt.Errorf("failed to rejec t'%s': %w", signups[signupIx].Filename, err))
}
// TODO remove from signups list
2023-02-14 07:33:53 +00:00
case 'n':
// TODO notate
case 'Q':
app.Stop()
}
return event
})
return app.Run()
2023-02-14 04:48:12 +00:00
}
func main() {
err := _main()
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}