package main import ( "os" "time" "github.com/google/uuid" "gopkg.in/yaml.v2" ) type ( yamlDB struct { Knowledge knowledge Users map[string]user Cadence []duration } knowledge struct { Questions map[string]Question Answers map[string]Answer } user struct { Tags tags History map[string][]History } tags struct { Assignments []string } ) func newYamlDB(p string) (yamlDB, error) { db := yamlDB{ Knowledge: knowledge{ Questions: map[string]Question{}, Answers: map[string]Answer{}, }, Users: map[string]user{}, Cadence: []duration{}, } if b, err := os.ReadFile(p); err != nil { return yamlDB{}, err } else if err := yaml.Unmarshal(b, &db); err != nil { return yamlDB{}, err } return db, nil } func (db yamlDB) HistoryOf(user string) map[string][]History { result := map[string][]History{} for k, v := range db.Users[user].History { result[k] = append([]History{}, v...) } for _, tag := range db.Users[user].Tags.Assignments { for qid, q := range db.Knowledge.Questions { if _, ok := result[qid]; !ok && q.Tagged(tag) { result[qid] = []History{} } } } return result } func (db yamlDB) Next(user, q string) time.Time { history := db.Users[user].History[q] progress := 0 for i := range history { if history[i].Pass { progress += 1 } else { progress -= 1 } } if progress < 0 { progress = 0 } else if progress > len(db.Cadence) { return time.Now().Add(time.Hour * 24 * 365 * 10) } return db.lastTS(user, q).Add(time.Duration(db.Cadence[progress])) } func (db yamlDB) Question(q string) Question { return db.Knowledge.Questions[q] } func (db yamlDB) LastAnswer(user, q string) (string, Answer) { maxk := "" var maxv Answer for k, v := range db.Knowledge.Answers { if v.Q == q && v.Author == user { if maxv.TS < v.TS { maxk = k maxv = v } } } return maxk, maxv } func (db yamlDB) Answer(a string) Answer { return db.Knowledge.Answers[a] } func (db yamlDB) PushAnswer(user, q, a string, pass bool) error { uuid := uuid.New().String() db.Knowledge.Answers[uuid] = Answer{ Q: q, A: a, TS: time.Now().UnixNano(), Author: user, } db.Users[user].History[q] = append(db.Users[user].History[q], History{ A: uuid, Pass: pass, TS: db.Knowledge.Answers[uuid].TS, }) return nil } func (db yamlDB) lastTS(user, q string) time.Time { max := int64(0) for _, v := range db.Users[user].History[q] { if v.TS > max { max = v.TS } } return time.Unix(0, max) }