diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-20 21:30:49 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-20 21:30:49 +0900 |
| commit | fa788237eb5649e08b2a38ec21689b481b10c073 (patch) | |
| tree | 13ad37ff587b81810f59e8e7c5943aafd25f61dd /backend/admin/handler.go | |
| parent | 9f9efc2bc07810d2e06b37bad94e5922681eadef (diff) | |
| download | phperkaigi-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.go | 61 |
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 { |
