diff --git a/assets/templates/admin.tmpl b/assets/templates/admin.tmpl index 07cde22c038d05e646871e162dc6f3c2c23d07ee..ad90885589a3f690fed17daf43b0353135fb856c 100644 --- a/assets/templates/admin.tmpl +++ b/assets/templates/admin.tmpl @@ -23,17 +23,19 @@ </li> <li> <div class="my-match-info"> - {{/* - TODO: send delete via hidden form - */}} - <a href="" target="_blank" class="live-btn">Delete</a> + <form id="destroy-{{.ID}}" method="post" action="/admin/{{.ID}}"> + <input type="hidden" name="Delete" value="true"> + <a class="live-btn" type="submit" style="cursor: default" + onclick="document.getElementById('destroy-{{.ID}}').submit() + ">Delete</a> + </form> <!-- Canlı yayın butonu --> <h5>{{index .Attributes "title"}}</h5> <span>{{.StartTimeFormatted}}</span> </div> </li> <li> - <a href="/admin/{{.ID}}" target="_blank" class="watch-stream"><i + <a href="/admin/{{.ID}}" class="watch-stream"><i class="fas fa-pencil-alt"></i> Düzenle</a> </li> </ul> diff --git a/assets/templates/tournament-config.tmpl b/assets/templates/tournament-config.tmpl index d7977c8750db2356aa096b68660b83e5ddaa08c4..e08207b355b56051111dc4fd2909dd4373ffb81a 100644 --- a/assets/templates/tournament-config.tmpl +++ b/assets/templates/tournament-config.tmpl @@ -16,41 +16,41 @@ <div class="row"> <div class="col-md-12"> <label> - <input type="text" name="Title" value="{{.title}}" + <input type="text" name="Title" value="{{.tournament.Title}}" placeholder="Turnuva Başlığı"> </label> </div> <div class="col-md-6"> <label> Turnuva Tarihi - <input type="date" name="StartTimeString" value="{{.start_time}}" + <input type="date" name="StartTimeString" value="{{.tournament.StartTimeString}}" placeholder="Turnuva Tarihi"> </label> </div> <div class="col-md-6"> <label> Son Kayıt Tarihi - <input type="date" name="DeadlineString" value="{{.deadline}}" + <input type="date" name="DeadlineString" value="{{.tournament.DeadlineString}}" placeholder="Son Kayıt Tarihi"> </label> </div> <div class="col-md-6"> <label for="size">Oyuncular</label><select id="size" name="TeamSize"> - <option value="0"{{if eq .team_size 0}} selected="selected" {{end}}>1 v 1 + <option value="0"{{if eq .tournament.TeamSizeString "0"}} selected="selected" {{end}}>1 v 1 </option> - <option value="1"{{if eq .team_size 1}} selected="selected" {{end}}>2 v 2 + <option value="1"{{if eq .tournament.TeamSizeString "1"}} selected="selected" {{end}}>2 v 2 </option> - <option value="2"{{if eq .team_size 2}} selected="selected" {{end}}>3 v 3 + <option value="2"{{if eq .tournament.TeamSizeString "2"}} selected="selected" {{end}}>3 v 3 </option> - <option value="3"{{if eq .team_size 3}} selected="selected" {{end}}>4 v 4 + <option value="3"{{if eq .tournament.TeamSizeString "3"}} selected="selected" {{end}}>4 v 4 </option> - <option value="4"{{if eq .team_size 4}} selected="selected" {{end}}>5 v 5 + <option value="4"{{if eq .tournament.TeamSizeString "4"}} selected="selected" {{end}}>5 v 5 </option> </select> </div> <div class="col-md-6"> <label> - <input type="text" name="Prize" placeholder="Turnuva Ödülü"> + <input type="text" name="Prize" value="{{.tournament.Prize}}" placeholder="Turnuva Ödülü"> </label> </div> </div> diff --git a/database.go b/database.go index 8697a944b3dcf9f5db8b5c2cc4351f2dcf560550..5a7b04b7d1ff298005deaa21180bd9b4424f52cf 100644 --- a/database.go +++ b/database.go @@ -31,3 +31,7 @@ func closeDatabase() { log.Printf("error closing user database: %s", err) } } + +func isNotFound(err error) bool { + return err == leveldb.ErrNotFound +} diff --git a/routes.go b/routes.go index d08e2f1c71b5ecbfed0582b6fad989b5eb3c1968..ce97232965308032314ed8be79332b3d6b0965d0 100644 --- a/routes.go +++ b/routes.go @@ -1,13 +1,13 @@ package main import ( + "fmt" "git.randomchars.net/levatax/tournament-website/oauth" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" "github.com/google/uuid" "log" "net/http" - "strconv" ) func registerRoutes() { @@ -62,7 +62,7 @@ func registerRoutes() { router.POST("/enroll/:id", func(context *gin.Context) { user := oauth.GetSelf(context) if user == nil { - context.Redirect(http.StatusTemporaryRedirect, "/auth/login") + context.Redirect(http.StatusFound, "/auth/login") return } @@ -120,42 +120,21 @@ func registerRoutes() { router.POST("/admin/new", func(context *gin.Context) { user := oauth.GetSelf(context) if user == nil { - context.Redirect(http.StatusTemporaryRedirect, "/auth/login") + context.Redirect(http.StatusFound, "/auth/login") return } if !administrators[user.ID] { - context.Redirect(http.StatusTemporaryRedirect, "/") - return - } - - payload := tournamentPayload{} - if err := context.Bind(&payload); err != nil { - if config.System.Verbose { - log.Printf("error binding creation form: %s", err) - } - context.String(http.StatusBadRequest, "Bad Request") + context.Redirect(http.StatusFound, "/") return } - if !validatePayloadTournament(&payload) { - if config.System.Verbose { - log.Print("invalid data submitted to creation form") - log.Print(payload) - } - context.String(http.StatusBadRequest, "Bad Request") + t, _ := bindTournament(context) + if t == nil { return } - if err := makeTournament(&tournament{ - StartTime: payload.StartTime(), - Deadline: payload.Deadline(), - Attributes: map[string]string{ - "title": payload.Title, - "prize": payload.Prize, - "size": strconv.Itoa(payload.TeamSize), - }, - }); err != nil { + if err := makeTournament(t); err != nil { log.Printf("error making tournament: %s", err) context.String(http.StatusInternalServerError, "Internal Server Error") } else { @@ -175,22 +154,69 @@ func registerRoutes() { return } - // TODO: render page + t := contextTournament(context) + if t == nil { + return + } + + authText, authRef := getAuthButton(user) + + sy, sm, sd := t.StartTime.Date() + dy, dm, dd := t.Deadline.Date() + context.HTML(http.StatusOK, "tournament-config.tmpl", gin.H{ + "auth_text": authText, + "auth_ref": authRef, + "tournament": tournamentPayload{ + Title: t.Attributes["title"], + StartTimeString: fmt.Sprintf("%d-%.2d-%.2d", sy, sm, sd), + DeadlineString: fmt.Sprintf("%d-%.2d-%.2d", dy, dm, dd), + TeamSizeString: t.Attributes["size"], + Prize: t.Attributes["prize"], + }, + }) }) router.POST("/admin/:id", func(context *gin.Context) { user := oauth.GetSelf(context) if user == nil { - context.Redirect(http.StatusTemporaryRedirect, "/auth/login") + context.Redirect(http.StatusFound, "/auth/login") return } if !administrators[user.ID] { - context.Redirect(http.StatusTemporaryRedirect, "/") + context.Redirect(http.StatusFound, "/") + return + } + + t := contextTournament(context) + if t == nil { + return + } + + tn, del := bindTournament(context) + if tn == nil { return } + tn.ID = t.ID - // TODO: handle updates + if del { + if err := destroyTournament(t.ID); err != nil { + log.Printf("error destroying tournament %s: %s", t.ID.String(), err) + context.String(http.StatusInternalServerError, "Internal Server Error") + return + } else { + context.Redirect(http.StatusFound, "/admin") + return + } + } + + if err := updateTournament(tn); err != nil { + log.Printf("error updating tournament %s: %s", t.ID.String(), err) + context.String(http.StatusInternalServerError, "Internal Server Error") + return + } else { + context.Redirect(http.StatusFound, "") + } }) // OAuth diff --git a/tournament.go b/tournament.go index 9195db5280152a39d39d489e3fbfd63c2805f089..7b6c3d8f7537a9e0e2a91bdd346a01cca170c388 100644 --- a/tournament.go +++ b/tournament.go @@ -1,16 +1,17 @@ package main import ( + "github.com/gin-gonic/gin" "github.com/google/uuid" json "github.com/json-iterator/go" + "log" + "net/http" "strconv" "strings" "sync" "time" ) -// TODO: leveldb.ErrNotFound - type tournament struct { ID uuid.UUID `json:"id"` StartTime time.Time `json:"start_time"` @@ -29,6 +30,7 @@ type tournamentPayload struct { DeadlineString string dl *time.Time TeamSize int + TeamSizeString string Prize string Delete bool } @@ -223,6 +225,58 @@ func destroyTournament(id uuid.UUID) error { return nil } +func contextTournament(context *gin.Context) *tournament { + var t *tournament + if id, err := uuid.Parse(context.Param("id")); err != nil { + if config.System.Verbose { + log.Printf("error parsing UUID %s: %s", context.Param("id"), err) + } + context.Redirect(http.StatusTemporaryRedirect, "/admin") + return nil + } else { + if t, _, err = getTournament(id); err != nil { + if isNotFound(err) { + context.Redirect(http.StatusTemporaryRedirect, "/admin") + return nil + } + log.Printf("error getting tournament %s: %s", id.String(), err) + context.String(http.StatusInternalServerError, "Internal Server Error") + return nil + } + } + return t +} + +func bindTournament(context *gin.Context) (*tournament, bool) { + payload := tournamentPayload{} + if err := context.Bind(&payload); err != nil { + if config.System.Verbose { + log.Printf("error binding creation form: %s", err) + } + context.String(http.StatusBadRequest, "Bad Request") + return nil, false + } + + if !payload.Delete && !validatePayloadTournament(&payload) { + if config.System.Verbose { + log.Print("invalid data submitted to creation form") + log.Print(payload) + } + context.String(http.StatusBadRequest, "Bad Request") + return nil, false + } + + return &tournament{ + StartTime: payload.StartTime(), + Deadline: payload.Deadline(), + Attributes: map[string]string{ + "title": payload.Title, + "prize": payload.Prize, + "size": strconv.Itoa(payload.TeamSize), + }, + }, payload.Delete +} + func validatePayloadTournament(payload *tournamentPayload) bool { return payload.TeamSize >= 0 && payload.TeamSize <= 4 &&