package main import ( "errors" "fmt" "strconv" "time" ) // A Choice is a ranking of a game in a vote type GameChoice struct { Team string // UUID of team Rank int } // A Vote is a collection of game rankings type Vote struct { Timestamp time.Time ClientId string // UUID of client Choices []GameChoice mPath []string // The path in the DB to this team } func NewVote(clId string, tm time.Time) (*Vote, error) { if clId == "" { return nil, errors.New("Client ID is required") } if tm.IsZero() { tm = time.Now() } vt := new(Vote) vt.Timestamp = tm vt.mPath = []string{"jam", "votes", clId, tm.Format(time.RFC3339)} return vt, nil } func (vt *Vote) SetChoices(ch []string) error { // Clear any previous choices from this vote vt.Choices = []GameChoice{} for i, v := range ch { vt.Choices = append(vt.Choices, GameChoice{Rank: i, Team: v}) } return nil } func (gj *Gamejam) GetVoteWithTimeString(clId, ts string) (*Vote, error) { timestamp, err := time.Parse(time.RFC3339, ts) if err != nil { return nil, err } return gj.GetVote(clId, timestamp) } func (gj *Gamejam) GetVote(clId string, ts time.Time) (*Vote, error) { for i := range gj.Votes { if gj.Votes[i].ClientId == clId && gj.Votes[i].Timestamp == ts { return &gj.Votes[i], nil } } return nil, errors.New("Couldn't find requested vote") } func (gj *Gamejam) AddVote(vt *Vote) error { // Make sure that this isn't a duplicate if _, err := gj.GetVote(vt.ClientId, vt.Timestamp); err == nil { return errors.New("Duplicate Vote") } gj.Votes = append(gj.Votes, *vt) return nil } /** * DB Functions * These are generally just called when the app starts up or when the periodic 'save' runs */ // LoadAllVotes loads all votes for the jam out of the database func (gj *Gamejam) LoadAllVotes() []Vote { var err error var ret []Vote if err = gj.m.openDB(); err != nil { return ret } defer gj.m.closeDB() votesPath := []string{"jam", "votes"} var cliUUIDs []string if cliUUIDs, err = gj.m.bolt.GetBucketList(votesPath); err != nil { return ret } for _, cId := range cliUUIDs { vtsPth := append(votesPath, cId) var times []string if times, err = gj.m.bolt.GetBucketList(vtsPth); err != nil { // Error reading this bucket, move on to the next continue } for _, t := range times { fmt.Println("Loading Vote", cId, t) if vt, err := gj.LoadVote(cId, t); err == nil { ret = append(ret, *vt) } } } return ret } // Load a vote from the DB and return it func (gj *Gamejam) LoadVote(clientId, t string) (*Vote, error) { var tm time.Time var err error if tm, err = time.Parse(time.RFC3339, t); err != nil { return nil, errors.New("Error loading vote: " + err.Error()) } vt, err := NewVote(clientId, tm) if err != nil { return nil, errors.New("Error creating vote: " + err.Error()) } var choices []string if choices, err = gj.m.bolt.GetKeyList(vt.mPath); err != nil { return nil, errors.New("Error creating vote: " + err.Error()) } for _, v := range choices { ch := new(GameChoice) var rank int if rank, err = strconv.Atoi(v); err == nil { ch.Rank = rank if ch.Team, err = gj.m.bolt.GetValue(vt.mPath, v); err == nil { vt.Choices = append(vt.Choices, *ch) } } } return vt, nil } func (gj *Gamejam) SaveVote(vt *Vote) error { var err error if err = gj.m.openDB(); err != nil { return err } defer gj.m.closeDB() for _, v := range vt.Choices { m.bolt.SetValue(vt.mPath, strconv.Itoa(v.Rank), v.Team) } return nil }