diff options
| -rw-r--r-- | backend/admin/handler.go | 54 | ||||
| -rw-r--r-- | backend/admin/templates/restart.html | 19 |
2 files changed, 73 insertions, 0 deletions
diff --git a/backend/admin/handler.go b/backend/admin/handler.go index fcf85a3..61c58a3 100644 --- a/backend/admin/handler.go +++ b/backend/admin/handler.go @@ -87,6 +87,9 @@ func (h *Handler) RegisterHandlers(g *echo.Group) { g.POST("/problems/:problemID/testcases/:testcaseID", h.postTestcaseEdit) g.POST("/problems/:problemID/testcases/:testcaseID/delete", h.postTestcaseDelete) + g.GET("/restart", h.getRestart) + g.POST("/restart", h.postRestart) + g.GET("/tournaments", h.getTournaments) g.GET("/tournaments/new", h.getTournamentNew) g.POST("/tournaments/new", h.postTournamentNew) @@ -1182,3 +1185,54 @@ func (h *Handler) postTournamentEdit(c echo.Context) error { return c.Redirect(http.StatusSeeOther, h.conf.BasePath+"admin/tournaments") } + +func (h *Handler) getRestart(c echo.Context) error { + return c.Render(http.StatusOK, "restart", echo.Map{ + "BasePath": h.conf.BasePath, + "Title": "Restart All Games", + }) +} + +func (h *Handler) postRestart(c echo.Context) error { + endAtRaw := c.FormValue("end_at") + endAt, err := time.ParseInLocation("2006-01-02T15:04", endAtRaw, jst) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, "Invalid end_at") + } + endAtUTC := endAt.UTC() + + startedAt := time.Now().Add(10 * time.Second) + durationSeconds := int(endAtUTC.Sub(startedAt).Seconds()) + if durationSeconds <= 0 { + return echo.NewHTTPError(http.StatusBadRequest, "end_at must be in the future") + } + + ctx := c.Request().Context() + + games, err := h.q.ListAllGames(ctx) + if err != nil { + return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) + } + + for _, g := range games { + err := h.gameSvc.UpdateGameWithPlayers(ctx, game.UpdateGameParams{ + GameID: int(g.GameID), + GameType: "multiplayer", + IsPublic: g.IsPublic, + DisplayName: g.DisplayName, + DurationSeconds: durationSeconds, + StartedAt: pgtype.Timestamp{ + Time: startedAt, + Valid: true, + }, + ProblemID: int(g.ProblemID), + MainPlayerIDs: []int{}, + }) + if err != nil { + slog.ErrorContext(ctx, "failed to restart game", "game_id", g.GameID, "error", err) + return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("failed to restart game %d: %s", g.GameID, err.Error())) + } + } + + return c.Redirect(http.StatusSeeOther, h.conf.BasePath+"admin/games") +} diff --git a/backend/admin/templates/restart.html b/backend/admin/templates/restart.html new file mode 100644 index 0000000..2bb77e9 --- /dev/null +++ b/backend/admin/templates/restart.html @@ -0,0 +1,19 @@ +{{ template "base.html" . }} + +{{ define "breadcrumb" }} +<a href="{{ .BasePath }}admin/dashboard">Dashboard</a> +{{ end }} + +{{ define "content" }} +<h2>Restart All Games</h2> +<p>全ゲームの main player を削除し、multiplayer に変更して一括リスタートします。</p> +<form method="post"> + <div> + <label>終了日時 (JST)</label> + <input type="datetime-local" name="end_at" required> + </div> + <div> + <button type="submit">Restart All Games</button> + </div> +</form> +{{ end }} |
