Pushing up, done for the day

This commit is contained in:
Brian Buller 2017-10-11 18:03:27 -05:00
parent 18eabf2f79
commit 9440565555
13 changed files with 611 additions and 456 deletions

View File

@ -62,7 +62,7 @@ func handleAdminSetMode(w http.ResponseWriter, req *http.Request, page *pageData
if err != nil { if err != nil {
page.session.setFlashMessage("Invalid Mode: "+vars["id"], "error") page.session.setFlashMessage("Invalid Mode: "+vars["id"], "error")
} }
if dbSetPublicSiteMode(newMode) != nil { if db.setPublicSiteMode(newMode) != nil {
page.session.setFlashMessage("Invalid Mode: "+vars["id"], "error") page.session.setFlashMessage("Invalid Mode: "+vars["id"], "error")
} }
redirect("/admin", w, req) redirect("/admin", w, req)
@ -74,7 +74,7 @@ func handleAdminSetAuthMode(w http.ResponseWriter, req *http.Request, page *page
if err != nil { if err != nil {
page.session.setFlashMessage("Invalid Authentication Mode: "+vars["id"], "error") page.session.setFlashMessage("Invalid Authentication Mode: "+vars["id"], "error")
} }
if db.setAuthMode(newMode) != nil { if db.site.setAuthMode(newMode) != nil {
page.session.setFlashMessage("Invalid Authentication Mode: "+vars["id"], "error") page.session.setFlashMessage("Invalid Authentication Mode: "+vars["id"], "error")
} }
redirect("/admin", w, req) redirect("/admin", w, req)

View File

@ -33,7 +33,7 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData)
if tm != nil { if tm != nil {
switch vars["function"] { switch vars["function"] {
case "save": case "save":
gm := newGame(tm.UUID) gm := db.newGame(tm.UUID)
gm.Name = req.FormValue("gamename") gm.Name = req.FormValue("gamename")
gm.Link = req.FormValue("gamelink") gm.Link = req.FormValue("gamelink")
gm.Description = req.FormValue("gamedesc") gm.Description = req.FormValue("gamedesc")

68
main.go
View File

@ -60,9 +60,14 @@ var sessionSecret = "JCOP5e8ohkTcOzcSMe74"
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret)) var sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
var site *siteData var site *siteData
var r *mux.Router var r *mux.Router
var m *model
func main() { func main() {
db = new(gjDatabase) var err error
if m, err = NewModel(); err != nil {
errorExit("Unable to initialize Model: " + err.Error())
}
loadConfig() loadConfig()
site.save() site.save()
initialize() initialize()
@ -70,13 +75,10 @@ func main() {
r = mux.NewRouter() r = mux.NewRouter()
r.StrictSlash(true) r.StrictSlash(true)
if site.DevMode { if m.site.DevMode {
fmt.Println("Operating in Development Mode") fmt.Println("Operating in Development Mode")
} }
//s := http.StripPrefix("/assets/", http.FileServer(FS(site.DevMode))) r.PathPrefix("/assets/").Handler(http.FileServer(FS(m.site.DevMode)))
//http.Dir(site.ServerDir+"assets/")))
//r.PathPrefix("/assets/").Handler(s)
r.PathPrefix("/assets/").Handler(http.FileServer(FS(site.DevMode)))
// Public Subrouter // Public Subrouter
pub := r.PathPrefix("/").Subrouter() pub := r.PathPrefix("/").Subrouter()
@ -110,8 +112,6 @@ func main() {
} }
func loadConfig() { func loadConfig() {
site = db.getSiteConfig()
if len(os.Args) > 1 { if len(os.Args) > 1 {
for _, v := range os.Args { for _, v := range os.Args {
key := v key := v
@ -124,27 +124,27 @@ func loadConfig() {
} }
switch key { switch key {
case "-title": case "-title":
site.Title = val m.site.Title = val
fmt.Print("Set site title: ", site.Title, "\n") fmt.Print("Set site title: ", m.site.Title, "\n")
case "-port": case "-port":
var tryPort int var tryPort int
var err error var err error
if tryPort, err = strconv.Atoi(val); err != nil { if tryPort, err = strconv.Atoi(val); err != nil {
fmt.Print("Invalid port given: ", val, " (Must be an integer)\n") fmt.Print("Invalid port given: ", val, " (Must be an integer)\n")
tryPort = site.Port tryPort = m.site.Port
} }
// TODO: Make sure a valid port number is given // TODO: Make sure a valid port number is given
site.Port = tryPort m.site.Port = tryPort
case "-session-name": case "-session-name":
site.SessionName = val m.site.SessionName = val
case "-server-dir": case "-server-dir":
// TODO: Probably check if the given directory is valid // TODO: Probably check if the given directory is valid
site.ServerDir = val m.site.ServerDir = val
case "-help", "-h", "-?": case "-help", "-h", "-?":
printHelp() printHelp()
done() done()
case "-dev": case "-dev":
site.DevMode = true m.site.DevMode = true
case "-reset-defaults": case "-reset-defaults":
resetToDefaults() resetToDefaults()
done() done()
@ -154,10 +154,9 @@ func loadConfig() {
} }
func initialize() { func initialize() {
// Check if the database has been created // Test if we have an admin user first
assertError(db.initialize()) if !m.hasUser() {
// Nope, create one
if !db.hasUser() {
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
fmt.Println("Create new Admin user") fmt.Println("Create new Admin user")
fmt.Print("Email: ") fmt.Print("Email: ")
@ -175,29 +174,26 @@ func initialize() {
fmt.Println("Entered Passwords don't match!") fmt.Println("Entered Passwords don't match!")
} }
} }
assertError(db.updateUserPassword(email, string(pw1))) assertError(m.updateUserPassword(email, string(pw1)))
} }
if !db.hasCurrentJam() {
// Now test if the 'current jam' is named
if m.jam.Name == "" {
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
fmt.Println("Create New Game Jam") fmt.Println("Create New Game Jam")
fmt.Print("GameJam Name: ") fmt.Print("GameJam Name: ")
gjName, _ := reader.ReadString('\n') gjName, _ := reader.ReadString('\n')
gjName = strings.TrimSpace(gjName) gjName = strings.TrimSpace(gjName)
if db.setCurrentJam(gjName) != nil { if db.setJamName(gjName) != nil {
fmt.Println("Error saving Current Jam") fmt.Println("Error saving Current Jam")
} }
} }
jmNm, err := db.getCurrentJam() if m.jam.Name != "" {
if err == nil {
fmt.Println("Current Jam Name: " + jmNm) fmt.Println("Current Jam Name: " + jmNm)
} else { } else {
fmt.Println(err.Error()) fmt.Println("No Jam Name Specified")
} }
// Load all votes into memory
site.Votes = db.getAllVotes()
site.Teams = db.getAllTeams()
} }
func loggingHandler(h http.Handler) http.Handler { func loggingHandler(h http.Handler) http.Handler {
@ -261,7 +257,7 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
} }
p.HideAdminMenu = true p.HideAdminMenu = true
if p.CurrentJam, err = db.getCurrentJam(); err != nil { if p.CurrentJam = db.getJamName(); p.CurrentJam != "" {
p.FlashMessage = "Error Loading Current GameJam: " + err.Error() p.FlashMessage = "Error Loading Current GameJam: " + err.Error()
p.FlashClass = "error" p.FlashClass = "error"
} }
@ -274,7 +270,7 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
// Public Mode // Public Mode
p.PublicMode = db.getPublicSiteMode() p.PublicMode = db.getPublicSiteMode()
// Authentication Mode // Authentication Mode
p.AuthMode = db.getAuthMode() p.AuthMode = db.site.getAuthMode()
return p return p
} }
@ -310,12 +306,12 @@ func redirect(url string, w http.ResponseWriter, req *http.Request) {
} }
func resetToDefaults() { func resetToDefaults() {
def := NewSiteData() def := NewSiteData(m)
fmt.Println("Reset settings to defaults?") fmt.Println("Reset settings to defaults?")
fmt.Print(site.Title, " -> ", def.Title, "\n") fmt.Print(m.site.Title, " -> ", def.Title, "\n")
fmt.Print(site.Port, " -> ", def.Port, "\n") fmt.Print(m.site.Port, " -> ", def.Port, "\n")
fmt.Print(site.SessionName, " -> ", def.SessionName, "\n") fmt.Print(m.site.SessionName, " -> ", def.SessionName, "\n")
fmt.Print(site.ServerDir, " -> ", def.ServerDir, "\n") fmt.Print(m.site.ServerDir, " -> ", def.ServerDir, "\n")
fmt.Println("Are you sure? (y/N): ") fmt.Println("Are you sure? (y/N): ")
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
conf, _ := reader.ReadString('\n') conf, _ := reader.ReadString('\n')

183
model.go
View File

@ -2,45 +2,66 @@ package main
import ( import (
"errors" "errors"
"strings"
"github.com/br0xen/boltease" "github.com/br0xen/boltease"
) )
// TODO: I don't think we need a global for this... // model stores the current jam in memory, and has the ability to access archived dbs
var db *currJamDb type model struct {
bolt *boltease.DB
dbOpened int
dbFileName string
// gjdb is the interface that works for the current jam database as well as all archive databases site *siteData // Configuration data for the site
type gjdb interface { jam *Gamejam // The currently active gamejam
getDB() *boltease.DB clients []Client // Web clients that have connected to the server
open() error
close() error
getJamName() string
setJamName(nm string)
} }
// Authentication Modes: Flags for which clients are able to vote
const ( const (
AuthModeAuthentication = iota AuthModeAuthentication = iota
AuthModeAll AuthModeAll
AuthModeError AuthModeError
) )
// currJamDb also contains site configuration information // Update Flags: Which parts of the model need to be updated
type currJamDb struct { const (
bolt *boltease.DB UpdateSiteData = iota
dbOpened int UpdateJamData
)
func NewModel() (*model, error) {
var err error
m := new(model)
m.dbFileName = DbName
if err = m.openDB(); err != nil {
return nil, errors.New("Unable to open DB: " + err.Error())
}
defer m.closeDB()
// Initialize the DB
if err = m.initDB(); err != nil {
return nil, errors.New("Unable to initialize DB: " + err.Error())
}
// Load the site data
m.site = m.LoadSiteData()
// Load the jam data
m.jam = m.LoadCurrentJam()
// Load web clients
m.clients = m.LoadAllClients()
return &m, nil
} }
func (db *currJamDb) getDB() *boltease.DB { func (m *model) openDB() error {
return db.bolt m.dbOpened += 1
}
func (db *currJamDb) open() error {
db.dbOpened += 1
if db.dbOpened == 1 { if db.dbOpened == 1 {
var err error var err error
db.bolt, err = boltease.Create(DbName, 0600, nil) m.bolt, err = boltease.Create(m.dbFileName, 0600, nil)
if err != nil { if err != nil {
return err return err
} }
@ -48,112 +69,58 @@ func (db *currJamDb) open() error {
return nil return nil
} }
func (db *currJamDb) close() error { func (m *model) closeDB() error {
db.dbOpened -= 1 m.dbOpened -= 1
if db.dbOpened == 0 { if m.dbOpened == 0 {
return db.bolt.CloseDB() return m.bolt.CloseDB()
} }
return nil return nil
} }
// initialize the 'current jam' database func (m *model) initDB() error {
func (db *currJamDb) initialize() error {
var err error var err error
if err = db.open(); err != nil { if err = m.openDB(); err != nil {
return err return err
} }
defer db.close() defer m.closeDB()
// Create the path to the bucket to store admin users // Create the path to the bucket to store admin users
if err := db.bolt.MkBucketPath([]string{"users"}); err != nil { if err = m.bolt.MkBucketPath([]string{"users"}); err != nil {
return err return err
} }
// Create the path to the bucket to store jam informations // Create the path to the bucket to store the web clients
if err := db.bolt.MkBucketPath([]string{"jam"}); err != nil { if err = m.bolt.MkBucketPath([]string{"clients"}); err != nil {
return err
}
// Create the path to the bucket to store the current jam & teams
if err = m.bolt.MkBucketPath([]string{"jam", "teams"}); err != nil {
return err
}
// Create the path to the bucket to store the list of archived jams
if err = m.bolt.MkBucketPath([]string{"archive"}); err != nil {
return err return err
} }
// Create the path to the bucket to store site config data // Create the path to the bucket to store site config data
return db.bolt.MkBucketPath([]string{"site"}) return m.bolt.MkBucketPath([]string{"site"})
} }
func (db *currJamDb) getSiteConfig() *siteData { // saveChanges saves any parts of the model that have been flagged as changed to the database
var ret *siteData func (m *model) saveChanges() error {
def := NewSiteData()
var err error var err error
if err = db.open(); err != nil { if err = m.openDB(); err != nil {
return def
}
defer db.close()
ret = new(siteData)
siteConf := []string{"site"}
if ret.Title, err = db.bolt.GetValue(siteConf, "title"); err != nil {
ret.Title = def.Title
}
if ret.Port, err = db.bolt.GetInt(siteConf, "port"); err != nil {
ret.Port = def.Port
}
if ret.SessionName, err = db.bolt.GetValue(siteConf, "session-name"); err != nil {
ret.SessionName = def.SessionName
}
if ret.ServerDir, err = db.bolt.GetValue(siteConf, "server-dir"); err != nil {
ret.ServerDir = def.ServerDir
}
return ret
}
func (db *currJamDb) setJamName(name string) error {
var err error
if err = db.open(); err != nil {
return err return err
} }
defer db.close() defer m.closeDB()
return db.bolt.SetValue([]string{"site"}, "current-jam", name) if m.site.needsSave() {
} if err = m.site.saveToDB(); err != nil {
return err
func (db *currJamDb) getJamName() string { }
var ret string
var err error
if err = db.open(); err != nil {
return "", err
} }
defer db.close() if m.jam.needsSave() {
if err = m.jam.saveToDB(); err != nil {
ret, err = db.bolt.GetValue([]string{"site"}, "current-jam") return err
}
if err == nil && strings.TrimSpace(ret) == "" {
return ret, errors.New("No Jam Name Specified")
} }
return ret, err return nil
}
func (db *currJamDb) getAuthMode() int {
if ret, err := db.bolt.GetInt([]string{"site"}, "auth-mode"); err != nil {
return AuthModeAuthentication
} else {
return ret
}
}
func (db *currJamDb) setAuthMode(mode int) error {
if mode < 0 || mode >= AuthModeError {
return errors.New("Invalid site mode")
}
return db.bolt.SetInt([]string{"site"}, "auth-mode", mode)
}
func (db *currJamDb) getPublicSiteMode() int {
if ret, err := db.bolt.GetInt([]string{"site"}, "public-mode"); err != nil {
return SiteModeWaiting
} else {
return ret
}
}
func (db *currJamDb) setPublicSiteMode(mode int) error {
if mode < 0 || mode >= SiteModeError {
return errors.New("Invalid site mode")
}
return db.bolt.SetInt([]string{"site"}, "public-mode", mode)
} }

View File

@ -1,12 +1,15 @@
package main package main
import ( import (
"fmt"
"strconv" "strconv"
"strings" "strings"
"time" "time"
) )
/**
* Client
* A client is a system that is connecting to the web server
*/
type Client struct { type Client struct {
UUID string UUID string
Auth bool Auth bool
@ -14,57 +17,53 @@ type Client struct {
IP string IP string
} }
func (db *currJamDb) getAllClients() []Client { // Load all clients
var ret []Client func (m *model) LoadAllClients() []Client {
var err error var err error
if err = db.open(); err != nil { if err = m.openDB(); err != nil {
return ret return err
} }
defer db.close() defer m.closeDB()
var clientUids []string var clientUids []string
if clientUids, err = db.bolt.GetBucketList([]string{"clients"}); err != nil { if clientUids, err = m.bolt.GetBucketList([]string{"clients"}); err != nil {
return ret return err
} }
for _, v := range clientUids { for _, v := range clientUids {
if cl := db.getClient(v); cl != nil { if cl := m.LoadClient(v); cl != nil {
ret = append(ret, *cl) m.clients = append(m.clients, *cl)
} }
} }
return ret
} }
func (db *currJamDb) getClient(id string) *Client { // Load a client from the DB and return it
func (m *model) LoadClient(clId string) *Client {
var err error var err error
if err = db.open(); err != nil { if err = m.openDB(); err != nil {
return nil return nil
} }
defer db.close() defer m.closeDB()
cl := new(Client) cl := new(Client)
cl.UUID = id cl.UUID = id
cl.Auth, _ = db.bolt.GetBool([]string{"clients", id}, "auth") cl.Auth, _ = m.bolt.GetBool([]string{"clients", id}, "auth")
cl.Name, _ = db.bolt.GetValue([]string{"clients", id}, "name") cl.Name, _ = m.bolt.GetValue([]string{"clients", id}, "name")
cl.IP, _ = db.bolt.GetValue([]string{"clients", id}, "ip") cl.IP, _ = m.bolt.GetValue([]string{"clients", id}, "ip")
return cl return cl
} }
func (db *currJamDb) getClientByIp(ip string) *Client { func (m *model) getClientById(ip string) *Client {
var err error for i := range m.clients {
if err = db.open(); err != nil { if m.clients[i].IP == ip {
return nil return &m.clients[i].IP
}
defer db.close()
allClients := db.getAllClients()
for i := range allClients {
if allClients[i].IP == ip {
return &allClients[i]
} }
} }
return nil return nil
} }
/**
* OLD FUNCTIONS
*/
func (c *Client) save() error { func (c *Client) save() error {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
@ -81,62 +80,6 @@ func (c *Client) save() error {
return db.bolt.SetValue([]string{"clients", c.UUID}, "ip", c.IP) return db.bolt.SetValue([]string{"clients", c.UUID}, "ip", c.IP)
} }
func (c *Client) getVotes() []Vote {
var ret []Vote
var err error
if err = db.open(); err != nil {
return ret
}
defer db.close()
var times []string
votesBkt := []string{"votes", c.UUID}
if times, err = db.bolt.GetBucketList(votesBkt); err != nil {
return ret
}
for _, t := range times {
var tm time.Time
if tm, err = time.Parse(time.RFC3339, t); err == nil {
var vt *Vote
if vt, err = c.getVote(tm); err == nil {
ret = append(ret, *vt)
} else {
fmt.Println(err)
}
}
}
return ret
}
func (c *Client) getVote(timestamp time.Time) (*Vote, error) {
var err error
if err = db.open(); err != nil {
return nil, err
}
defer db.close()
vt := new(Vote)
vt.Timestamp = timestamp
vt.ClientId = c.UUID
votesBkt := []string{"votes", c.UUID, timestamp.Format(time.RFC3339)}
var choices []string
if choices, err = db.bolt.GetKeyList(votesBkt); err != nil {
// Couldn't find the vote...
return nil, err
}
for _, v := range choices {
ch := new(GameChoice)
var rank int
if rank, err = strconv.Atoi(v); err == nil {
ch.Rank = rank
ch.Team, err = db.bolt.GetValue(votesBkt, v)
vt.Choices = append(vt.Choices, *ch)
}
}
return vt, nil
}
func (c *Client) saveVote(timestamp time.Time, votes []string) error { func (c *Client) saveVote(timestamp time.Time, votes []string) error {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {

View File

@ -1,12 +1,11 @@
package main package main
import ( import "time"
"time"
"github.com/br0xen/boltease" /**
) * Gamejam
* Gamejam is the struct for any gamejam (current or archived)
// Gamejam is specifically for an archived game jam */
type Gamejam struct { type Gamejam struct {
UUID string UUID string
Name string Name string
@ -14,74 +13,56 @@ type Gamejam struct {
Teams []Team Teams []Team
Votes []Vote Votes []Vote
db *boltease.DB m *model
dbOpened int updates []string
} }
// Archived Gamejam data is stored in it's own file to keep things nice and organized func NewGamejam(m *model) *Gamejam {
func (gj *Gamejam) openDB() error { gj := new(Gamejam)
gj.dbOpened += 1 gj.m = m
if gj.dbOpened == 1 { return gj
var err error
gj.db, err = boltease.Create(gj.UUID+".db", 0600, nil)
if err != nil {
return err
}
}
return nil
} }
func (gj *Gamejam) closeDB() error { func (m *model) LoadCurrentJam() *Gamejam {
gj.dbOpened -= 1 if err := m.openDB(); err != nil {
if gj.dbOpened == 0 {
return gj.db.CloseDB()
}
return nil
}
// archiveGameJam creates a separate gamejam file and populates it with the
// given name, teams, and votes
func archiveGamejam(nm string, teams []Team, votes []Vote) error {
// TODO
return nil
}
// dbGetGamejam returns a gamejam with the given uuid
// or nil if it couldn't be found
func dbGetGamejam(id string) *Gamejam {
var err error
if err = openDatabase(); err != nil {
return nil
}
defer closeDatabase()
ret := Gamejam{UUID: id}
// TODO: Load gamejam teams, other details
return ret
}
// dbGetGamejamByName looks for a gamejam with the given name
// and returns it, or it returns nil if it couldn't find it
func dbGetGamejamByName(nm string) *Gamejam {
var err error
if err = openDatabase(); err != nil {
return err return err
} }
defer closeDatabase() defer m.closeDB()
var gjid string var err error
if gjs, err = db.GetBucketList([]string{"gamejams"}); err == nil { jamPath := []string{"jam"}
for _, v := range gjUids { gj := NewGamejam(m)
tstNm, _ := db.GetValue([]string{"gamejams", v}, "name") gj.Name, _ = m.bolt.GetValue(jamPath, "name")
if tstNm == nm {
// We've got it // Load all teams
gjid = v gj.Teams = gj.LoadAllTeams()
break
} // Load all votes
gj.Votes = gj.LoadAllVotes()
return gj
}
func (gj *Gamejam) getTeamByUUID(uuid string) *Team {
for i := range gj.Teams {
if gj.Teams[i].UUID == uuid {
return &gj.Teams[i]
} }
} }
if gjid == "" { return nil
return nil }
}
return dbGetGamejam(gjid) func (gj *Gamejam) needsSave() bool {
return len(updates) > 0
}
func (gj *Gamejam) saveToDB() error {
if err := s.m.openDB(); err != nil {
return err
}
defer s.m.closeDB()
for i := range updates {
// TODO: Save
}
} }

View File

@ -2,6 +2,10 @@ package main
import "errors" import "errors"
/**
* Game
* A team's game, including links, description, and screenshots
*/
type Game struct { type Game struct {
Name string Name string
TeamId string TeamId string
@ -18,8 +22,87 @@ type Screenshot struct {
Filetype string Filetype string
} }
// Load a team's game from the DB and return it
func (gj *Gamejam) LoadTeamGame(tmId string) *Game {
var err error
if err = gj.m.openDB(); err != nil {
return nil
}
defer gj.m.closeDB()
gamePath := []string{"jam", "teams", tmId, "game"}
gm := new(Game)
gm.TeamId = tm.UUID
if gm.Name, err = gj.m.bolt.GetValue(gamePath, "name"); err != nil {
gm.Name = ""
}
if gm.Description, err = gj.m.bolt.GetValue(gamePath, "description"); err != nil {
gm.Description = ""
}
if gm.Link, err = gj.m.bolt.GetValue(gamePath, "link"); err != nil {
gm.Link = ""
}
// Now get the game screenshots
gm.Screenshots = gj.LoadTeamGameScreenshots(tmId)
return &gm
}
func (gj *Gamejam) LoadTeamGameScreenshots(tmId string) []Screenshot {
var err error
if err = gj.m.openDB(); err != nil {
return nil
}
defer gj.m.closeDB()
var ret []Screenshot
ssBktPath := []string{"jam", "teams", tmId, "game", "screenshots"}
var ssIds []string
ssIds, _ = gj.m.bolt.GetBucketList(ssBktPath)
for _, v := range ssIds {
ssLd := gj.LoadTeamGameScreenshot(tmId, v)
if ssLd != nil {
ret = append(ret, ssLd)
}
}
return ret
}
func (gj *Gamejam) LoadTeamGameScreenshot(tmId, ssId string) *Screenshot {
var err error
if err = gj.m.openDB(); err != nil {
return nil
}
defer gj.m.closeDB()
var ret []Screenshot
ssPath := []string{"jam", "teams", tmId, "game", "screenshots", ssId}
ret := new(Screenshot)
ret.UUID = ssId
if ret.Description, err = gj.m.bolt.GetValue(ssPath, "description"); err != nil {
return nil
}
if ret.Image, err = gj.m.bolt.GetValue(ssPath, "image"); err != nil {
return nil
}
if ret.Thumbnail, err = gj.m.bolt.GetValue(ssPath, "thumbnail"); err != nil {
return nil
}
if ret.Thumbnail == "" {
ret.Thumbnail = ret.Image
}
if ret.Filetype, err = gj.m.bolt.GetValue(ssPath, "filetype"); err != nil {
return nil
}
return ret
}
/**
* OLD FUNCTIONS
*/
// Create a new game object, must have a valid team id // Create a new game object, must have a valid team id
func newGame(tmId string) *Game { func (db *currJamDb) newGame(tmId string) *Game {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
return nil return nil
@ -33,6 +116,15 @@ func newGame(tmId string) *Game {
return &Game{TeamId: tmId} return &Game{TeamId: tmId}
} }
func (db *currJamDb) getAllGames() []Game {
var ret []Game
tms := db.getAllTeams()
for i := range tms {
ret = append(ret, *tms[i].getGame())
}
return ret
}
func (gm *Game) save() error { func (gm *Game) save() error {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
@ -67,12 +159,3 @@ func (gm *Game) save() error {
return err return err
} }
func (db *gjDatabase) getAllGames() []Game {
var ret []Game
tms := db.getAllTeams()
for i := range tms {
ret = append(ret, *tms[i].getGame())
}
return ret
}

View File

@ -1,62 +0,0 @@
package main
const (
SiteModeWaiting = iota
SiteModeVoting
SiteModeError
)
// SiteData is stuff that stays the same
type siteData struct {
Title string
Port int
SessionName string
ServerDir string
DevMode bool
Mode int
CurrentJam string
Teams []Team
Votes []Vote
}
// NewSiteData returns a siteData object with the default values
func NewSiteData() *siteData {
ret := new(siteData)
ret.Title = "ICT GameJam"
ret.Port = 8080
ret.SessionName = "ict-gamejam"
ret.ServerDir = "./"
return ret
}
func (s *siteData) getTeamByUUID(uuid string) *Team {
for i := range s.Teams {
if s.Teams[i].UUID == uuid {
return &s.Teams[i]
}
}
return nil
}
// save 's' to the database
func (s *siteData) save() error {
var err error
if err = db.open(); err != nil {
return err
}
defer db.close()
siteConf := []string{"site"}
if err = db.bolt.SetValue(siteConf, "title", s.Title); err != nil {
return err
}
if err = db.bolt.SetInt(siteConf, "port", s.Port); err != nil {
return err
}
if err = db.bolt.SetValue(siteConf, "session-name", s.SessionName); err != nil {
return err
}
return db.bolt.SetValue(siteConf, "server-dir", s.ServerDir)
}

112
model_sitedata.go Normal file
View File

@ -0,0 +1,112 @@
package main
/**
* SiteData
* Contains configuration for the website
*/
type siteData struct {
title string
port int
sessionName string
serverDir string
authMode int
publicMode int
DevMode bool
Mode int
m *model
changed bool
}
// NewSiteData returns a siteData object with the default values
func NewSiteData(m *model) *siteData {
ret := new(siteData)
ret.Title = "ICT GameJam"
ret.Port = 8080
ret.SessionName = "ict-gamejam"
ret.ServerDir = "./"
ret.m = m
return ret
}
// Mode flags for how the site is currently running
const (
SiteModeWaiting = iota
SiteModeVoting
SiteModeError
)
// load the site data out of the database
// If fields don't exist in the DB, don't clobber what is already in s
func (s *siteData) loadFromDB() error {
if err := s.m.openDB(); err != nil {
return err
}
defer s.m.closeDB()
siteConf := []string{"site"}
if title, err := s.m.bolt.GetValue(siteConf, "title"); err == nil {
s.Title = title
}
if port, err := s.m.bolt.GetInt(siteConf, "port"); err == nil {
s.Port = port
}
if sessionName, err = s.m.bolt.GetValue(siteConf, "session-name"); err == nil {
s.SessionName = sessionName
}
if serverDir, err = s.m.bolt.GetValue(siteConf, "server-dir"); err == nil {
s.ServerDir = serverDir
}
s.changed = false
return nil
}
func (s *siteData) needsSave() bool {
return s.changed
}
func (s *siteData) saveToDB() error {
if err := s.m.openDB(); err != nil {
return err
}
defer s.m.closeDB()
siteConf := []string{"site"}
if err = s.m.bolt.SetValue(siteConf, "title", s.Title); err != nil {
return err
}
if err = s.m.bolt.SetInt(siteConf, "port", s.Port); err != nil {
return err
}
if err = s.m.bolt.SetValue(siteConf, "session-name", s.SessionName); err != nil {
return err
}
if err = s.m.bolt.SetValue(siteConf, "server-dir", s.ServerDir); err != nil {
return err
}
s.changed = false
return nil
}
func (s *siteData) getAuthMode() int {
return s.authMode
}
func (s *siteData) setAuthMode(mode int) {
if mode != s.authMode {
s.authMode = mode
s.changed = true
}
}
func (s *siteData) getPublicMode() int {
return s.publicMode
}
func (s *siteData) setPublicMode(mode int) {
if mode != s.publicMode {
s.publicMode = mode
s.changed = true
}
}

View File

@ -6,6 +6,9 @@ import (
"github.com/pborman/uuid" "github.com/pborman/uuid"
) )
/**
* Team
*/
type Team struct { type Team struct {
UUID string UUID string
Name string Name string
@ -13,8 +16,130 @@ type Team struct {
Game *Game Game *Game
} }
// newTeam creates a team with name nm and stores it in the DB // Create a team
func (db *gjDatabase) newTeam(nm string) error { func NewTeam(nm string) *Team {
return &Team{
UUID: uuid.New(),
Name: nm,
}
}
type TeamMember struct {
UUID string
Name string
SlackId string
Twitter string
Email string
}
// Create a new team member, only a name is required
func NewTeamMember(nm string) *TeamMember {
m := TeamMember{Name: nm}
return &m
}
// LoadAllTeams loads all teams for the jam out of the database
func (gj *Gamejam) LoadAllTeams() []Team {
var err error
var ret []Team
if err = gj.m.openDB(); err != nil {
return err
}
defer gj.m.closeDB()
teamsPath := []string{"jam", "teams"}
if tmUUIDs, err = m.bolt.GetBucketList(mbrsPath); err != nil {
return ret
}
for _, v := range tmUUIDs {
tm := gj.LoadTeam(v)
if tm != nil {
ret = append(ret, tm)
}
}
return ret
}
// Load a team out of the database
func (gj *Gamejam) LoadTeam(uuid string) *Team {
var err error
if err = gj.m.openDB(); err != nil {
return err
}
defer gj.m.closeDB()
// Team Data
tmPath := []string{"jam", "teams", uuid}
tm := new(Team)
tm.UUID = uuid
if tm.Name, err = gj.m.bolt.GetValue(tmPath, "name"); err != nil {
return nil
}
// Team Members
tm.Members = gj.LoadTeamMembers(uuid)
// Team Game
tm.Game = gj.LoadTeamGame(uuid)
}
// Load the members of a team from the DB and return them
func (gj *Gamejam) LoadTeamMembers(tmId string) []TeamMember {
var err error
var ret []TeamMember
if err = gj.m.openDB(); err != nil {
return ret
}
defer gj.m.closeDB()
// Team Members
var memberUuids []string
mbrsPath := []string{"jam", "teams", tmId, "members"}
if memberUuids, err = gj.m.bolt.GetBucketList(mbrsPath); err == nil {
for _, v := range memberUuids {
mbr := gj.LoadTeamMember(tmId, v)
if mbr != nil {
ret = append(ret, mbr)
}
}
}
return ret
}
// Load a team member from the DB and return it
func (gj *Gamejam) LoadTeamMember(tmId, mbrId string) *TeamMember {
var err error
if err = gj.m.openDB(); err != nil {
return nil
}
defer gj.m.closeDB()
mbr := new(TeamMember)
mbr.UUID = v
teamMbrPath := append(mbrsPath, mbr.UUID)
// Name is the only required field
if mbr.Name, err = gj.m.bolt.GetValue(teamMbrPath, "name"); err != nil {
return nil
}
if mbr.SlackId, err = gj.m.bolt.GetValue(teamMbrPath, "slackid"); err != nil {
mbr.SlackId = ""
}
if mbr.Twitter, err = gj.m.bolt.GetValue(teamMbrPath, "twitter"); err != nil {
mbr.Twitter = ""
}
if mbr.Email, err = gj.m.bolt.GetValue(teamMbrPath, "email"); err != nil {
mbr.Email = ""
}
return mbr
}
/**
* OLD FUNCTIONS
*/
// NewTeam creates a team with name nm and stores it in the DB
func NewTeam(nm string) error {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
return err return err
@ -45,7 +170,7 @@ func (db *gjDatabase) newTeam(nm string) error {
} }
// getTeam returns a team with the given id, or nil // getTeam returns a team with the given id, or nil
func (db *gjDatabase) getTeam(id string) *Team { func (db *currJamDb) getTeam(id string) *Team {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
return nil return nil
@ -64,7 +189,7 @@ func (db *gjDatabase) getTeam(id string) *Team {
} }
// This function returns the team for a specific member // This function returns the team for a specific member
func (db *gjDatabase) getTeamForMember(mbrid string) (*Team, error) { func (db *currJamDb) getTeamForMember(mbrid string) (*Team, error) {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
return nil, err return nil, err
@ -87,7 +212,7 @@ func (db *gjDatabase) getTeamForMember(mbrid string) (*Team, error) {
} }
// getAllTeams returns all teams in the database // getAllTeams returns all teams in the database
func (db *gjDatabase) getAllTeams() []Team { func (db *currJamDb) getAllTeams() []Team {
var ret []Team var ret []Team
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
@ -109,7 +234,7 @@ func (db *gjDatabase) getAllTeams() []Team {
} }
// getTeamByName returns a team with the given name or nil // getTeamByName returns a team with the given name or nil
func (db *gjDatabase) getTeamByName(nm string) *Team { func (db *currJamDb) getTeamByName(nm string) *Team {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
return nil return nil
@ -212,45 +337,6 @@ func (tm *Team) saveScreenshot(ss *Screenshot) error {
return nil return nil
} }
func (tm *Team) getScreenshots() []Screenshot {
var ret []Screenshot
var err error
ssPath := []string{"teams", tm.UUID, "game", "screenshots"}
var ssIds []string
if ssIds, err = db.bolt.GetBucketList(ssPath); err != nil {
return ret
}
for _, v := range ssIds {
if ss := tm.getScreenshot(v); ss != nil {
ret = append(ret, *ss)
}
}
return ret
}
func (tm *Team) getScreenshot(ssId string) *Screenshot {
var err error
ssPath := []string{"teams", tm.UUID, "game", "screenshots", ssId}
ret := new(Screenshot)
ret.UUID = ssId
if ret.Description, err = db.bolt.GetValue(ssPath, "description"); err != nil {
return nil
}
if ret.Image, err = db.bolt.GetValue(ssPath, "image"); err != nil {
return nil
}
if ret.Thumbnail, err = db.bolt.GetValue(ssPath, "thumbnail"); err != nil {
return nil
}
if ret.Thumbnail == "" {
ret.Thumbnail = ret.Image
}
if ret.Filetype, err = db.bolt.GetValue(ssPath, "filetype"); err != nil {
return nil
}
return ret
}
func (tm *Team) deleteScreenshot(ssId string) error { func (tm *Team) deleteScreenshot(ssId string) error {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {
@ -262,20 +348,6 @@ func (tm *Team) deleteScreenshot(ssId string) error {
return db.bolt.DeleteBucket(ssPath, ssId) return db.bolt.DeleteBucket(ssPath, ssId)
} }
type TeamMember struct {
UUID string
Name string
SlackId string
Twitter string
Email string
}
// Create a new team member, only a name is required
func newTeamMember(nm string) *TeamMember {
m := TeamMember{Name: nm}
return &m
}
func (tm *Team) getTeamMember(mbrId string) *TeamMember { func (tm *Team) getTeamMember(mbrId string) *TeamMember {
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {

View File

@ -2,46 +2,49 @@ package main
import "golang.org/x/crypto/bcrypt" import "golang.org/x/crypto/bcrypt"
// dbHasUser // These are all model functions that have to do with users
// Returns true if there are any users in the database // Returns true if there are any users in the database
func (db *gjDatabase) hasUser() bool { func (m *model) hasUser() bool {
return len(db.getAllUsers()) > 0 return len(m.getAllUsers()) > 0
} }
func (db *gjDatabase) getAllUsers() []string { func (m *model) getAllUsers() []string {
if err := db.open(); err != nil { if err := m.openDB(); err != nil {
return []string{} return []string{}
} }
defer db.close() defer m.closeDB()
usrs, err := db.bolt.GetBucketList([]string{"users"}) usrs, err := m.bolt.GetBucketList([]string{"users"})
if err != nil { if err != nil {
return []string{} return []string{}
} }
return usrs return usrs
} }
func (db *gjDatabase) isValidUserEmail(email string) bool { // Is the given email one that is in our DB?
if err := db.open(); err != nil { func (m *model) isValidUserEmail(email string) bool {
if err := m.openDB(); err != nil {
return false return false
} }
defer db.close() defer m.closeDB()
usrPath := []string{"users", email} usrPath := []string{"users", email}
_, err := db.bolt.GetValue(usrPath, "password") _, err := m.bolt.GetValue(usrPath, "password")
return err == nil return err == nil
} }
func (db *gjDatabase) checkCredentials(email, pw string) error { // Is the email and pw given valid?
func (m *model) checkCredentials(email, pw string) error {
var err error var err error
if err = db.open(); err != nil { if err = m.openDB(); err != nil {
return err return err
} }
defer db.close() defer m.closeDB()
var uPw string var uPw string
usrPath := []string{"users", email} usrPath := []string{"users", email}
if uPw, err = db.bolt.GetValue(usrPath, "password"); err != nil { if uPw, err = m.bolt.GetValue(usrPath, "password"); err != nil {
return err return err
} }
return bcrypt.CompareHashAndPassword([]byte(uPw), []byte(pw)) return bcrypt.CompareHashAndPassword([]byte(uPw), []byte(pw))
@ -51,26 +54,26 @@ func (db *gjDatabase) checkCredentials(email, pw string) error {
// Takes an email address and a password // Takes an email address and a password
// Creates the user if it doesn't exist, encrypts the password // Creates the user if it doesn't exist, encrypts the password
// and updates it in the db // and updates it in the db
func (db *gjDatabase) updateUserPassword(email, password string) error { func (m *model) updateUserPassword(email, password string) error {
cryptPw, cryptError := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) cryptPw, cryptError := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if cryptError != nil { if cryptError != nil {
return cryptError return cryptError
} }
if err := db.open(); err != nil { if err := m.openDB(); err != nil {
return err return err
} }
defer db.close() defer m.closeDB()
usrPath := []string{"users", email} usrPath := []string{"users", email}
return db.bolt.SetValue(usrPath, "password", string(cryptPw)) return m.bolt.SetValue(usrPath, "password", string(cryptPw))
} }
func (db *gjDatabase) deleteUser(email string) error { func (m *model) deleteUser(email string) error {
var err error var err error
if err = db.open(); err != nil { if err = m.openDB(); err != nil {
return err return err
} }
defer db.close() defer m.closeDB()
return db.bolt.DeleteBucket([]string{"users"}, email) return m.bolt.DeleteBucket([]string{"users"}, email)
} }

View File

@ -1,6 +1,9 @@
package main package main
import "time" import (
"strconv"
"time"
)
// A Choice is a ranking of a game in a vote // A Choice is a ranking of a game in a vote
type GameChoice struct { type GameChoice struct {
@ -15,7 +18,64 @@ type Vote struct {
Choices []GameChoice Choices []GameChoice
} }
func (db *gjDatabase) getAllVotes() []Vote { // LoadAllVotes loads all votes for the jam out of the database
func (gj *Gamejam) LoadAllVotes() []Vote {
var ret []Vote
if err := gj.m.openDB(); err != nil {
return err
}
defer gj.m.closeDB()
votesPath := []string{"jam", "votes"}
if cliUUIDs, err = m.bolt.GetBucketList(votesPath); err != nil {
return ret
}
for _, cId := range cliUUIDs {
vtsPth := append(votesPath, cId)
if times, err := m.bolt.GetBucketList(vtsPth); err != nil {
// Error reading this bucket, move on to the next
continue
}
for _, t := range times {
vt := gj.LoadVote(cId, t)
if vt != nil {
ret = append(ret, vt)
}
}
}
return ret
}
// Load a vote from the DB and return it
func (gj *Gamejam) LoadVote(clientId, tm string) *Vote {
var tm time.Time
if tm, err = time.Parse(time.RFC3339, t); err != nil {
return nil
}
vt := new(Vote)
vt.Timestamp = tm
vt.ClientId = cId
vtPth := append(vtsPth, t)
var choices []string
if choices, err = m.bolt.GetKeyList(vtPth); err != nil {
return nil
}
for _, v := range choices {
ch := new(GameChoices)
var rank int
if rank, err = strconv.Atoi(v); err == nil {
ch.Rank = rank
ch.Team, _ = m.bolt.GetValue(vtPth, v)
vt.Choices = append(vt.Choices, *ch)
}
}
return &vt
}
/**
* OLD FUNCTIONS
*/
func (db *currJamDb) getAllVotes() []Vote {
var ret []Vote var ret []Vote
var err error var err error
if err = db.open(); err != nil { if err = db.open(); err != nil {

View File

@ -28,7 +28,7 @@ func handleMain(w http.ResponseWriter, req *http.Request) {
func loadVotingPage(w http.ResponseWriter, req *http.Request) { func loadVotingPage(w http.ResponseWriter, req *http.Request) {
page := initPublicPage(w, req) page := initPublicPage(w, req)
// Client authentication required // Client authentication required
if (db.getAuthMode() == AuthModeAuthentication) && !page.ClientIsAuth { if (db.site.getAuthMode() == AuthModeAuthentication) && !page.ClientIsAuth {
page.show("unauthorized.html", w) page.show("unauthorized.html", w)
return return
} }
@ -55,7 +55,7 @@ func loadVotingPage(w http.ResponseWriter, req *http.Request) {
func handlePublicSaveVote(w http.ResponseWriter, req *http.Request) { func handlePublicSaveVote(w http.ResponseWriter, req *http.Request) {
page := initPublicPage(w, req) page := initPublicPage(w, req)
// Client authentication required // Client authentication required
if (db.getAuthMode() == AuthModeAuthentication) && !page.ClientIsAuth { if (db.site.getAuthMode() == AuthModeAuthentication) && !page.ClientIsAuth {
page.show("unauthorized.html", w) page.show("unauthorized.html", w)
return return
} }