diff --git a/admin_games.go b/admin_games.go
index 72b6e5f..0c5dda4 100644
--- a/admin_games.go
+++ b/admin_games.go
@@ -15,21 +15,11 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData)
teamId := vars["id"]
if teamId == "" {
// Games List
- type gamePage struct {
- Game *Game
- Team *Team
- }
type gamesPageData struct {
- Games []gamePage
+ Teams []Team
}
gpd := new(gamesPageData)
- allGames := dbGetAllGames()
- for _, gm := range allGames {
- gamePage := new(gamePage)
- gamePage.Game = &gm
- gamePage.Team = dbGetTeam(gm.TeamId)
- gpd.Games = append(gpd.Games, *gamePage)
- }
+ gpd.Teams = dbGetAllTeams()
page.TemplateData = gpd
page.SubTitle = "Games"
page.show("admin-games.html", w)
diff --git a/assets.go b/assets.go
index 5e9b6ea..e8b6b55 100644
--- a/assets.go
+++ b/assets.go
@@ -192,35 +192,38 @@ var _escData = map[string]*_escFile{
"/assets/css/admin.css": {
local: "assets/css/admin.css",
- size: 83,
- modtime: 1497482098,
+ size: 121,
+ modtime: 1498145831,
compressed: `
-H4sIAAAAAAAA/0rJLNNLzs8rSc0rUajmUlDITSxKz8zTzUlNK7FSMDQ1KKiw5qrl4gIpS8ovKcnP1S0u
-SExORVYLEQephigGBAAA//8E7lAbUwAAAA==
+H4sIAAAAAAAA/0zKQQoCMQwAwHtekQ/sogcv62u6NdZAk5Q0FUH8u1Q9eB3mwvc1mwZp4BMQJXlhXSpd
+Y8Pj6dAeZ3gBzLZbhMnSW8r0f78+9y+zlDVuQ3ZNXD8zD+/mGzZjDfK53gEAAP//D/6XxHkAAAA=
`,
},
"/assets/css/gjvote.css": {
local: "assets/css/gjvote.css",
- size: 2862,
- modtime: 1497542484,
+ size: 3710,
+ modtime: 1498849329,
compressed: `
-H4sIAAAAAAAA/6xW22rkOBB9768QNAsJrIydSU8SB4Z9mOx/yFa1XUSWjCR3O7Pk3xdd7PY17MI0/WCX
-6nKqdKrKtW0E+edASIOS1oBVbXOSpekfr4fPw6FQ/MOflkoonZPj09PTa1SGusKZMsdLUippQVpv0zLO
-UVY5yU5t/7oZYnRcCFa+ey9JDYyDDpiYrlBSAWebk9Qfo2w7m5xRwDxGcoKGJN+hcU45mlawj5ygFCiB
-FkI574QUSnPQOcnanhglkJNjWZbhpKemZlxdnZUBS1Kv9a3tyZFzfrOmmnHsTE4eXVafh8OxAdl5NFfk
-tr7lNuT6mIb8W2XQopI50SCYxQt4r6x8r7TqJM/JMXvJnrNnJ75C8Y6Wqgvos1BXakqthPC5WtWV9SR0
-0nYaqHukrngoK49mpwpbZlI5lfetq55XOFsUeKyshd5SDqXSLKQolfTpXWu0QE3LSnDCq2btFIMPX3TW
-KrkFel42VhglOuulVrU5iYXVoc7xLbLGK2RzmR7IF6QxVQ/xiyQcKwNOZa1qZld9iq4iN0LQkV3R8yJd
-1yQMZST5mPFQse185zn6OAOvbgyiw+UNPNqL/KMLXf+1qevoWmn85cxEpKC3G2nZ5ySIQ3c2VWLrrikk
-Q7FoiYB10v+xfW4Ge4UZSTYaP+xn/vb2FtxG4s7HxGkI6gk5GTLLI2qQg1lPodMWn0bTAiu69pyNqTof
-/sgzjQmsZE6c0B0n3tvq2Ev9eQnSxtpMFYI4BAjPlMVr2lIj5ALaYsnE+mRAzDqrvEPLCgFDYMu/ih1U
-h6pH3XXh/dAJDU9Ba6X3ePjzZ5qm6aRNj3/7XyS14kz46ShYWFEXNFigQPuRkxo5B7nfTHGjTHopPu9M
-8OF9u56/KEoOvVdLt2mpq4LdpX+S+E9O9xtp/OB4mTbNKZ1Nr9g08XI2a+bLs7nmBmTzFTYMwtWq3rnj
-vxrgyMid2+QR5GMKzb1HfduD6/G4LuX0as7Yg9+wn4fRz2ozbEzKlfo4QBYGKNEiE68zbBGId7Ka71sp
-bABeUMkV2LkYBcH55JNmMU5G716RuaGTnAUz9f9STkxXlmBMNNogxsPDCzu/BIjLdhpQTr/d9iPfWGBK
-DSAJk5zcNayPhPh2ch8K93GCX0K/O9daCepQtUSwAkQyyPxbDLoei/8l5PdHFzAIJ8R8/v0w/g0AAP//
-ePEOly4LAAA=
+H4sIAAAAAAAA/6xX62rrOBD+36cQhIVTWBmnpzltHDgs9LTvIVuKPUSWjCQnaZe++6KLHcuWuxcW+iOW
+5vLNzDczamNajv68Q6gFgRsGdWMKtM3z3w53n3d3paTv7raSXKoCbZ6eng5BmDU1RMLESRp2NZiySipi
+QIoCCSmYu6dwziopDBPGSXaEUhB1gba77npIQhgdl5xUp9FKQ/jRmbgANU2BdgFB1jBCmfLxEFWDwJwd
+TYFyf90paImKI8rzp2f2FN3jsnYiJalOtZK9oDghDaLrTXYEzuJosh1rUfaDtRY+Bd1x8l4gEBwEwyWX
+Ng6ESqkoUwXadlekJQeKNlVV+Zsr1g2h8mK1NDMod1LfuyvaUEpv2lgRCr0u0KPN3whJEXECUWP3FafJ
+53mmvZueRoheXl4OQ0kJh1oUqGLCMOXJ0RsjRab7sgWDz9LYRFgUWSvPDEMlhc90r7RNntBYMQ0fng2b
+lol+im6o+MCAx4C2kxo8kxTjxMCZHaLaFGiz3W+ft8/2+MLKExgsz0wdubxgXSnJuauLkX3VTFxnXa8Y
+tj+xpQ0IX/SViqXUhLQip1SDxGzYzsgwsmClWRC6NGAY1h2pmD28KNJNMTj3Pv8p0HHaSKkl7407NbIr
+UEis8nkOX6FfnMA2PlNDS/rTEKqD+EUQtqE8TmmMbKNSz5jonY68C5Zn4drRQUCE9h4jHjKWjjeO0fkZ
+eJXo7oFHa55/9nxtMExU3YSSCj6sGg8UdHojLa8F8se+bds6M03floKAF5xMwdDaN4G1RIykGpUf1iN9
+fX0NI88TNR5hu8GpI+BknM6vsAbK9HLe7lL8mamemTJQET7VdgWKlT17Jtol1HiJazsmyiK4baIwtuyh
+vc4clsW1O3X3fr4tBCZjL4hgEoqaEkNoiG55MyAmvZHOoCElZ4NjQ7/y7UWHmgXZZdnciPLjATOlpFpj
+7a9feZ7nk6bevL29LW0YWdec4SMo7XN361tf3HGXxH3ta5cS+Uw6aIHSsE5nOyoeSJ5keBs584fz7ZV2
+xMkyEKv/dRwpif+CKIJUUNC2qnStRmEJD5/7/T4MKEkJd5uOE/+kOYOGEjiY9wI1QCkT64MxvIsmczH8
+XtnGw3ea7R8YBGVXJ5anR46qS/It/x2Fv2x3nwjjJ4Vz/GKJ0hwGYmidZLYcf5OPmQFZTKxhqS0eoysd
++EfLKBD0zb5VA8jHnLX3DvXtTbNcdctUTktzhCtzL7vPu9HOYssntt5CfFwOMwUQYIDwQ4QtAHFGFrs6
+FUIC8IxKNsF+YIcDb3zyMJ/1zGjdCRK7ULIjJ7r5V8LZbcz9zaCLRl1gy8Ka7quKab1u7+FhT477L+1F
+/+usx3HjlK4UYwIRQdG3llwDvb7v7BPyPuz6sx8d1rSSHFtUHeKkZDwbztxXcLpcgf/E5Y9H69AfTmj+
+/P/D+CsAAP//kMgK/X4OAAA=
`,
},
@@ -315,22 +318,22 @@ H4sIAAAAAAAA/0rOzyvOz0nVy8lP11DydA5RcE/MTfVKzFVwTMnNzFPStOYCBAAA//8imS6KIgAAAA==
"/assets/js/gjvote.js": {
local: "assets/js/gjvote.js",
- size: 2430,
- modtime: 1497536571,
+ size: 2455,
+ modtime: 1498145831,
compressed: `
-H4sIAAAAAAAA/6RWT2+rOBC/8ylG6cGgtGi1l5XComq3W2lXaquV2ttqDwRPwiiOnYcNeajNd3+yDYSk
-IUn1emiL5/cHz4zHLCqZG1ISjFouBf7B1yT/zSSKMIL3AICrvFqjNPG3CsvmFQXmRpUhu1mjrFgU5yLT
-+om0ib1AyAriHCWLkmAXBEHPV3KFDVdbCSl0piHWxttgbSB1vz8+YEuSq22MNUqTBAB1VgLpR51nG7Ts
-TGi067QIJytsJkASeiUYQq1BvMIG0hQmfnViHY6WJ5GV2wEKjeMiD4qjZfz6m4f7N+iAnfvnPHrwLgj6
-XOtCbZ8Vz0SoNnZBe7Ld59ouQ7rP+xLNo0D775/NPzxkDnCnaixF1jAnfgFryAhkUUxSYvmG322mO+PY
-BaP7g8fZZHKFrK7mZ5W7+F68W2n1adFj54o3XQIv2FrokeVQZVDII/0XxfFrHtlmg5I/FCT4Z6VBC/Sx
-ypi+mAALVYaudSGFXxIg+B2OkLFAuTRFAjSddizfBnMjk/bxs8F/9H9M+rWar8nsaWBJw87JS8wMttsL
-mXZ43zH256DdL9OzAbP9e+K1XH2HXXAcS9NKclyQRB7dMzYbwyXjHkWJixELGzp0uDlpYXFnHHJB+WrE
-wsUOPPppFr3vTpk5xlm3TOtRt0zrK3LmcGc8NkqTGz2nbbrwoVNJy8KctOvwSRD0veOP5N9vz0/DIzlS
-VovveuUabFvzC6W0SJeJl2xtlZneZDnCpirxzlOATceyN2Wng/u9ehMts3wVC9IGJZZhf3zepeI4mxt5
-C+7mmjFXeLa77SFjzdEC+gN2aTx5+tGEmhvZCuza0eTQsTaNwLgmTXMSZBqbF/ckkCUH11JBHP219HP3
-0bhv+23w1UurbSp2DXF4Pxzw3Fj1mfuL6stb6rMcAGwLEhju2fGCSm1c3rsBPAiWuFY1tlU5yek+CX4E
-AAD///kqVXt+CQAA
+H4sIAAAAAAAA/6RWT0/jOhC/51OMysGJChF6lye1L0Lv8ZB2JUArwW21hzSeNqO6djd20o2g331lO0nT
+0rRFywGI5/cnnhl7Mi9lZkhJMGqxEPgvX5H8lkoUYQRvAQBXWblCaeKfJRb1CwrMjCpCdrVCWbIozkSq
+9SNpE3uBkOXEOUoWTYNtEAQdX8kl1lxtJCTQmoZYGW+DlYHE/X5/hw1JrjYxVijNNACo0gJIP+gsXaNl
+p0KjXad5OFpiPQKS0ClBH2oN4iXWkCQw8qsj63CwPIqs3BZQaBwWuVccLeOvvz3cv0ELbN0/5tGDt0HQ
+5VrnavOkeCpCtbYL2pPtPld2GZJd3hdoHgTaf/+rv/KQOcCNqrAQac2c+BmsISOQRTFJicUr/rKZbo1j
+F4zu9h4no9EFsrqcnVRu4zvxdqXRp3mHnSletwk8Y2uhB5Z9lV4hD/SfFcfPeaTrNUp+n5PgH5V6LdDF
+SmO6YgLMVRG61oUEbqdA8A8cIGOBcmHyKdB43LJ8G8yMnDaPHw2+04+Y9Es5W5HZ0cCS+p2TFZgabLYX
+Mu3wvmPsz167n6enPWbz98hrufr2u+AwliSl5DgniTy6Y2wyhJsOe+QFzgcsbGjf4eqohcWdcMgEZcsB
+Cxfb8+hus+hte8zMMU66pVoPuqVaX5AzhzvhsVaa3NVz3KYN7zsVtMjNUbsWPw2Crnf8kfzy+vTYP5ID
+ZbX4tlcuwTY1P1NKi3SZeE5XVpnpdZohrMsCbzwF2Hgoe2N2PLjbqzfRMs2WsSBtUGIRdsfnTSqOk5mR
+1+Am14S5wrPtdQcZao4G0B2wc9eTpx/cUDMjG4FtczU5dKxNLTCuSNOMBJna5sU9CWQW30xbnRVKiFcV
+3l7DrR/e3bzKiaOfV382qIZfqPlo+Ow0a7qNXULsD449nrtvfUr/p+r8lrr02+TlJDDcseM5Fdq4grQ3
+cy9Y4EpV2JTrKKf9VvgdAAD//3s8PKeXCQAA
`,
},
diff --git a/assets/css/gjvote.css b/assets/css/gjvote.css
index 4460bbf..d7fe0fc 100644
--- a/assets/css/gjvote.css
+++ b/assets/css/gjvote.css
@@ -7,16 +7,32 @@ body {
min-ehgiht: 100%;
}
+a {
+ text-decoration: none;
+}
+
div.content {
padding: 15px;
min-height: 100%;
color: black;
}
+div.half {
+ width: 50%;
+}
+
.header {
margin-left: 0;
}
+.primary {
+ color: #0078e7;
+}
+
+.primary-bg {
+ background-color: #0078e7;
+}
+
input.file {
padding: .5em .6em;
display: inline-block;
@@ -25,6 +41,20 @@ input.file {
border-radius: 4px;
}
+input.ranking-input {
+ width: 50px;
+ border-radius: 5px;
+ border: 1px solid #CCC;
+ text-align: center;
+}
+
+button.submit-vote {
+}
+
+i.move-icon {
+ cursor: ns-resize;
+}
+
#menu {
width: 100%;
height: 40px;
@@ -100,6 +130,11 @@ img.thumbnail {
margin-right: 5px;
}
+.space-vertical {
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+
.big-space {
margin: 10px;
}
@@ -139,16 +174,21 @@ table.padding td {
}
.pure-button-toggle-middle {
border-radius: 0px;
- margin-left: -5px;
+ margin-left: -1px;
border-left: 1px solid #CCC;
}
.pure-button-toggle-last {
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
- margin-left: -5px;
+ margin-left: -1px;
border-left: 1px solid #CCC;
}
+.pure-button:disabled {
+ background-color: #CCC;
+ color: #999;
+}
+
#modal-overlay {
visibility: hidden;
position: absolute;
diff --git a/main.go b/main.go
index cc70594..4648c83 100644
--- a/main.go
+++ b/main.go
@@ -51,7 +51,7 @@ type pageData struct {
HideAdminMenu bool
session *pageSession
CurrentJam string
- ClientID string
+ ClientId string
ClientIsAuth bool
ClientIsServer bool
TeamID string
@@ -91,6 +91,7 @@ func main() {
// Public Subrouter
pub := r.PathPrefix("/").Subrouter()
pub.HandleFunc("/", handleMain)
+ pub.HandleFunc("/vote", handlePublicSaveVote)
// API Subrouter
//api := r.PathPrefix("/api").Subtrouter()
@@ -265,8 +266,8 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
p.FlashClass = "error"
}
- p.ClientID = p.session.getClientID()
- p.ClientIsAuth = clientIsAuthenticated(p.ClientID, req)
+ p.ClientId = p.session.getClientId()
+ p.ClientIsAuth = clientIsAuthenticated(p.ClientId, req)
p.ClientIsServer = clientIsServer(req)
// TeamID is for team self-administration
p.TeamID, _ = p.session.getStringValue("teamid")
diff --git a/model_teams.go b/model_teams.go
index 1e89ad2..e116337 100644
--- a/model_teams.go
+++ b/model_teams.go
@@ -2,7 +2,6 @@ package main
import (
"errors"
- "fmt"
"github.com/pborman/uuid"
)
@@ -217,10 +216,8 @@ func dbGetTeamMembers(teamid string) ([]TeamMember, error) {
ret = append(ret, *mbr)
}
}
- } else {
- fmt.Println(err.Error())
}
- return ret, nil
+ return ret, err
}
func dbGetTeamMember(teamid, mbrid string) (*TeamMember, error) {
diff --git a/model_votes.go b/model_votes.go
index bf6e29c..5b30e7a 100644
--- a/model_votes.go
+++ b/model_votes.go
@@ -1,10 +1,21 @@
package main
-import "time"
+import (
+ "strconv"
+ "time"
+)
+// A Choice is a ranking of a game in a vote
+type GameChoice struct {
+ Team string // UUID of team
+ Rank int
+}
+
+// A Vote is a collection of game rankings
type Vote struct {
Timestamp time.Time
- ClientId string
+ ClientId string // UUID of client
+ Choices []GameChoice
}
func dbGetAllVotes() []Vote {
@@ -16,19 +27,70 @@ func dbGetAllVotes() []Vote {
defer db.CloseDB()
votesBkt := []string{"votes"}
+ var clients []string
+ if clients, err = db.GetBucketList(votesBkt); err != nil {
+ // Couldn't get the list of clients
+ return ret
+ }
+ for _, clid := range clients {
+ ret = append(ret, dbGetClientVotes(clid)...)
+ }
return ret
}
-func dbGetVote(clientId string, timestamp time.Time) *Vote {
+func dbGetClientVotes(clientId string) []Vote {
+ var ret []Vote
var err error
if err = db.OpenDB(); err != nil {
- return nil
+ return ret
+ }
+ defer db.CloseDB()
+
+ var times []string
+ votesBkt := []string{"votes", clientId}
+ if times, err = db.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 = dbGetVote(clientId, tm); err == nil {
+ ret = append(ret, *vt)
+ }
+ }
+ }
+ return ret
+}
+
+func dbGetVote(clientId string, timestamp time.Time) (*Vote, error) {
+ var err error
+ if err = db.OpenDB(); err != nil {
+ return nil, err
}
defer db.CloseDB()
vt := new(Vote)
-
- return vt
+ vt.Timestamp = timestamp
+ vt.ClientId = clientId
+ votesBkt := []string{"votes", clientId, timestamp.Format(time.RFC3339)}
+ var choices []string
+ if choices, err = db.GetBucketList(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.GetValue(votesBkt, v)
+ }
+ if err == nil {
+ vt.Choices = append(vt.Choices, *ch)
+ }
+ }
+ return vt, nil
}
func dbSaveVote(clientId string, timestamp time.Time, votes []string) error {
@@ -37,8 +99,10 @@ func dbSaveVote(clientId string, timestamp time.Time, votes []string) error {
return nil
}
defer db.CloseDB()
-
- votesBkt := []string{"votes", clientId}
-
+ // Make sure we don't clobber a duplicate vote
+ votesBkt := []string{"votes", clientId, timestamp.Format(time.RFC3339)}
+ for i := range votes {
+ db.SetValue(votesBkt, strconv.Itoa(i), votes[i])
+ }
return err
}
diff --git a/page_session.go b/page_session.go
index c4e33ab..f3f787a 100644
--- a/page_session.go
+++ b/page_session.go
@@ -31,7 +31,7 @@ func (p *pageSession) setStringValue(key, val string) {
p.session.Save(p.req, p.w)
}
-func (p *pageSession) getClientID() string {
+func (p *pageSession) getClientId() string {
var clientId string
var err error
if clientId, err = p.getStringValue("client_id"); err != nil {
diff --git a/public_endpoints.go b/public_endpoints.go
index c5f6299..4bf62e5 100644
--- a/public_endpoints.go
+++ b/public_endpoints.go
@@ -2,6 +2,8 @@ package main
import (
"net/http"
+ "strings"
+ "time"
)
func initPublicPage(w http.ResponseWriter, req *http.Request) *pageData {
@@ -16,6 +18,44 @@ func handleMain(w http.ResponseWriter, req *http.Request) {
case SiteModeWaiting:
page.show("public-waiting.html", w)
case SiteModeVoting:
- page.show("public-voting.html", w)
+ loadVotingPage(w, req)
}
}
+
+func loadVotingPage(w http.ResponseWriter, req *http.Request) {
+ page := initPublicPage(w, req)
+ type votingPageData struct {
+ Teams []Team
+ Timestamp string
+ }
+ vpd := new(votingPageData)
+ vpd.Teams = dbGetAllTeams()
+ vpd.Timestamp = time.Now().Format(time.RFC3339)
+ page.TemplateData = vpd
+ page.show("public-voting.html", w)
+}
+
+func handlePublicSaveVote(w http.ResponseWriter, req *http.Request) {
+ page := initPublicPage(w, req)
+ page.SubTitle = ""
+
+ // Check if we already have a vote for this client id/timestamp
+ ts := req.FormValue("timestamp")
+ timestamp, err := time.Parse(time.RFC3339, ts)
+ if err != nil {
+ page.session.setFlashMessage("Error parsing timestamp: "+ts, "error")
+ redirect("/", w, req)
+ }
+ if _, err := dbGetVote(page.ClientId, timestamp); err == nil {
+ // Duplicate vote... Cancel it.
+ page.session.setFlashMessage("Duplicate vote!", "error")
+ redirect("/", w, req)
+ }
+ // voteSlice is an ordered string slice of the voters preferences
+ voteCSV := req.FormValue("uservote")
+ voteSlice := strings.Split(voteCSV, ",")
+ if err := dbSaveVote(page.ClientId, timestamp, voteSlice); err != nil {
+ page.session.setFlashMessage("Error Saving Vote: "+err.Error(), "error")
+ }
+ redirect("/", w, req)
+}
diff --git a/templates/admin-games.html b/templates/admin-games.html
index c00ed01..dfdb7fe 100644
--- a/templates/admin-games.html
+++ b/templates/admin-games.html
@@ -1,4 +1,4 @@
-{{ if not .TemplateData.Games }}
+{{ if not .TemplateData.Teams }}
No games have been created
{{ else }}
@@ -10,11 +10,11 @@
- {{ range $i, $v := .TemplateData.Games }}
+ {{ range $i, $v := .TemplateData.Teams }}
+ {{ $v.Game.Name }} |
{{ $v.Name }} |
- |
- {{ len $v.Screenshots }} |
+ {{ len $v.Game.Screenshots }} |
{{ end }}
diff --git a/templates/admin-menu.html b/templates/admin-menu.html
index b1fa816..0c3a25f 100644
--- a/templates/admin-menu.html
+++ b/templates/admin-menu.html
@@ -13,10 +13,10 @@
{{ if .ClientIsAuth }}
{{ if not .ClientIsServer }}
-
+
{{ end }}
{{ else }}
-
+
{{ end }}