Working on editing team games
This commit is contained in:
		@@ -55,3 +55,31 @@ func handleAdminClients(w http.ResponseWriter, req *http.Request, page *pageData
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func clientIsAuthenticated(cid string, req *http.Request) bool {
 | 
			
		||||
	return clientIsServer(req) || dbClientIsAuth(cid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func clientIsServer(req *http.Request) bool {
 | 
			
		||||
	clientIp, _, _ := net.SplitHostPort(req.RemoteAddr)
 | 
			
		||||
	ifaces, err := net.Interfaces()
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		for _, i := range ifaces {
 | 
			
		||||
			if addrs, err := i.Addrs(); err == nil {
 | 
			
		||||
				for _, addr := range addrs {
 | 
			
		||||
					var ip net.IP
 | 
			
		||||
					switch v := addr.(type) {
 | 
			
		||||
					case *net.IPNet:
 | 
			
		||||
						ip = v.IP
 | 
			
		||||
					case *net.IPAddr:
 | 
			
		||||
						ip = v.IP
 | 
			
		||||
					}
 | 
			
		||||
					if clientIp == ip.String() {
 | 
			
		||||
						return true
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,12 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"mime/multipart"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
)
 | 
			
		||||
@@ -10,23 +14,63 @@ import (
 | 
			
		||||
func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData) {
 | 
			
		||||
	vars := mux.Vars(req)
 | 
			
		||||
	page.SubTitle = "Games"
 | 
			
		||||
	gameId := vars["id"]
 | 
			
		||||
	teamId := req.FormValue("teamid")
 | 
			
		||||
	if strings.TrimSpace(teamId) != "" {
 | 
			
		||||
		page.session.setStringValue("teamid", teamId)
 | 
			
		||||
		page.TeamID = teamId
 | 
			
		||||
	}
 | 
			
		||||
	if gameId == "new" {
 | 
			
		||||
	teamId := vars["id"]
 | 
			
		||||
	if teamId == "" {
 | 
			
		||||
		// Games List
 | 
			
		||||
		type gamesPageData struct {
 | 
			
		||||
			Games []Game
 | 
			
		||||
		}
 | 
			
		||||
		page.TemplateData = gamesPageData{Games: dbGetAllGames()}
 | 
			
		||||
		page.SubTitle = "Games"
 | 
			
		||||
		page.show("admin-games.html", w)
 | 
			
		||||
	} else {
 | 
			
		||||
		switch vars["function"] {
 | 
			
		||||
		case "save":
 | 
			
		||||
			name := req.FormValue("gamename")
 | 
			
		||||
			desc := req.FormValue("gamedesc")
 | 
			
		||||
			if dbIsValidTeam(teamId) {
 | 
			
		||||
				if dbEditTeamGame(teamId, name) != nil {
 | 
			
		||||
				if err := dbUpdateTeamGame(teamId, name, desc); err != nil {
 | 
			
		||||
					page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
 | 
			
		||||
				} else {
 | 
			
		||||
					page.session.setFlashMessage("Team game updated", "success")
 | 
			
		||||
				}
 | 
			
		||||
				redirect("/admin/teams/"+teamId, w, req)
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			page.SubTitle = "Add New Game"
 | 
			
		||||
			page.show("admin-addgame.html", w)
 | 
			
		||||
		case "screenshotupload":
 | 
			
		||||
			if err := saveScreenshots(teamId, req); err != nil {
 | 
			
		||||
				page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
 | 
			
		||||
			}
 | 
			
		||||
			redirect("/admin/teams/"+teamId, w, req)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func saveScreenshots(teamId string, req *http.Request) error {
 | 
			
		||||
	err := req.ParseMultipartForm((1 << 10) * 24)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, fheaders := range req.MultipartForm.File {
 | 
			
		||||
		for _, hdr := range fheaders {
 | 
			
		||||
			// open uploaded
 | 
			
		||||
			var infile multipart.File
 | 
			
		||||
			if infile, err = hdr.Open(); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// open destination
 | 
			
		||||
			var outfile *os.File
 | 
			
		||||
			if outfile, err = os.Create("./uploaded/" + hdr.Filename); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			// 32K buffer copy
 | 
			
		||||
			var written int64
 | 
			
		||||
			if written, err = io.Copy(outfile, infile); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Println("uploaded file:" + hdr.Filename + ";length:" + strconv.Itoa(int(written)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
 | 
			
		||||
	page.SubTitle = "Teams"
 | 
			
		||||
	teamId := vars["id"]
 | 
			
		||||
	if teamId == "new" {
 | 
			
		||||
		// Add a new team
 | 
			
		||||
		switch vars["function"] {
 | 
			
		||||
		case "save":
 | 
			
		||||
			name := req.FormValue("teamname")
 | 
			
		||||
@@ -30,6 +31,7 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
 | 
			
		||||
			page.show("admin-addteam.html", w)
 | 
			
		||||
		}
 | 
			
		||||
	} else if teamId != "" {
 | 
			
		||||
		// Functions for existing team
 | 
			
		||||
		if dbIsValidTeam(teamId) {
 | 
			
		||||
			switch vars["function"] {
 | 
			
		||||
			case "save":
 | 
			
		||||
@@ -44,8 +46,11 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
 | 
			
		||||
				redirect("/admin/teams", w, req)
 | 
			
		||||
			case "delete":
 | 
			
		||||
				var err error
 | 
			
		||||
				t := dbGetTeam(teamId)
 | 
			
		||||
				if err = dbDeleteTeam(teamId); err != nil {
 | 
			
		||||
					page.session.setFlashMessage("Error deleting team: "+err.Error(), "error")
 | 
			
		||||
				} else {
 | 
			
		||||
					page.session.setFlashMessage("Team "+t.Name+" Deleted", "success")
 | 
			
		||||
				}
 | 
			
		||||
				redirect("/admin/teams", w, req)
 | 
			
		||||
			case "savemember":
 | 
			
		||||
@@ -61,10 +66,11 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
 | 
			
		||||
				redirect("/admin/teams/"+teamId, w, req)
 | 
			
		||||
			case "deletemember":
 | 
			
		||||
				mbrId := req.FormValue("memberid")
 | 
			
		||||
				m, _ := dbGetTeamMember(teamId, mbrId)
 | 
			
		||||
				if err := dbDeleteTeamMember(teamId, mbrId); err != nil {
 | 
			
		||||
					page.session.setFlashMessage("Error deleting team member: "+err.Error(), "error")
 | 
			
		||||
				} else {
 | 
			
		||||
					page.session.setFlashMessage("Member deleted from team", "success")
 | 
			
		||||
					page.session.setFlashMessage(m.Name+" deleted from team", "success")
 | 
			
		||||
				}
 | 
			
		||||
				redirect("/admin/teams/"+teamId, w, req)
 | 
			
		||||
			default:
 | 
			
		||||
@@ -78,10 +84,10 @@ func handleAdminTeams(w http.ResponseWriter, req *http.Request, page *pageData)
 | 
			
		||||
			redirect("/admin/teams", w, req)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// Team List
 | 
			
		||||
		type teamsPageData struct {
 | 
			
		||||
			Teams []Team
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		page.TemplateData = teamsPageData{Teams: dbGetAllTeams()}
 | 
			
		||||
		page.SubTitle = "Teams"
 | 
			
		||||
		page.show("admin-teams.html", w)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,14 @@ div.content {
 | 
			
		||||
  margin-left: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input.file {
 | 
			
		||||
  padding: .5em .6em;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  border: 1px solid #ccc;
 | 
			
		||||
  box-shadow: inset 0 1px 3px #ddd;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#menu {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 40px;
 | 
			
		||||
@@ -29,6 +37,14 @@ div.content {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#menu .pure-menu-nonlink {
 | 
			
		||||
  color: #777;
 | 
			
		||||
  padding: .5em 1em;
 | 
			
		||||
  display: block;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#menu .menu-button {
 | 
			
		||||
  display: inline;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
@@ -57,8 +73,87 @@ div.content {
 | 
			
		||||
  background-color: #191818;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input.uuid-field {
 | 
			
		||||
  width: 360px;
 | 
			
		||||
div.horizontal-scroll {
 | 
			
		||||
  overflow-x: scroll;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img.thumbnail {
 | 
			
		||||
  width: 100px;
 | 
			
		||||
  height: 100px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.thumbnail-container {
 | 
			
		||||
  display: block;
 | 
			
		||||
  height: 120px;
 | 
			
		||||
  background-color: #EEE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.padding {
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.space {
 | 
			
		||||
  margin: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.space-sides {
 | 
			
		||||
  margin-left: 5px;
 | 
			
		||||
  margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.big-space {
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.left {
 | 
			
		||||
  text-align: left;
 | 
			
		||||
}
 | 
			
		||||
.right {
 | 
			
		||||
  text-align: right;
 | 
			
		||||
}
 | 
			
		||||
.center {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.center-all {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  vertical-align: center;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.center td {
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.padding td {
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.pure-button-error {
 | 
			
		||||
  background-color: #DD0000;
 | 
			
		||||
  color: #FFFFFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#modal-overlay {
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 0px;
 | 
			
		||||
  top: 0px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  z-index: 1000;
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#modal-overlay>div {
 | 
			
		||||
  width: 500px;
 | 
			
		||||
  margin: 100px auto;
 | 
			
		||||
  background-color: #FFF;
 | 
			
		||||
  border: 1px solid #000;
 | 
			
		||||
  border-radius: 10px;
 | 
			
		||||
  padding: 15px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (min-width: 40em) {
 | 
			
		||||
@@ -92,6 +187,11 @@ input.uuid-field {
 | 
			
		||||
    margin-left: 150px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  aside.flash.success {
 | 
			
		||||
    background-color: #229af9;
 | 
			
		||||
    color: #FFFFFF;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .content {
 | 
			
		||||
    margin-left: 150px;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,3 +15,51 @@ document.onkeydown = function(evt) {
 | 
			
		||||
    toggleAdminPanel();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function showModal(options) {
 | 
			
		||||
  var modal = document.getElementById('modal-overlay');
 | 
			
		||||
  document.getElementById('modal-title').innerText = (options.title)?options.title:"";
 | 
			
		||||
  document.getElementById('modal-subtitle').innerText = (options.subtitle)?options.subtitle:"";
 | 
			
		||||
  if(options.body) {
 | 
			
		||||
    document.getElementById('modal-body').innerText = options.body;
 | 
			
		||||
  } else if(options.bodyNode) {
 | 
			
		||||
    document.getElementById('modal-body').appendChild(options.bodyNode);
 | 
			
		||||
  }
 | 
			
		||||
  if(options.buttons) {
 | 
			
		||||
    for(var i = 0; i < options.buttons.length; i++) {
 | 
			
		||||
      var btn;
 | 
			
		||||
      if(options.buttons[i].isSubmit) {
 | 
			
		||||
        btn = document.createElement('submit');
 | 
			
		||||
      } else {
 | 
			
		||||
        btn = document.createElement('a');
 | 
			
		||||
      }
 | 
			
		||||
      options.buttons[i].title = (options.buttons[i].title==undefined)?'':options.buttons[i].title;
 | 
			
		||||
      options.buttons[i].href = (options.buttons[i].href==undefined)?'#':options.buttons[i].href;
 | 
			
		||||
      options.buttons[i].click = (options.buttons[i].click==undefined)?function(){}:options.buttons[i].click;
 | 
			
		||||
      options.buttons[i].class = (options.buttons[i].class==undefined)?'':options.buttons[i].class;
 | 
			
		||||
      options.buttons[i].position = (options.buttons[i].position==undefined)?'right':options.buttons[i].position;
 | 
			
		||||
 | 
			
		||||
      btn.innerHTML = options.buttons[i].title;
 | 
			
		||||
      btn.title = options.buttons[i].title;
 | 
			
		||||
      btn.href = options.buttons[i].href;
 | 
			
		||||
      btn.className = 'space pure-button '+options.buttons[i].class+' '+options.buttons[i].position;
 | 
			
		||||
      snack.listener(
 | 
			
		||||
        {node:btn, event:'click'},
 | 
			
		||||
        options.buttons[i].click
 | 
			
		||||
      );
 | 
			
		||||
      document.getElementById('modal-buttons').appendChild(btn);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  modal.style.visibility = 'visible';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function hideModal() {
 | 
			
		||||
  var modal = document.getElementById('modal-overlay');
 | 
			
		||||
  modal.style.visibility = 'hidden';
 | 
			
		||||
  document.getElementById('modal-title').innerHTML = '';
 | 
			
		||||
  document.getElementById('modal-body').innerHTML = '';
 | 
			
		||||
  var buttonsDiv = document.getElementById('modal-buttons')
 | 
			
		||||
  while(buttonsDiv.firstChild) {
 | 
			
		||||
    buttonsDiv.removeChild(buttonsDiv.firstChild);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.go
									
									
									
									
									
								
							@@ -53,6 +53,7 @@ type pageData struct {
 | 
			
		||||
	CurrentJam     string
 | 
			
		||||
	ClientID       string
 | 
			
		||||
	ClientIsAuth   bool
 | 
			
		||||
	ClientIsServer bool
 | 
			
		||||
	TeamID         string
 | 
			
		||||
 | 
			
		||||
	TemplateData interface{}
 | 
			
		||||
@@ -237,7 +238,8 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p.ClientID = p.session.getClientID()
 | 
			
		||||
	p.ClientIsAuth = dbClientIsAuth(p.ClientID)
 | 
			
		||||
	p.ClientIsAuth = clientIsAuthenticated(p.ClientID, req)
 | 
			
		||||
	p.ClientIsServer = clientIsServer(req)
 | 
			
		||||
	p.TeamID, _ = p.session.getStringValue("teamid")
 | 
			
		||||
 | 
			
		||||
	return p
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										143
									
								
								model_games.go
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								model_games.go
									
									
									
									
									
								
							@@ -1,12 +1,145 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import "github.com/pborman/uuid"
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
 | 
			
		||||
	"github.com/pborman/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Game struct {
 | 
			
		||||
	UUID *uuid.UUID
 | 
			
		||||
	Name string
 | 
			
		||||
	Name        string
 | 
			
		||||
	TeamId      string
 | 
			
		||||
	Description string
 | 
			
		||||
	Screenshots []Screenshot
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbIsValidGame(id string) bool {
 | 
			
		||||
	return true
 | 
			
		||||
type Screenshot struct {
 | 
			
		||||
	Description string
 | 
			
		||||
	Image       string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbUpdateTeamGame(teamId, name, desc string) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	if err = openDatabase(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer closeDatabase()
 | 
			
		||||
 | 
			
		||||
	// Make sure the team is valid
 | 
			
		||||
	tm := dbGetTeam(teamId)
 | 
			
		||||
	if tm == nil {
 | 
			
		||||
		return errors.New("Invalid team")
 | 
			
		||||
	}
 | 
			
		||||
	gamePath := []string{"teams", teamId, "game"}
 | 
			
		||||
 | 
			
		||||
	if err := db.MkBucketPath(gamePath); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		name = tm.Name + "'s Game"
 | 
			
		||||
	}
 | 
			
		||||
	if err := db.SetValue(gamePath, "name", name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := db.SetValue(gamePath, "description", desc); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := db.MkBucketPath(append(gamePath, "screenshots")); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbGetAllGames() []Game {
 | 
			
		||||
	var ret []Game
 | 
			
		||||
	tms := dbGetAllTeams()
 | 
			
		||||
	for i := range tms {
 | 
			
		||||
		ret = append(ret, *dbGetTeamGame(tms[i].UUID))
 | 
			
		||||
	}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbGetTeamGame(teamId string) *Game {
 | 
			
		||||
	var err error
 | 
			
		||||
	if err = openDatabase(); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	defer closeDatabase()
 | 
			
		||||
 | 
			
		||||
	gamePath := []string{"teams", teamId, "game"}
 | 
			
		||||
	gm := new(Game)
 | 
			
		||||
	if gm.Name, err = db.GetValue(gamePath, "name"); err != nil {
 | 
			
		||||
		gm.Name = ""
 | 
			
		||||
	}
 | 
			
		||||
	gm.TeamId = teamId
 | 
			
		||||
	if gm.Description, err = db.GetValue(gamePath, "description"); err != nil {
 | 
			
		||||
		gm.Description = ""
 | 
			
		||||
	}
 | 
			
		||||
	gm.Screenshots = dbGetTeamGameScreenshots(teamId)
 | 
			
		||||
	return gm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Screenshots are saved as base64 encoded pngs
 | 
			
		||||
func dbGetTeamGameScreenshots(teamId string) []Screenshot {
 | 
			
		||||
	var ret []Screenshot
 | 
			
		||||
	var err error
 | 
			
		||||
	ssPath := []string{"teams", teamId, "game", "screenshots"}
 | 
			
		||||
	var ssIds []string
 | 
			
		||||
	if ssIds, err = db.GetBucketList(ssPath); err != nil {
 | 
			
		||||
		return ret
 | 
			
		||||
	}
 | 
			
		||||
	for _, v := range ssIds {
 | 
			
		||||
		if ss := dbGetTeamGameScreenshot(teamId, v); ss != nil {
 | 
			
		||||
			ret = append(ret, *ss)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbGetTeamGameScreenshot(teamId, ssId string) *Screenshot {
 | 
			
		||||
	var err error
 | 
			
		||||
	ssPath := []string{"teams", teamId, "game", "screenshots", ssId}
 | 
			
		||||
	ret := new(Screenshot)
 | 
			
		||||
	if ret.Description, err = db.GetValue(ssPath, "description"); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if ret.Image, err = db.GetValue(ssPath, "image"); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbSaveTeamGameScreenshot(teamId string, ss *Screenshot) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	if err = openDatabase(); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	defer closeDatabase()
 | 
			
		||||
 | 
			
		||||
	ssPath := []string{"teams", teamId, "game", "screenshots"}
 | 
			
		||||
	// Generate a UUID for this screenshot
 | 
			
		||||
	uuid := uuid.New()
 | 
			
		||||
	ssPath = append(ssPath, uuid)
 | 
			
		||||
	if err := db.MkBucketPath(ssPath); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := db.SetValue(ssPath, "description", ss.Description); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err := db.SetValue(ssPath, "image", ss.Image); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func dbDeleteTeamGameScreenshot(teamId, ssId string) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	if err = openDatabase(); err != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	defer closeDatabase()
 | 
			
		||||
 | 
			
		||||
	ssPath := []string{"teams", teamId, "game", "screenshots"}
 | 
			
		||||
	return db.DeleteBucket(ssPath, ssId)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -105,6 +105,7 @@ func dbGetTeam(id string) *Team {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	tm.Members, _ = dbGetTeamMembers(id)
 | 
			
		||||
	tm.Game = dbGetTeamGame(id)
 | 
			
		||||
	return tm
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -213,7 +214,6 @@ func dbGetTeamMembers(teamid string) ([]TeamMember, error) {
 | 
			
		||||
		for _, v := range memberUuids {
 | 
			
		||||
			var mbr *TeamMember
 | 
			
		||||
			if mbr, err = dbGetTeamMember(teamid, v); err == nil {
 | 
			
		||||
				fmt.Println("Finding Team Members", teamid, mbr.Name)
 | 
			
		||||
				ret = append(ret, *mbr)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,70 +1,126 @@
 | 
			
		||||
{{ $uuid := .TemplateData.UUID }}
 | 
			
		||||
<div class="center">
 | 
			
		||||
  <form class="pure-form pure-form-aligned" action="/admin/teams/{{ .TemplateData.UUID }}/save" method="POST">
 | 
			
		||||
  <div class="left">
 | 
			
		||||
    <form class="pure-form pure-form-aligned" action="/admin/teams/{{ $uuid }}/save" method="POST">
 | 
			
		||||
      <h3>Team Details</h3>
 | 
			
		||||
      <fieldset>
 | 
			
		||||
        <div class="left big-space">
 | 
			
		||||
          <div class="pure-control-group">
 | 
			
		||||
            <label class="control-label" for="teamname">Team Name</label>
 | 
			
		||||
            <input id="teamname" name="teamname" value="{{ .TemplateData.Name }}" placeholder="Team Name">
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="pure-control-group reset-pull">
 | 
			
		||||
          <a href="/admin/teams" class="pull-left space pure-button pure-button-plain">Cancel</a>
 | 
			
		||||
          <button type="submit" class="pull-right space pure-button pure-button-primary">Update Team</button>
 | 
			
		||||
          <button type="button" id="btnDeleteTeam" class="pull-right space pure-button pure-button-error">Delete Team</button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </fieldset>
 | 
			
		||||
    </form>
 | 
			
		||||
    <hr />
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <form class="pure-form pure-form-aligned" action="/admin/games/{{ $uuid }}/save" method="POST">
 | 
			
		||||
    <fieldset>
 | 
			
		||||
      <div class="pure-control-group">
 | 
			
		||||
        <span>{{ .TemplateData.Name }}</span>
 | 
			
		||||
      <div class="left big-space">
 | 
			
		||||
        <h3>Team Game</h3>
 | 
			
		||||
        <div class="pure-control-group">
 | 
			
		||||
          <label class="control-label" for="gamename">Game Name</label>
 | 
			
		||||
          <input id="gamename" name="gamename" value="{{ .TemplateData.Game.Name }}" placeholder="Game Name">
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="pure-control-group">
 | 
			
		||||
          <label class="control-label" for="gamedesc">Description</label>
 | 
			
		||||
          <textarea id="gamedesc" name="gamedesc" placeholder="Description...">{{ .TemplateData.Game.Description }}</textarea>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="pure-control-group">
 | 
			
		||||
          <label class="control-label">Screenshots</label>
 | 
			
		||||
          <div class="center-all horizontal-scroll thumbnail-container">
 | 
			
		||||
          {{ if not .TemplateData.Game.Screenshots }}
 | 
			
		||||
            <a style="margin-top:40px;" class="center-all pure-button pure-button-primary" href="javascript:toggleUploadSSForm();">Upload Screenshot</a>
 | 
			
		||||
          {{ else }}
 | 
			
		||||
            {{ range $i, $v := .TemplateData.Game.Screenshots }}
 | 
			
		||||
            <img class="thumbnail" alt="{{ $v.Description }}" src="{{ $v.Image }}" />
 | 
			
		||||
            {{ end }}
 | 
			
		||||
          {{ end }}
 | 
			
		||||
          </div>
 | 
			
		||||
          {{ if .TemplateData.Game.Screenshots }}
 | 
			
		||||
          <div class="right">
 | 
			
		||||
            <a id="toggleUploadSSFormBtn" class="pure-button pure-button-primary" href="javascript:toggleUploadSSForm();">Upload Screenshot</a>
 | 
			
		||||
          </div>
 | 
			
		||||
          {{ end }}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="pure-control-group">
 | 
			
		||||
        <label class="control-label" for="teamname">Team Name</label>
 | 
			
		||||
        <input id="teamname" name="teamname" value="{{ .TemplateData.Name }}" placeholder="Team Name">
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="pure-control-group reset-pull">
 | 
			
		||||
        <a href="/admin/teams" class="pull-left space pure-button pure-button-plain">Cancel</a>
 | 
			
		||||
        <button type="submit" class="pull-right space pure-button pure-button-primary">Update</button>
 | 
			
		||||
        <button type="button" id="btnDeleteUser" class="pull-right space pure-button pure-button-error">Delete</button>
 | 
			
		||||
        <a href="/admin/teams/{{ $uuid }}" class="pull-left space pure-button pure-button-plain">Cancel</a>
 | 
			
		||||
        <button type="submit" class="pull-right space pure-button pure-button-primary">Update Game</button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </fieldset>
 | 
			
		||||
  </form>
 | 
			
		||||
 | 
			
		||||
  <h2>Members</h2>
 | 
			
		||||
      <table>
 | 
			
		||||
        <thead>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th>Name</th>
 | 
			
		||||
            <th>Slack ID</th>
 | 
			
		||||
            <th>Twitter</th>
 | 
			
		||||
            <th>Email</th>
 | 
			
		||||
            <th>Edit</th>
 | 
			
		||||
            <th>Remove</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
          {{ range $i, $v := .TemplateData.Members }}
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td>{{ $v.Name }}</td>
 | 
			
		||||
            <td>{{ $v.SlackId }}</td>
 | 
			
		||||
            <td>{{ $v.Twitter }}</td>
 | 
			
		||||
            <td>{{ $v.Email }}</td>
 | 
			
		||||
            <td>
 | 
			
		||||
              <a href="/admin/teams/{{ $v.UUID }}/edit" class="pure-button pure-button-plain"><i class="fa fa-pencil"></i></a>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>
 | 
			
		||||
              <form action="/admin/teams/{{ $uuid }}/deletemember" method="POST">
 | 
			
		||||
                <input type="hidden" name="memberid" value="{{ $v.UUID }}"/>
 | 
			
		||||
                <button type="submit" class="pure-button pure-button-plain"><i class="fa fa-trash"></i></button>
 | 
			
		||||
              </form>
 | 
			
		||||
            </td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          {{ end }}
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td colspan="6" class="center">Add a new member</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td colspan="6">
 | 
			
		||||
              <form action="/admin/teams/{{ $uuid }}/savemember" method="POST">
 | 
			
		||||
                <input id="newmembername" name="newmembername" value="" placeholder="Member Name" />
 | 
			
		||||
  <hr />
 | 
			
		||||
  <div class="left">
 | 
			
		||||
    <h3>Team Members</h3>
 | 
			
		||||
    <table class="center padding hide">
 | 
			
		||||
      <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <th>Name</th>
 | 
			
		||||
          <th>Slack ID</th>
 | 
			
		||||
          <th>Twitter</th>
 | 
			
		||||
          <th>Email</th>
 | 
			
		||||
          <th>Edit</th>
 | 
			
		||||
          <th>Remove</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </thead>
 | 
			
		||||
      <tbody>
 | 
			
		||||
        {{ range $i, $v := .TemplateData.Members }}
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td>{{ $v.Name }}</td>
 | 
			
		||||
          <td>{{ $v.SlackId }}</td>
 | 
			
		||||
          <td>{{ $v.Twitter }}</td>
 | 
			
		||||
          <td>{{ $v.Email }}</td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <a href="/admin/teams/{{ $v.UUID }}/edit" class="pure-button pure-button-plain"><i class="fa fa-pencil"></i></a>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td>
 | 
			
		||||
            <form action="/admin/teams/{{ $uuid }}/deletemember" method="POST">
 | 
			
		||||
              <input type="hidden" name="memberid" value="{{ $v.UUID }}"/>
 | 
			
		||||
              <button type="submit" class="pure-button pure-button-error"><i class="fa fa-trash"></i></button>
 | 
			
		||||
            </form>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        {{ end }}
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td colspan="6">Add a new member</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td colspan="6" class="padding">
 | 
			
		||||
            <form class="pure-form" action="/admin/teams/{{ $uuid }}/savemember" method="POST">
 | 
			
		||||
              <div class="pure-control-group">
 | 
			
		||||
                <input id="newmembername" name="newmembername" value="" placeholder="Member Name" autofocus />
 | 
			
		||||
                <input id="newmemberslackid" name="newmemberslackid" value="" placeholder="@SlackID" />
 | 
			
		||||
                <input id="newmembertwitter" name="newmembertwitter" value="" placeholder="@Twitter" />
 | 
			
		||||
                <input id="newmemberemail" name="newmemberemail" value="" placeholder="user@email.com" />
 | 
			
		||||
                <button type="submit" class="pull-right space pure-button pure-button-primary">Add</button>
 | 
			
		||||
              </form>
 | 
			
		||||
            </td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
      </table>
 | 
			
		||||
                <button type="submit" class="pull-right space-sides pure-button pure-button-primary">Add</button>
 | 
			
		||||
              </div>
 | 
			
		||||
            </form>
 | 
			
		||||
          </td>
 | 
			
		||||
        </tr>
 | 
			
		||||
      </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="pure-control-group reset-pull">
 | 
			
		||||
    <a href="/admin/teams" class="pull-left space pure-button pure-button-plain">Cancel</a>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
<div id="uploadscreenshotform" style="display:none;">
 | 
			
		||||
  <h3>Upload Screenshot</h3>
 | 
			
		||||
  <form class="pure-form pure-form-aligned" action="/admin/games/{{ $uuid }}/screenshotupload" method="POST" enctype="multipart/form-data">
 | 
			
		||||
    <div class="pure-control-group" style="margin-bottom:50px;">
 | 
			
		||||
      <input class="file" type="file" name="newssfile" multiple>
 | 
			
		||||
    </div>
 | 
			
		||||
    <a href="javascript:hideModal();" class="pull-left space-sides pure-button">Cancel</a>
 | 
			
		||||
    <button type="submit" class="pull-right space-sides pure-button pure-button-primary">Add</button>
 | 
			
		||||
  </form>
 | 
			
		||||
</div>
 | 
			
		||||
<script>
 | 
			
		||||
  snack.listener(
 | 
			
		||||
@@ -72,7 +128,7 @@
 | 
			
		||||
    function() {
 | 
			
		||||
      showModal({
 | 
			
		||||
        title: 'Delete Team',
 | 
			
		||||
        subtitle: '({{ .TemplateData.Name }} - {{ $uuid}})',
 | 
			
		||||
        subtitle: '({{ .TemplateData.Name }})',
 | 
			
		||||
        body: 'Are you sure? This cannot be undone.',
 | 
			
		||||
        buttons: [{
 | 
			
		||||
          title:'Cancel',
 | 
			
		||||
@@ -87,4 +143,14 @@
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  );
 | 
			
		||||
  function toggleUploadSSForm() {
 | 
			
		||||
    var uploadForm = document.getElementById('uploadscreenshotform');
 | 
			
		||||
    showModal({
 | 
			
		||||
      title: 'Upload Screenshot',
 | 
			
		||||
      subtitle: '({{ .TemplateData.Name }})',
 | 
			
		||||
      bodyNode: uploadForm
 | 
			
		||||
    });
 | 
			
		||||
    uploadForm.style.display="block";
 | 
			
		||||
    document.getElementById('modal-body').style.height='165px';
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -12,11 +12,15 @@
 | 
			
		||||
        </li>
 | 
			
		||||
        {{ end }}
 | 
			
		||||
      </ul>
 | 
			
		||||
      {{if .ClientIsAuth}}
 | 
			
		||||
      <a href="/admin/clients/{{.ClientID}}/remove" class="pure-menu-link"><i class="fa fa-key"></i> DeAuth Client</a>
 | 
			
		||||
      {{else}}
 | 
			
		||||
      {{ if .ClientIsAuth }}
 | 
			
		||||
        {{ if .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>
 | 
			
		||||
        {{ end }}
 | 
			
		||||
      {{ else }}
 | 
			
		||||
      <a href="/admin/clients/{{.ClientID}}/add" class="pure-menu-link"><i class="fa fa-key"></i> Auth Client</a>
 | 
			
		||||
      {{end}}
 | 
			
		||||
      {{ end }}
 | 
			
		||||
      <ul class="pure-menu-list menu-bottom">
 | 
			
		||||
        {{ range $k, $v := .BottomMenu }}
 | 
			
		||||
        <li class="pure-menu-item">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
<script>
 | 
			
		||||
var clientID = "{{.ClientID}}";
 | 
			
		||||
</script>
 | 
			
		||||
<aside class="flash center {{.FlashClass}}">
 | 
			
		||||
  {{.FlashMessage}}
 | 
			
		||||
</aside>
 | 
			
		||||
<div class="content">
 | 
			
		||||
  <aside class="flash center {{.FlashClass}}">
 | 
			
		||||
    {{.FlashMessage}}
 | 
			
		||||
  </aside>
 | 
			
		||||
  <div class="header">
 | 
			
		||||
    devICT Game Jam - {{.CurrentJam}}
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="header-menu">
 | 
			
		||||
    <h1>{{.SubTitle}}</h1>
 | 
			
		||||
    <h2>{{.SubTitle}}</h2>
 | 
			
		||||
  </div>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user