Merge branch 'split-dbs'
This commit is contained in:
commit
4957f9eccc
14
.gitignore
vendored
14
.gitignore
vendored
@ -1,11 +1,11 @@
|
|||||||
# Ignore the binaries
|
# Ignore the binaries
|
||||||
gjvote
|
ictgj-voting
|
||||||
gjvote.darwin64
|
ictgj-voting.darwin64
|
||||||
gjvote.linux386
|
ictgj-voting.linux386
|
||||||
gjvote.linux64
|
ictgj-voting.linux64
|
||||||
gjvote.linuxarm
|
ictgj-voting.linuxarm
|
||||||
gjvote.win386.exe
|
ictgj-voting.win386.exe
|
||||||
gjvote.win64.exe
|
ictgj-voting.win64.exe
|
||||||
|
|
||||||
# Ignore the DBs
|
# Ignore the DBs
|
||||||
*.db
|
*.db
|
||||||
|
@ -15,6 +15,6 @@ func handleAdminArchive(w http.ResponseWriter, req *http.Request, page *pageData
|
|||||||
type archivePageData struct {
|
type archivePageData struct {
|
||||||
Gamejams []Gamejam
|
Gamejams []Gamejam
|
||||||
}
|
}
|
||||||
apd := new(archivePageData)
|
//apd := new(archivePageData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,29 +11,31 @@ func handleAdminClients(w http.ResponseWriter, req *http.Request, page *pageData
|
|||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
page.SubTitle = "Clients"
|
page.SubTitle = "Clients"
|
||||||
clientId := vars["id"]
|
clientId := vars["id"]
|
||||||
client := db.getClient(clientId)
|
client, err := m.GetClient(clientId)
|
||||||
|
if err != nil {
|
||||||
|
client = NewClient(clientId)
|
||||||
|
}
|
||||||
clientIp, _, _ := net.SplitHostPort(req.RemoteAddr)
|
clientIp, _, _ := net.SplitHostPort(req.RemoteAddr)
|
||||||
if clientId == "" {
|
if clientId == "" {
|
||||||
type clientsPageData struct {
|
type clientsPageData struct {
|
||||||
Clients []Client
|
Clients []Client
|
||||||
}
|
}
|
||||||
page.TemplateData = clientsPageData{Clients: db.getAllClients()}
|
page.TemplateData = clientsPageData{Clients: m.clients}
|
||||||
page.SubTitle = "Clients"
|
page.SubTitle = "Clients"
|
||||||
page.show("admin-clients.html", w)
|
page.show("admin-clients.html", w)
|
||||||
} else {
|
} else {
|
||||||
switch vars["function"] {
|
switch vars["function"] {
|
||||||
case "add":
|
case "add":
|
||||||
page.SubTitle = "Authenticate Client"
|
page.SubTitle = "Authenticate Client"
|
||||||
cli := db.getClient(clientId)
|
if client.IP == "" {
|
||||||
if cli.IP == "" {
|
client.IP = clientIp
|
||||||
cli.IP = clientIp
|
|
||||||
}
|
}
|
||||||
type actClientPageData struct {
|
type actClientPageData struct {
|
||||||
Id string
|
Id string
|
||||||
Ip string
|
Ip string
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
page.TemplateData = actClientPageData{Id: cli.UUID, Ip: cli.IP, Name: cli.Name}
|
page.TemplateData = actClientPageData{Id: client.UUID, Ip: client.IP, Name: client.Name}
|
||||||
page.show("admin-activateclient.html", w)
|
page.show("admin-activateclient.html", w)
|
||||||
case "auth":
|
case "auth":
|
||||||
email := req.FormValue("email")
|
email := req.FormValue("email")
|
||||||
@ -44,16 +46,13 @@ func handleAdminClients(w http.ResponseWriter, req *http.Request, page *pageData
|
|||||||
client.Name = clientName
|
client.Name = clientName
|
||||||
}
|
}
|
||||||
client.IP = clientIp
|
client.IP = clientIp
|
||||||
client.save()
|
m.UpdateClient(client)
|
||||||
if page.LoggedIn || doLogin(email, password) == nil {
|
if page.LoggedIn || doLogin(email, password) == nil {
|
||||||
// Received a valid login
|
// Received a valid login
|
||||||
// Authenticate the client
|
// Authenticate the client
|
||||||
client.Auth = true
|
client.Auth = true
|
||||||
if client.save() == nil {
|
m.UpdateClient(client)
|
||||||
page.session.setFlashMessage("Client Authenticated", "success")
|
page.session.setFlashMessage("Client Authenticated", "success")
|
||||||
} else {
|
|
||||||
page.session.setFlashMessage("Client Authentication Failed", "error")
|
|
||||||
}
|
|
||||||
if page.LoggedIn {
|
if page.LoggedIn {
|
||||||
redirect("/admin/clients", w, req)
|
redirect("/admin/clients", w, req)
|
||||||
}
|
}
|
||||||
@ -61,11 +60,8 @@ func handleAdminClients(w http.ResponseWriter, req *http.Request, page *pageData
|
|||||||
redirect("/", w, req)
|
redirect("/", w, req)
|
||||||
case "deauth":
|
case "deauth":
|
||||||
client.Auth = false
|
client.Auth = false
|
||||||
if client.save() == nil {
|
m.UpdateClient(client)
|
||||||
page.session.setFlashMessage("Client De-Authenticated", "success")
|
page.session.setFlashMessage("Client De-Authenticated", "success")
|
||||||
} else {
|
|
||||||
page.session.setFlashMessage("Client De-Authentication Failed", "success")
|
|
||||||
}
|
|
||||||
redirect("/admin/clients", w, req)
|
redirect("/admin/clients", w, req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,8 @@ 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 err = m.site.SetPublicMode(newMode); err != nil {
|
||||||
page.session.setFlashMessage("Invalid Mode: "+vars["id"], "error")
|
page.session.setFlashMessage(err.Error(), "error")
|
||||||
}
|
}
|
||||||
redirect("/admin", w, req)
|
redirect("/admin", w, req)
|
||||||
}
|
}
|
||||||
@ -74,8 +74,8 @@ 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 err = m.site.SetAuthMode(newMode); err != nil {
|
||||||
page.session.setFlashMessage("Invalid Authentication Mode: "+vars["id"], "error")
|
page.session.setFlashMessage(err.Error(), "error")
|
||||||
}
|
}
|
||||||
redirect("/admin", w, req)
|
redirect("/admin", w, req)
|
||||||
}
|
}
|
||||||
|
@ -20,40 +20,72 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
teamId := vars["id"]
|
teamId := vars["id"]
|
||||||
if teamId == "" {
|
if teamId == "" {
|
||||||
// Games List
|
// Games List
|
||||||
type gamesPageData struct {
|
page.TemplateData = m.jam
|
||||||
Teams []Team
|
|
||||||
}
|
|
||||||
gpd := new(gamesPageData)
|
|
||||||
gpd.Teams = db.getAllTeams()
|
|
||||||
page.TemplateData = gpd
|
|
||||||
page.SubTitle = "Games"
|
page.SubTitle = "Games"
|
||||||
page.show("admin-games.html", w)
|
page.show("admin-games.html", w)
|
||||||
} else {
|
} else {
|
||||||
tm := db.getTeam(teamId)
|
tm, _ := m.jam.GetTeamById(teamId)
|
||||||
if tm != nil {
|
if tm != nil {
|
||||||
switch vars["function"] {
|
switch vars["function"] {
|
||||||
case "save":
|
case "save":
|
||||||
gm := newGame(tm.UUID)
|
var err error
|
||||||
|
var gm *Game
|
||||||
|
if gm, err = NewGame(tm.UUID); err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
}
|
||||||
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")
|
||||||
if err := gm.save(); err != nil {
|
if err := m.jam.UpdateGame(tm.UUID, gm); err != nil {
|
||||||
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("Team game updated", "success")
|
page.session.setFlashMessage("Team game updated", "success")
|
||||||
}
|
}
|
||||||
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
||||||
|
|
||||||
case "screenshotupload":
|
case "screenshotupload":
|
||||||
if err := saveScreenshots(tm, req); err != nil {
|
var ss *Screenshot
|
||||||
|
tm, err := m.jam.GetTeamById(tm.UUID)
|
||||||
|
if err != nil {
|
||||||
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
||||||
|
}
|
||||||
|
ss, err = ssFromRequest(tm, req)
|
||||||
|
if err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
||||||
|
}
|
||||||
|
gm := tm.Game
|
||||||
|
gm.Screenshots = append(gm.Screenshots, *ss)
|
||||||
|
if err = m.jam.UpdateGame(tm.UUID, gm); err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
} else {
|
||||||
|
page.session.setFlashMessage("Screenshot Uploaded", "success")
|
||||||
}
|
}
|
||||||
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
||||||
|
|
||||||
case "screenshotdelete":
|
case "screenshotdelete":
|
||||||
|
var err error
|
||||||
ssid := vars["subid"]
|
ssid := vars["subid"]
|
||||||
if err := tm.deleteScreenshot(ssid); err != nil {
|
tm, err := m.jam.GetTeamById(tm.UUID)
|
||||||
page.session.setFlashMessage("Error deleting screenshot: "+err.Error(), "error")
|
if err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
gm := tm.Game
|
||||||
|
if err = gm.RemoveScreenshot(ssid); err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err = m.jam.UpdateGame(tm.UUID, gm); err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
} else {
|
||||||
|
page.session.setFlashMessage("Screenshot Removed", "success")
|
||||||
}
|
}
|
||||||
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
redirect("/admin/teams/"+tm.UUID+"#game", w, req)
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("Not a valid team id", "error")
|
page.session.setFlashMessage("Not a valid team id", "error")
|
||||||
@ -62,40 +94,47 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveScreenshots(tm *Team, req *http.Request) error {
|
func ssFromRequest(tm *Team, req *http.Request) (*Screenshot, error) {
|
||||||
var err error
|
var err error
|
||||||
|
var ss *Screenshot
|
||||||
|
|
||||||
file, hdr, err := req.FormFile("newssfile")
|
file, hdr, err := req.FormFile("newssfile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
extIdx := strings.LastIndex(hdr.Filename, ".")
|
extIdx := strings.LastIndex(hdr.Filename, ".")
|
||||||
fltp := "png"
|
fltp := "png"
|
||||||
if len(hdr.Filename) > extIdx {
|
if len(hdr.Filename) > extIdx {
|
||||||
fltp = hdr.Filename[extIdx+1:]
|
fltp = hdr.Filename[extIdx+1:]
|
||||||
}
|
}
|
||||||
m, _, err := image.Decode(file)
|
mI, _, err := image.Decode(file)
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
// We convert everything to jpg
|
// We convert everything to jpg
|
||||||
if err = jpeg.Encode(buf, m, nil); err != nil {
|
if err = jpeg.Encode(buf, mI, nil); err != nil {
|
||||||
return errors.New("Unable to encode image")
|
return nil, errors.New("Unable to encode image")
|
||||||
}
|
}
|
||||||
thm := resize.Resize(200, 0, m, resize.Lanczos3)
|
thm := resize.Resize(200, 0, mI, resize.Lanczos3)
|
||||||
thmBuf := new(bytes.Buffer)
|
thmBuf := new(bytes.Buffer)
|
||||||
var thmString string
|
var thmString string
|
||||||
if fltp == "gif" {
|
if fltp == "gif" {
|
||||||
if err = gif.Encode(thmBuf, thm, nil); err != nil {
|
if err = gif.Encode(thmBuf, thm, nil); err != nil {
|
||||||
return errors.New("Unable to encode image")
|
return nil, errors.New("Unable to encode image")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = jpeg.Encode(thmBuf, thm, nil); err != nil {
|
if err = jpeg.Encode(thmBuf, thm, nil); err != nil {
|
||||||
return errors.New("Unable to encode image")
|
return nil, errors.New("Unable to encode image")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thmString = base64.StdEncoding.EncodeToString(thmBuf.Bytes())
|
thmString = base64.StdEncoding.EncodeToString(thmBuf.Bytes())
|
||||||
|
|
||||||
return tm.saveScreenshot(&Screenshot{
|
if ss, err = NewScreenshot(tm.UUID, ""); err != nil {
|
||||||
Image: base64.StdEncoding.EncodeToString(buf.Bytes()),
|
return nil, err
|
||||||
Thumbnail: thmString,
|
}
|
||||||
Filetype: fltp,
|
|
||||||
})
|
ss.Image = base64.StdEncoding.EncodeToString(buf.Bytes())
|
||||||
|
ss.Thumbnail = thmString
|
||||||
|
ss.Filetype = fltp
|
||||||
|
|
||||||
|
return ss, nil
|
||||||
|
//return m.jam.SaveScreenshot(ss)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
_ "image/gif"
|
_ "image/gif"
|
||||||
@ -10,10 +11,6 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
func refreshTeamsInMemory() {
|
|
||||||
site.Teams = db.getAllTeams()
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData) {
|
func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData) {
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
page.SubTitle = "Teams"
|
page.SubTitle = "Teams"
|
||||||
@ -23,17 +20,11 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
switch vars["function"] {
|
switch vars["function"] {
|
||||||
case "save":
|
case "save":
|
||||||
name := req.FormValue("teamname")
|
name := req.FormValue("teamname")
|
||||||
if db.getTeamByName(name) != nil {
|
tm := NewTeam("")
|
||||||
// A team with that name already exists
|
tm.Name = name
|
||||||
page.session.setFlashMessage("A team with the name "+name+" already exists!", "error")
|
if err := m.jam.AddTeam(tm); err != nil {
|
||||||
} else {
|
page.session.setFlashMessage("Error adding team: "+err.Error(), "error")
|
||||||
if err := db.newTeam(name); err != nil {
|
|
||||||
page.session.setFlashMessage(err.Error(), "error")
|
|
||||||
} else {
|
|
||||||
page.session.setFlashMessage("Team "+name+" created!", "success")
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
refreshTeamsInMemory()
|
|
||||||
redirect("/admin/teams", w, req)
|
redirect("/admin/teams", w, req)
|
||||||
default:
|
default:
|
||||||
page.SubTitle = "Add New Team"
|
page.SubTitle = "Add New Team"
|
||||||
@ -41,57 +32,58 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
}
|
}
|
||||||
} else if teamId != "" {
|
} else if teamId != "" {
|
||||||
// Functions for existing team
|
// Functions for existing team
|
||||||
tm := db.getTeam(teamId)
|
tm, _ := m.jam.GetTeamById(teamId)
|
||||||
if tm != nil {
|
if tm != nil {
|
||||||
switch vars["function"] {
|
switch vars["function"] {
|
||||||
case "save":
|
case "save":
|
||||||
tm.UUID = teamId
|
|
||||||
tm.Name = req.FormValue("teamname")
|
tm.Name = req.FormValue("teamname")
|
||||||
if err := tm.save(); err != nil {
|
|
||||||
page.session.setFlashMessage("Error updating team: "+err.Error(), "error")
|
|
||||||
} else {
|
|
||||||
page.session.setFlashMessage("Team Updated!", "success")
|
page.session.setFlashMessage("Team Updated!", "success")
|
||||||
}
|
|
||||||
refreshTeamsInMemory()
|
|
||||||
redirect("/admin/teams", w, req)
|
redirect("/admin/teams", w, req)
|
||||||
case "delete":
|
case "delete":
|
||||||
var err error
|
var err error
|
||||||
if err = tm.delete(); err != nil {
|
if err = m.jam.RemoveTeamById(teamId); err != nil {
|
||||||
page.session.setFlashMessage("Error deleting team: "+err.Error(), "error")
|
page.session.setFlashMessage("Error removing team: "+err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("Team "+tm.Name+" Deleted", "success")
|
page.session.setFlashMessage("Team "+tm.Name+" Removed", "success")
|
||||||
}
|
}
|
||||||
refreshTeamsInMemory()
|
|
||||||
redirect("/admin/teams", w, req)
|
redirect("/admin/teams", w, req)
|
||||||
case "savemember":
|
case "savemember":
|
||||||
mbrName := req.FormValue("newmembername")
|
mbrName := req.FormValue("newmembername")
|
||||||
mbr := newTeamMember(mbrName)
|
mbr, err := NewTeamMember(tm.UUID, "")
|
||||||
|
if err == nil {
|
||||||
|
mbr.Name = mbrName
|
||||||
mbr.SlackId = req.FormValue("newmemberslackid")
|
mbr.SlackId = req.FormValue("newmemberslackid")
|
||||||
mbr.Twitter = req.FormValue("newmembertwitter")
|
mbr.Twitter = req.FormValue("newmembertwitter")
|
||||||
mbr.Email = req.FormValue("newmemberemail")
|
mbr.Email = req.FormValue("newmemberemail")
|
||||||
if err := tm.updateTeamMember(mbr); err != nil {
|
}
|
||||||
|
if err := tm.AddTeamMember(mbr); err != nil {
|
||||||
page.session.setFlashMessage("Error adding team member: "+err.Error(), "error")
|
page.session.setFlashMessage("Error adding team member: "+err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage(mbrName+" added to team!", "success")
|
page.session.setFlashMessage(mbrName+" added to team!", "success")
|
||||||
}
|
}
|
||||||
refreshTeamsInMemory()
|
|
||||||
redirect("/admin/teams/"+teamId+"#members", w, req)
|
redirect("/admin/teams/"+teamId+"#members", w, req)
|
||||||
case "deletemember":
|
case "deletemember":
|
||||||
m := tm.getTeamMember(req.FormValue("memberid"))
|
var err error
|
||||||
if m != nil {
|
var mbr *TeamMember
|
||||||
if err := tm.deleteTeamMember(m); err != nil {
|
if mbr, err = tm.GetTeamMemberById(req.FormValue("memberid")); err != nil {
|
||||||
page.session.setFlashMessage("Error deleting team member: "+err.Error(), "error")
|
fmt.Println("Error removing team member: " + err.Error())
|
||||||
} else {
|
page.session.setFlashMessage("Error deleting team member", "error")
|
||||||
page.session.setFlashMessage(m.Name+" deleted from team", "success")
|
redirect("/admin/teams/"+teamId+"#members", w, req)
|
||||||
}
|
}
|
||||||
refreshTeamsInMemory()
|
if err = tm.RemoveTeamMemberById(mbr.UUID); err != nil {
|
||||||
|
fmt.Println("Error removing team member: " + err.Error())
|
||||||
|
page.session.setFlashMessage("Error deleting team member", "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("Couldn't find team member to delete", "error")
|
page.session.setFlashMessage(mbr.Name+" deleted from team", "success")
|
||||||
}
|
}
|
||||||
redirect("/admin/teams/"+teamId+"#members", w, req)
|
redirect("/admin/teams/"+teamId+"#members", w, req)
|
||||||
default:
|
default:
|
||||||
page.SubTitle = "Edit Team"
|
page.SubTitle = "Edit Team"
|
||||||
t := db.getTeam(teamId)
|
t, err := m.jam.GetTeamById(teamId)
|
||||||
|
if err != nil {
|
||||||
|
page.session.setFlashMessage("Error loading team: "+err.Error(), "error")
|
||||||
|
redirect("/admin/teams", w, req)
|
||||||
|
}
|
||||||
page.TemplateData = t
|
page.TemplateData = t
|
||||||
page.show("admin-editteam.html", w)
|
page.show("admin-editteam.html", w)
|
||||||
}
|
}
|
||||||
@ -104,7 +96,7 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
type teamsPageData struct {
|
type teamsPageData struct {
|
||||||
Teams []Team
|
Teams []Team
|
||||||
}
|
}
|
||||||
page.TemplateData = teamsPageData{Teams: db.getAllTeams()}
|
page.TemplateData = m.jam
|
||||||
page.SubTitle = "Teams"
|
page.SubTitle = "Teams"
|
||||||
page.show("admin-teams.html", w)
|
page.show("admin-teams.html", w)
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ func handleAdminDoLogin(w http.ResponseWriter, req *http.Request) {
|
|||||||
// If it can't, it returns an error
|
// If it can't, it returns an error
|
||||||
func doLogin(email, password string) error {
|
func doLogin(email, password string) error {
|
||||||
if strings.TrimSpace(email) != "" && strings.TrimSpace(password) != "" {
|
if strings.TrimSpace(email) != "" && strings.TrimSpace(password) != "" {
|
||||||
return db.checkCredentials(email, password)
|
return m.checkCredentials(email, password)
|
||||||
}
|
}
|
||||||
return errors.New("Invalid Credentials")
|
return errors.New("Invalid Credentials")
|
||||||
}
|
}
|
||||||
@ -53,12 +53,12 @@ func handleAdminUsers(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
switch vars["function"] {
|
switch vars["function"] {
|
||||||
case "save":
|
case "save":
|
||||||
email = req.FormValue("email")
|
email = req.FormValue("email")
|
||||||
if db.isValidUserEmail(email) {
|
if m.isValidUserEmail(email) {
|
||||||
// User already exists
|
// User already exists
|
||||||
page.session.setFlashMessage("A user with email address "+email+" already exists!", "error")
|
page.session.setFlashMessage("A user with email address "+email+" already exists!", "error")
|
||||||
} else {
|
} else {
|
||||||
password := req.FormValue("password")
|
password := req.FormValue("password")
|
||||||
if err := db.updateUserPassword(email, string(password)); err != nil {
|
if err := m.updateUserPassword(email, string(password)); err != nil {
|
||||||
page.session.setFlashMessage(err.Error(), "error")
|
page.session.setFlashMessage(err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("User "+email+" created!", "success")
|
page.session.setFlashMessage("User "+email+" created!", "success")
|
||||||
@ -73,10 +73,10 @@ func handleAdminUsers(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
switch vars["function"] {
|
switch vars["function"] {
|
||||||
case "save":
|
case "save":
|
||||||
var err error
|
var err error
|
||||||
if db.isValidUserEmail(email) {
|
if m.isValidUserEmail(email) {
|
||||||
password := req.FormValue("password")
|
password := req.FormValue("password")
|
||||||
if password != "" {
|
if password != "" {
|
||||||
if err = db.updateUserPassword(email, password); err != nil {
|
if err = m.updateUserPassword(email, password); err != nil {
|
||||||
page.session.setFlashMessage(err.Error(), "error")
|
page.session.setFlashMessage(err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("User "+email+" created!", "success")
|
page.session.setFlashMessage("User "+email+" created!", "success")
|
||||||
@ -86,8 +86,8 @@ func handleAdminUsers(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
}
|
}
|
||||||
case "delete":
|
case "delete":
|
||||||
var err error
|
var err error
|
||||||
if db.isValidUserEmail(email) {
|
if m.isValidUserEmail(email) {
|
||||||
if err = db.deleteUser(email); err != nil {
|
if err = m.deleteUser(email); err != nil {
|
||||||
page.session.setFlashMessage(err.Error(), "error")
|
page.session.setFlashMessage(err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("User "+email+" deleted!", "success")
|
page.session.setFlashMessage("User "+email+" deleted!", "success")
|
||||||
@ -96,7 +96,7 @@ func handleAdminUsers(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
redirect("/admin/users", w, req)
|
redirect("/admin/users", w, req)
|
||||||
default:
|
default:
|
||||||
page.SubTitle = "Edit Admin User"
|
page.SubTitle = "Edit Admin User"
|
||||||
if !db.isValidUserEmail(email) {
|
if !m.isValidUserEmail(email) {
|
||||||
page.session.setFlashMessage("Couldn't find the requested user, please try again.", "error")
|
page.session.setFlashMessage("Couldn't find the requested user, please try again.", "error")
|
||||||
redirect("/admin/users", w, req)
|
redirect("/admin/users", w, req)
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ func handleAdminUsers(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
type usersPageData struct {
|
type usersPageData struct {
|
||||||
Users []string
|
Users []string
|
||||||
}
|
}
|
||||||
page.TemplateData = usersPageData{Users: db.getAllUsers()}
|
page.TemplateData = usersPageData{Users: m.getAllUsers()}
|
||||||
|
|
||||||
page.SubTitle = "Admin Users"
|
page.SubTitle = "Admin Users"
|
||||||
page.show("admin-users.html", w)
|
page.show("admin-users.html", w)
|
||||||
|
@ -23,22 +23,22 @@ func getCondorcetResult() []Ranking {
|
|||||||
}
|
}
|
||||||
var allPairs []teamPair
|
var allPairs []teamPair
|
||||||
var ret []Ranking
|
var ret []Ranking
|
||||||
for i := 0; i < len(site.Teams); i++ {
|
for i := 0; i < len(m.jam.Teams); i++ {
|
||||||
for j := i + 1; j < len(site.Teams); j++ {
|
for j := i + 1; j < len(m.jam.Teams); j++ {
|
||||||
// For each pairing find a winner
|
// For each pairing find a winner
|
||||||
winner, pct, _ := findWinnerBetweenTeams(&site.Teams[i], &site.Teams[j])
|
winner, pct, _ := findWinnerBetweenTeams(&m.jam.Teams[i], &m.jam.Teams[j])
|
||||||
newPair := new(teamPair)
|
newPair := new(teamPair)
|
||||||
if winner != nil {
|
if winner != nil {
|
||||||
newPair.winner = winner
|
newPair.winner = winner
|
||||||
if winner.UUID == site.Teams[i].UUID {
|
if winner.UUID == m.jam.Teams[i].UUID {
|
||||||
newPair.loser = &site.Teams[j]
|
newPair.loser = &m.jam.Teams[j]
|
||||||
} else {
|
} else {
|
||||||
newPair.loser = &site.Teams[i]
|
newPair.loser = &m.jam.Teams[i]
|
||||||
}
|
}
|
||||||
newPair.majority = pct
|
newPair.majority = pct
|
||||||
} else {
|
} else {
|
||||||
newPair.winner = &site.Teams[i]
|
newPair.winner = &m.jam.Teams[i]
|
||||||
newPair.loser = &site.Teams[j]
|
newPair.loser = &m.jam.Teams[j]
|
||||||
newPair.majority = 50
|
newPair.majority = 50
|
||||||
}
|
}
|
||||||
allPairs = append(allPairs, *newPair)
|
allPairs = append(allPairs, *newPair)
|
||||||
@ -46,8 +46,8 @@ func getCondorcetResult() []Ranking {
|
|||||||
}
|
}
|
||||||
// initialize map of team wins
|
// initialize map of team wins
|
||||||
teamWins := make(map[string]int)
|
teamWins := make(map[string]int)
|
||||||
for i := range site.Teams {
|
for i := range m.jam.Teams {
|
||||||
teamWins[site.Teams[i].UUID] = 0
|
teamWins[m.jam.Teams[i].UUID] = 0
|
||||||
}
|
}
|
||||||
// Figure out how many wins each team has
|
// Figure out how many wins each team has
|
||||||
for i := range allPairs {
|
for i := range allPairs {
|
||||||
@ -72,7 +72,10 @@ func getCondorcetResult() []Ranking {
|
|||||||
nR := new(Ranking)
|
nR := new(Ranking)
|
||||||
nR.Rank = currRank
|
nR.Rank = currRank
|
||||||
for i := range rankedWins[topWins] {
|
for i := range rankedWins[topWins] {
|
||||||
nR.Teams = append(nR.Teams, *site.getTeamByUUID(rankedWins[topWins][i]))
|
tm, _ := m.jam.GetTeamById(rankedWins[topWins][i])
|
||||||
|
if tm != nil {
|
||||||
|
nR.Teams = append(nR.Teams, *tm)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ret = append(ret, *nR)
|
ret = append(ret, *nR)
|
||||||
delete(rankedWins, topWins)
|
delete(rankedWins, topWins)
|
||||||
@ -99,7 +102,7 @@ func uuidIsInRankingSlice(uuid string, sl []Ranking) bool {
|
|||||||
func findWinnerBetweenTeams(tm1, tm2 *Team) (*Team, float32, error) {
|
func findWinnerBetweenTeams(tm1, tm2 *Team) (*Team, float32, error) {
|
||||||
// tally gets incremented for a tm1 win, decremented for a tm2 win
|
// tally gets incremented for a tm1 win, decremented for a tm2 win
|
||||||
var tm1votes, tm2votes float32
|
var tm1votes, tm2votes float32
|
||||||
for _, v := range site.Votes {
|
for _, v := range m.jam.Votes {
|
||||||
for _, chc := range v.Choices {
|
for _, chc := range v.Choices {
|
||||||
if chc.Team == tm1.UUID {
|
if chc.Team == tm1.UUID {
|
||||||
tm1votes++
|
tm1votes++
|
||||||
@ -138,12 +141,12 @@ func handleAdminVotes(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
Results []Ranking
|
Results []Ranking
|
||||||
}
|
}
|
||||||
vpd := new(votePageData)
|
vpd := new(votePageData)
|
||||||
for i := range site.Votes {
|
for i := range m.jam.Votes {
|
||||||
v := new(vpdVote)
|
v := new(vpdVote)
|
||||||
v.Timestamp = site.Votes[i].Timestamp.Format(time.RFC3339)
|
v.Timestamp = m.jam.Votes[i].Timestamp.Format(time.RFC3339)
|
||||||
v.ClientId = site.Votes[i].ClientId
|
v.ClientId = m.jam.Votes[i].ClientId
|
||||||
for _, choice := range site.Votes[i].Choices {
|
for _, choice := range m.jam.Votes[i].Choices {
|
||||||
for _, fndTm := range site.Teams {
|
for _, fndTm := range m.jam.Teams {
|
||||||
if fndTm.UUID == choice.Team {
|
if fndTm.UUID == choice.Team {
|
||||||
v.Choices = append(v.Choices, fndTm)
|
v.Choices = append(v.Choices, fndTm)
|
||||||
break
|
break
|
||||||
|
18
assets.go
18
assets.go
@ -12113,16 +12113,16 @@ XzHfrrS2uzLN6JsOkTvo3Iny7fxf2KYCxs3I30osvf4OAAD//yR+jxHtAwAA
|
|||||||
|
|
||||||
"/templates/admin-votes.html": {
|
"/templates/admin-votes.html": {
|
||||||
local: "templates/admin-votes.html",
|
local: "templates/admin-votes.html",
|
||||||
size: 837,
|
size: 848,
|
||||||
modtime: 1506689947,
|
modtime: 1508506407,
|
||||||
compressed: `
|
compressed: `
|
||||||
H4sIAAAJbogA/3xSTW/cIBC9768YWXusbam9RRip2lxy6SFd9Y7NJIuKwYJZS1WU/94Bm5Av5cTM4w3z
|
H4sIAAAJbogA/3xSPW/cMAzd/SsI48b6DLRbIAsoLkuWDsGhu2wxOaGyZEg8A0WQ/15KtqPcRzOJfHoU
|
||||||
5g1CmxUmq2IcmoDxaim2k3ekjMPQyIO4fJenawjoCO63e9Ezdnh6gqDcI8LRfIPjCjcDdGecF6sIbxWp
|
Hx8ltJlhsCrGrg4Yz5ZiM3hHyjgMtazE6bs8nENAR/C83IuWsertDYJyrwg78w12Mzx0sD/iOFlF+KhI
|
||||||
bmfD8/MBoLIp0SnzjytXqHmnZBJD98r9ZeQmp7R2v9SMnIsxQC+3p9DpVFMj0fMYLJbUaBGMHprVE8Y2
|
7Vc2vL9XAIVNiU6Zv5u5Qo0rJZMYelbuDyMPOaV5/0uNyLnoA7RyeQqdTjUlEi2PwWJJ9RbB6K6ePWFs
|
||||||
502ZL/qwEZZrwPZ92I4+aAyoYeJh8/AAgi6otMzyBIUtyLA8mxkjqXkRPWevLk7WJLfubt9fpMmMe4wV
|
cl5v80UfFsJ0Dthch03vg8aAGgYeNg8PIOiESsssT1BYggzLoxkxkhon0XL26eJgTXLr6fH6Ik1m3Gss
|
||||||
5yi/mZC9j6DR63+yGPK1xz+t/ZMGLQ6+kajlZuiL0ORiT/ojY1N8pz8h7CEn3takCpuSsqms83TxZqpy
|
OEf5zYSsfQT1Xv+VmyFfe/zT2t9p0M3BC4laLoZ+CE0utqRvGYviJ32HsIaceFuSImxIyoZtnYeTN0OR
|
||||||
9kprcp+p7rJn6PVj+xpfKvrarAoqZr2tYLQYJujBe/pkWbr8AIsPxN/B27goNzQ/miTMooPutyHsipdw
|
s1Zak/sMZZctQ58fW9f4UdGWZkXQZtZlBaObYYJevKc7y9LbD7D4QvwdvI2Tcl39o07CLLr/2wpHT8pC
|
||||||
9qQs5PRjfz63PhykjyMP/wMAAP//x7l0qEUDAAA=
|
Tm+l8Lm05CD9IVn9CwAA//8Mc47HUAMAAA==
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
132
main.go
132
main.go
@ -9,8 +9,11 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
|
||||||
@ -58,25 +61,37 @@ type menuItem struct {
|
|||||||
var sessionSecret = "JCOP5e8ohkTcOzcSMe74"
|
var sessionSecret = "JCOP5e8ohkTcOzcSMe74"
|
||||||
|
|
||||||
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
|
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
|
||||||
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()
|
if err = m.site.SaveToDB(); err != nil {
|
||||||
|
errorExit("Unable to save site config to DB: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save changes to the DB every 5 minutes
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
m.saveChanges()
|
||||||
|
time.Sleep(5 * time.Minute)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
initialize()
|
initialize()
|
||||||
|
|
||||||
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()
|
||||||
@ -105,13 +120,22 @@ func main() {
|
|||||||
|
|
||||||
chain := alice.New(loggingHandler).Then(r)
|
chain := alice.New(loggingHandler).Then(r)
|
||||||
|
|
||||||
fmt.Printf("Listening on port %d\n", site.Port)
|
// Set up a channel to intercept Ctrl+C for graceful shutdowns
|
||||||
log.Fatal(http.ListenAndServe("127.0.0.1:"+strconv.Itoa(site.Port), chain))
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-c
|
||||||
|
// Save the changes when the app quits
|
||||||
|
fmt.Println("\nFinishing up...")
|
||||||
|
m.saveChanges()
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
|
||||||
|
fmt.Printf("Listening on port %d\n", m.site.Port)
|
||||||
|
log.Fatal(http.ListenAndServe("127.0.0.1:"+strconv.Itoa(m.site.Port), chain))
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +148,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 +178,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 +198,25 @@ 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 {
|
m.jam.Name = gjName
|
||||||
fmt.Println("Error saving Current Jam")
|
assertError(m.jam.SaveToDB())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jmNm, err := db.getCurrentJam()
|
if m.jam.Name != "" {
|
||||||
if err == nil {
|
fmt.Println("Current Jam Name: " + m.jam.Name)
|
||||||
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 {
|
||||||
@ -205,14 +224,14 @@ func loggingHandler(h http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
||||||
if site.DevMode {
|
if m.site.DevMode {
|
||||||
w.Header().Set("Cache-Control", "no-cache")
|
w.Header().Set("Cache-Control", "no-cache")
|
||||||
}
|
}
|
||||||
p := new(pageData)
|
p := new(pageData)
|
||||||
// Get session
|
// Get session
|
||||||
var err error
|
var err error
|
||||||
var s *sessions.Session
|
var s *sessions.Session
|
||||||
if s, err = sessionStore.Get(req, site.SessionName); err != nil {
|
if s, err = sessionStore.Get(req, m.site.SessionName); err != nil {
|
||||||
http.Error(w, err.Error(), 500)
|
http.Error(w, err.Error(), 500)
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
@ -224,9 +243,9 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
|||||||
// First check if we're logged in
|
// First check if we're logged in
|
||||||
userEmail, _ := p.session.getStringValue("email")
|
userEmail, _ := p.session.getStringValue("email")
|
||||||
// With a valid account
|
// With a valid account
|
||||||
p.LoggedIn = db.isValidUserEmail(userEmail)
|
p.LoggedIn = m.isValidUserEmail(userEmail)
|
||||||
|
|
||||||
p.Site = site
|
p.Site = m.site
|
||||||
p.SubTitle = "GameJam Voting"
|
p.SubTitle = "GameJam Voting"
|
||||||
p.Stylesheets = make([]string, 0, 0)
|
p.Stylesheets = make([]string, 0, 0)
|
||||||
p.Stylesheets = append(p.Stylesheets, "/assets/vendor/css/pure-min.css")
|
p.Stylesheets = append(p.Stylesheets, "/assets/vendor/css/pure-min.css")
|
||||||
@ -261,20 +280,19 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
|||||||
}
|
}
|
||||||
p.HideAdminMenu = true
|
p.HideAdminMenu = true
|
||||||
|
|
||||||
if p.CurrentJam, err = db.getCurrentJam(); err != nil {
|
|
||||||
p.FlashMessage = "Error Loading Current GameJam: " + err.Error()
|
|
||||||
p.FlashClass = "error"
|
|
||||||
}
|
|
||||||
|
|
||||||
p.ClientId = p.session.getClientId()
|
p.ClientId = p.session.getClientId()
|
||||||
cl := db.getClient(p.ClientId)
|
var cl *Client
|
||||||
|
if cl, err = m.GetClient(p.ClientId); err != nil {
|
||||||
|
// A new client
|
||||||
|
cl = NewClient(p.ClientId)
|
||||||
|
}
|
||||||
p.ClientIsAuth = cl.Auth
|
p.ClientIsAuth = cl.Auth
|
||||||
p.ClientIsServer = clientIsServer(req)
|
p.ClientIsServer = clientIsServer(req)
|
||||||
|
|
||||||
// Public Mode
|
// Public Mode
|
||||||
p.PublicMode = db.getPublicSiteMode()
|
p.PublicMode = m.site.GetPublicMode()
|
||||||
// Authentication Mode
|
// Authentication Mode
|
||||||
p.AuthMode = db.getAuthMode()
|
p.AuthMode = m.site.GetAuthMode()
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
@ -299,8 +317,8 @@ func (p *pageData) show(tmplName string, w http.ResponseWriter) error {
|
|||||||
// Spit out a template
|
// Spit out a template
|
||||||
func outputTemplate(tmplName string, tmplData interface{}, w http.ResponseWriter) error {
|
func outputTemplate(tmplName string, tmplData interface{}, w http.ResponseWriter) error {
|
||||||
n := "/templates/" + tmplName
|
n := "/templates/" + tmplName
|
||||||
l := template.Must(template.New("layout").Parse(FSMustString(site.DevMode, n)))
|
l := template.Must(template.New("layout").Parse(FSMustString(m.site.DevMode, n)))
|
||||||
t := template.Must(l.Parse(FSMustString(site.DevMode, n)))
|
t := template.Must(l.Parse(FSMustString(m.site.DevMode, n)))
|
||||||
return t.Execute(w, tmplData)
|
return t.Execute(w, tmplData)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,19 +328,19 @@ 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')
|
||||||
conf = strings.ToUpper(strings.TrimSpace(conf))
|
conf = strings.ToUpper(strings.TrimSpace(conf))
|
||||||
if strings.HasPrefix(conf, "Y") {
|
if strings.HasPrefix(conf, "Y") {
|
||||||
if def.save() != nil {
|
if err := def.SaveToDB(); err != nil {
|
||||||
errorExit("Error resetting to defaults")
|
errorExit("Error resetting to defaults: " + err.Error())
|
||||||
}
|
}
|
||||||
fmt.Println("Reset to defaults")
|
fmt.Println("Reset to defaults")
|
||||||
}
|
}
|
||||||
|
208
model.go
208
model.go
@ -2,45 +2,69 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"fmt"
|
||||||
|
|
||||||
"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 {
|
||||||
|
|
||||||
// gjdb is the interface that works for the current jam database as well as all archive databases
|
|
||||||
type gjdb interface {
|
|
||||||
getDB() *boltease.DB
|
|
||||||
open() error
|
|
||||||
close() error
|
|
||||||
|
|
||||||
getJamName() string
|
|
||||||
setJamName(nm string)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
AuthModeAuthentication = iota
|
|
||||||
AuthModeAll
|
|
||||||
AuthModeError
|
|
||||||
)
|
|
||||||
|
|
||||||
// currJamDb also contains site configuration information
|
|
||||||
type currJamDb struct {
|
|
||||||
bolt *boltease.DB
|
bolt *boltease.DB
|
||||||
dbOpened int
|
dbOpened int
|
||||||
|
dbFileName string
|
||||||
|
|
||||||
|
site *siteData // Configuration data for the site
|
||||||
|
jam *Gamejam // The currently active gamejam
|
||||||
|
clients []Client // Web clients that have connected to the server
|
||||||
|
|
||||||
|
clientsUpdated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *currJamDb) getDB() *boltease.DB {
|
// Update Flags: Which parts of the model need to be updated
|
||||||
return db.bolt
|
const (
|
||||||
}
|
UpdateSiteData = iota
|
||||||
|
UpdateJamData
|
||||||
|
)
|
||||||
|
|
||||||
func (db *currJamDb) open() error {
|
func NewModel() (*model, error) {
|
||||||
db.dbOpened += 1
|
|
||||||
if db.dbOpened == 1 {
|
|
||||||
var err error
|
var err error
|
||||||
db.bolt, err = boltease.Create(DbName, 0600, nil)
|
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 = NewSiteData(m)
|
||||||
|
if err = m.site.LoadFromDB(); err != nil {
|
||||||
|
// Error loading from the DB, set to defaults
|
||||||
|
def := NewSiteData(m)
|
||||||
|
m.site = def
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the jam data
|
||||||
|
if m.jam, err = m.LoadCurrentJam(); err != nil {
|
||||||
|
return nil, errors.New("Unable to load current jam: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load web clients
|
||||||
|
m.clients = m.LoadAllClients()
|
||||||
|
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) openDB() error {
|
||||||
|
m.dbOpened += 1
|
||||||
|
if m.dbOpened == 1 {
|
||||||
|
var err error
|
||||||
|
m.bolt, err = boltease.Create(m.dbFileName, 0600, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -48,112 +72,68 @@ 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() {
|
||||||
|
fmt.Println("Saving Site data to DB")
|
||||||
|
if err = m.site.SaveToDB(); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
//}
|
||||||
func (db *currJamDb) getJamName() string {
|
//if m.jam.IsChanged {
|
||||||
var ret string
|
fmt.Println("Saving Jam data to DB")
|
||||||
var err error
|
if err = m.jam.SaveToDB(); err != nil {
|
||||||
if err = db.open(); err != nil {
|
return err
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
defer db.close()
|
m.jam.IsChanged = false
|
||||||
|
//}
|
||||||
ret, err = db.bolt.GetValue([]string{"site"}, "current-jam")
|
//if m.clientsUpdated {
|
||||||
|
fmt.Println("Saving Client data to DB")
|
||||||
if err == nil && strings.TrimSpace(ret) == "" {
|
if err = m.SaveAllClients(); err != nil {
|
||||||
return ret, errors.New("No Jam Name Specified")
|
return err
|
||||||
}
|
}
|
||||||
return ret, err
|
m.clientsUpdated = false
|
||||||
}
|
//}
|
||||||
|
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)
|
|
||||||
}
|
}
|
||||||
|
228
model_clients.go
228
model_clients.go
@ -1,154 +1,164 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"github.com/pborman/uuid"
|
||||||
"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
|
||||||
Name string
|
Name string
|
||||||
IP string
|
IP string
|
||||||
|
|
||||||
|
mPath []string // The path in the DB to this client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *currJamDb) getAllClients() []Client {
|
func NewClient(id string) *Client {
|
||||||
var ret []Client
|
if id == "" {
|
||||||
|
id = uuid.New()
|
||||||
|
}
|
||||||
|
return &Client{
|
||||||
|
UUID: id,
|
||||||
|
mPath: []string{"clients", id},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *model) AddClient(cl *Client) error {
|
||||||
|
for i := range m.clients {
|
||||||
|
if m.clients[i].UUID == cl.UUID {
|
||||||
|
return errors.New("A client with that ID already exists")
|
||||||
|
}
|
||||||
|
if m.clients[i].IP == cl.IP {
|
||||||
|
return errors.New("A client with that IP already exists")
|
||||||
|
}
|
||||||
|
if m.clients[i].Name == cl.Name {
|
||||||
|
return errors.New("A client with that Name already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.clients = append(m.clients, *cl)
|
||||||
|
m.clientsUpdated = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB Functions
|
||||||
|
* These are generally just called when the app starts up, or when the periodic 'save' runs
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Load all clients from the DB
|
||||||
|
func (m *model) LoadAllClients() []Client {
|
||||||
var err error
|
var err error
|
||||||
if err = db.open(); err != nil {
|
var ret []Client
|
||||||
|
if err = m.openDB(); err != nil {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
defer db.close()
|
defer m.closeDB()
|
||||||
|
|
||||||
var clientUids []string
|
var clientUids []string
|
||||||
if clientUids, err = db.bolt.GetBucketList([]string{"clients"}); err != nil {
|
cliPath := []string{"clients"}
|
||||||
|
if clientUids, err = m.bolt.GetBucketList(cliPath); err != nil {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
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)
|
ret = append(ret, *cl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret
|
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 := NewClient(clId)
|
||||||
cl.UUID = id
|
cl.Auth, _ = m.bolt.GetBool(cl.mPath, "auth")
|
||||||
cl.Auth, _ = db.bolt.GetBool([]string{"clients", id}, "auth")
|
cl.Name, _ = m.bolt.GetValue(cl.mPath, "name")
|
||||||
cl.Name, _ = db.bolt.GetValue([]string{"clients", id}, "name")
|
cl.IP, _ = m.bolt.GetValue(cl.mPath, "ip")
|
||||||
cl.IP, _ = db.bolt.GetValue([]string{"clients", id}, "ip")
|
|
||||||
return cl
|
return cl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *currJamDb) getClientByIp(ip string) *Client {
|
// SaveAllClients saves all clients to the DB
|
||||||
|
func (m *model) SaveAllClients() error {
|
||||||
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()
|
||||||
|
|
||||||
allClients := db.getAllClients()
|
for _, v := range m.clients {
|
||||||
for i := range allClients {
|
if err = m.SaveClient(&v); err != nil {
|
||||||
if allClients[i].IP == ip {
|
|
||||||
return &allClients[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) save() error {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
if err = db.bolt.SetBool([]string{"clients", c.UUID}, "auth", c.Auth); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = db.bolt.SetValue([]string{"clients", c.UUID}, "name", c.Name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
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 {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer db.close()
|
|
||||||
// Make sure we don't clobber a duplicate vote
|
// SaveClient saves a client to the DB
|
||||||
votesBkt := []string{"votes", c.UUID, timestamp.Format(time.RFC3339)}
|
func (m *model) SaveClient(cl *Client) error {
|
||||||
for i := range votes {
|
var err error
|
||||||
if strings.TrimSpace(votes[i]) != "" {
|
if err = m.openDB(); err != nil {
|
||||||
db.bolt.SetValue(votesBkt, strconv.Itoa(i), votes[i])
|
return nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
defer m.closeDB()
|
||||||
|
|
||||||
|
if err = m.bolt.SetBool(cl.mPath, "auth", cl.Auth); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err = m.bolt.SetValue(cl.mPath, "name", cl.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return m.bolt.SetValue(cl.mPath, "ip", cl.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In Memory functions
|
||||||
|
* This is generally how the app accesses client data
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Return a client by it's UUID
|
||||||
|
func (m *model) GetClient(id string) (*Client, error) {
|
||||||
|
for i := range m.clients {
|
||||||
|
if m.clients[i].UUID == id {
|
||||||
|
return &m.clients[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Invalid Id")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a client by it's IP address
|
||||||
|
func (m *model) GetClientByIp(ip string) (*Client, error) {
|
||||||
|
for i := range m.clients {
|
||||||
|
if m.clients[i].IP == ip {
|
||||||
|
return &m.clients[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Invalid Ip")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add/Update a client in the data model
|
||||||
|
func (m *model) UpdateClient(cl *Client) {
|
||||||
|
var found bool
|
||||||
|
for i := range m.clients {
|
||||||
|
if m.clients[i].UUID == cl.UUID {
|
||||||
|
found = true
|
||||||
|
m.clients[i].Auth = cl.Auth
|
||||||
|
m.clients[i].Name = cl.Name
|
||||||
|
m.clients[i].IP = cl.IP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
m.clients = append(m.clients, *cl)
|
||||||
|
}
|
||||||
|
m.clientsUpdated = true
|
||||||
|
}
|
||||||
|
136
model_gamejam.go
136
model_gamejam.go
@ -1,12 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/br0xen/boltease"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gamejam is specifically for an archived game jam
|
/**
|
||||||
|
* Gamejam
|
||||||
|
* Gamejam is the struct for any gamejam (current or archived)
|
||||||
|
*/
|
||||||
type Gamejam struct {
|
type Gamejam struct {
|
||||||
UUID string
|
UUID string
|
||||||
Name string
|
Name string
|
||||||
@ -14,74 +17,73 @@ type Gamejam struct {
|
|||||||
Teams []Team
|
Teams []Team
|
||||||
Votes []Vote
|
Votes []Vote
|
||||||
|
|
||||||
db *boltease.DB
|
m *model // The model that holds this gamejam's data
|
||||||
dbOpened int
|
mPath []string // The path in the db to this gamejam
|
||||||
|
|
||||||
|
IsChanged bool // Flag to tell if we need to update the db
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
gj.mPath = []string{"jam"}
|
||||||
var err error
|
return gj
|
||||||
gj.db, err = boltease.Create(gj.UUID+".db", 0600, nil)
|
}
|
||||||
if err != nil {
|
|
||||||
|
/**
|
||||||
|
* DB Functions
|
||||||
|
* These are generally just called when the app starts up, or when the periodic 'save' runs
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (m *model) LoadCurrentJam() (*Gamejam, error) {
|
||||||
|
if err := m.openDB(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer m.closeDB()
|
||||||
|
|
||||||
|
gj := NewGamejam(m)
|
||||||
|
gj.Name, _ = m.bolt.GetValue(gj.mPath, "name")
|
||||||
|
|
||||||
|
// Load all teams
|
||||||
|
gj.Teams = gj.LoadAllTeams()
|
||||||
|
|
||||||
|
// Load all votes
|
||||||
|
gj.Votes = gj.LoadAllVotes()
|
||||||
|
|
||||||
|
return gj, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save everything to the DB whether it's flagged as changed or not
|
||||||
|
func (gj *Gamejam) SaveToDB() error {
|
||||||
|
if err := gj.m.openDB(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
var errs []error
|
||||||
|
if err := gj.m.bolt.SetValue(gj.mPath, "name", gj.Name); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
// Save all Teams
|
||||||
|
for _, tm := range gj.Teams {
|
||||||
|
if err := gj.SaveTeam(&tm); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all Votes
|
||||||
|
for _, vt := range gj.Votes {
|
||||||
|
if err := gj.SaveVote(&vt); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(errs) > 0 {
|
||||||
|
var errTxt string
|
||||||
|
for i := range errs {
|
||||||
|
errTxt = errTxt + errs[i].Error() + "\n"
|
||||||
|
}
|
||||||
|
errTxt = strings.TrimSpace(errTxt)
|
||||||
|
return errors.New("Error(s) saving to DB: " + errTxt)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gj *Gamejam) closeDB() error {
|
|
||||||
gj.dbOpened -= 1
|
|
||||||
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
|
|
||||||
}
|
|
||||||
defer closeDatabase()
|
|
||||||
|
|
||||||
var gjid string
|
|
||||||
if gjs, err = db.GetBucketList([]string{"gamejams"}); err == nil {
|
|
||||||
for _, v := range gjUids {
|
|
||||||
tstNm, _ := db.GetValue([]string{"gamejams", v}, "name")
|
|
||||||
if tstNm == nm {
|
|
||||||
// We've got it
|
|
||||||
gjid = v
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if gjid == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return dbGetGamejam(gjid)
|
|
||||||
}
|
|
||||||
|
314
model_games.go
314
model_games.go
@ -1,13 +1,59 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pborman/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Game
|
||||||
|
* A team's game, including links, description, and screenshots
|
||||||
|
*/
|
||||||
type Game struct {
|
type Game struct {
|
||||||
Name string
|
Name string
|
||||||
TeamId string
|
TeamId string
|
||||||
Link string
|
Link string
|
||||||
Description string
|
Description string
|
||||||
Screenshots []Screenshot
|
Screenshots []Screenshot
|
||||||
|
|
||||||
|
mPath []string // The path in the DB to this game
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new game object
|
||||||
|
func NewGame(tmId string) (*Game, error) {
|
||||||
|
if tmId == "" {
|
||||||
|
return nil, errors.New("Team ID is required")
|
||||||
|
}
|
||||||
|
return &Game{
|
||||||
|
TeamId: tmId,
|
||||||
|
mPath: []string{"jam", "teams", tmId, "game"},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gm *Game) GetScreenshot(ssId string) (*Screenshot, error) {
|
||||||
|
for _, ss := range gm.Screenshots {
|
||||||
|
if ss.UUID == ssId {
|
||||||
|
return &ss, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Invalid Id")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gm *Game) RemoveScreenshot(ssId string) error {
|
||||||
|
idx := -1
|
||||||
|
for i, ss := range gm.Screenshots {
|
||||||
|
if ss.UUID == ssId {
|
||||||
|
idx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx < 0 {
|
||||||
|
return errors.New("Invalid Id")
|
||||||
|
}
|
||||||
|
fmt.Print("Removing Screenshot (", ssId, ") (IDX:", idx, ")\n")
|
||||||
|
gm.Screenshots = append(gm.Screenshots[:idx], gm.Screenshots[idx+1:]...)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Screenshot struct {
|
type Screenshot struct {
|
||||||
@ -16,63 +62,231 @@ type Screenshot struct {
|
|||||||
Image string
|
Image string
|
||||||
Thumbnail string
|
Thumbnail string
|
||||||
Filetype string
|
Filetype string
|
||||||
|
|
||||||
|
mPath []string // The path in the DB to this screenshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new game object, must have a valid team id
|
// Create a Screenshot Object
|
||||||
func newGame(tmId string) *Game {
|
func NewScreenshot(tmId, ssId string) (*Screenshot, error) {
|
||||||
|
if tmId == "" {
|
||||||
|
return nil, errors.New("Team ID is required")
|
||||||
|
}
|
||||||
|
if ssId == "" {
|
||||||
|
// Generate a new UUID
|
||||||
|
ssId = uuid.New()
|
||||||
|
}
|
||||||
|
return &Screenshot{
|
||||||
|
UUID: ssId,
|
||||||
|
mPath: []string{"jam", "teams", tmId, "game", "screenshots", ssId},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB Functions
|
||||||
|
* These are generally just called when the app starts up, or when the periodic 'save' runs
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Load a team's game from the DB and return it
|
||||||
|
func (gj *Gamejam) LoadTeamGame(tmId string) (*Game, error) {
|
||||||
var err error
|
var err error
|
||||||
if err = db.open(); err != nil {
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
gm, err := NewGame(tmId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if gm.Name, err = gj.m.bolt.GetValue(gm.mPath, "name"); err != nil {
|
||||||
|
gm.Name = ""
|
||||||
|
}
|
||||||
|
if gm.Description, err = gj.m.bolt.GetValue(gm.mPath, "description"); err != nil {
|
||||||
|
gm.Description = ""
|
||||||
|
}
|
||||||
|
if gm.Link, err = gj.m.bolt.GetValue(gm.mPath, "link"); err != nil {
|
||||||
|
gm.Link = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now get the game screenshots
|
||||||
|
gm.Screenshots = gj.LoadTeamGameScreenshots(tmId)
|
||||||
|
|
||||||
|
return gm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a games screenshots from the DB
|
||||||
|
func (gj *Gamejam) LoadTeamGameScreenshots(tmId string) []Screenshot {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer db.close()
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
tm := db.getTeam(tmId)
|
var ret []Screenshot
|
||||||
if tm == nil {
|
gm, err := NewGame(tmId)
|
||||||
return nil
|
if err != nil {
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
return &Game{TeamId: tmId}
|
ssBktPath := append(gm.mPath, "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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gm *Game) save() error {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
tm := db.getTeam(gm.TeamId)
|
|
||||||
if tm == nil {
|
|
||||||
return errors.New("Invalid Team: " + gm.TeamId)
|
|
||||||
}
|
|
||||||
gamePath := []string{"teams", gm.TeamId, "game"}
|
|
||||||
if err := db.bolt.MkBucketPath(gamePath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if gm.Name == "" {
|
|
||||||
gm.Name = tm.Name + "'s Game"
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(gamePath, "name", gm.Name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(gamePath, "link", gm.Link); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(gamePath, "description", gm.Description); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.MkBucketPath(append(gamePath, "screenshots")); err != nil {
|
|
||||||
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
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load a screenshot from the DB
|
||||||
|
func (gj *Gamejam) LoadTeamGameScreenshot(tmId, ssId string) (*Screenshot, error) {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
ret, err := NewScreenshot(tmId, ssId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ret.Description, err = gj.m.bolt.GetValue(ret.mPath, "description"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ret.Image, err = gj.m.bolt.GetValue(ret.mPath, "image"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ret.Thumbnail, err = gj.m.bolt.GetValue(ret.mPath, "thumbnail"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if ret.Thumbnail == "" {
|
||||||
|
ret.Thumbnail = ret.Image
|
||||||
|
}
|
||||||
|
if ret.Filetype, err = gj.m.bolt.GetValue(ret.mPath, "filetype"); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save a game to the DB
|
||||||
|
func (gj *Gamejam) SaveGame(gm *Game) error {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
if err := gj.m.bolt.MkBucketPath(gm.mPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tm *Team
|
||||||
|
if tm, err = gj.GetTeamById(gm.TeamId); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if gm.Name == "" {
|
||||||
|
gm.Name = tm.Name + "'s Game"
|
||||||
|
}
|
||||||
|
if err := gj.m.bolt.SetValue(gm.mPath, "name", gm.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := gj.m.bolt.SetValue(gm.mPath, "link", gm.Link); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := gj.m.bolt.SetValue(gm.mPath, "description", gm.Description); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := gj.m.bolt.MkBucketPath(append(gm.mPath, "screenshots")); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return gj.SaveScreenshots(gm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all of the game's screenshots to the DB
|
||||||
|
// Remove screenshots from the DB that aren't in the game object
|
||||||
|
func (gj *Gamejam) SaveScreenshots(gm *Game) error {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
for _, ss := range gm.Screenshots {
|
||||||
|
if err = gj.SaveScreenshot(&ss); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now remove unused screenshots
|
||||||
|
ssPath := append(gm.mPath, "screenshots")
|
||||||
|
var ssIds []string
|
||||||
|
if ssIds, err = gj.m.bolt.GetBucketList(ssPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := range ssIds {
|
||||||
|
ss, _ := gm.GetScreenshot(ssIds[i])
|
||||||
|
if ss != nil {
|
||||||
|
// A valid screenshot, next
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ss, err = NewScreenshot(gm.TeamId, ssIds[i]); err != nil {
|
||||||
|
// Error building screenshot to delete...
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = gj.DeleteScreenshot(ss); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save a screenshot
|
||||||
|
func (gj *Gamejam) SaveScreenshot(ss *Screenshot) error {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
if err = gj.m.bolt.MkBucketPath(ss.mPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = gj.m.bolt.SetValue(ss.mPath, "description", ss.Description); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = gj.m.bolt.SetValue(ss.mPath, "image", ss.Image); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = gj.m.bolt.SetValue(ss.mPath, "filetype", ss.Filetype); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a screenshot
|
||||||
|
func (gj *Gamejam) DeleteScreenshot(ss *Screenshot) error {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
ssPath := ss.mPath[:len(ss.mPath)-1]
|
||||||
|
return gj.m.bolt.DeleteBucket(ssPath, ss.UUID)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In Memory functions
|
||||||
|
* This is generally how the app accesses client data
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set the given team's game to gm
|
||||||
|
func (gj *Gamejam) UpdateGame(tmId string, gm *Game) error {
|
||||||
|
tm, err := gj.GetTeamById(tmId)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("Error getting team: " + err.Error())
|
||||||
|
}
|
||||||
|
tm.Game = gm
|
||||||
|
gj.IsChanged = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -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)
|
|
||||||
}
|
|
140
model_sitedata.go
Normal file
140
model_sitedata.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
mPath []string // The path in the db to this site data
|
||||||
|
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.mPath = []string{"site"}
|
||||||
|
ret.m = m
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication Modes: Flags for which clients are able to vote
|
||||||
|
const (
|
||||||
|
AuthModeAuthentication = iota
|
||||||
|
AuthModeAll
|
||||||
|
AuthModeError
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
|
||||||
|
if title, _ := s.m.bolt.GetValue(s.mPath, "title"); strings.TrimSpace(title) != "" {
|
||||||
|
s.Title = title
|
||||||
|
}
|
||||||
|
if port, err := s.m.bolt.GetInt(s.mPath, "port"); err == nil {
|
||||||
|
s.Port = port
|
||||||
|
}
|
||||||
|
if sessionName, _ := s.m.bolt.GetValue(s.mPath, "session-name"); strings.TrimSpace(sessionName) != "" {
|
||||||
|
s.SessionName = sessionName
|
||||||
|
}
|
||||||
|
if serverDir, _ := s.m.bolt.GetValue(s.mPath, "server-dir"); strings.TrimSpace(serverDir) != "" {
|
||||||
|
s.ServerDir = serverDir
|
||||||
|
}
|
||||||
|
s.changed = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if the site data in memory has changed
|
||||||
|
func (s *siteData) NeedsSave() bool {
|
||||||
|
return s.changed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the site data into the DB
|
||||||
|
func (s *siteData) SaveToDB() error {
|
||||||
|
var err error
|
||||||
|
if err = s.m.openDB(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer s.m.closeDB()
|
||||||
|
|
||||||
|
if err = s.m.bolt.SetValue(s.mPath, "title", s.Title); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = s.m.bolt.SetInt(s.mPath, "port", s.Port); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = s.m.bolt.SetValue(s.mPath, "session-name", s.SessionName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = s.m.bolt.SetValue(s.mPath, "server-dir", s.ServerDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.changed = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the Auth Mode
|
||||||
|
func (s *siteData) GetAuthMode() int {
|
||||||
|
return s.authMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the auth mode
|
||||||
|
func (s *siteData) SetAuthMode(mode int) error {
|
||||||
|
if mode < AuthModeAuthentication || mode >= AuthModeError {
|
||||||
|
return errors.New("Invalid Authentication Mode: " + strconv.Itoa(mode))
|
||||||
|
}
|
||||||
|
if mode != s.authMode {
|
||||||
|
s.authMode = mode
|
||||||
|
s.changed = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the public site mode
|
||||||
|
func (s *siteData) GetPublicMode() int {
|
||||||
|
return s.publicMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the public site mode
|
||||||
|
func (s *siteData) SetPublicMode(mode int) error {
|
||||||
|
if mode < SiteModeWaiting || mode >= SiteModeError {
|
||||||
|
return errors.New("Invalid Public Mode: " + strconv.Itoa(mode))
|
||||||
|
}
|
||||||
|
if mode != s.publicMode {
|
||||||
|
s.publicMode = mode
|
||||||
|
s.changed = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
554
model_teams.go
554
model_teams.go
@ -2,264 +2,44 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Team
|
||||||
|
*/
|
||||||
type Team struct {
|
type Team struct {
|
||||||
UUID string
|
UUID string
|
||||||
Name string
|
Name string
|
||||||
Members []TeamMember
|
Members []TeamMember
|
||||||
Game *Game
|
Game *Game
|
||||||
|
|
||||||
|
mPath []string // The path in the DB to this team
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(id string) *Team {
|
||||||
var err error
|
if id == "" {
|
||||||
if err = db.open(); err != nil {
|
id = uuid.New()
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
defer db.close()
|
// Create an emtpy game for the team
|
||||||
|
gm, _ := NewGame(id)
|
||||||
// Generate a UUID
|
return &Team{
|
||||||
uuid := uuid.New()
|
UUID: id,
|
||||||
teamPath := []string{"teams", uuid}
|
Game: gm,
|
||||||
|
mPath: []string{"jam", "teams", id},
|
||||||
if err := db.bolt.MkBucketPath(teamPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if err := db.bolt.SetValue(teamPath, "name", nm); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.MkBucketPath(append(teamPath, "members")); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
gamePath := append(teamPath, "game")
|
|
||||||
if err := db.bolt.MkBucketPath(gamePath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(append(gamePath), "name", ""); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return db.bolt.MkBucketPath(append(gamePath, "screenshots"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTeam returns a team with the given id, or nil
|
func (gj *Gamejam) GetTeamById(id string) (*Team, error) {
|
||||||
func (db *gjDatabase) getTeam(id string) *Team {
|
for i := range gj.Teams {
|
||||||
var err error
|
if gj.Teams[i].UUID == id {
|
||||||
if err = db.open(); err != nil {
|
return &gj.Teams[i], nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
teamPath := []string{"teams", id}
|
|
||||||
tm := new(Team)
|
|
||||||
tm.UUID = id
|
|
||||||
if tm.Name, err = db.bolt.GetValue(teamPath, "name"); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
tm.Members = tm.getTeamMembers()
|
|
||||||
tm.Game = tm.getGame()
|
|
||||||
return tm
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function returns the team for a specific member
|
|
||||||
func (db *gjDatabase) getTeamForMember(mbrid string) (*Team, error) {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
teams := db.getAllTeams()
|
|
||||||
for i := range teams {
|
|
||||||
var tmMbrs []TeamMember
|
|
||||||
tmMbrs = teams[i].getTeamMembers()
|
|
||||||
if err == nil {
|
|
||||||
for j := range tmMbrs {
|
|
||||||
if tmMbrs[j].UUID == mbrid {
|
|
||||||
return &teams[i], nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return nil, errors.New("Invalid Team Id given")
|
||||||
}
|
|
||||||
return nil, errors.New("Unable to find team member")
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAllTeams returns all teams in the database
|
|
||||||
func (db *gjDatabase) getAllTeams() []Team {
|
|
||||||
var ret []Team
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
teamPath := []string{"teams"}
|
|
||||||
var teamUids []string
|
|
||||||
if teamUids, err = db.bolt.GetBucketList(teamPath); err != nil {
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
for _, v := range teamUids {
|
|
||||||
if tm := db.getTeam(v); tm != nil {
|
|
||||||
ret = append(ret, *tm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// getTeamByName returns a team with the given name or nil
|
|
||||||
func (db *gjDatabase) getTeamByName(nm string) *Team {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
teamPath := []string{"teams"}
|
|
||||||
var teamUids []string
|
|
||||||
if teamUids, err = db.bolt.GetBucketList(teamPath); err != nil {
|
|
||||||
for _, v := range teamUids {
|
|
||||||
var name string
|
|
||||||
if name, err = db.bolt.GetValue(append(teamPath, v), "name"); name == nm {
|
|
||||||
return db.getTeam(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// save saves the team to the db
|
|
||||||
func (tm *Team) save() error {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
teamPath := []string{"teams", tm.UUID}
|
|
||||||
if err = db.bolt.SetValue(teamPath, "name", tm.Name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Save Team Members
|
|
||||||
// TODO: Save Team Game
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete removes the team from the database
|
|
||||||
func (tm *Team) delete() error {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
teamPath := []string{"teams"}
|
|
||||||
return db.bolt.DeleteBucket(teamPath, tm.UUID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *Team) getGame() *Game {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
gamePath := []string{"teams", tm.UUID, "game"}
|
|
||||||
gm := new(Game)
|
|
||||||
if gm.Name, err = db.bolt.GetValue(gamePath, "name"); err != nil {
|
|
||||||
gm.Name = ""
|
|
||||||
}
|
|
||||||
gm.TeamId = tm.UUID
|
|
||||||
if gm.Description, err = db.bolt.GetValue(gamePath, "description"); err != nil {
|
|
||||||
gm.Description = ""
|
|
||||||
}
|
|
||||||
if gm.Link, err = db.bolt.GetValue(gamePath, "link"); err != nil {
|
|
||||||
gm.Link = ""
|
|
||||||
}
|
|
||||||
gm.Screenshots = tm.getScreenshots()
|
|
||||||
return gm
|
|
||||||
}
|
|
||||||
|
|
||||||
// Screenshots are saved as base64 encoded pngs
|
|
||||||
func (tm *Team) saveScreenshot(ss *Screenshot) error {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
ssPath := []string{"teams", tm.UUID, "game", "screenshots"}
|
|
||||||
// Generate a UUID for this screenshot
|
|
||||||
uuid := uuid.New()
|
|
||||||
ssPath = append(ssPath, uuid)
|
|
||||||
if err := db.bolt.MkBucketPath(ssPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(ssPath, "description", ss.Description); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(ssPath, "image", ss.Image); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(ssPath, "thumbnail", ss.Thumbnail); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := db.bolt.SetValue(ssPath, "filetype", ss.Filetype); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
ssPath := []string{"teams", tm.UUID, "game", "screenshots"}
|
|
||||||
return db.bolt.DeleteBucket(ssPath, ssId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TeamMember struct {
|
type TeamMember struct {
|
||||||
@ -268,53 +48,131 @@ type TeamMember struct {
|
|||||||
SlackId string
|
SlackId string
|
||||||
Twitter string
|
Twitter string
|
||||||
Email string
|
Email string
|
||||||
|
|
||||||
|
mPath []string // The path in the DB to this team member
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new team member, only a name is required
|
// Create a new team member
|
||||||
func newTeamMember(nm string) *TeamMember {
|
func NewTeamMember(tmId, uId string) (*TeamMember, error) {
|
||||||
m := TeamMember{Name: nm}
|
if tmId == "" {
|
||||||
return &m
|
return nil, errors.New("Team ID is required")
|
||||||
|
}
|
||||||
|
if uId == "" {
|
||||||
|
uId = uuid.New()
|
||||||
|
}
|
||||||
|
return &TeamMember{
|
||||||
|
UUID: uId,
|
||||||
|
mPath: []string{"jam", "teams", tmId, "members", uId},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *Team) getTeamMember(mbrId string) *TeamMember {
|
// AddTeamMember adds a new team member
|
||||||
|
func (tm *Team) AddTeamMember(mbr *TeamMember) error {
|
||||||
|
lkup, _ := tm.GetTeamMemberById(mbr.UUID)
|
||||||
|
if lkup != nil {
|
||||||
|
return errors.New("A Team Member with that Id already exists")
|
||||||
|
}
|
||||||
|
tm.Members = append(tm.Members, *mbr)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTeamMemberById returns a member with the given uuid
|
||||||
|
// or an error if it couldn't find it
|
||||||
|
func (tm *Team) GetTeamMemberById(uuid string) (*TeamMember, error) {
|
||||||
|
for i := range tm.Members {
|
||||||
|
if tm.Members[i].UUID == uuid {
|
||||||
|
return &tm.Members[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Invalid Team Member Id given")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tm *Team) RemoveTeamMemberById(id string) error {
|
||||||
|
idx := -1
|
||||||
|
for i := range tm.Members {
|
||||||
|
if tm.Members[i].UUID == id {
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx < 0 {
|
||||||
|
return errors.New("Invalid Team Member ID given")
|
||||||
|
}
|
||||||
|
tm.Members = append(tm.Members[:idx], tm.Members[idx+1:]...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB Functions
|
||||||
|
* These are generally just called when the app starts up, or when the periodic 'save' runs
|
||||||
|
*/
|
||||||
|
|
||||||
|
// LoadAllTeams loads all teams for the jam out of the database
|
||||||
|
func (gj *Gamejam) LoadAllTeams() []Team {
|
||||||
var err error
|
var err error
|
||||||
if err = db.open(); err != nil {
|
var ret []Team
|
||||||
return nil
|
if err = gj.m.openDB(); err != nil {
|
||||||
}
|
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
mbr := new(TeamMember)
|
|
||||||
mbr.UUID = mbrId
|
|
||||||
teamMbrPath := []string{"teams", tm.UUID, "members", mbr.UUID}
|
|
||||||
if mbr.Name, err = db.bolt.GetValue(teamMbrPath, "name"); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if mbr.SlackId, err = db.bolt.GetValue(teamMbrPath, "slackid"); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if mbr.Twitter, err = db.bolt.GetValue(teamMbrPath, "twitter"); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if mbr.Email, err = db.bolt.GetValue(teamMbrPath, "email"); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return mbr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm *Team) getTeamMembers() []TeamMember {
|
|
||||||
var ret []TeamMember
|
|
||||||
var err error
|
|
||||||
if err = db.open(); err != nil {
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
defer db.close()
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
teamPath := []string{"teams", tm.UUID, "members"}
|
var tmUUIDs []string
|
||||||
|
tmsPath := append(gj.mPath, "teams")
|
||||||
|
if tmUUIDs, err = gj.m.bolt.GetBucketList(tmsPath); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
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, error) {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
// Team Data
|
||||||
|
tm := NewTeam(uuid)
|
||||||
|
if tm.Name, err = gj.m.bolt.GetValue(tm.mPath, "name"); err != nil {
|
||||||
|
return nil, errors.New("Error loading team: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Team Members
|
||||||
|
tm.Members = gj.LoadTeamMembers(uuid)
|
||||||
|
|
||||||
|
// Team Game
|
||||||
|
if tm.Game, err = gj.LoadTeamGame(uuid); err != nil {
|
||||||
|
return nil, errors.New("Error loading team game: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return tm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
var memberUuids []string
|
||||||
if memberUuids, err = db.bolt.GetBucketList(teamPath); err == nil {
|
tm := NewTeam(tmId)
|
||||||
|
mbrsPath := append(tm.mPath, "members")
|
||||||
|
if memberUuids, err = gj.m.bolt.GetBucketList(mbrsPath); err == nil {
|
||||||
for _, v := range memberUuids {
|
for _, v := range memberUuids {
|
||||||
var mbr *TeamMember
|
mbr, _ := gj.LoadTeamMember(tmId, v)
|
||||||
if mbr = tm.getTeamMember(v); mbr != nil {
|
if mbr != nil {
|
||||||
ret = append(ret, *mbr)
|
ret = append(ret, *mbr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,53 +180,139 @@ func (tm *Team) getTeamMembers() []TeamMember {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm *Team) updateTeamMember(mbr *TeamMember) error {
|
// Load a team member from the DB and return it
|
||||||
|
func (gj *Gamejam) LoadTeamMember(tmId, mbrId string) (*TeamMember, error) {
|
||||||
var err error
|
var err error
|
||||||
if err = db.open(); err != nil {
|
if err = gj.m.openDB(); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer db.close()
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
if mbr.UUID == "" {
|
mbr, err := NewTeamMember(tmId, mbrId)
|
||||||
mbrs := tm.getTeamMembers()
|
if err != nil {
|
||||||
if len(mbrs) > 0 {
|
return nil, errors.New("Error loading team member: " + err.Error())
|
||||||
for i := range mbrs {
|
|
||||||
if mbrs[i].Name == mbr.Name {
|
|
||||||
mbr.UUID = mbrs[i].UUID
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
// Name is the only required field
|
||||||
|
if mbr.Name, err = gj.m.bolt.GetValue(mbr.mPath, "name"); err != nil {
|
||||||
|
return nil, errors.New("Error loading team member: " + err.Error())
|
||||||
}
|
}
|
||||||
|
if mbr.SlackId, err = gj.m.bolt.GetValue(mbr.mPath, "slackid"); err != nil {
|
||||||
|
mbr.SlackId = ""
|
||||||
}
|
}
|
||||||
|
if mbr.Twitter, err = gj.m.bolt.GetValue(mbr.mPath, "twitter"); err != nil {
|
||||||
|
mbr.Twitter = ""
|
||||||
}
|
}
|
||||||
if mbr.UUID == "" {
|
if mbr.Email, err = gj.m.bolt.GetValue(mbr.mPath, "email"); err != nil {
|
||||||
// It's really a new one
|
mbr.Email = ""
|
||||||
mbr.UUID = uuid.New()
|
}
|
||||||
|
return mbr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mbrPath := []string{"teams", tm.UUID, "members", mbr.UUID}
|
func (gj *Gamejam) SaveTeam(tm *Team) error {
|
||||||
if db.bolt.SetValue(mbrPath, "name", mbr.Name) != nil {
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if db.bolt.SetValue(mbrPath, "slackid", mbr.SlackId) != nil {
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
// Save team data
|
||||||
|
if err = gj.m.bolt.SetValue(tm.mPath, "name", tm.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if db.bolt.SetValue(mbrPath, "twitter", mbr.Twitter) != nil {
|
|
||||||
|
// Save team members
|
||||||
|
for _, mbr := range tm.Members {
|
||||||
|
if err = gj.m.bolt.SetValue(mbr.mPath, "name", mbr.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if db.bolt.SetValue(mbrPath, "email", mbr.Email) != nil {
|
if err = gj.m.bolt.SetValue(mbr.mPath, "slackid", mbr.SlackId); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err = gj.m.bolt.SetValue(mbr.mPath, "twitter", mbr.Twitter); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = gj.m.bolt.SetValue(mbr.mPath, "email", mbr.Email); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save team game
|
||||||
|
return gj.SaveGame(tm.Game)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the team tm
|
||||||
|
// TODO: Deletes should be done all at once when syncing memory to the DB
|
||||||
|
/*
|
||||||
|
func (gj *Gamejam) DeleteTeam(tm *Team) error {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
if len(tm.mPath) < 2 {
|
||||||
|
return errors.New("Invalid team path: " + string(tm.mPath))
|
||||||
|
}
|
||||||
|
return gj.m.bolt.DeleteBucket(tm.mPath[:len(tm.mPath)-1], tm.UUID)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Delete the TeamMember mbr from Team tm
|
||||||
|
// TODO: Deletes should be done all at once when syncing memory to the DB
|
||||||
|
/*
|
||||||
|
func (gj *Gamejam) DeleteTeamMember(tm *Team, mbr *TeamMember) error {
|
||||||
|
var err error
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
|
if len(mbr.mPath) < 2 {
|
||||||
|
return errors.New("Invalid team path: " + string(tm.mPath))
|
||||||
|
}
|
||||||
|
return gj.m.bolt.DeleteBucket(mbr.mPath[:len(mbr.mPath)-1], mbr.UUID)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In Memory functions
|
||||||
|
* This is generally how the app accesses data
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Add a team
|
||||||
|
func (gj *Gamejam) AddTeam(tm *Team) error {
|
||||||
|
if _, err := gj.GetTeamById(tm.UUID); err == nil {
|
||||||
|
return errors.New("A team with that ID already exists")
|
||||||
|
}
|
||||||
|
if _, err := gj.GetTeamByName(tm.Name); err == nil {
|
||||||
|
return errors.New("A team with that Name already exists")
|
||||||
|
}
|
||||||
|
gj.Teams = append(gj.Teams, *tm)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteTeamMember removes a member from the database
|
// Find a team by name
|
||||||
func (tm *Team) deleteTeamMember(mbr *TeamMember) error {
|
func (gj *Gamejam) GetTeamByName(nm string) (*Team, error) {
|
||||||
var err error
|
for i := range gj.Teams {
|
||||||
if err = db.open(); err != nil {
|
if gj.Teams[i].Name == nm {
|
||||||
return err
|
return &gj.Teams[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, errors.New("Invalid team name given")
|
||||||
}
|
}
|
||||||
defer db.close()
|
|
||||||
|
|
||||||
teamPath := []string{"teams", tm.UUID, "members"}
|
// Remove a team by id
|
||||||
return db.bolt.DeleteBucket(teamPath, mbr.UUID)
|
func (gj *Gamejam) RemoveTeamById(id string) error {
|
||||||
|
idx := -1
|
||||||
|
for i := range gj.Teams {
|
||||||
|
if gj.Teams[i].UUID == id {
|
||||||
|
idx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx == -1 {
|
||||||
|
return errors.New("Invalid Team ID given")
|
||||||
|
}
|
||||||
|
gj.Teams = append(gj.Teams[:idx], gj.Teams[idx+1:]...)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -2,46 +2,52 @@ 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
|
||||||
|
// Unlike gamejam functions, we manipulate the DB directly
|
||||||
|
// We want to make sure that we always use the most up-to-date user
|
||||||
|
// information.
|
||||||
|
|
||||||
// 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 +57,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)
|
||||||
}
|
}
|
||||||
|
136
model_votes.go
136
model_votes.go
@ -1,6 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"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 {
|
||||||
@ -13,19 +18,134 @@ type Vote struct {
|
|||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
ClientId string // UUID of client
|
ClientId string // UUID of client
|
||||||
Choices []GameChoice
|
Choices []GameChoice
|
||||||
|
|
||||||
|
mPath []string // The path in the DB to this team
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *gjDatabase) getAllVotes() []Vote {
|
func NewVote(clId string, tm time.Time) (*Vote, error) {
|
||||||
var ret []Vote
|
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 err error
|
||||||
if err = db.open(); err != nil {
|
var ret []Vote
|
||||||
|
if err = gj.m.openDB(); err != nil {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
defer db.close()
|
defer gj.m.closeDB()
|
||||||
|
|
||||||
clients := db.getAllClients()
|
votesPath := []string{"jam", "votes"}
|
||||||
for _, cl := range clients {
|
var cliUUIDs []string
|
||||||
ret = append(ret, cl.getVotes()...)
|
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
|
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
|
||||||
|
}
|
||||||
|
@ -43,7 +43,9 @@ func (p *pageSession) getClientId() string {
|
|||||||
fmt.Println(" Client IP:" + clientIp)
|
fmt.Println(" Client IP:" + clientIp)
|
||||||
if clientIp != "127.0.0.1" {
|
if clientIp != "127.0.0.1" {
|
||||||
fmt.Println(" Pulling data by IP")
|
fmt.Println(" Pulling data by IP")
|
||||||
cli = db.getClientByIp(clientIp)
|
if cli, err = m.GetClientByIp(clientIp); err != nil {
|
||||||
|
cli = NewClient(clientId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if cli != nil {
|
if cli != nil {
|
||||||
clientId = cli.UUID
|
clientId = cli.UUID
|
||||||
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@ -17,7 +18,7 @@ func initPublicPage(w http.ResponseWriter, req *http.Request) *pageData {
|
|||||||
|
|
||||||
func handleMain(w http.ResponseWriter, req *http.Request) {
|
func handleMain(w http.ResponseWriter, req *http.Request) {
|
||||||
page := initPublicPage(w, req)
|
page := initPublicPage(w, req)
|
||||||
if db.getPublicSiteMode() == SiteModeWaiting {
|
if m.site.GetPublicMode() == SiteModeWaiting {
|
||||||
page.SubTitle = ""
|
page.SubTitle = ""
|
||||||
page.show("public-waiting.html", w)
|
page.show("public-waiting.html", w)
|
||||||
} else {
|
} else {
|
||||||
@ -28,7 +29,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 (m.site.GetAuthMode() == AuthModeAuthentication) && !page.ClientIsAuth {
|
||||||
page.show("unauthorized.html", w)
|
page.show("unauthorized.html", w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -37,7 +38,8 @@ func loadVotingPage(w http.ResponseWriter, req *http.Request) {
|
|||||||
Timestamp string
|
Timestamp string
|
||||||
}
|
}
|
||||||
vpd := new(votingPageData)
|
vpd := new(votingPageData)
|
||||||
tms := db.getAllTeams()
|
tms := make([]Team, len(m.jam.Teams))
|
||||||
|
copy(tms, m.jam.Teams)
|
||||||
|
|
||||||
// Randomize the team list
|
// Randomize the team list
|
||||||
rand.Seed(time.Now().Unix())
|
rand.Seed(time.Now().Unix())
|
||||||
@ -55,7 +57,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 (m.site.GetAuthMode() == AuthModeAuthentication) && !page.ClientIsAuth {
|
||||||
page.show("unauthorized.html", w)
|
page.show("unauthorized.html", w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -66,23 +68,40 @@ func handlePublicSaveVote(w http.ResponseWriter, req *http.Request) {
|
|||||||
ts := req.FormValue("timestamp")
|
ts := req.FormValue("timestamp")
|
||||||
timestamp, err := time.Parse(time.RFC3339, ts)
|
timestamp, err := time.Parse(time.RFC3339, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
page.session.setFlashMessage("Error parsing timestamp: "+ts, "error")
|
page.session.setFlashMessage("Error creating vote", "error")
|
||||||
|
fmt.Println("Error parsing timestamp: " + ts)
|
||||||
redirect("/", w, req)
|
redirect("/", w, req)
|
||||||
}
|
}
|
||||||
client := db.getClient(page.ClientId)
|
client, err := m.GetClient(page.ClientId)
|
||||||
if _, err := client.getVote(timestamp); err == nil {
|
if err != nil {
|
||||||
|
client = NewClient(page.ClientId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// voteSlice is an ordered string slice of the voters preferences
|
||||||
|
voteCSV := req.FormValue("uservote")
|
||||||
|
voteSlice := strings.Split(voteCSV, ",")
|
||||||
|
|
||||||
|
if _, err = m.jam.GetVote(client.UUID, timestamp); err == nil {
|
||||||
// Duplicate vote... Cancel it.
|
// Duplicate vote... Cancel it.
|
||||||
page.session.setFlashMessage("Duplicate vote!", "error")
|
page.session.setFlashMessage("Duplicate vote!", "error")
|
||||||
redirect("/", w, req)
|
redirect("/", w, req)
|
||||||
}
|
}
|
||||||
// voteSlice is an ordered string slice of the voters preferences
|
|
||||||
voteCSV := req.FormValue("uservote")
|
var vt *Vote
|
||||||
voteSlice := strings.Split(voteCSV, ",")
|
if vt, err = NewVote(client.UUID, timestamp); err != nil {
|
||||||
if err := client.saveVote(timestamp, voteSlice); err != nil {
|
fmt.Println("Error creating vote: " + err.Error())
|
||||||
page.session.setFlashMessage("Error Saving Vote: "+err.Error(), "error")
|
page.session.setFlashMessage("Error creating vote", "error")
|
||||||
|
redirect("/", w, req)
|
||||||
}
|
}
|
||||||
if newVote, err := client.getVote(timestamp); err == nil {
|
if err = vt.SetChoices(voteSlice); err != nil {
|
||||||
site.Votes = append(site.Votes, *newVote)
|
fmt.Println("Error creating vote: " + err.Error())
|
||||||
|
page.session.setFlashMessage("Error creating vote", "error")
|
||||||
|
redirect("/", w, req)
|
||||||
|
}
|
||||||
|
if err := m.jam.AddVote(vt); err != nil {
|
||||||
|
fmt.Println("Error adding vote: " + err.Error())
|
||||||
|
page.session.setFlashMessage("Error creating vote", "error")
|
||||||
|
redirect("/", w, req)
|
||||||
}
|
}
|
||||||
page.session.setFlashMessage("Vote Saved!", "success large fading")
|
page.session.setFlashMessage("Vote Saved!", "success large fading")
|
||||||
redirect("/", w, req)
|
redirect("/", w, req)
|
||||||
@ -91,19 +110,22 @@ func handlePublicSaveVote(w http.ResponseWriter, req *http.Request) {
|
|||||||
func handleThumbnailRequest(w http.ResponseWriter, req *http.Request) {
|
func handleThumbnailRequest(w http.ResponseWriter, req *http.Request) {
|
||||||
// Thumbnail requests are open even without client authentication
|
// Thumbnail requests are open even without client authentication
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
tm := db.getTeam(vars["teamid"])
|
tm, err := m.jam.GetTeamById(vars["teamid"])
|
||||||
if tm == nil {
|
if err != nil {
|
||||||
|
fmt.Println("handleThumbnailRequest: " + err.Error())
|
||||||
http.Error(w, "Couldn't find image", 404)
|
http.Error(w, "Couldn't find image", 404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ss := tm.getScreenshot(vars["imageid"])
|
ss, err := tm.Game.GetScreenshot(vars["imageid"])
|
||||||
if ss == nil {
|
if err != nil {
|
||||||
|
fmt.Println("handleThumbnailRequest: " + err.Error())
|
||||||
http.Error(w, "Couldn't find image", 404)
|
http.Error(w, "Couldn't find image", 404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "image/"+ss.Filetype)
|
w.Header().Set("Content-Type", "image/"+ss.Filetype)
|
||||||
dat, err := base64.StdEncoding.DecodeString(ss.Thumbnail)
|
dat, err := base64.StdEncoding.DecodeString(ss.Thumbnail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println("handleThumbnailRequest: " + err.Error())
|
||||||
http.Error(w, "Couldn't find image", 404)
|
http.Error(w, "Couldn't find image", 404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -113,19 +135,22 @@ func handleThumbnailRequest(w http.ResponseWriter, req *http.Request) {
|
|||||||
func handleImageRequest(w http.ResponseWriter, req *http.Request) {
|
func handleImageRequest(w http.ResponseWriter, req *http.Request) {
|
||||||
// Image requests are open even without client authentication
|
// Image requests are open even without client authentication
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
tm := db.getTeam(vars["teamid"])
|
tm, err := m.jam.GetTeamById(vars["teamid"])
|
||||||
if tm == nil {
|
if err != nil {
|
||||||
|
fmt.Println("handleImageRequest: " + err.Error())
|
||||||
http.Error(w, "Couldn't find image", 404)
|
http.Error(w, "Couldn't find image", 404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ss := tm.getScreenshot(vars["imageid"])
|
ss, err := tm.Game.GetScreenshot(vars["imageid"])
|
||||||
if ss == nil {
|
if err != nil {
|
||||||
|
fmt.Println("handleImageRequest: " + err.Error())
|
||||||
http.Error(w, "Couldn't find image", 404)
|
http.Error(w, "Couldn't find image", 404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "image/"+ss.Filetype)
|
w.Header().Set("Content-Type", "image/"+ss.Filetype)
|
||||||
dat, err := base64.StdEncoding.DecodeString(ss.Image)
|
dat, err := base64.StdEncoding.DecodeString(ss.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println("handleImageRequest: " + err.Error())
|
||||||
http.Error(w, "Couldn't find image", 404)
|
http.Error(w, "Couldn't find image", 404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -134,69 +159,78 @@ func handleImageRequest(w http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
func handleTeamMgmtRequest(w http.ResponseWriter, req *http.Request) {
|
func handleTeamMgmtRequest(w http.ResponseWriter, req *http.Request) {
|
||||||
// Team Management pages are open even without client authentication
|
// Team Management pages are open even without client authentication
|
||||||
if db.getPublicSiteMode() == SiteModeVoting {
|
if m.site.GetPublicMode() == SiteModeVoting {
|
||||||
redirect("/", w, req)
|
redirect("/", w, req)
|
||||||
}
|
}
|
||||||
page := initPublicPage(w, req)
|
page := initPublicPage(w, req)
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
page.SubTitle = "Team Details"
|
page.SubTitle = "Team Details"
|
||||||
teamId := vars["id"]
|
teamId := vars["id"]
|
||||||
tm := db.getTeam(teamId)
|
tm, err := m.jam.GetTeamById(teamId)
|
||||||
if tm != nil {
|
if err == nil {
|
||||||
// Team self-management functions
|
// Team self-management functions
|
||||||
switch vars["function"] {
|
switch vars["function"] {
|
||||||
case "":
|
case "":
|
||||||
page.SubTitle = "Team Management"
|
page.SubTitle = "Team Management"
|
||||||
page.TemplateData = tm
|
page.TemplateData = tm
|
||||||
page.show("public-teammgmt.html", w)
|
page.show("public-teammgmt.html", w)
|
||||||
|
|
||||||
case "savemember":
|
case "savemember":
|
||||||
m := newTeamMember(req.FormValue("newmembername"))
|
m, err := NewTeamMember(tm.UUID, "")
|
||||||
|
if err != nil {
|
||||||
|
page.session.setFlashMessage("Error adding team member: "+err.Error(), "error")
|
||||||
|
redirect("/team/"+tm.UUID+"#members", w, req)
|
||||||
|
}
|
||||||
|
m.Name = req.FormValue("newmembername")
|
||||||
m.SlackId = req.FormValue("newmemberslackid")
|
m.SlackId = req.FormValue("newmemberslackid")
|
||||||
m.Twitter = req.FormValue("newmembertwitter")
|
m.Twitter = req.FormValue("newmembertwitter")
|
||||||
m.Email = req.FormValue("newmemberemail")
|
m.Email = req.FormValue("newmemberemail")
|
||||||
if err := tm.updateTeamMember(m); err != nil {
|
if err := tm.AddTeamMember(m); err != nil {
|
||||||
page.session.setFlashMessage("Error adding team member: "+err.Error(), "error")
|
page.session.setFlashMessage("Error adding team member: "+err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage(m.Name+" added to team!", "success")
|
page.session.setFlashMessage(m.Name+" added to team!", "success")
|
||||||
}
|
}
|
||||||
refreshTeamsInMemory()
|
|
||||||
redirect("/team/"+tm.UUID+"#members", w, req)
|
redirect("/team/"+tm.UUID+"#members", w, req)
|
||||||
|
|
||||||
case "deletemember":
|
case "deletemember":
|
||||||
mbrId := req.FormValue("memberid")
|
mbrId := req.FormValue("memberid")
|
||||||
m := tm.getTeamMember(mbrId)
|
err := tm.RemoveTeamMemberById(mbrId)
|
||||||
if m != nil {
|
if err != nil {
|
||||||
if err := tm.deleteTeamMember(m); err != nil {
|
|
||||||
page.session.setFlashMessage("Error deleting team member: "+err.Error(), "error")
|
page.session.setFlashMessage("Error deleting team member: "+err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage(m.Name+" deleted from team", "success")
|
page.session.setFlashMessage("Team member removed", "success")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
page.session.setFlashMessage("Couldn't find member to delete", "error")
|
|
||||||
}
|
|
||||||
refreshTeamsInMemory()
|
|
||||||
redirect("/team/"+tm.UUID, w, req)
|
redirect("/team/"+tm.UUID, w, req)
|
||||||
|
|
||||||
case "savegame":
|
case "savegame":
|
||||||
gm := newGame(tm.UUID)
|
tm.Game.Name = req.FormValue("gamename")
|
||||||
gm.Name = req.FormValue("gamename")
|
tm.Game.Link = req.FormValue("gamelink")
|
||||||
gm.Link = req.FormValue("gamelink")
|
tm.Game.Description = req.FormValue("gamedesc")
|
||||||
gm.Description = req.FormValue("gamedesc")
|
page.session.setFlashMessage("Team game updated", "success")
|
||||||
if err := gm.save(); err != nil {
|
redirect("/team/"+tm.UUID, w, req)
|
||||||
|
|
||||||
|
case "screenshotupload":
|
||||||
|
ss, err := ssFromRequest(tm, req)
|
||||||
|
if err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
redirect("/team/"+tm.UUID, w, req)
|
||||||
|
}
|
||||||
|
gm := tm.Game
|
||||||
|
gm.Screenshots = append(gm.Screenshots, *ss)
|
||||||
|
if err = m.jam.UpdateGame(tm.UUID, gm); err != nil {
|
||||||
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
} else {
|
} else {
|
||||||
page.session.setFlashMessage("Team game updated", "success")
|
page.session.setFlashMessage("Screenshot Uploaded", "success")
|
||||||
}
|
|
||||||
redirect("/team/"+tm.UUID, w, req)
|
|
||||||
case "screenshotupload":
|
|
||||||
if err := saveScreenshots(tm, req); err != nil {
|
|
||||||
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
|
||||||
}
|
}
|
||||||
redirect("/team/"+tm.UUID, w, req)
|
redirect("/team/"+tm.UUID, w, req)
|
||||||
|
|
||||||
case "screenshotdelete":
|
case "screenshotdelete":
|
||||||
ssid := vars["subid"]
|
ssid := vars["subid"]
|
||||||
if err := tm.deleteScreenshot(ssid); err != nil {
|
if err := tm.Game.RemoveScreenshot(ssid); err != nil {
|
||||||
page.session.setFlashMessage("Error deleting screenshot: "+err.Error(), "error")
|
page.session.setFlashMessage("Error deleting screenshot: "+err.Error(), "error")
|
||||||
}
|
}
|
||||||
redirect("/team/"+tm.UUID, w, req)
|
redirect("/team/"+tm.UUID, w, req)
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
http.Error(w, "Page Not Found", 404)
|
http.Error(w, "Page Not Found", 404)
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="left" colspan="3">{{ len .Site.Votes }} Total Votes</td>
|
<td class="left" colspan="3">{{ len .TemplateData.AllVotes }} Total Votes</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
Loading…
Reference in New Issue
Block a user