2017-06-22 Build
* Use 'https://github.com/mjibson/esc' for embedded assets * Pull database name out of siteData object * Load site config from database, if available * Allow customizing site config from command line arguments * Clean up some templates * Update Readme (it still needs a lot of updating) * Started work on vote accumulation/management
This commit is contained in:
parent
b283aacc6a
commit
ba35073d95
@ -1,2 +1,11 @@
|
|||||||
# ictgj-voting
|
# ictgj-voting
|
||||||
The ICT GameJam Voting Application
|
The ICT GameJam Voting Application
|
||||||
|
|
||||||
|
pass in the `-dev` flag to enable development mode (load assets from file system instead of embedded).
|
||||||
|
|
||||||
|
Uses 'esc' for embedding assets:
|
||||||
|
https://github.com/mjibson/esc
|
||||||
|
|
||||||
|
TODO: Build Instructions
|
||||||
|
|
||||||
|
TODO: Contribution Instructions
|
||||||
|
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
@ -40,8 +41,24 @@ func handleAdmin(w http.ResponseWriter, req *http.Request) {
|
|||||||
handleAdminGames(w, req, page)
|
handleAdminGames(w, req, page)
|
||||||
case "clients":
|
case "clients":
|
||||||
handleAdminClients(w, req, page)
|
handleAdminClients(w, req, page)
|
||||||
|
case "votes":
|
||||||
|
handleAdminVotes(w, req, page)
|
||||||
|
case "mode":
|
||||||
|
handleAdminSetMode(w, req, page)
|
||||||
default:
|
default:
|
||||||
page.show("admin-main.html", w)
|
page.show("admin-main.html", w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleAdminSetMode(w http.ResponseWriter, req *http.Request, page *pageData) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
newMode, err := strconv.Atoi(vars["id"])
|
||||||
|
if err != nil {
|
||||||
|
page.session.setFlashMessage("Invalid Mode: "+vars["id"], "error")
|
||||||
|
}
|
||||||
|
if dbSetPublicSiteMode(newMode) != nil {
|
||||||
|
page.session.setFlashMessage("Invalid Mode: "+vars["id"], "error")
|
||||||
|
}
|
||||||
|
redirect("/admin", w, req)
|
||||||
|
}
|
||||||
|
20
admin_votes.go
Normal file
20
admin_votes.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handleAdminVotes(w http.ResponseWriter, req *http.Request, page *pageData) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
page.SubTitle = "Votes"
|
||||||
|
switch vars["function"] {
|
||||||
|
default:
|
||||||
|
type votesPageData struct {
|
||||||
|
Votes []Vote
|
||||||
|
}
|
||||||
|
page.TemplateData = votesPageData{Votes: dbGetAllVotes()}
|
||||||
|
page.show("admin-votes.html", w)
|
||||||
|
}
|
||||||
|
}
|
@ -131,7 +131,23 @@ table.padding td {
|
|||||||
|
|
||||||
.pure-button-error {
|
.pure-button-error {
|
||||||
background-color: #DD0000;
|
background-color: #DD0000;
|
||||||
color: #FFFFFF;
|
color: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pure-button-toggle-first {
|
||||||
|
border-top-right-radius: 0px;
|
||||||
|
border-bottom-right-radius: 0px;
|
||||||
|
}
|
||||||
|
.pure-button-toggle-middle {
|
||||||
|
border-radius: 0px;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-left: 1px solid #CCC;
|
||||||
|
}
|
||||||
|
.pure-button-toggle-last {
|
||||||
|
border-top-left-radius: 0px;
|
||||||
|
border-bottom-left-radius: 0px;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-left: 1px solid #CCC;
|
||||||
}
|
}
|
||||||
|
|
||||||
#modal-overlay {
|
#modal-overlay {
|
||||||
@ -187,6 +203,11 @@ table.padding td {
|
|||||||
margin-left: 150px;
|
margin-left: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aside.flash.error {
|
||||||
|
background-color: #DD0000;
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
aside.flash.success {
|
aside.flash.success {
|
||||||
background-color: #229af9;
|
background-color: #229af9;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
|
@ -1 +0,0 @@
|
|||||||
{"title":"ICT GameJam Voting","port":8080,"session":"ict-gamejam","dir":"./","devmode":true,"db":"gjvote.db","CurrentJam":""}
|
|
141
main.go
141
main.go
@ -1,11 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
//go:generate esc -o assets.go assets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -21,15 +21,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const AppName = "gjvote"
|
const AppName = "gjvote"
|
||||||
|
const DbName = AppName + ".db"
|
||||||
|
|
||||||
// SiteData is stuff that stays the same
|
// SiteData is stuff that stays the same
|
||||||
type siteData struct {
|
type siteData struct {
|
||||||
Title string `json:"title"`
|
Title string
|
||||||
Port int `json:"port"`
|
Port int
|
||||||
SessionName string `json:"session"`
|
SessionName string
|
||||||
ServerDir string `json:"dir"`
|
ServerDir string
|
||||||
DevMode bool `json:"devmode"`
|
DevMode bool
|
||||||
DB string `json:"db"`
|
|
||||||
|
|
||||||
CurrentJam string
|
CurrentJam string
|
||||||
}
|
}
|
||||||
@ -56,6 +56,7 @@ type pageData struct {
|
|||||||
ClientIsServer bool
|
ClientIsServer bool
|
||||||
TeamID string
|
TeamID string
|
||||||
|
|
||||||
|
PublicMode int
|
||||||
TemplateData interface{}
|
TemplateData interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,19 +71,22 @@ var sessionSecret = "JCOP5e8ohkTcOzcSMe74"
|
|||||||
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
|
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
|
||||||
var site *siteData
|
var site *siteData
|
||||||
var r *mux.Router
|
var r *mux.Router
|
||||||
var configFile string
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
configFile = "./config.json"
|
|
||||||
loadConfig()
|
loadConfig()
|
||||||
saveConfig()
|
dbSaveSiteConfig(site)
|
||||||
initialize()
|
initialize()
|
||||||
|
|
||||||
r = mux.NewRouter()
|
r = mux.NewRouter()
|
||||||
r.StrictSlash(true)
|
r.StrictSlash(true)
|
||||||
|
|
||||||
s := http.StripPrefix("/assets/", http.FileServer(http.Dir(site.ServerDir+"assets/")))
|
if site.DevMode {
|
||||||
r.PathPrefix("/assets/").Handler(s)
|
fmt.Println("Operating in Development Mode")
|
||||||
|
}
|
||||||
|
//s := http.StripPrefix("/assets/", http.FileServer(FS(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()
|
||||||
@ -109,25 +113,47 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig() {
|
func loadConfig() {
|
||||||
site = new(siteData)
|
site = dbGetSiteConfig()
|
||||||
// Defaults:
|
|
||||||
site.Title = "ICT GameJam"
|
|
||||||
site.Port = 8080
|
|
||||||
site.SessionName = "ict-gamejam"
|
|
||||||
site.ServerDir = "./"
|
|
||||||
site.DevMode = false
|
|
||||||
site.DB = AppName + ".db"
|
|
||||||
|
|
||||||
jsonInp, err := ioutil.ReadFile(configFile)
|
if len(os.Args) > 1 {
|
||||||
if err == nil {
|
for _, v := range os.Args {
|
||||||
assertError(json.Unmarshal(jsonInp, &site))
|
key := v
|
||||||
|
val := ""
|
||||||
|
eqInd := strings.Index(v, "=")
|
||||||
|
if eqInd > 0 {
|
||||||
|
// It's a key/val argument
|
||||||
|
key = v[:eqInd]
|
||||||
|
val = v[eqInd+1:]
|
||||||
|
}
|
||||||
|
switch key {
|
||||||
|
case "-title":
|
||||||
|
site.Title = val
|
||||||
|
fmt.Print("Set site title: ", site.Title, "\n")
|
||||||
|
case "-port":
|
||||||
|
var tryPort int
|
||||||
|
var err error
|
||||||
|
if tryPort, err = strconv.Atoi(val); err != nil {
|
||||||
|
fmt.Print("Invalid port given: ", val, " (Must be an integer)\n")
|
||||||
|
tryPort = site.Port
|
||||||
|
}
|
||||||
|
// TODO: Make sure a valid port number is given
|
||||||
|
site.Port = tryPort
|
||||||
|
case "-session-name":
|
||||||
|
site.SessionName = val
|
||||||
|
case "-server-dir":
|
||||||
|
// TODO: Probably check if the given directory is valid
|
||||||
|
site.ServerDir = val
|
||||||
|
case "-help", "-h", "-?":
|
||||||
|
printHelp()
|
||||||
|
done()
|
||||||
|
case "-dev":
|
||||||
|
site.DevMode = true
|
||||||
|
case "-reset-defaults":
|
||||||
|
resetToDefaults()
|
||||||
|
done()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveConfig() {
|
|
||||||
var jsonInp []byte
|
|
||||||
jsonInp, _ = json.Marshal(site)
|
|
||||||
assertError(ioutil.WriteFile(configFile, jsonInp, 0644))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialize() {
|
func initialize() {
|
||||||
@ -221,9 +247,10 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
|||||||
// Build the menu
|
// Build the menu
|
||||||
if p.LoggedIn {
|
if p.LoggedIn {
|
||||||
p.Menu = append(p.Menu, menuItem{"Admin", "/admin", "fa-key"})
|
p.Menu = append(p.Menu, menuItem{"Admin", "/admin", "fa-key"})
|
||||||
p.Menu = append(p.Menu, menuItem{"Votes", "/admin/votes", "fa-sticky-note"})
|
|
||||||
p.Menu = append(p.Menu, menuItem{"Teams", "/admin/teams", "fa-users"})
|
p.Menu = append(p.Menu, menuItem{"Teams", "/admin/teams", "fa-users"})
|
||||||
p.Menu = append(p.Menu, menuItem{"Games", "/admin/games", "fa-gamepad"})
|
p.Menu = append(p.Menu, menuItem{"Games", "/admin/games", "fa-gamepad"})
|
||||||
|
p.Menu = append(p.Menu, menuItem{"Votes", "/admin/votes", "fa-sticky-note"})
|
||||||
|
p.Menu = append(p.Menu, menuItem{"Clients", "/admin/clients", "fa-desktop"})
|
||||||
|
|
||||||
p.BottomMenu = append(p.BottomMenu, menuItem{"Users", "/admin/users", "fa-user"})
|
p.BottomMenu = append(p.BottomMenu, menuItem{"Users", "/admin/users", "fa-user"})
|
||||||
p.BottomMenu = append(p.BottomMenu, menuItem{"Logout", "/admin/dologout", "fa-sign-out"})
|
p.BottomMenu = append(p.BottomMenu, menuItem{"Logout", "/admin/dologout", "fa-sign-out"})
|
||||||
@ -240,8 +267,12 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
|||||||
p.ClientID = p.session.getClientID()
|
p.ClientID = p.session.getClientID()
|
||||||
p.ClientIsAuth = clientIsAuthenticated(p.ClientID, req)
|
p.ClientIsAuth = clientIsAuthenticated(p.ClientID, req)
|
||||||
p.ClientIsServer = clientIsServer(req)
|
p.ClientIsServer = clientIsServer(req)
|
||||||
|
// TeamID is for team self-administration
|
||||||
p.TeamID, _ = p.session.getStringValue("teamid")
|
p.TeamID, _ = p.session.getStringValue("teamid")
|
||||||
|
|
||||||
|
// Public Mode
|
||||||
|
p.PublicMode = dbGetPublicSiteMode()
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,6 +296,7 @@ func (p *pageData) show(tmplName string, w http.ResponseWriter) error {
|
|||||||
// outputTemplate
|
// outputTemplate
|
||||||
// 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 {
|
||||||
|
// TODO: Use embedded files for these... Hopefully?
|
||||||
_, err := os.Stat("templates/" + tmplName)
|
_, err := os.Stat("templates/" + tmplName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t := template.New(tmplName)
|
t := template.New(tmplName)
|
||||||
@ -279,10 +311,53 @@ func redirect(url string, w http.ResponseWriter, req *http.Request) {
|
|||||||
http.Redirect(w, req, url, 303)
|
http.Redirect(w, req, url, 303)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printOutput(out string) {
|
func resetToDefaults() {
|
||||||
if site.DevMode {
|
def := GetDefaultSiteConfig()
|
||||||
fmt.Print(out)
|
fmt.Println("Reset settings to defaults?")
|
||||||
|
fmt.Print(site.Title, " -> ", def.Title, "\n")
|
||||||
|
fmt.Print(site.Port, " -> ", def.Port, "\n")
|
||||||
|
fmt.Print(site.SessionName, " -> ", def.SessionName, "\n")
|
||||||
|
fmt.Print(site.ServerDir, " -> ", def.ServerDir, "\n")
|
||||||
|
fmt.Println("Are you sure? (y/N): ")
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
conf, _ := reader.ReadString('\n')
|
||||||
|
conf = strings.ToUpper(strings.TrimSpace(conf))
|
||||||
|
if strings.HasPrefix(conf, "Y") {
|
||||||
|
if dbSaveSiteConfig(def) != nil {
|
||||||
|
errorExit("Error resetting to defaults")
|
||||||
}
|
}
|
||||||
|
fmt.Println("Reset to defaults")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHelp() {
|
||||||
|
help := []string{
|
||||||
|
"Game Jam Voting Help",
|
||||||
|
" -help, -h, -? Print this message",
|
||||||
|
" -dev Development mode, load assets from file system",
|
||||||
|
" -port=<port num> Set the site port",
|
||||||
|
" -session-name=<session> Set the name of the session to be used",
|
||||||
|
" -server-dir=<directory> Set the server directory",
|
||||||
|
" This designates where the database will be saved",
|
||||||
|
" and where the app will look for files if you're",
|
||||||
|
" operating in 'development' mode (-dev)",
|
||||||
|
" -title=<title> Set the site title",
|
||||||
|
" -current-jam=<name> Change the name of the current jam",
|
||||||
|
" -reset-defaults Reset all configuration options to defaults",
|
||||||
|
"",
|
||||||
|
}
|
||||||
|
for _, v := range help {
|
||||||
|
fmt.Println(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func done() {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorExit(msg string) {
|
||||||
|
fmt.Println(msg)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertError(err error) {
|
func assertError(err error) {
|
||||||
|
78
model.go
78
model.go
@ -10,11 +10,26 @@ import (
|
|||||||
var db *boltease.DB
|
var db *boltease.DB
|
||||||
var dbOpened int
|
var dbOpened int
|
||||||
|
|
||||||
|
const (
|
||||||
|
SiteModeWaiting = iota
|
||||||
|
SiteModeVoting
|
||||||
|
SiteModeError
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetDefaultSiteConfig() *siteData {
|
||||||
|
ret := new(siteData)
|
||||||
|
ret.Title = "ICT GameJam"
|
||||||
|
ret.Port = 8080
|
||||||
|
ret.SessionName = "ict-gamejam"
|
||||||
|
ret.ServerDir = "./"
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func openDatabase() error {
|
func openDatabase() error {
|
||||||
dbOpened += 1
|
dbOpened += 1
|
||||||
if dbOpened == 1 {
|
if dbOpened == 1 {
|
||||||
var err error
|
var err error
|
||||||
db, err = boltease.Create(site.DB, 0600, nil)
|
db, err = boltease.Create(DbName, 0600, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -82,3 +97,64 @@ func dbGetCurrentJam() (string, error) {
|
|||||||
}
|
}
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dbGetSiteConfig() *siteData {
|
||||||
|
var ret *siteData
|
||||||
|
def := GetDefaultSiteConfig()
|
||||||
|
var err error
|
||||||
|
if err = openDatabase(); err != nil {
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
defer closeDatabase()
|
||||||
|
|
||||||
|
ret = new(siteData)
|
||||||
|
siteConf := []string{"site"}
|
||||||
|
if ret.Title, err = db.GetValue(siteConf, "title"); err != nil {
|
||||||
|
ret.Title = def.Title
|
||||||
|
}
|
||||||
|
if ret.Port, err = db.GetInt(siteConf, "port"); err != nil {
|
||||||
|
ret.Port = def.Port
|
||||||
|
}
|
||||||
|
if ret.SessionName, err = db.GetValue(siteConf, "session-name"); err != nil {
|
||||||
|
ret.SessionName = def.SessionName
|
||||||
|
}
|
||||||
|
if ret.ServerDir, err = db.GetValue(siteConf, "server-dir"); err != nil {
|
||||||
|
ret.ServerDir = def.ServerDir
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbSaveSiteConfig(dat *siteData) error {
|
||||||
|
var err error
|
||||||
|
if err = openDatabase(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closeDatabase()
|
||||||
|
|
||||||
|
siteConf := []string{"site"}
|
||||||
|
if err = db.SetValue(siteConf, "title", dat.Title); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = db.SetInt(siteConf, "port", dat.Port); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = db.SetValue(siteConf, "session-name", dat.SessionName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return db.SetValue(siteConf, "server-dir", dat.ServerDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbGetPublicSiteMode() int {
|
||||||
|
if ret, err := db.GetInt([]string{"site"}, "public-mode"); err != nil {
|
||||||
|
return SiteModeWaiting
|
||||||
|
} else {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbSetPublicSiteMode(mode int) error {
|
||||||
|
if mode < 0 || mode >= SiteModeError {
|
||||||
|
return errors.New("Invalid site mode")
|
||||||
|
}
|
||||||
|
return db.SetInt([]string{"site"}, "public-mode", mode)
|
||||||
|
}
|
||||||
|
44
model_votes.go
Normal file
44
model_votes.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Vote struct {
|
||||||
|
Timestamp time.Time
|
||||||
|
ClientId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbGetAllVotes() []Vote {
|
||||||
|
var ret []Vote
|
||||||
|
var err error
|
||||||
|
if err = db.OpenDB(); err != nil {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
defer db.CloseDB()
|
||||||
|
|
||||||
|
votesBkt := []string{"votes"}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbGetVote(clientId string, timestamp time.Time) *Vote {
|
||||||
|
var err error
|
||||||
|
if err = db.OpenDB(); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer db.CloseDB()
|
||||||
|
|
||||||
|
vt := new(Vote)
|
||||||
|
|
||||||
|
return vt
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbSaveVote(clientId string, timestamp time.Time, votes []string) error {
|
||||||
|
var err error
|
||||||
|
if err = db.OpenDB(); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer db.CloseDB()
|
||||||
|
|
||||||
|
votesBkt := []string{"votes", clientId}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
@ -1,30 +1,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initPublicPage(w http.ResponseWriter, req *http.Request) *pageData {
|
func initPublicPage(w http.ResponseWriter, req *http.Request) *pageData {
|
||||||
p := InitPageData(w, req)
|
p := InitPageData(w, req)
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMain(w http.ResponseWriter, req *http.Request) {
|
func handleMain(w http.ResponseWriter, req *http.Request) {
|
||||||
page := initPublicPage(w, req)
|
page := initPublicPage(w, req)
|
||||||
page.SubTitle = ""
|
page.SubTitle = ""
|
||||||
|
switch dbGetPublicSiteMode() {
|
||||||
for _, tmpl := range []string{
|
case SiteModeWaiting:
|
||||||
"htmlheader.html",
|
page.show("public-waiting.html", w)
|
||||||
"admin-menu.html",
|
case SiteModeVoting:
|
||||||
"header.html",
|
page.show("public-voting.html", w)
|
||||||
"main.html",
|
|
||||||
"footer.html",
|
|
||||||
"htmlfooter.html",
|
|
||||||
} {
|
|
||||||
if err := outputTemplate(tmpl, page, w); err != nil {
|
|
||||||
fmt.Printf("%s\n", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,45 +5,6 @@
|
|||||||
<label for="teamname">Team Name</label>
|
<label for="teamname">Team Name</label>
|
||||||
<input id="teamname" name="teamname" type="text" placeholder="Team Name" value="" autofocus>
|
<input id="teamname" name="teamname" type="text" placeholder="Team Name" value="" autofocus>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Members</h2>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Slack ID</th>
|
|
||||||
<th>Twitter</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th></th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
<td>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="team-member">
|
|
||||||
<div class="pure-control-group">
|
|
||||||
<label for="membername">Name</label>
|
|
||||||
<input id="membername" name="membername" type="text" placeholder="Name" value="">
|
|
||||||
</div>
|
|
||||||
<div class="pure-control-group">
|
|
||||||
<label for="memberslackid">Slack ID</label>
|
|
||||||
<input id="memberslackid" name="memberslackid" type="text" placeholder="@SlackID" value="">
|
|
||||||
</div>
|
|
||||||
<div class="pure-control-group">
|
|
||||||
<label for="membertwitter">Twitter</label>
|
|
||||||
<input id="membertwitter" name="membertwitter" type="text" placeholder="@TwitterID" value="">
|
|
||||||
</div>
|
|
||||||
<div class="pure-control-group">
|
|
||||||
<label for="memberemail">Email</label>
|
|
||||||
<input id="memberemail" name="memberemail" type="text" placeholder="user@email.com" value="">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="pure-button pure-button-primary">Add Team</button>
|
<button type="submit" class="pure-button pure-button-primary">Add Team</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
<div>The hosting server is always an authenticated client</div>
|
||||||
|
{{ if not .TemplateData.Clients }}
|
||||||
|
<div>No additional clients have been authenticated</div>
|
||||||
|
{{ else }}
|
||||||
<table id="clients-table" class="hidden sortable pure-table pure-table-bordered center">
|
<table id="clients-table" class="hidden sortable pure-table pure-table-bordered center">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -17,12 +21,4 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<script>
|
{{ end }}
|
||||||
snack.ready(function() {
|
|
||||||
var tableBody = document.querySelector("#clients-table>tbody");
|
|
||||||
if(tableBody.children.length>0) {
|
|
||||||
// Show the table
|
|
||||||
document.getElementById('clients-table').classList.remove('hidden');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
<table id="games-table" class="hidden sortable pure-table pure-table-bordered center">
|
{{ if not .TemplateData.Games }}
|
||||||
|
<div>No games have been created</div>
|
||||||
|
{{ else }}
|
||||||
|
<table id="games-table" class="sortable pure-table pure-table-bordered center">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Game Name</th>
|
<th>Game Name</th>
|
||||||
|
<th>Team Name</th>
|
||||||
|
<th>Screenshots</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{ range $i, $v := .TemplateData.Games }}
|
{{ range $i, $v := .TemplateData.Games }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $v.Name }}</td>
|
<td>{{ $v.Name }}</td>
|
||||||
|
<td></td>
|
||||||
|
<td>{{ len $v.Screenshots }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<script>
|
{{ end }}
|
||||||
snack.ready(function() {
|
|
||||||
var tableBody = document.querySelector("#games-table>tbody");
|
|
||||||
if(tableBody.children.length>0) {
|
|
||||||
// Show the table
|
|
||||||
document.getElementById('games-table').classList.remove('hidden');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
<button onclick="window.location.href='/admin/votes'">Votes</button>
|
<div>
|
||||||
<button onclick="window.location.href='/admin/teams'">Teams</button>
|
<h3>Public Mode</h3>
|
||||||
<button onclick="window.location.href='/admin/games'">Games</button>
|
<button onclick="window.location.href='/admin/mode/0'" class="pure-button-toggle-first pure-button {{ if eq .PublicMode 0 }}pure-button-primary{{ end }}">Waiting</button>
|
||||||
<button onclick="window.location.href='/admin/users'">Users</button>
|
<button onclick="window.location.href='/admin/mode/1'" class="pure-button-toggle-last pure-button {{ if eq .PublicMode 1 }}pure-button-primary{{ end }}">Voting</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>Admin Sections</h3>
|
||||||
|
<button class="pure-button" onclick="window.location.href='/admin/votes'">Votes</button>
|
||||||
|
<button class="pure-button" onclick="window.location.href='/admin/teams'">Teams</button>
|
||||||
|
<button class="pure-button" onclick="window.location.href='/admin/games'">Games</button>
|
||||||
|
<button class="pure-button" onclick="window.location.href='/admin/users'">Users</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<div id="menu" class="{{if .HideAdminMenu}}hidden{{end}}">
|
<div id="menu" class="{{if .HideAdminMenu}}hidden{{end}}">
|
||||||
<div class="pure-menu">
|
<div class="pure-menu">
|
||||||
<a class="pure-menu-heading" href="/admin/">Admin</a>
|
|
||||||
<a href="#menu" class="menu-button">
|
<a href="#menu" class="menu-button">
|
||||||
<i class="fa fa-bars"></i>
|
<i class="fa fa-bars"></i>
|
||||||
</a>
|
</a>
|
||||||
@ -13,9 +12,7 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
{{ if .ClientIsAuth }}
|
{{ if .ClientIsAuth }}
|
||||||
{{ if .ClientIsServer }}
|
{{ if not .ClientIsServer }}
|
||||||
<span class="pure-menu-nonlink"><i class="fa fa-server"></i> Server Mode</span>
|
|
||||||
{{ else }}
|
|
||||||
<a href="/admin/clients/{{.ClientID}}/remove" class="pure-menu-link"><i class="fa fa-key"></i> DeAuth Client</a>
|
<a href="/admin/clients/{{.ClientID}}/remove" class="pure-menu-link"><i class="fa fa-key"></i> DeAuth Client</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
<div class="bottom-space center">
|
<div class="bottom-space center">
|
||||||
<a id="btnAddTeam" class="pure-button pure-button-success" href="/admin/teams/new"><i class="fa fa-plus"></i> Add Team</a>
|
<a id="btnAddTeam" class="pure-button pure-button-success" href="/admin/teams/new"><i class="fa fa-plus"></i> Add Team</a>
|
||||||
</div>
|
</div>
|
||||||
<table id="teams-table" class="hidden sortable pure-table pure-table-bordered center">
|
{{ if not .TemplateData.Teams }}
|
||||||
|
<div>No teams have been created</div>
|
||||||
|
{{ else }}
|
||||||
|
<table id="teams-table" class="sortable pure-table pure-table-bordered center">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Key</th>
|
<th>Key</th>
|
||||||
<th>Members</th>
|
<th>Members</th>
|
||||||
|
<th>Game</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -16,6 +20,7 @@
|
|||||||
<td>{{ $v.Name }}</td>
|
<td>{{ $v.Name }}</td>
|
||||||
<td>{{ $v.UUID }}</td>
|
<td>{{ $v.UUID }}</td>
|
||||||
<td>{{ len $v.Members }}</td>
|
<td>{{ len $v.Members }}</td>
|
||||||
|
<td>{{ $v.Game.Name }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/admin/teams/{{ $v.UUID }}/edit" class="pure-button pure-button-plain"><i class="fa fa-pencil"></i></a>
|
<a href="/admin/teams/{{ $v.UUID }}/edit" class="pure-button pure-button-plain"><i class="fa fa-pencil"></i></a>
|
||||||
<a href="/admin/teams/{{ $v.UUID }}/delete" class="pure-button pure-button-plain"><i class="fa fa-trash"></i></a>
|
<a href="/admin/teams/{{ $v.UUID }}/delete" class="pure-button pure-button-plain"><i class="fa fa-trash"></i></a>
|
||||||
@ -24,12 +29,4 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<script>
|
{{ end }}
|
||||||
snack.ready(function() {
|
|
||||||
var tableBody = document.querySelector("#teams-table>tbody");
|
|
||||||
if(tableBody.children.length>0) {
|
|
||||||
// Show the table
|
|
||||||
document.getElementById('teams-table').classList.remove('hidden');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
14
templates/admin-votes.html
Normal file
14
templates/admin-votes.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<table id="votes-table" class="sortable pure-table pure-table-bordered center">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{ range $i, $v, := .TemplateData.Votes }}
|
||||||
|
<tr>
|
||||||
|
<td>{{ $v.Timestamp }}</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
@ -8,6 +8,8 @@ var clientID = "{{.ClientID}}";
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
devICT Game Jam - {{.CurrentJam}}
|
devICT Game Jam - {{.CurrentJam}}
|
||||||
</div>
|
</div>
|
||||||
|
{{ if .SubTitle }}
|
||||||
<div class="header-menu">
|
<div class="header-menu">
|
||||||
<h2>{{.SubTitle}}</h2>
|
<h2>{{.SubTitle}}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<div>Default Public Facing Page</div>
|
|
1
templates/public-voting.html
Normal file
1
templates/public-voting.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<h1>VOTING TIME</h1>
|
1
templates/public-waiting.html
Normal file
1
templates/public-waiting.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<div>ICT Game Jam</div>
|
Loading…
Reference in New Issue
Block a user