aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2024-08-10 19:55:28 +0900
committernsfisis <nsfisis@gmail.com>2024-08-10 19:55:50 +0900
commit47f95342097e8828059053c168e06cd44e0ab43b (patch)
tree843d09397ccc1e5ec36c926e3eb555e1d6e5ed52
parent0b520dc2529d7df6263842480d4ba7eaf07f4dcd (diff)
downloadiosdc-japan-2024-albatross-47f95342097e8828059053c168e06cd44e0ab43b.tar.gz
iosdc-japan-2024-albatross-47f95342097e8828059053c168e06cd44e0ab43b.tar.zst
iosdc-japan-2024-albatross-47f95342097e8828059053c168e06cd44e0ab43b.zip
feat(backend): include `verification_steps` in `Game` object
-rw-r--r--backend/api/generated.go76
-rw-r--r--backend/api/handler.go33
-rw-r--r--backend/db/query.sql.go26
-rw-r--r--backend/query.sql5
-rw-r--r--frontend/app/.server/api/schema.d.ts7
-rw-r--r--openapi.yaml18
6 files changed, 123 insertions, 42 deletions
diff --git a/backend/api/generated.go b/backend/api/generated.go
index 2a113a4..b33747a 100644
--- a/backend/api/generated.go
+++ b/backend/api/generated.go
@@ -61,14 +61,15 @@ type Error struct {
// Game defines model for Game.
type Game struct {
- DisplayName string `json:"display_name"`
- DurationSeconds int `json:"duration_seconds"`
- GameID int `json:"game_id"`
- GameType GameGameType `json:"game_type"`
- Players []User `json:"players"`
- Problem *Problem `json:"problem,omitempty"`
- StartedAt *int `json:"started_at,omitempty"`
- State GameState `json:"state"`
+ DisplayName string `json:"display_name"`
+ DurationSeconds int `json:"duration_seconds"`
+ GameID int `json:"game_id"`
+ GameType GameGameType `json:"game_type"`
+ Players []User `json:"players"`
+ Problem *Problem `json:"problem,omitempty"`
+ StartedAt *int `json:"started_at,omitempty"`
+ State GameState `json:"state"`
+ VerificationSteps []VerificationStep `json:"verification_steps"`
}
// GameGameType defines model for Game.GameType.
@@ -228,6 +229,12 @@ type User struct {
Username string `json:"username"`
}
+// VerificationStep defines model for VerificationStep.
+type VerificationStep struct {
+ Label string `json:"label"`
+ TestcaseID nullable.Nullable[int] `json:"testcase_id"`
+}
+
// HeaderAuthorization defines model for header_authorization.
type HeaderAuthorization = string
@@ -1108,32 +1115,33 @@ func (sh *strictHandler) GetToken(ctx echo.Context, params GetTokenParams) error
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
- "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",
+ "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",
}
// GetSwagger returns the content of the embedded swagger specification file
diff --git a/backend/api/handler.go b/backend/api/handler.go
index 8830d1c..134a4f9 100644
--- a/backend/api/handler.go
+++ b/backend/api/handler.go
@@ -3,11 +3,13 @@ package api
import (
"context"
"errors"
+ "fmt"
"log"
"net/http"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/nullable"
"github.com/nsfisis/iosdc-japan-2024-albatross/backend/auth"
"github.com/nsfisis/iosdc-japan-2024-albatross/backend/db"
@@ -149,15 +151,30 @@ func (h *Handler) GetGame(ctx context.Context, request GetGameRequestObject, use
IsAdmin: playerRow.IsAdmin,
}
}
+ testcaseIDs, err := h.q.ListTestcaseIDsByGameID(ctx, int32(gameID))
+ if err != nil {
+ return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+ }
+ verificationSteps := make([]VerificationStep, len(testcaseIDs)+1)
+ verificationSteps[0] = VerificationStep{
+ Label: "Compile",
+ }
+ for i, testcaseID := range testcaseIDs {
+ verificationSteps[i+1] = VerificationStep{
+ TestcaseID: nullable.NewNullableWithValue(int(testcaseID)),
+ Label: fmt.Sprintf("Testcase %d", i+1),
+ }
+ }
game := Game{
- GameID: int(row.GameID),
- GameType: GameGameType(row.GameType),
- State: GameState(row.State),
- DisplayName: row.DisplayName,
- DurationSeconds: int(row.DurationSeconds),
- StartedAt: startedAt,
- Problem: problem,
- Players: players,
+ GameID: int(row.GameID),
+ GameType: GameGameType(row.GameType),
+ State: GameState(row.State),
+ DisplayName: row.DisplayName,
+ DurationSeconds: int(row.DurationSeconds),
+ StartedAt: startedAt,
+ Problem: problem,
+ Players: players,
+ VerificationSteps: verificationSteps,
}
return GetGame200JSONResponse{
Game: game,
diff --git a/backend/db/query.sql.go b/backend/db/query.sql.go
index 392e6a6..cbef51d 100644
--- a/backend/db/query.sql.go
+++ b/backend/db/query.sql.go
@@ -403,6 +403,32 @@ func (q *Queries) ListGamesForPlayer(ctx context.Context, userID int32) ([]ListG
return items, nil
}
+const listTestcaseIDsByGameID = `-- name: ListTestcaseIDsByGameID :many
+SELECT testcases.testcase_id FROM testcases
+WHERE testcases.problem_id = (SELECT problem_id FROM games WHERE game_id = $1)
+ORDER BY testcases.testcase_id
+`
+
+func (q *Queries) ListTestcaseIDsByGameID(ctx context.Context, gameID int32) ([]int32, error) {
+ rows, err := q.db.Query(ctx, listTestcaseIDsByGameID, gameID)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ var items []int32
+ for rows.Next() {
+ var testcase_id int32
+ if err := rows.Scan(&testcase_id); err != nil {
+ return nil, err
+ }
+ items = append(items, testcase_id)
+ }
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
+ return items, nil
+}
+
const listTestcasesByGameID = `-- name: ListTestcasesByGameID :many
SELECT testcase_id, problem_id, stdin, stdout FROM testcases
WHERE testcases.problem_id = (SELECT problem_id FROM games WHERE game_id = $1)
diff --git a/backend/query.sql b/backend/query.sql
index 12b67b9..bcbee12 100644
--- a/backend/query.sql
+++ b/backend/query.sql
@@ -83,6 +83,11 @@ SELECT * FROM testcases
WHERE testcases.problem_id = (SELECT problem_id FROM games WHERE game_id = $1)
ORDER BY testcases.testcase_id;
+-- name: ListTestcaseIDsByGameID :many
+SELECT testcases.testcase_id FROM testcases
+WHERE testcases.problem_id = (SELECT problem_id FROM games WHERE game_id = $1)
+ORDER BY testcases.testcase_id;
+
-- name: CreateSubmissionResult :exec
INSERT INTO submission_results (submission_id, status, stdout, stderr)
VALUES ($1, $2, $3, $4);
diff --git a/frontend/app/.server/api/schema.d.ts b/frontend/app/.server/api/schema.d.ts
index f7caebb..779f11e 100644
--- a/frontend/app/.server/api/schema.d.ts
+++ b/frontend/app/.server/api/schema.d.ts
@@ -113,6 +113,13 @@ export interface components {
started_at?: number;
problem?: components["schemas"]["Problem"];
players: components["schemas"]["User"][];
+ verification_steps: components["schemas"]["VerificationStep"][];
+ };
+ VerificationStep: {
+ /** @example 1 */
+ testcase_id: number | null;
+ /** @example Test case 1 */
+ label: string;
};
Problem: {
/** @example 1 */
diff --git a/openapi.yaml b/openapi.yaml
index fdd0146..6d9dea3 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -220,6 +220,10 @@ components:
type: array
items:
$ref: '#/components/schemas/User'
+ verification_steps:
+ type: array
+ items:
+ $ref: '#/components/schemas/VerificationStep'
required:
- game_id
- game_type
@@ -227,6 +231,20 @@ components:
- display_name
- duration_seconds
- players
+ - verification_steps
+ VerificationStep:
+ type: object
+ properties:
+ testcase_id:
+ type: integer
+ nullable: true
+ example: 1
+ label:
+ type: string
+ example: "Test case 1"
+ required:
+ - testcase_id
+ - label
Problem:
type: object
properties: