Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d81394c
ci: attempt 123129037123 to make multiarch images
jus1d Oct 16, 2025
1da19ac
ci: Update Dockerfile to sped up multiarch builds
jus1d Oct 16, 2025
d11d2e2
ci: try to fix warn
jus1d Oct 16, 2025
d7a340b
chore: use CONFIG_PATH from .env
jus1d Oct 16, 2025
949d6f0
chore: rollback multiarch builds
jus1d Oct 16, 2025
ef4a34f
chore: change 404 to 401 on /api/account
jus1d Oct 16, 2025
92c10cd
chore: return err if we cant publish to q
jus1d Oct 19, 2025
ca76081
chore: Remove migrations [moved to infra repo]
jus1d Oct 21, 2025
0459953
chore: Introduce status field in submission
jus1d Oct 21, 2025
61f3702
chore: remove unused verdicts
jus1d Oct 21, 2025
070b43e
refactor: Replace relation `failed_tests` with `testing_report`
jus1d Oct 23, 2025
dc55081
chore: Introduce `failed` status
jus1d Oct 23, 2025
048121c
chore: Remove text answer problem support
jus1d Oct 24, 2025
4161dee
chore: Remove log of /api/healthcheck
jus1d Oct 24, 2025
bdf20ad
chore: skip only 200 healthchecks
jus1d Oct 24, 2025
bc8efde
chore: Add submission deadline
jus1d Oct 25, 2025
b00ff7a
FIX: personal deadline counts with respect to contest.start_time
jus1d Oct 26, 2025
b8b0ade
fix: remove submission deadline if contest is not started
jus1d Oct 26, 2025
cb5311f
chore: add memory limit
jus1d Oct 26, 2025
b428ab8
chore: add time and memory limits to problem items responses
jus1d Oct 27, 2025
70df59a
chore: Introduce different checkers support
jus1d Oct 29, 2025
1babedf
ci: add builds with branch tags
jus1d Oct 29, 2025
29ff31f
fix(#16): forbid to view contest problems before start
jus1d Oct 30, 2025
c1f22e6
ci: push images on tag pushed
jus1d Oct 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,16 @@ on:
branches:
- master
- dev
tags:
- '*'

jobs:
build-image:
runs-on: ubuntu-latest

env:
IMAGE_NAME: ghcr.io/voidcontests/api

steps:
- name: Checkout code
uses: actions/checkout@v4
Expand All @@ -22,9 +27,8 @@ jobs:
password: ${{ secrets.GHCR_TOKEN }}

- name: Build and push image
run: |
SHORT_SHA=${GITHUB_SHA::7}
docker build -t ghcr.io/voidcontests/api:$SHORT_SHA \
-t ghcr.io/voidcontests/api:latest .
docker push ghcr.io/voidcontests/api:$SHORT_SHA
docker push ghcr.io/voidcontests/api:latest
run: curl -sSL https://raw.githubusercontent.com/voidcontests/infra/refs/heads/master/push-image.sh | bash -s -- $IMAGE_NAME
env:
GITHUB_SHA: ${{ github.sha }}
GITHUB_REF: ${{ github.ref }}
IMAGE_NAME: ${{ env.IMAGE_NAME }}
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ RUN go mod download

COPY . .
RUN go build -a -ldflags "-w -s \
-X github.com/voidcontests/api/internal/version.GIT_COMMIT=$(git rev-parse --short HEAD) \
-X github.com/voidcontests/api/internal/version.GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" \
-X github.com/voidcontests/api/internal/version.Commit=$(git rev-parse --short HEAD) \
-X github.com/voidcontests/api/internal/version.Branch=$(git rev-parse --abbrev-ref HEAD)" \
-o build/api ./cmd/api

# Lightweight docker container with binaries only
# lightweight docker container with binaries only
FROM alpine:latest

WORKDIR /app
Expand Down
88 changes: 0 additions & 88 deletions build.sh

This file was deleted.

21 changes: 0 additions & 21 deletions docker-compose.local.yaml

This file was deleted.

2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
container_name: void-api
restart: unless-stopped
environment:
CONFIG_PATH: ./config/dev.yaml
CONFIG_PATH: ${CONFIG_PATH}
ports:
- "5919:5919"
volumes:
Expand Down
2 changes: 1 addition & 1 deletion internal/app/handler/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (h *Handler) GetAccount(c echo.Context) error {

user, err := h.repo.User.GetByID(ctx, claims.UserID)
if errors.Is(err, pgx.ErrNoRows) {
return Error(http.StatusNotFound, "user not found")
return Error(http.StatusUnauthorized, "invalid or expired token")
}
if err != nil {
return fmt.Errorf("%s: can't get user: %v", op, err)
Expand Down
19 changes: 13 additions & 6 deletions internal/app/handler/contest.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,18 @@ func (h *Handler) GetContestByID(c echo.Context) error {

for i := range n {
cdetailed.Problems[i] = response.ContestProblemListItem{
ID: problems[i].ID,
Charcode: problems[i].Charcode,
ContestID: contest.ID,
ID: problems[i].ID,
Charcode: problems[i].Charcode,
Writer: response.User{
ID: problems[i].WriterID,
Username: problems[i].WriterUsername,
},
Title: problems[i].Title,
Difficulty: problems[i].Difficulty,
CreatedAt: problems[i].CreatedAt,
Title: problems[i].Title,
Difficulty: problems[i].Difficulty,
TimeLimitMS: problems[i].TimeLimitMS,
MemoryLimitMB: problems[i].MemoryLimitMB,
Checker: problems[i].Checker,
CreatedAt: problems[i].CreatedAt,
}
}

Expand All @@ -135,6 +137,11 @@ func (h *Handler) GetContestByID(c echo.Context) error {

cdetailed.IsParticipant = true

_, deadline := AllowSubmitAt(contest, entry)
if contest.StartTime.Before(time.Now()) {
cdetailed.SubmissionDeadline = &deadline
}

statuses, err := h.repo.Submission.GetProblemStatuses(ctx, entry.ID)
if err != nil {
return fmt.Errorf("%s: can't get submissions: %v", op, err)
Expand Down
20 changes: 9 additions & 11 deletions internal/app/handler/dto/request/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,16 @@ type CreateContestRequest struct {
}

type CreateProblemRequest struct {
Title string `json:"title" required:"true"`
Kind string `json:"kind" required:"true"`
Statement string `json:"statement" required:"true"`
Difficulty string `json:"difficulty" required:"true"`
TimeLimitMS int `json:"time_limit_ms"`
TestCases []models.TestCaseDTO `json:"test_cases"`
Answer string `json:"answer"`
Title string `json:"title" required:"true"`
Statement string `json:"statement" required:"true"`
Difficulty string `json:"difficulty" required:"true"`
TimeLimitMS int `json:"time_limit_ms"`
MemoryLimitMB int `json:"memory_limit_mb"`
Checker string `json:"checker"`
TestCases []models.TestCaseDTO `json:"test_cases"`
}

type CreateSubmissionRequest struct {
ProblemKind string `json:"problem_kind" required:"true"`
Answer string `json:"answer"`
Code string `json:"code"`
Language string `json:"language"`
Code string `json:"code"`
Language string `json:"language"`
}
118 changes: 64 additions & 54 deletions internal/app/handler/dto/response/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,20 @@ type User struct {
}

type ContestDetailed struct {
ID int32 `json:"id"`
Creator User `json:"creator"`
Title string `json:"title"`
Description string `json:"description"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
DurationMins int32 `json:"duration_mins"`
MaxEntries int32 `json:"max_entries,omitempty"`
Participants int32 `json:"participants"`
AllowLateJoin bool `json:"allow_late_join"`
IsParticipant bool `json:"is_participant,omitempty"`
Problems []ContestProblemListItem `json:"problems"`
CreatedAt time.Time `json:"created_at"`
ID int32 `json:"id"`
Creator User `json:"creator"`
Title string `json:"title"`
Description string `json:"description"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
DurationMins int32 `json:"duration_mins"`
MaxEntries int32 `json:"max_entries,omitempty"`
Participants int32 `json:"participants"`
AllowLateJoin bool `json:"allow_late_join"`
IsParticipant bool `json:"is_participant,omitempty"`
SubmissionDeadline *time.Time `json:"submission_deadline,omitempty"`
Problems []ContestProblemListItem `json:"problems"`
CreatedAt time.Time `json:"created_at"`
}

type ContestListItem struct {
Expand All @@ -73,72 +74,81 @@ type ContestListItem struct {
type Submission struct {
ID int32 `json:"id"`
ProblemID int32 `json:"problem_id"`
ProblemKind string `json:"problem_kind"`
Status string `json:"status"`
Verdict string `json:"verdict"`
Answer string `json:"answer,omitempty"`
Code string `json:"code,omitempty"`
Language string `json:"language,omitempty"`
TestingReport *TestingReport `json:"testing_report,omitempty"`
CreatedAt time.Time `json:"created_at"`
}

type TestingReport struct {
Passed int `json:"passed"`
Total int `json:"total"`
Stderr string `json:"stderr,omitempty"`
FailedTest *FailedTest `json:"failed_test,omitempty"`
ID int32 `json:"id"`
PassedTestsCount int32 `json:"passed_tests_count"`
TotalTestsCount int32 `json:"total_tests_count"`
FailedTest *Test `json:"failed_test,omitempty"`
Stderr string `json:"stderr"`
CreatedAt time.Time `json:"created_at"`
}

type FailedTest struct {
type Test struct {
Input string `json:"input"`
ExpectedOutput string `json:"expected_output"`
ActualOutput string `json:"actual_output"`
}

type ContestProblemDetailed struct {
ID int32 `json:"id"`
Charcode string `json:"charcode"`
ContestID int32 `json:"contest_id"`
Writer User `json:"writer"`
Kind string `json:"kind"`
Title string `json:"title"`
Statement string `json:"statement"`
Examples []TC `json:"examples,omitempty"`
Difficulty string `json:"difficulty"`
Status string `json:"status,omitempty"`
TimeLimitMS int32 `json:"time_limit_ms"`
CreatedAt time.Time `json:"created_at"`
ID int32 `json:"id"`
Charcode string `json:"charcode"`
ContestID int32 `json:"contest_id"`
Writer User `json:"writer"`
Title string `json:"title"`
Statement string `json:"statement"`
Examples []TC `json:"examples,omitempty"`
Difficulty string `json:"difficulty"`
Status string `json:"status,omitempty"`
TimeLimitMS int32 `json:"time_limit_ms"`
MemoryLimitMB int32 `json:"memory_limit_mb"`
Checker string `json:"checker"`
SubmissionDeadline *time.Time `json:"submission_deadline,omitempty"`
CreatedAt time.Time `json:"created_at"`
}

type ContestProblemListItem struct {
ID int32 `json:"id"`
Charcode string `json:"charcode"`
ContestID int32 `json:"contest_id"`
Writer User `json:"writer"`
Title string `json:"title"`
Difficulty string `json:"difficulty"`
Status string `json:"status,omitempty"`
CreatedAt time.Time `json:"created_at"`
ID int32 `json:"id"`
Charcode string `json:"charcode"`
Writer User `json:"writer"`
Title string `json:"title"`
Difficulty string `json:"difficulty"`
Status string `json:"status,omitempty"`
TimeLimitMS int32 `json:"time_limit_ms"`
MemoryLimitMB int32 `json:"memory_limit_mb"`
Checker string `json:"checker"`
CreatedAt time.Time `json:"created_at"`
}

type ProblemDetailed struct {
ID int32 `json:"id"`
Writer User `json:"writer"`
Kind string `json:"kind"`
Title string `json:"title"`
Statement string `json:"statement"`
Examples []TC `json:"examples,omitempty"`
Difficulty string `json:"difficulty"`
TimeLimitMS int32 `json:"time_limit_ms"`
CreatedAt time.Time `json:"created_at"`
ID int32 `json:"id"`
Writer User `json:"writer"`
Title string `json:"title"`
Statement string `json:"statement"`
Examples []TC `json:"examples,omitempty"`
Difficulty string `json:"difficulty"`
TimeLimitMS int32 `json:"time_limit_ms"`
MemoryLimitMB int32 `json:"memory_limit_mb"`
Checker string `json:"checker"`
CreatedAt time.Time `json:"created_at"`
}

type ProblemListItem struct {
ID int32 `json:"id"`
Writer User `json:"writer"`
Title string `json:"title"`
Difficulty string `json:"difficulty"`
CreatedAt time.Time `json:"created_at"`
ID int32 `json:"id"`
Writer User `json:"writer"`
Title string `json:"title"`
Difficulty string `json:"difficulty"`
TimeLimitMS int32 `json:"time_limit_ms"`
MemoryLimitMB int32 `json:"memory_limit_mb"`
Checker string `json:"checker"`
CreatedAt time.Time `json:"created_at"`
}

type TC struct {
Expand Down
Loading