aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/admin/handler.go
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-20 21:30:49 +0900
committernsfisis <nsfisis@gmail.com>2026-02-20 21:30:49 +0900
commitfa788237eb5649e08b2a38ec21689b481b10c073 (patch)
tree13ad37ff587b81810f59e8e7c5943aafd25f61dd /backend/admin/handler.go
parent9f9efc2bc07810d2e06b37bad94e5922681eadef (diff)
downloadphperkaigi-2026-albatross-fa788237eb5649e08b2a38ec21689b481b10c073.tar.gz
phperkaigi-2026-albatross-fa788237eb5649e08b2a38ec21689b481b10c073.tar.zst
phperkaigi-2026-albatross-fa788237eb5649e08b2a38ec21689b481b10c073.zip
feat(admin): add rejudge functionality for submissions
Allow administrators to re-execute test cases for a specific submission from the submission detail page. This is useful after testcase fixes or worker issues. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'backend/admin/handler.go')
-rw-r--r--backend/admin/handler.go61
1 files changed, 59 insertions, 2 deletions
diff --git a/backend/admin/handler.go b/backend/admin/handler.go
index 6e981bc..c8ddd25 100644
--- a/backend/admin/handler.go
+++ b/backend/admin/handler.go
@@ -3,6 +3,7 @@ package admin
import (
"context"
"errors"
+ "fmt"
"log/slog"
"net/http"
"strconv"
@@ -20,14 +21,19 @@ import (
var jst = time.FixedZone("Asia/Tokyo", 9*60*60)
+type GameHub interface {
+ EnqueueTestTasks(ctx context.Context, submissionID, gameID, userID int, language, code string) error
+}
+
type Handler struct {
q db.Querier
txm db.TxManager
+ hub GameHub
conf *config.Config
}
-func NewHandler(q db.Querier, txm db.TxManager, conf *config.Config) *Handler {
- return &Handler{q: q, txm: txm, conf: conf}
+func NewHandler(q db.Querier, txm db.TxManager, hub GameHub, conf *config.Config) *Handler {
+ return &Handler{q: q, txm: txm, hub: hub, conf: conf}
}
func (h *Handler) newAdminMiddleware() echo.MiddlewareFunc {
@@ -67,6 +73,7 @@ func (h *Handler) RegisterHandlers(g *echo.Group) {
g.POST("/games/:gameID/start", h.postGameStart)
g.GET("/games/:gameID/submissions", h.getSubmissions)
g.GET("/games/:gameID/submissions/:submissionID", h.getSubmissionDetail)
+ g.POST("/games/:gameID/submissions/:submissionID/rejudge", h.postSubmissionRejudge)
g.GET("/problems", h.getProblems)
g.GET("/problems/new", h.getProblemNew)
@@ -664,6 +671,56 @@ func (h *Handler) getSubmissionDetail(c echo.Context) error {
})
}
+func (h *Handler) postSubmissionRejudge(c echo.Context) error {
+ gameID, err := strconv.Atoi(c.Param("gameID"))
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Invalid game_id")
+ }
+
+ submissionID, err := strconv.Atoi(c.Param("submissionID"))
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Invalid submission_id")
+ }
+
+ ctx := c.Request().Context()
+
+ submission, err := h.q.GetSubmissionByID(ctx, int32(submissionID))
+ if err != nil {
+ if errors.Is(err, pgx.ErrNoRows) {
+ return echo.NewHTTPError(http.StatusNotFound)
+ }
+ return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+ }
+
+ game, err := h.q.GetGameByID(ctx, int32(gameID))
+ if err != nil {
+ if errors.Is(err, pgx.ErrNoRows) {
+ return echo.NewHTTPError(http.StatusNotFound)
+ }
+ return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+ }
+
+ err = h.txm.RunInTx(ctx, func(qtx db.Querier) error {
+ if err := qtx.DeleteTestcaseResultsBySubmissionID(ctx, int32(submissionID)); err != nil {
+ return err
+ }
+ return qtx.UpdateSubmissionStatus(ctx, db.UpdateSubmissionStatusParams{
+ SubmissionID: int32(submissionID),
+ Status: "running",
+ })
+ })
+ if err != nil {
+ return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+ }
+
+ err = h.hub.EnqueueTestTasks(ctx, submissionID, gameID, int(submission.UserID), game.Language, submission.Code)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+ }
+
+ return c.Redirect(http.StatusSeeOther, fmt.Sprintf("%sadmin/games/%d/submissions/%d", h.conf.BasePath, gameID, submissionID))
+}
+
func (h *Handler) getProblems(c echo.Context) error {
rows, err := h.q.ListProblems(c.Request().Context())
if err != nil {