xcpcio 0.63.6__py3-none-any.whl → 0.64.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xcpcio might be problematic. Click here for more details.
- xcpcio/__version__.py +1 -1
- xcpcio/ccs/api_server/dependencies.py +8 -3
- xcpcio/ccs/api_server/routes/__init__.py +2 -0
- xcpcio/ccs/api_server/routes/access.py +2 -4
- xcpcio/ccs/api_server/routes/accounts.py +35 -0
- xcpcio/ccs/api_server/routes/awards.py +4 -9
- xcpcio/ccs/api_server/routes/clarifications.py +7 -15
- xcpcio/ccs/api_server/routes/contests.py +55 -39
- xcpcio/ccs/api_server/routes/general.py +5 -4
- xcpcio/ccs/api_server/routes/groups.py +6 -13
- xcpcio/ccs/api_server/routes/judgement_types.py +6 -13
- xcpcio/ccs/api_server/routes/judgements.py +4 -9
- xcpcio/ccs/api_server/routes/languages.py +6 -13
- xcpcio/ccs/api_server/routes/organizations.py +9 -41
- xcpcio/ccs/api_server/routes/problems.py +9 -36
- xcpcio/ccs/api_server/routes/runs.py +4 -9
- xcpcio/ccs/api_server/routes/submissions.py +9 -41
- xcpcio/ccs/api_server/routes/teams.py +9 -41
- xcpcio/ccs/api_server/services/contest_service.py +105 -319
- xcpcio/ccs/base/__init__.py +3 -0
- xcpcio/ccs/base/types.py +9 -0
- xcpcio/ccs/contest_archiver.py +2 -3
- xcpcio/ccs/reader/__init__.py +0 -0
- xcpcio/ccs/reader/base_ccs_reader.py +165 -0
- xcpcio/ccs/reader/contest_package_reader.py +331 -0
- {xcpcio-0.63.6.dist-info → xcpcio-0.64.0.dist-info}/METADATA +2 -1
- xcpcio-0.64.0.dist-info/RECORD +39 -0
- xcpcio-0.63.6.dist-info/RECORD +0 -33
- {xcpcio-0.63.6.dist-info → xcpcio-0.64.0.dist-info}/WHEEL +0 -0
- {xcpcio-0.63.6.dist-info → xcpcio-0.64.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from pathlib import Path
|
|
3
2
|
from typing import Any, Dict, List
|
|
4
3
|
|
|
5
|
-
from fastapi import APIRouter
|
|
4
|
+
from fastapi import APIRouter
|
|
6
5
|
from fastapi import Path as FastAPIPath
|
|
7
6
|
from fastapi.responses import FileResponse
|
|
8
7
|
|
|
9
|
-
from ...model import Problem, Problems
|
|
10
8
|
from ..dependencies import ContestServiceDep
|
|
11
9
|
|
|
12
10
|
router = APIRouter()
|
|
@@ -15,36 +13,32 @@ logger = logging.getLogger(__name__)
|
|
|
15
13
|
|
|
16
14
|
@router.get(
|
|
17
15
|
"/contests/{contest_id}/problems",
|
|
18
|
-
summary="Get
|
|
19
|
-
|
|
20
|
-
response_model=Problems,
|
|
16
|
+
summary="Get all the problems for this contest",
|
|
17
|
+
response_model=List[Dict[str, Any]],
|
|
21
18
|
)
|
|
22
19
|
async def get_problems(
|
|
23
|
-
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
20
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
21
|
+
service: ContestServiceDep = None,
|
|
24
22
|
) -> List[Dict[str, Any]]:
|
|
25
|
-
"""Get all problems in the contest"""
|
|
26
23
|
return service.get_problems(contest_id)
|
|
27
24
|
|
|
28
25
|
|
|
29
26
|
@router.get(
|
|
30
27
|
"/contests/{contest_id}/problems/{problem_id}",
|
|
31
|
-
summary="Get
|
|
32
|
-
|
|
33
|
-
response_model=Problem,
|
|
28
|
+
summary="Get the given problem for this contest",
|
|
29
|
+
response_model=Dict[str, Any],
|
|
34
30
|
)
|
|
35
31
|
async def get_problem(
|
|
36
32
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
37
33
|
problem_id: str = FastAPIPath(..., description="Problem identifier"),
|
|
38
34
|
service: ContestServiceDep = None,
|
|
39
35
|
) -> Dict[str, Any]:
|
|
40
|
-
"""Get specific problem information"""
|
|
41
36
|
return service.get_problem(contest_id, problem_id)
|
|
42
37
|
|
|
43
38
|
|
|
44
39
|
@router.get(
|
|
45
40
|
"/contests/{contest_id}/problems/{problem_id}/statement",
|
|
46
41
|
summary="Get Problem Statement",
|
|
47
|
-
description="Get problem statement file",
|
|
48
42
|
response_class=FileResponse,
|
|
49
43
|
)
|
|
50
44
|
async def get_problem_statement(
|
|
@@ -52,26 +46,5 @@ async def get_problem_statement(
|
|
|
52
46
|
problem_id: str = FastAPIPath(..., description="Problem identifier"),
|
|
53
47
|
service: ContestServiceDep = None,
|
|
54
48
|
) -> FileResponse:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
# Get problem from indexed data
|
|
59
|
-
problem: Dict = service.problems_by_id.get(problem_id)
|
|
60
|
-
if not problem:
|
|
61
|
-
raise HTTPException(status_code=404, detail=f"Problem {problem_id} not found")
|
|
62
|
-
|
|
63
|
-
# Expected href pattern for this endpoint
|
|
64
|
-
expected_href = f"contests/{contest_id}/problems/{problem_id}/statement"
|
|
65
|
-
|
|
66
|
-
try:
|
|
67
|
-
statements = problem.get("statement", [])
|
|
68
|
-
for statement in statements:
|
|
69
|
-
href = statement["href"]
|
|
70
|
-
filename = statement["filename"]
|
|
71
|
-
if href == expected_href and filename:
|
|
72
|
-
statement_file: Path = service.contest_package_dir / "problems" / problem_id / filename
|
|
73
|
-
if statement_file.exists():
|
|
74
|
-
mime_type = statement["mime"]
|
|
75
|
-
return FileResponse(path=statement_file, media_type=mime_type, filename=filename)
|
|
76
|
-
except Exception as e:
|
|
77
|
-
raise HTTPException(status_code=404, detail=f"Statement not found. [problem_id={problem_id}] [err={e}]")
|
|
49
|
+
file_attr = service.get_problem_statement(contest_id, problem_id)
|
|
50
|
+
return FileResponse(path=file_attr.path, media_type=file_attr.media_type, filename=file_attr.name)
|
|
@@ -3,7 +3,6 @@ from typing import Any, Dict, List, Optional
|
|
|
3
3
|
|
|
4
4
|
from fastapi import APIRouter, Path, Query
|
|
5
5
|
|
|
6
|
-
from ...model import Run, Runs
|
|
7
6
|
from ..dependencies import ContestServiceDep
|
|
8
7
|
|
|
9
8
|
router = APIRouter()
|
|
@@ -12,29 +11,25 @@ logger = logging.getLogger(__name__)
|
|
|
12
11
|
|
|
13
12
|
@router.get(
|
|
14
13
|
"/contests/{contest_id}/runs",
|
|
15
|
-
summary="Get
|
|
16
|
-
|
|
17
|
-
response_model=Runs,
|
|
14
|
+
summary="Get all the runs for this contest",
|
|
15
|
+
response_model=List[Dict[str, Any]],
|
|
18
16
|
)
|
|
19
17
|
async def get_runs(
|
|
20
18
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
21
19
|
judgement_id: Optional[str] = Query(None, description="Filter runs by judgement ID"),
|
|
22
20
|
service: ContestServiceDep = None,
|
|
23
21
|
) -> List[Dict[str, Any]]:
|
|
24
|
-
"""Get all test case runs, optionally filtered by judgement"""
|
|
25
22
|
return service.get_runs(contest_id, judgement_id)
|
|
26
23
|
|
|
27
24
|
|
|
28
25
|
@router.get(
|
|
29
26
|
"/contests/{contest_id}/runs/{run_id}",
|
|
30
|
-
summary="Get
|
|
31
|
-
|
|
32
|
-
response_model=Run,
|
|
27
|
+
summary="Get the given run for this contest",
|
|
28
|
+
response_model=Dict[str, Any],
|
|
33
29
|
)
|
|
34
30
|
async def get_run(
|
|
35
31
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
36
32
|
run_id: str = Path(..., description="Run identifier"),
|
|
37
33
|
service: ContestServiceDep = None,
|
|
38
34
|
) -> Dict[str, Any]:
|
|
39
|
-
"""Get specific test case run information"""
|
|
40
35
|
return service.get_run(contest_id, run_id)
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
2
|
+
from typing import Any, Dict, List
|
|
4
3
|
|
|
5
|
-
from fastapi import APIRouter
|
|
4
|
+
from fastapi import APIRouter
|
|
6
5
|
from fastapi import Path as FastAPIPath
|
|
7
6
|
from fastapi.responses import FileResponse
|
|
8
7
|
|
|
9
|
-
from ...model import Submission, Submissions
|
|
10
8
|
from ..dependencies import ContestServiceDep
|
|
11
9
|
|
|
12
10
|
router = APIRouter()
|
|
@@ -15,39 +13,32 @@ logger = logging.getLogger(__name__)
|
|
|
15
13
|
|
|
16
14
|
@router.get(
|
|
17
15
|
"/contests/{contest_id}/submissions",
|
|
18
|
-
summary="Get
|
|
19
|
-
|
|
20
|
-
response_model=Submissions,
|
|
16
|
+
summary="Get all the submissions for this contest",
|
|
17
|
+
response_model=List[Dict[str, Any]],
|
|
21
18
|
)
|
|
22
19
|
async def get_submissions(
|
|
23
20
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
24
|
-
team_id: Optional[str] = Query(None, description="Filter submissions by team ID"),
|
|
25
|
-
problem_id: Optional[str] = Query(None, description="Filter submissions by problem ID"),
|
|
26
21
|
service: ContestServiceDep = None,
|
|
27
22
|
) -> List[Dict[str, Any]]:
|
|
28
|
-
|
|
29
|
-
return service.get_submissions(contest_id, team_id, problem_id)
|
|
23
|
+
return service.get_submissions(contest_id)
|
|
30
24
|
|
|
31
25
|
|
|
32
26
|
@router.get(
|
|
33
27
|
"/contests/{contest_id}/submissions/{submission_id}",
|
|
34
|
-
summary="Get
|
|
35
|
-
|
|
36
|
-
response_model=Submission,
|
|
28
|
+
summary="Get the given submission for this contest",
|
|
29
|
+
response_model=Dict[str, Any],
|
|
37
30
|
)
|
|
38
31
|
async def get_submission(
|
|
39
32
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
40
33
|
submission_id: str = FastAPIPath(..., description="Submission identifier"),
|
|
41
34
|
service: ContestServiceDep = None,
|
|
42
35
|
) -> Dict[str, Any]:
|
|
43
|
-
"""Get specific submission information"""
|
|
44
36
|
return service.get_submission(contest_id, submission_id)
|
|
45
37
|
|
|
46
38
|
|
|
47
39
|
@router.get(
|
|
48
40
|
"/contests/{contest_id}/submissions/{submission_id}/files",
|
|
49
41
|
summary="Get Submission Files",
|
|
50
|
-
description="Get files for a specific submission",
|
|
51
42
|
response_class=FileResponse,
|
|
52
43
|
)
|
|
53
44
|
async def get_submission_files(
|
|
@@ -55,28 +46,5 @@ async def get_submission_files(
|
|
|
55
46
|
submission_id: str = FastAPIPath(..., description="Submission identifier"),
|
|
56
47
|
service: ContestServiceDep = None,
|
|
57
48
|
) -> FileResponse:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# Get submission from indexed data
|
|
62
|
-
submission = service.submissions_by_id.get(submission_id)
|
|
63
|
-
if not submission:
|
|
64
|
-
raise HTTPException(status_code=404, detail=f"Submission {submission_id} not found")
|
|
65
|
-
|
|
66
|
-
# Expected href pattern for this endpoint
|
|
67
|
-
expected_href = f"contests/{contest_id}/submissions/{submission_id}/files"
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
files: List[Dict] = submission["files"]
|
|
71
|
-
for file_info in files:
|
|
72
|
-
href = file_info["href"]
|
|
73
|
-
if href == expected_href:
|
|
74
|
-
filename = file_info["filename"]
|
|
75
|
-
submission_file: Path = service.contest_package_dir / "submissions" / submission_id / filename
|
|
76
|
-
if submission_file.exists():
|
|
77
|
-
mime_type = file_info["mime"]
|
|
78
|
-
return FileResponse(path=submission_file, media_type=mime_type, filename=filename)
|
|
79
|
-
except Exception as e:
|
|
80
|
-
raise HTTPException(
|
|
81
|
-
status_code=404, detail=f"Submission files not found. [submission_id={submission_id}] [err={e}]"
|
|
82
|
-
)
|
|
49
|
+
file_attr = service.get_submission_file(contest_id, submission_id)
|
|
50
|
+
return FileResponse(path=file_attr.path, media_type=file_attr.media_type, filename=file_attr.name)
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
2
|
+
from typing import Any, Dict, List
|
|
4
3
|
|
|
5
|
-
from fastapi import APIRouter
|
|
4
|
+
from fastapi import APIRouter
|
|
6
5
|
from fastapi import Path as FastAPIPath
|
|
7
6
|
from fastapi.responses import FileResponse
|
|
8
7
|
|
|
9
|
-
from ...model import (
|
|
10
|
-
Team,
|
|
11
|
-
Teams,
|
|
12
|
-
)
|
|
13
8
|
from ..dependencies import ContestServiceDep
|
|
14
9
|
|
|
15
10
|
router = APIRouter()
|
|
@@ -18,38 +13,32 @@ logger = logging.getLogger(__name__)
|
|
|
18
13
|
|
|
19
14
|
@router.get(
|
|
20
15
|
"/contests/{contest_id}/teams",
|
|
21
|
-
summary="Get
|
|
22
|
-
|
|
23
|
-
response_model=Teams,
|
|
16
|
+
summary="Get all the teams for this contest",
|
|
17
|
+
response_model=List[Dict[str, Any]],
|
|
24
18
|
)
|
|
25
19
|
async def get_teams(
|
|
26
20
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
27
|
-
group_id: Optional[str] = Query(None, description="Filter teams by group ID"),
|
|
28
21
|
service: ContestServiceDep = None,
|
|
29
22
|
) -> List[Dict[str, Any]]:
|
|
30
|
-
|
|
31
|
-
return service.get_teams(contest_id, group_id)
|
|
23
|
+
return service.get_teams(contest_id)
|
|
32
24
|
|
|
33
25
|
|
|
34
26
|
@router.get(
|
|
35
27
|
"/contests/{contest_id}/teams/{team_id}",
|
|
36
|
-
summary="Get
|
|
37
|
-
|
|
38
|
-
response_model=Team,
|
|
28
|
+
summary="Get the given team for this contest",
|
|
29
|
+
response_model=Dict[str, Any],
|
|
39
30
|
)
|
|
40
31
|
async def get_team(
|
|
41
32
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
42
33
|
team_id: str = FastAPIPath(..., description="Team identifier"),
|
|
43
34
|
service: ContestServiceDep = None,
|
|
44
35
|
) -> Dict[str, Any]:
|
|
45
|
-
"""Get specific team information"""
|
|
46
36
|
return service.get_team(contest_id, team_id)
|
|
47
37
|
|
|
48
38
|
|
|
49
39
|
@router.get(
|
|
50
40
|
"/contests/{contest_id}/teams/{team_id}/photo",
|
|
51
41
|
summary="Get Team Photo",
|
|
52
|
-
description="Get photo file for a specific team",
|
|
53
42
|
response_class=FileResponse,
|
|
54
43
|
)
|
|
55
44
|
async def get_team_photo(
|
|
@@ -57,26 +46,5 @@ async def get_team_photo(
|
|
|
57
46
|
team_id: str = FastAPIPath(..., description="Team identifier"),
|
|
58
47
|
service: ContestServiceDep = None,
|
|
59
48
|
) -> FileResponse:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
# Get team from indexed data
|
|
64
|
-
team = service.teams_by_id.get(team_id)
|
|
65
|
-
if not team:
|
|
66
|
-
raise HTTPException(status_code=404, detail=f"Team {team_id} not found")
|
|
67
|
-
|
|
68
|
-
# Expected href pattern for this endpoint
|
|
69
|
-
expected_href = f"contests/{contest_id}/teams/{team_id}/photo"
|
|
70
|
-
|
|
71
|
-
try:
|
|
72
|
-
photos = team["photo"]
|
|
73
|
-
for photo in photos:
|
|
74
|
-
href = photo["href"]
|
|
75
|
-
if href == expected_href:
|
|
76
|
-
filename = ["filename"]
|
|
77
|
-
photo_file: Path = service.contest_package_dir / "teams" / team_id / filename
|
|
78
|
-
if photo_file.exists():
|
|
79
|
-
mime_type = photo["mime"]
|
|
80
|
-
return FileResponse(path=photo_file, media_type=mime_type, filename=filename)
|
|
81
|
-
except Exception as e:
|
|
82
|
-
raise HTTPException(status_code=404, detail=f"Photo not found. [team_id={team_id}] [err={e}]")
|
|
49
|
+
file_attr = service.get_team_photo(contest_id, team_id)
|
|
50
|
+
return FileResponse(path=file_attr.path, media_type=file_attr.media_type, filename=file_attr.name)
|