Skip to content

Commit 74b2053

Browse files
authored
Merge pull request #25 from ddps-lab/feat/versionupgrade
Test & Submit 기능 변경 및 채점 플랫폼 업그레이드
2 parents ed18485 + be9df05 commit 74b2053

11 files changed

Lines changed: 222 additions & 155 deletions

File tree

platform/CTFd/api/v1/challenges.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -631,19 +631,19 @@ def post(self):
631631
request_data = request.get_json()
632632

633633
challenge_id = request_data.get("challenge_id")
634-
635-
# Check for preview flag in request data (for both admin and regular users)
636-
preview = request_data.get("preview", False)
637-
638-
# Allow preview for SQL challenges
639-
if preview:
634+
635+
# Check for test flag in request data (for testing without recording submission)
636+
test = request_data.get("test", False)
637+
638+
# Allow test mode for SQL challenges
639+
if test:
640640
challenge = Challenges.query.filter_by(id=challenge_id).first_or_404()
641641

642642
# Check if challenge is hidden and user is not admin
643643
if challenge.state == "hidden" and not is_admin():
644644
abort(403)
645645

646-
# Only allow preview for SQL challenges
646+
# Only allow test mode for SQL challenges
647647
if challenge.type == "sql":
648648
chal_class = get_chal_class(challenge.type)
649649
response = chal_class.attempt(challenge, request)

platform/CTFd/plugins/sql_challenges/Dockerfile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
FROM golang:1.22-alpine AS builder
1+
FROM golang:1.23-alpine AS builder
22

33
WORKDIR /app
44

55
# Copy go mod files
66
COPY go.mod go.sum ./
77

8-
# Download dependencies
9-
RUN go mod download
10-
11-
# Copy source code
8+
# Copy source code (needed for go mod tidy to detect dependencies)
129
COPY sql_judge_server.go .
1310

11+
# Download dependencies and tidy
12+
RUN go mod download && go mod tidy
13+
1414
# Build the application
1515
RUN go build -o sql-judge-server sql_judge_server.go
1616

platform/CTFd/plugins/sql_challenges/__init__.py

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -211,26 +211,26 @@ def attempt(cls, challenge, request):
211211
"""
212212
data = request.form or request.get_json()
213213
submission = data.get("submission", "").strip()
214-
is_preview = data.get("preview", False) # Check if this is just a preview/test
215-
214+
is_test = data.get("test", False) # Check if this is test mode (checks correctness but doesn't record)
215+
216216
# Get user information from request
217217
user_id = str(data.get("user_id", ""))
218218
user_name = data.get("user_name", "")
219219
client_ip = get_ip()
220-
220+
221221
# Debug logging
222222
import logging
223-
logging.info(f"SQL Challenge attempt - Preview: {is_preview}, User ID: {user_id}, User Name: {user_name}, IP: {client_ip}")
224-
223+
logging.info(f"SQL Challenge attempt - Test mode: {is_test}, User ID: {user_id}, User Name: {user_name}, IP: {client_ip}")
224+
225225
if not submission:
226226
return ChallengeResponse(
227227
status="incorrect",
228228
message="Please provide a SQL query"
229229
)
230-
231-
# Check deadline only for actual submissions, not previews
230+
231+
# Check deadline only for actual submissions, not test mode
232232
# Use deadline_utc (raw datetime) for comparison, not the property (which returns a string)
233-
if not is_preview and challenge.deadline_utc and datetime.utcnow() > challenge.deadline_utc:
233+
if not is_test and challenge.deadline_utc and datetime.utcnow() > challenge.deadline_utc:
234234
return ChallengeResponse(
235235
status="incorrect",
236236
message="Submission deadline has passed"
@@ -240,17 +240,17 @@ def attempt(cls, challenge, request):
240240
try:
241241
import requests
242242
import json
243-
243+
244244
# Use Go MySQL server
245245
go_server_url = os.environ.get('SQL_JUDGE_SERVER_URL', 'http://localhost:8080')
246-
247-
if is_preview:
248-
# For preview, only execute the user query without comparing
246+
247+
if is_test:
248+
# For test mode, check correctness but format message differently
249249
response = requests.post(
250250
f"{go_server_url}/judge",
251251
json={
252252
'init_query': challenge.init_query,
253-
'solution_query': submission, # Use user query as solution to get its result
253+
'solution_query': challenge.solution_query,
254254
'user_query': submission,
255255
'user_id': user_id,
256256
'user_name': user_name,
@@ -259,26 +259,34 @@ def attempt(cls, challenge, request):
259259
},
260260
timeout=10
261261
)
262-
262+
263263
if response.status_code == 200:
264264
result = response.json()
265-
265+
266266
if not result.get('success'):
267267
return ChallengeResponse(
268268
status="incorrect",
269-
message=f"[PREVIEW]\nError: {result.get('error', 'Unknown error')}"
269+
message=f"[TEST]\nError: {result.get('error', 'Unknown error')}"
270270
)
271-
272-
# Just show the query result without grading
271+
272+
# Format results for display
273273
user_result_str = json.dumps(result['user_result'])
274-
return ChallengeResponse(
275-
status="incorrect",
276-
message=f"[PREVIEW]\nQuery executed successfully:\n\n[USER_RESULT]\n{user_result_str}\n[/USER_RESULT]"
277-
)
274+
275+
if result['match']:
276+
return ChallengeResponse(
277+
status="correct",
278+
message=f"[TEST]\n✅ Correct! Your query produces the expected result.\n\n[USER_RESULT]\n{user_result_str}\n[/USER_RESULT]"
279+
)
280+
else:
281+
expected_result_str = json.dumps(result['expected_result'])
282+
return ChallengeResponse(
283+
status="incorrect",
284+
message=f"[TEST]\n❌ Incorrect. Your query does not produce the expected result.\n\n[USER_RESULT]\n{user_result_str}\n[/USER_RESULT]\n\n[EXPECTED_RESULT]\n{expected_result_str}\n[/EXPECTED_RESULT]"
285+
)
278286
else:
279287
return ChallengeResponse(
280288
status="incorrect",
281-
message=f"[PREVIEW]\nSQL judge server error: HTTP {response.status_code}"
289+
message=f"[TEST]\nSQL judge server error: HTTP {response.status_code}"
282290
)
283291
else:
284292
# Normal submission - compare with solution

platform/CTFd/plugins/sql_challenges/assets/update.html

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ <h5>Test Results:</h5>
8383
The state of the challenge (visible, hidden)
8484
</small>
8585
</label>
86-
<select class="form-control challenge-state" name="state">
86+
<select class="form-control" name="state">
8787
<option value="visible" {% if challenge.state == "visible" %}selected{% endif %}>Visible</option>
8888
<option value="hidden" {% if challenge.state == "hidden" %}selected{% endif %}>Hidden</option>
8989
</select>
@@ -97,6 +97,11 @@ <h5>Test Results:</h5>
9797
</label>
9898
<input type="number" class="form-control challenge-max-attempts" name="max_attempts" placeholder="0" value="{{ challenge.max_attempts }}">
9999
</div>
100-
101-
<button type="submit" class="btn btn-primary">Update</button>
100+
101+
<div class="d-flex gap-8">
102+
<button type="submit" class="btn btn-primary mr-2">Update</button>
103+
<a href="/challenges/sql/{{ challenge.id }}" class="btn btn-info" target="_blank">
104+
<i class="fas fa-external-link-alt me-1"></i> View Challenge Page
105+
</a>
106+
</div>
102107
</form>

platform/CTFd/plugins/sql_challenges/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.22
44

55
toolchain go1.24.5
66

7-
require github.com/dolthub/go-mysql-server v0.18.1
7+
require github.com/dolthub/go-mysql-server v0.20.0
88

99
require (
1010
github.com/cespare/xxhash/v2 v2.2.0 // indirect

platform/CTFd/plugins/sql_challenges/sql_judge_server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ func executeQuery(initQueries []string, query string, req *QueryRequest) (*Query
291291
// }
292292
// }
293293

294-
_, iter, err := engine.Query(ctx, stmt)
294+
_, iter, _, err := engine.Query(ctx, stmt)
295295
if err != nil {
296296
if len(stmt) > logMaxLength {
297297
log.Printf("Failed to execute (truncated): %s...", stmt[:logMaxLength])
@@ -317,7 +317,7 @@ func executeQuery(initQueries []string, query string, req *QueryRequest) (*Query
317317
}
318318

319319
// Execute the main query
320-
schema, iter, err := engine.Query(ctx, query)
320+
schema, iter, _, err := engine.Query(ctx, query)
321321
if err != nil {
322322
return nil, fmt.Errorf("query error: %v", err)
323323
}

0 commit comments

Comments
 (0)