Merge pull request #11 from br0xen/master
Teams can now manage their own information (their team link can be found on the 'admin/teams' page) Process images on upload, build thumbnail in addition to original size Show thumbnail size images inline, load original sizes on embiggening
This commit is contained in:
commit
439f13754f
@ -1,12 +1,18 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"bytes"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/gif"
|
||||||
|
"image/jpeg"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/nfnt/resize"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData) {
|
func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData) {
|
||||||
@ -52,11 +58,40 @@ func handleAdminGames(w http.ResponseWriter, req *http.Request, page *pageData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func saveScreenshots(teamId string, req *http.Request) error {
|
func saveScreenshots(teamId string, req *http.Request) error {
|
||||||
file, _, err := req.FormFile("newssfile")
|
var err error
|
||||||
|
file, hdr, err := req.FormFile("newssfile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
data, err := ioutil.ReadAll(file)
|
fmt.Println("File Received: " + hdr.Filename)
|
||||||
str := base64.StdEncoding.EncodeToString(data)
|
extIdx := strings.LastIndex(hdr.Filename, ".")
|
||||||
return dbSaveTeamGameScreenshot(teamId, &Screenshot{Image: str})
|
fltp := "png"
|
||||||
|
if len(hdr.Filename) > extIdx {
|
||||||
|
fltp = hdr.Filename[extIdx+1:]
|
||||||
|
}
|
||||||
|
m, _, err := image.Decode(file)
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
// We convert everything to jpg
|
||||||
|
if err = jpeg.Encode(buf, m, nil); err != nil {
|
||||||
|
return errors.New("Unable to encode image")
|
||||||
|
}
|
||||||
|
thm := resize.Resize(200, 0, m, resize.Lanczos3)
|
||||||
|
thmBuf := new(bytes.Buffer)
|
||||||
|
var thmString string
|
||||||
|
if fltp == "gif" {
|
||||||
|
if err = gif.Encode(thmBuf, thm, nil); err != nil {
|
||||||
|
return errors.New("Unable to encode image")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err = jpeg.Encode(thmBuf, thm, nil); err != nil {
|
||||||
|
return errors.New("Unable to encode image")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
thmString = base64.StdEncoding.EncodeToString(thmBuf.Bytes())
|
||||||
|
|
||||||
|
return dbSaveTeamGameScreenshot(teamId, &Screenshot{
|
||||||
|
Image: base64.StdEncoding.EncodeToString(buf.Bytes()),
|
||||||
|
Thumbnail: thmString,
|
||||||
|
Filetype: fltp,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
_ "image/gif"
|
||||||
|
_ "image/jpeg"
|
||||||
|
_ "image/png"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -263,16 +263,19 @@ div.fullscreen {
|
|||||||
margin-left: 150px;
|
margin-left: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
aside.flash {
|
div.flash {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
aside.flash.error {
|
div.flash.error {
|
||||||
background-color: #DD0000;
|
background-color: #DD0000;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
aside.flash.success {
|
div.flash.success {
|
||||||
background-color: #229af9;
|
background-color: #229af9;
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
console.log("ICT GameJam Admin");
|
|
@ -73,7 +73,10 @@ function hideModal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setFlashMessage(msg, cls) {
|
function setFlashMessage(msg, cls) {
|
||||||
var flash = document.querySelector('aside.flash');
|
if( Object.prototype.toString.call( cls ) !== '[object Array]' ) {
|
||||||
|
cls = [ cls ];
|
||||||
|
}
|
||||||
|
var flash = document.querySelector('div.flash');
|
||||||
flash.innerText = msg;
|
flash.innerText = msg;
|
||||||
for(var i = 0; i < cls.length; i++) {
|
for(var i = 0; i < cls.length; i++) {
|
||||||
flash.classList.add(cls[i]);
|
flash.classList.add(cls[i]);
|
||||||
@ -84,14 +87,14 @@ function setFlashMessage(msg, cls) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleFlashMessage() {
|
function handleFlashMessage() {
|
||||||
var flash = document.querySelector('aside.flash');
|
var flash = document.querySelector('div.flash');
|
||||||
if(flash.classList.contains('fading')) {
|
if(flash.classList.contains('fading')) {
|
||||||
setTimeout(fadeOutFlashMessage, 1000);
|
setTimeout(fadeOutFlashMessage, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function fadeOutFlashMessage() {
|
function fadeOutFlashMessage() {
|
||||||
var flash = document.querySelector('aside');
|
var flash = document.querySelector('div.flash');
|
||||||
var opac = flash.style.opacity;
|
var opac = flash.style.opacity;
|
||||||
if(opac == "") { opac = 1; }
|
if(opac == "") { opac = 1; }
|
||||||
if(opac > 0) {
|
if(opac > 0) {
|
||||||
|
6
main.go
6
main.go
@ -104,6 +104,11 @@ func main() {
|
|||||||
pub := r.PathPrefix("/").Subrouter()
|
pub := r.PathPrefix("/").Subrouter()
|
||||||
pub.HandleFunc("/", handleMain)
|
pub.HandleFunc("/", handleMain)
|
||||||
pub.HandleFunc("/vote", handlePublicSaveVote)
|
pub.HandleFunc("/vote", handlePublicSaveVote)
|
||||||
|
pub.HandleFunc("/image/{teamid}/{imageid}", handleImageRequest)
|
||||||
|
pub.HandleFunc("/thumbnail/{teamid}/{imageid}", handleThumbnailRequest)
|
||||||
|
pub.HandleFunc("/team/{id}", handleTeamMgmtRequest)
|
||||||
|
pub.HandleFunc("/team/{id}/{function}", handleTeamMgmtRequest)
|
||||||
|
pub.HandleFunc("/team/{id}/{function}/{subid}", handleTeamMgmtRequest)
|
||||||
|
|
||||||
// API Subrouter
|
// API Subrouter
|
||||||
//api := r.PathPrefix("/api").Subtrouter()
|
//api := r.PathPrefix("/api").Subtrouter()
|
||||||
@ -297,7 +302,6 @@ func InitPageData(w http.ResponseWriter, req *http.Request) *pageData {
|
|||||||
func (p *pageData) show(tmplName string, w http.ResponseWriter) error {
|
func (p *pageData) show(tmplName string, w http.ResponseWriter) error {
|
||||||
for _, tmpl := range []string{
|
for _, tmpl := range []string{
|
||||||
"htmlheader.html",
|
"htmlheader.html",
|
||||||
"admin-menu.html",
|
|
||||||
"header.html",
|
"header.html",
|
||||||
tmplName,
|
tmplName,
|
||||||
"footer.html",
|
"footer.html",
|
||||||
|
@ -14,9 +14,11 @@ type Game struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Screenshot struct {
|
type Screenshot struct {
|
||||||
|
UUID string
|
||||||
Description string
|
Description string
|
||||||
Image string
|
Image string
|
||||||
UUID string
|
Thumbnail string
|
||||||
|
Filetype string
|
||||||
}
|
}
|
||||||
|
|
||||||
func dbUpdateTeamGame(teamId, name, desc string) error {
|
func dbUpdateTeamGame(teamId, name, desc string) error {
|
||||||
@ -109,6 +111,15 @@ func dbGetTeamGameScreenshot(teamId, ssId string) *Screenshot {
|
|||||||
if ret.Image, err = db.GetValue(ssPath, "image"); err != nil {
|
if ret.Image, err = db.GetValue(ssPath, "image"); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if ret.Thumbnail, err = db.GetValue(ssPath, "thumbnail"); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ret.Thumbnail == "" {
|
||||||
|
ret.Thumbnail = ret.Image
|
||||||
|
}
|
||||||
|
if ret.Filetype, err = db.GetValue(ssPath, "filetype"); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +143,12 @@ func dbSaveTeamGameScreenshot(teamId string, ss *Screenshot) error {
|
|||||||
if err := db.SetValue(ssPath, "image", ss.Image); err != nil {
|
if err := db.SetValue(ssPath, "image", ss.Image); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := db.SetValue(ssPath, "thumbnail", ss.Thumbnail); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := db.SetValue(ssPath, "filetype", ss.Filetype); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initPublicPage(w http.ResponseWriter, req *http.Request) *pageData {
|
func initPublicPage(w http.ResponseWriter, req *http.Request) *pageData {
|
||||||
@ -73,3 +76,103 @@ func handlePublicSaveVote(w http.ResponseWriter, req *http.Request) {
|
|||||||
page.session.setFlashMessage("Vote Saved!", "success large fading")
|
page.session.setFlashMessage("Vote Saved!", "success large fading")
|
||||||
redirect("/", w, req)
|
redirect("/", w, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleThumbnailRequest(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
ss := dbGetTeamGameScreenshot(vars["teamid"], vars["imageid"])
|
||||||
|
if ss == nil {
|
||||||
|
http.Error(w, "Couldn't find image", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "image/"+ss.Filetype)
|
||||||
|
dat, err := base64.StdEncoding.DecodeString(ss.Thumbnail)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Couldn't find image", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write(dat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleImageRequest(w http.ResponseWriter, req *http.Request) {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
ss := dbGetTeamGameScreenshot(vars["teamid"], vars["imageid"])
|
||||||
|
if ss == nil {
|
||||||
|
http.Error(w, "Couldn't find image", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "image/"+ss.Filetype)
|
||||||
|
dat, err := base64.StdEncoding.DecodeString(ss.Image)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Couldn't find image", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write(dat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleTeamMgmtRequest(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if dbGetPublicSiteMode() == SiteModeVoting {
|
||||||
|
redirect("/", w, req)
|
||||||
|
}
|
||||||
|
page := initPublicPage(w, req)
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
page.SubTitle = "Team Details"
|
||||||
|
teamId := vars["id"]
|
||||||
|
if teamId != "" {
|
||||||
|
// Team self-management functions
|
||||||
|
if !dbIsValidTeam(teamId) {
|
||||||
|
http.Error(w, "Page Not Found", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch vars["function"] {
|
||||||
|
case "":
|
||||||
|
page.SubTitle = "Team Management"
|
||||||
|
t := dbGetTeam(teamId)
|
||||||
|
page.TemplateData = t
|
||||||
|
page.show("public-teammgmt.html", w)
|
||||||
|
case "savemember":
|
||||||
|
mbrName := req.FormValue("newmembername")
|
||||||
|
mbrSlack := req.FormValue("newmemberslackid")
|
||||||
|
mbrTwitter := req.FormValue("newmembertwitter")
|
||||||
|
mbrEmail := req.FormValue("newmemberemail")
|
||||||
|
if err := dbAddTeamMember(teamId, mbrName, mbrEmail, mbrSlack, mbrTwitter); err != nil {
|
||||||
|
page.session.setFlashMessage("Error adding team member: "+err.Error(), "error")
|
||||||
|
} else {
|
||||||
|
page.session.setFlashMessage(mbrName+" added to team!", "success")
|
||||||
|
}
|
||||||
|
refreshTeamsInMemory()
|
||||||
|
redirect("/team/"+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(m.Name+" deleted from team", "success")
|
||||||
|
}
|
||||||
|
refreshTeamsInMemory()
|
||||||
|
redirect("/team/"+teamId, w, req)
|
||||||
|
case "savegame":
|
||||||
|
name := req.FormValue("gamename")
|
||||||
|
desc := req.FormValue("gamedesc")
|
||||||
|
if dbIsValidTeam(teamId) {
|
||||||
|
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("/team/"+teamId, w, req)
|
||||||
|
}
|
||||||
|
case "screenshotupload":
|
||||||
|
if err := saveScreenshots(teamId, req); err != nil {
|
||||||
|
page.session.setFlashMessage("Error updating game: "+err.Error(), "error")
|
||||||
|
}
|
||||||
|
redirect("/team/"+teamId, w, req)
|
||||||
|
case "screenshotdelete":
|
||||||
|
ssid := vars["subid"]
|
||||||
|
if err := dbDeleteTeamGameScreenshot(teamId, ssid); err != nil {
|
||||||
|
page.session.setFlashMessage("Error deleting screenshot: "+err.Error(), "error")
|
||||||
|
}
|
||||||
|
redirect("/team/"+teamId, w, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,9 +20,9 @@
|
|||||||
<hr />
|
<hr />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form class="pure-form pure-form-aligned" action="/admin/games/{{ $uuid }}/save" method="POST">
|
<div class="left big-space">
|
||||||
<fieldset>
|
<form class="pure-form pure-form-aligned" action="/admin/games/{{ $uuid }}/save" method="POST">
|
||||||
<div class="left big-space">
|
<fieldset>
|
||||||
<a name="game" />
|
<a name="game" />
|
||||||
<h3>Team Game</h3>
|
<h3>Team Game</h3>
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
@ -33,30 +33,30 @@
|
|||||||
<label class="control-label" for="gamedesc">Description</label>
|
<label class="control-label" for="gamedesc">Description</label>
|
||||||
<textarea id="gamedesc" name="gamedesc" placeholder="Description...">{{ .TemplateData.Game.Description }}</textarea>
|
<textarea id="gamedesc" name="gamedesc" placeholder="Description...">{{ .TemplateData.Game.Description }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group reset-pull">
|
||||||
<label class="control-label">Screenshots</label>
|
<a href="/admin/teams/{{ $uuid }}" class="pull-left space pure-button pure-button-plain">Cancel</a>
|
||||||
<div class="center-all horizontal-scroll thumbnail-container" id="thumbnail-container">
|
<button type="submit" class="pull-right space pure-button pure-button-primary">Update Game</button>
|
||||||
{{ 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 data-teamid="{{ $uuid }}" data-ssid="{{ $v.UUID }}" class="thumbnail" alt="{{ $v.Description }}" src="data:image/png;base64,{{ $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>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label class="control-label">Screenshots</label>
|
||||||
|
<div class="center-all horizontal-scroll thumbnail-container" id="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 data-teamid="{{ $uuid }}" data-ssid="{{ $v.UUID }}" class="thumbnail" alt="{{ $v.Description }}" src="data:image/{{$v.Filetype}};base64,{{ $v.Thumbnail }}" />
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-control-group reset-pull">
|
{{ if .TemplateData.Game.Screenshots }}
|
||||||
<a href="/admin/teams/{{ $uuid }}" class="pull-left space pure-button pure-button-plain">Cancel</a>
|
<div class="right">
|
||||||
<button type="submit" class="pull-right space pure-button pure-button-primary">Update Game</button>
|
<a id="toggleUploadSSFormBtn" class="pure-button pure-button-primary" href="javascript:toggleUploadSSForm();">Upload Screenshot</a>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
{{ end }}
|
||||||
</form>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<div class="left">
|
<div class="left">
|
||||||
@ -68,7 +68,6 @@
|
|||||||
<th>Slack ID</th>
|
<th>Slack ID</th>
|
||||||
<th>Twitter</th>
|
<th>Twitter</th>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Edit</th>
|
|
||||||
<th>Remove</th>
|
<th>Remove</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -79,9 +78,6 @@
|
|||||||
<td>{{ $v.SlackId }}</td>
|
<td>{{ $v.SlackId }}</td>
|
||||||
<td>{{ $v.Twitter }}</td>
|
<td>{{ $v.Twitter }}</td>
|
||||||
<td>{{ $v.Email }}</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>
|
<td>
|
||||||
<form action="/admin/teams/{{ $uuid }}/deletemember" method="POST">
|
<form action="/admin/teams/{{ $uuid }}/deletemember" method="POST">
|
||||||
<input type="hidden" name="memberid" value="{{ $v.UUID }}"/>
|
<input type="hidden" name="memberid" value="{{ $v.UUID }}"/>
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
<div id="menu" class="{{if .HideAdminMenu}}hidden{{end}}">
|
|
||||||
<div class="pure-menu">
|
|
||||||
<a href="#menu" class="menu-button">
|
|
||||||
<i class="fa fa-bars"></i>
|
|
||||||
</a>
|
|
||||||
<div class="menu-container">
|
|
||||||
<ul class="pure-menu-list">
|
|
||||||
{{ range $k, $v := .Menu }}
|
|
||||||
<li class="pure-menu-item">
|
|
||||||
<a href="{{ $v.Location }}" class="pure-menu-link"><i class="fa {{ $v.Icon }}"></i> {{ $v.Label }}</a>
|
|
||||||
</li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
{{ if .ClientIsAuth }}
|
|
||||||
{{ if not .ClientIsServer }}
|
|
||||||
<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 }}
|
|
||||||
<ul class="pure-menu-list menu-bottom">
|
|
||||||
{{ range $k, $v := .BottomMenu }}
|
|
||||||
<li class="pure-menu-item">
|
|
||||||
<a href="{{ $v.Location }}" class="pure-menu-link"><i class="fa {{ $v.Icon }}"></i> {{ $v.Label }}</a>
|
|
||||||
</li>
|
|
||||||
{{ end }}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -8,7 +8,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Key</th>
|
<th>Management Link</th>
|
||||||
<th>Members</th>
|
<th>Members</th>
|
||||||
<th>Game</th>
|
<th>Game</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
{{ range $i, $v := .TemplateData.Teams }}
|
{{ range $i, $v := .TemplateData.Teams }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $v.Name }}</td>
|
<td>{{ $v.Name }}</td>
|
||||||
<td>{{ $v.UUID }}</td>
|
<td><a href="/team/{{ $v.UUID }}">{{ $v.UUID }}</a></td>
|
||||||
<td>{{ len $v.Members }}</td>
|
<td>{{ len $v.Members }}</td>
|
||||||
<td>{{ $v.Game.Name }}</td>
|
<td>{{ $v.Game.Name }}</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1,9 +1,39 @@
|
|||||||
<script>
|
<script>
|
||||||
var clientId = "{{.ClientId}}";
|
var clientId = "{{.ClientId}}";
|
||||||
</script>
|
</script>
|
||||||
<aside class="flash center {{.FlashClass}}">
|
<div class="flash center {{.FlashClass}}">
|
||||||
{{.FlashMessage}}
|
{{.FlashMessage}}
|
||||||
</aside>
|
</div>
|
||||||
|
<div id="menu" class="{{if .HideAdminMenu}}hidden{{end}}">
|
||||||
|
<div class="pure-menu">
|
||||||
|
<a href="#menu" class="menu-button">
|
||||||
|
<i class="fa fa-bars"></i>
|
||||||
|
</a>
|
||||||
|
<div class="menu-container">
|
||||||
|
<ul class="pure-menu-list">
|
||||||
|
{{ range $k, $v := .Menu }}
|
||||||
|
<li class="pure-menu-item">
|
||||||
|
<a href="{{ $v.Location }}" class="pure-menu-link"><i class="fa {{ $v.Icon }}"></i> {{ $v.Label }}</a>
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
{{ if .ClientIsAuth }}
|
||||||
|
{{ if not .ClientIsServer }}
|
||||||
|
<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 }}
|
||||||
|
<ul class="pure-menu-list menu-bottom">
|
||||||
|
{{ range $k, $v := .BottomMenu }}
|
||||||
|
<li class="pure-menu-item">
|
||||||
|
<a href="{{ $v.Location }}" class="pure-menu-link"><i class="fa {{ $v.Icon }}"></i> {{ $v.Label }}</a>
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{{ if .SubTitle }}
|
{{ if .SubTitle }}
|
||||||
<div class="header-menu">
|
<div class="header-menu">
|
||||||
|
159
templates/public-teammgmt.html
Normal file
159
templates/public-teammgmt.html
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
{{ $uuid := .TemplateData.UUID }}
|
||||||
|
<div class="center">
|
||||||
|
<div class="left">
|
||||||
|
<h3>{{.TemplateData.Name}}</h3>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="left big-space">
|
||||||
|
<form class="pure-form pure-form-aligned" action="/team/{{ $uuid }}/savegame" method="POST">
|
||||||
|
<fieldset>
|
||||||
|
<a name="game" />
|
||||||
|
<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 reset-pull">
|
||||||
|
<a href="/team/{{ $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>
|
||||||
|
<div class="pure-control-group">
|
||||||
|
<label class="control-label">Screenshots</label>
|
||||||
|
<div class="center-all horizontal-scroll thumbnail-container" id="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 data-teamid="{{ $uuid }}" data-ssid="{{ $v.UUID }}" class="thumbnail" alt="{{ $v.Description }}" src="data:image/{{$v.Filetype}};base64,{{ $v.Thumbnail }}" />
|
||||||
|
{{ 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>
|
||||||
|
|
||||||
|
<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>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>
|
||||||
|
<form action="/team/{{ $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="/team/{{ $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-sides pure-button pure-button-primary">Add</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="pure-control-group reset-pull">
|
||||||
|
<a href="/team/{{ $uuid }}" 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="/team/{{ $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>
|
||||||
|
<div id="editscreenshotform" style="display:none;">
|
||||||
|
<div id="editss-container" class="pure-control-group" style="margin-bottom:50px;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
snack.listener(
|
||||||
|
{
|
||||||
|
node:document.getElementById('thumbnail-container'),
|
||||||
|
event:'click',
|
||||||
|
delegate: function(node) {
|
||||||
|
return node.getElementsByTagName('img');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
showEditScreenShotModal(snack.wrap(this)[0]);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function showEditScreenShotModal(img) {
|
||||||
|
var newImg = img.cloneNode();
|
||||||
|
var editSSForm = document.getElementById('editscreenshotform');
|
||||||
|
var cont = document.getElementById('editss-container');
|
||||||
|
while(cont.hasChildNodes()) {
|
||||||
|
cont.removeChild(cont.lastChild);
|
||||||
|
}
|
||||||
|
cont.appendChild(newImg);
|
||||||
|
showModal({
|
||||||
|
title: 'Edit Screenshot',
|
||||||
|
bodyNode: editSSForm,
|
||||||
|
buttons: [
|
||||||
|
{ title: 'Delete', class: 'pure-button-error', position: 'right',
|
||||||
|
click: function() {
|
||||||
|
window.location = "/team/{{ $uuid }}/screenshotdelete/"+img.dataset.ssid;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ title: 'Cancel', class: 'pure-button', position: 'right', click: hideModal }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
editSSForm.style.display="block";
|
||||||
|
editSSForm.style.height="200px";
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
@ -63,7 +63,7 @@
|
|||||||
<div class="center-all horizontal-scroll thumbnail-container" id="thumbnail-container">
|
<div class="center-all horizontal-scroll thumbnail-container" id="thumbnail-container">
|
||||||
{{ range $imgi, $imgv := $v.Game.Screenshots }}
|
{{ range $imgi, $imgv := $v.Game.Screenshots }}
|
||||||
<a href="javascript:embiggenScreenshot('{{$imgv.UUID}}');">
|
<a href="javascript:embiggenScreenshot('{{$imgv.UUID}}');">
|
||||||
<img id="{{ $imgv.UUID }}" data-teamid="{{ $v.UUID }}" data-ssid="{{ $imgv.UUID }}" class="thumbnail" alt="{{ $imgv.Description }}" src="data:image/png;base64,{{ $imgv.Image }}" />
|
<img id="{{ $imgv.UUID }}" data-teamid="{{ $v.UUID }}" data-ssid="{{ $imgv.UUID }}" class="thumbnail" alt="{{ $imgv.Description }}" src="data:image/{{$imgv.Filetype}};base64,{{ $imgv.Thumbnail }}" />
|
||||||
</a>
|
</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
@ -72,9 +72,13 @@
|
|||||||
<div id="embiggenedScreenShot" class="hidden fullscreen" onclick="javascript:document.getElementById('embiggenedScreenShot').classList.add('hidden');"></div>
|
<div id="embiggenedScreenShot" class="hidden fullscreen" onclick="javascript:document.getElementById('embiggenedScreenShot').classList.add('hidden');"></div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<script>
|
<script>
|
||||||
var teamNames = { };
|
var teams = { };
|
||||||
{{ range $i, $v := .TemplateData.Teams }}
|
{{ range $i, $v := .TemplateData.Teams }}
|
||||||
teamNames[{{$v.UUID}}] = { "team-name": "{{$v.Name}}", "game-name": "{{$v.Game.Name}}" };
|
teams[{{$v.UUID}}] = {
|
||||||
|
"team-name": "{{$v.Name}}",
|
||||||
|
"game-name": "{{$v.Game.Name}}",
|
||||||
|
"screenshots": [ {{ range $ssi, $ssv := $v.Game.Screenshots }} {{ $ssv.UUID }}, {{ end }} ]
|
||||||
|
};
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
function showScreenshots(tmuuid) {
|
function showScreenshots(tmuuid) {
|
||||||
@ -82,7 +86,7 @@ function showScreenshots(tmuuid) {
|
|||||||
screenshots.style.display='';
|
screenshots.style.display='';
|
||||||
showModal({
|
showModal({
|
||||||
title: 'Screenshots',
|
title: 'Screenshots',
|
||||||
subtitle: teamNames[tmuuid].game-name,
|
subtitle: teams[tmuuid].game-name,
|
||||||
bodyNode: screenshots,
|
bodyNode: screenshots,
|
||||||
buttons: [{
|
buttons: [{
|
||||||
title: 'Done',
|
title: 'Done',
|
||||||
@ -100,15 +104,16 @@ function embiggenScreenshot(img) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var container = document.getElementById('embiggenedScreenShot');
|
var container = document.getElementById('embiggenedScreenShot');
|
||||||
var clone = ss.cloneNode(true);
|
|
||||||
clone.classList.remove('thumbnail');
|
|
||||||
while(container.hasChildNodes()) {
|
while(container.hasChildNodes()) {
|
||||||
container.removeChild(container.firstChild);
|
container.removeChild(container.firstChild);
|
||||||
}
|
}
|
||||||
var clickToCloseMsg = document.createElement('div');
|
var clickToCloseMsg = document.createElement('div');
|
||||||
clickToCloseMsg.innerText = "Click Image to Close";
|
clickToCloseMsg.innerText = "Click Image to Close";
|
||||||
|
var oImg = document.createElement("img");
|
||||||
|
oImg.setAttribute('src', '/image/'+ss.dataset.teamid+'/'+ss.dataset.ssid);
|
||||||
|
oImg.setAttribute('alt', ss.getAttribute('alt'));
|
||||||
container.appendChild(clickToCloseMsg);
|
container.appendChild(clickToCloseMsg);
|
||||||
container.appendChild(clone);
|
container.appendChild(oImg);
|
||||||
container.classList.remove('hidden');
|
container.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user