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
|
||||
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 (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
@ -40,8 +41,24 @@ func handleAdmin(w http.ResponseWriter, req *http.Request) {
|
||||
handleAdminGames(w, req, page)
|
||||
case "clients":
|
||||
handleAdminClients(w, req, page)
|
||||
case "votes":
|
||||
handleAdminVotes(w, req, page)
|
||||
case "mode":
|
||||
handleAdminSetMode(w, req, page)
|
||||
default:
|
||||
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 {
|
||||
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 {
|
||||
@ -187,6 +203,11 @@ table.padding td {
|
||||
margin-left: 150px;
|
||||
}
|
||||
|
||||
aside.flash.error {
|
||||
background-color: #DD0000;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
aside.flash.success {
|
||||
background-color: #229af9;
|
||||
color: #FFFFFF;
|
||||
|
@ -1 +0,0 @@
|
||||
{"title":"ICT GameJam Voting","port":8080,"session":"ict-gamejam","dir":"./","devmode":true,"db":"gjvote.db","CurrentJam":""}
|
143
main.go
143
main.go
@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
//go:generate esc -o assets.go assets
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -21,15 +21,15 @@ import (
|
||||
)
|
||||
|
||||
const AppName = "gjvote"
|
||||
const DbName = AppName + ".db"
|
||||
|
||||
// SiteData is stuff that stays the same
|
||||
type siteData struct {
|
||||
Title string `json:"title"`
|
||||
Port int `json:"port"`
|
||||
SessionName string `json:"session"`
|
||||
ServerDir string `json:"dir"`
|
||||
DevMode bool `json:"devmode"`
|
||||
DB string `json:"db"`
|
||||
Title string
|
||||
Port int
|
||||
SessionName string
|
||||
ServerDir string
|
||||
DevMode bool
|
||||
|
||||
CurrentJam string
|
||||
}
|
||||
@ -56,6 +56,7 @@ type pageData struct {
|
||||
ClientIsServer bool
|
||||
TeamID string
|
||||
|
||||
PublicMode int
|
||||
TemplateData interface{}
|
||||
}
|
||||
|
||||
@ -70,19 +71,22 @@ var sessionSecret = "JCOP5e8ohkTcOzcSMe74"
|
||||
var sessionStore = sessions.NewCookieStore([]byte(sessionSecret))
|
||||
var site *siteData
|
||||
var r *mux.Router
|
||||
var configFile string
|
||||
|
||||
func main() {
|
||||
configFile = "./config.json"
|
||||
loadConfig()
|
||||
saveConfig()
|
||||
dbSaveSiteConfig(site)
|
||||
initialize()
|
||||
|
||||
r = mux.NewRouter()
|
||||
r.StrictSlash(true)
|
||||
|
||||
s := http.StripPrefix("/assets/", http.FileServer(http.Dir(site.ServerDir+"assets/")))
|
||||
r.PathPrefix("/assets/").Handler(s)
|
||||
if site.DevMode {
|
||||
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
|
||||
pub := r.PathPrefix("/").Subrouter()
|
||||
@ -109,25 +113,47 @@ func main() {
|
||||
}
|
||||
|
||||
func loadConfig() {
|
||||
site = new(siteData)
|
||||
// Defaults:
|
||||
site.Title = "ICT GameJam"
|
||||
site.Port = 8080
|
||||
site.SessionName = "ict-gamejam"
|
||||
site.ServerDir = "./"
|
||||
site.DevMode = false
|
||||
site.DB = AppName + ".db"
|
||||
site = dbGetSiteConfig()
|
||||
|
||||
jsonInp, err := ioutil.ReadFile(configFile)
|
||||
if err == nil {
|
||||
assertError(json.Unmarshal(jsonInp, &site))
|
||||
if len(os.Args) > 1 {
|
||||
for _, v := range os.Args {
|
||||
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() {
|
||||
@ -221,9 +247,10 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
||||
// Build the menu
|
||||
if p.LoggedIn {
|
||||
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{"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{"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.ClientIsAuth = clientIsAuthenticated(p.ClientID, req)
|
||||
p.ClientIsServer = clientIsServer(req)
|
||||
// TeamID is for team self-administration
|
||||
p.TeamID, _ = p.session.getStringValue("teamid")
|
||||
|
||||
// Public Mode
|
||||
p.PublicMode = dbGetPublicSiteMode()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
@ -265,6 +296,7 @@ func (p *pageData) show(tmplName string, w http.ResponseWriter) error {
|
||||
// outputTemplate
|
||||
// Spit out a template
|
||||
func outputTemplate(tmplName string, tmplData interface{}, w http.ResponseWriter) error {
|
||||
// TODO: Use embedded files for these... Hopefully?
|
||||
_, err := os.Stat("templates/" + tmplName)
|
||||
if err == nil {
|
||||
t := template.New(tmplName)
|
||||
@ -279,10 +311,53 @@ func redirect(url string, w http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(w, req, url, 303)
|
||||
}
|
||||
|
||||
func printOutput(out string) {
|
||||
if site.DevMode {
|
||||
fmt.Print(out)
|
||||
func resetToDefaults() {
|
||||
def := GetDefaultSiteConfig()
|
||||
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) {
|
||||
|
78
model.go
78
model.go
@ -10,11 +10,26 @@ import (
|
||||
var db *boltease.DB
|
||||
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 {
|
||||
dbOpened += 1
|
||||
if dbOpened == 1 {
|
||||
var err error
|
||||
db, err = boltease.Create(site.DB, 0600, nil)
|
||||
db, err = boltease.Create(DbName, 0600, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -82,3 +97,64 @@ func dbGetCurrentJam() (string, error) {
|
||||
}
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func initPublicPage(w http.ResponseWriter, req *http.Request) *pageData {
|
||||
p := InitPageData(w, req)
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func handleMain(w http.ResponseWriter, req *http.Request) {
|
||||
page := initPublicPage(w, req)
|
||||
page.SubTitle = ""
|
||||
|
||||
for _, tmpl := range []string{
|
||||
"htmlheader.html",
|
||||
"admin-menu.html",
|
||||
"header.html",
|
||||
"main.html",
|
||||
"footer.html",
|
||||
"htmlfooter.html",
|
||||
} {
|
||||
if err := outputTemplate(tmpl, page, w); err != nil {
|
||||
fmt.Printf("%s\n", err)
|
||||
}
|
||||
switch dbGetPublicSiteMode() {
|
||||
case SiteModeWaiting:
|
||||
page.show("public-waiting.html", w)
|
||||
case SiteModeVoting:
|
||||
page.show("public-voting.html", w)
|
||||
}
|
||||
}
|
||||
|
@ -5,45 +5,6 @@
|
||||
<label for="teamname">Team Name</label>
|
||||
<input id="teamname" name="teamname" type="text" placeholder="Team Name" value="" autofocus>
|
||||
</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>
|
||||
</fieldset>
|
||||
</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">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -17,12 +21,4 @@
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
<script>
|
||||
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>
|
||||
{{ end }}
|
||||
|
@ -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>
|
||||
<tr>
|
||||
<th>Game Name</th>
|
||||
<th>Team Name</th>
|
||||
<th>Screenshots</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range $i, $v := .TemplateData.Games }}
|
||||
<tr>
|
||||
<td>{{ $v.Name }}</td>
|
||||
<td></td>
|
||||
<td>{{ len $v.Screenshots }}</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
<script>
|
||||
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>
|
||||
{{ end }}
|
||||
|
@ -1,6 +1,14 @@
|
||||
<div class="content">
|
||||
<button onclick="window.location.href='/admin/votes'">Votes</button>
|
||||
<button onclick="window.location.href='/admin/teams'">Teams</button>
|
||||
<button onclick="window.location.href='/admin/games'">Games</button>
|
||||
<button onclick="window.location.href='/admin/users'">Users</button>
|
||||
<div>
|
||||
<h3>Public Mode</h3>
|
||||
<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/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>
|
||||
|
@ -1,6 +1,5 @@
|
||||
<div id="menu" class="{{if .HideAdminMenu}}hidden{{end}}">
|
||||
<div class="pure-menu">
|
||||
<a class="pure-menu-heading" href="/admin/">Admin</a>
|
||||
<a href="#menu" class="menu-button">
|
||||
<i class="fa fa-bars"></i>
|
||||
</a>
|
||||
@ -13,9 +12,7 @@
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ if .ClientIsAuth }}
|
||||
{{ if .ClientIsServer }}
|
||||
<span class="pure-menu-nonlink"><i class="fa fa-server"></i> Server Mode</span>
|
||||
{{ else }}
|
||||
{{ if not .ClientIsServer }}
|
||||
<a href="/admin/clients/{{.ClientID}}/remove" class="pure-menu-link"><i class="fa fa-key"></i> DeAuth Client</a>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
|
@ -1,12 +1,16 @@
|
||||
<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>
|
||||
</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>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Key</th>
|
||||
<th>Members</th>
|
||||
<th>Game</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -16,6 +20,7 @@
|
||||
<td>{{ $v.Name }}</td>
|
||||
<td>{{ $v.UUID }}</td>
|
||||
<td>{{ len $v.Members }}</td>
|
||||
<td>{{ $v.Game.Name }}</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 }}/delete" class="pure-button pure-button-plain"><i class="fa fa-trash"></i></a>
|
||||
@ -24,12 +29,4 @@
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
<script>
|
||||
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>
|
||||
{{ end }}
|
||||
|
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">
|
||||
devICT Game Jam - {{.CurrentJam}}
|
||||
</div>
|
||||
{{ if .SubTitle }}
|
||||
<div class="header-menu">
|
||||
<h2>{{.SubTitle}}</h2>
|
||||
</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