xcpcio 0.63.7__py3-none-any.whl → 0.64.1__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/contests.py +5 -34
- xcpcio/ccs/api_server/routes/organizations.py +3 -24
- xcpcio/ccs/api_server/routes/problems.py +3 -22
- xcpcio/ccs/api_server/routes/submissions.py +3 -24
- xcpcio/ccs/api_server/routes/teams.py +3 -22
- xcpcio/ccs/api_server/services/contest_service.py +104 -235
- xcpcio/ccs/base/__init__.py +3 -0
- xcpcio/ccs/base/types.py +9 -0
- 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.64.1.dist-info/METADATA +86 -0
- {xcpcio-0.63.7.dist-info → xcpcio-0.64.1.dist-info}/RECORD +17 -12
- xcpcio-0.63.7.dist-info/METADATA +0 -30
- {xcpcio-0.63.7.dist-info → xcpcio-0.64.1.dist-info}/WHEEL +0 -0
- {xcpcio-0.63.7.dist-info → xcpcio-0.64.1.dist-info}/entry_points.txt +0 -0
xcpcio/__version__.py
CHANGED
|
@@ -5,13 +5,15 @@ Dependency injection system for Contest API Server.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Annotated
|
|
8
|
+
from typing import Annotated, Dict
|
|
9
9
|
|
|
10
10
|
from fastapi import Depends
|
|
11
11
|
|
|
12
|
+
from xcpcio.ccs.reader.base_ccs_reader import BaseCCSReader
|
|
13
|
+
from xcpcio.ccs.reader.contest_package_reader import ContestPackageReader
|
|
14
|
+
|
|
12
15
|
from .services.contest_service import ContestService
|
|
13
16
|
|
|
14
|
-
# Global contest service instance cache
|
|
15
17
|
_contest_service_instance = None
|
|
16
18
|
|
|
17
19
|
|
|
@@ -41,7 +43,10 @@ def configure_dependencies(contest_package_dir: Path) -> None:
|
|
|
41
43
|
contest_package_dir: Path to contest package directory
|
|
42
44
|
"""
|
|
43
45
|
global _contest_service_instance
|
|
44
|
-
|
|
46
|
+
reader_dict: Dict[str, BaseCCSReader] = {}
|
|
47
|
+
contest_package_reader = ContestPackageReader(contest_package_dir)
|
|
48
|
+
reader_dict[contest_package_reader.get_contest_id()] = contest_package_reader
|
|
49
|
+
_contest_service_instance = ContestService(reader_dict)
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
# Type alias for dependency injection
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
-
from pathlib import Path
|
|
4
3
|
from typing import Any, Dict, List, Optional
|
|
5
4
|
|
|
6
|
-
from fastapi import APIRouter,
|
|
5
|
+
from fastapi import APIRouter, Query
|
|
7
6
|
from fastapi import Path as FastAPIPath
|
|
8
7
|
from fastapi.responses import FileResponse, StreamingResponse
|
|
9
8
|
|
|
@@ -55,22 +54,8 @@ async def get_contest_banner(
|
|
|
55
54
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
56
55
|
service: ContestServiceDep = None,
|
|
57
56
|
) -> FileResponse:
|
|
58
|
-
service.
|
|
59
|
-
|
|
60
|
-
expected_href = f"contests/{contest_id}/banner"
|
|
61
|
-
|
|
62
|
-
try:
|
|
63
|
-
banners = service.contest.get("banner", [])
|
|
64
|
-
for banner in banners:
|
|
65
|
-
href = banner["href"]
|
|
66
|
-
if href == expected_href:
|
|
67
|
-
filename = banner["filename"]
|
|
68
|
-
banner_file: Path = service.contest_package_dir / "contest" / filename
|
|
69
|
-
if banner_file.exists():
|
|
70
|
-
mime_type = banner["mime"]
|
|
71
|
-
return FileResponse(path=banner_file, media_type=mime_type, filename=filename)
|
|
72
|
-
except Exception as e:
|
|
73
|
-
raise HTTPException(status_code=404, detail=f"Banner not found. [contest_id={contest_id}] [err={e}]")
|
|
57
|
+
file_attr = service.get_contest_banner(contest_id)
|
|
58
|
+
return FileResponse(path=file_attr.path, media_type=file_attr.media_type, filename=file_attr.name)
|
|
74
59
|
|
|
75
60
|
|
|
76
61
|
@router.get(
|
|
@@ -82,22 +67,8 @@ async def get_contest_problem_set(
|
|
|
82
67
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
83
68
|
service: ContestServiceDep = None,
|
|
84
69
|
) -> FileResponse:
|
|
85
|
-
service.
|
|
86
|
-
|
|
87
|
-
expected_href = f"contests/{contest_id}/problemset"
|
|
88
|
-
|
|
89
|
-
try:
|
|
90
|
-
problem_set_list = service.contest.get("problemset", [])
|
|
91
|
-
for problem_set in problem_set_list:
|
|
92
|
-
href = problem_set["href"]
|
|
93
|
-
if href == expected_href:
|
|
94
|
-
filename = problem_set["filename"]
|
|
95
|
-
problem_set_file: Path = service.contest_package_dir / "contest" / filename
|
|
96
|
-
if problem_set_file.exists():
|
|
97
|
-
mime_type = problem_set["mime"]
|
|
98
|
-
return FileResponse(path=problem_set_file, media_type=mime_type, filename=filename)
|
|
99
|
-
except Exception as e:
|
|
100
|
-
raise HTTPException(status_code=404, detail=f"Problem set not found. [contest_id={contest_id}] [err={e}]")
|
|
70
|
+
file_attr = service.get_contest_problemset(contest_id)
|
|
71
|
+
return FileResponse(path=file_attr.path, media_type=file_attr.media_type, filename=file_attr.name)
|
|
101
72
|
|
|
102
73
|
|
|
103
74
|
@router.get(
|
|
@@ -1,8 +1,7 @@
|
|
|
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
|
|
|
@@ -47,25 +46,5 @@ async def get_organization_logo(
|
|
|
47
46
|
organization_id: str = FastAPIPath(..., description="Organization identifier"),
|
|
48
47
|
service: ContestServiceDep = None,
|
|
49
48
|
) -> FileResponse:
|
|
50
|
-
service.
|
|
51
|
-
|
|
52
|
-
org = service.organizations_by_id.get(organization_id)
|
|
53
|
-
if not org:
|
|
54
|
-
raise HTTPException(status_code=404, detail=f"Organization {organization_id} not found")
|
|
55
|
-
|
|
56
|
-
expected_href = f"contests/{contest_id}/organizations/{organization_id}/logo"
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
logos = org["logo"]
|
|
60
|
-
for logo in logos:
|
|
61
|
-
href = logo["href"]
|
|
62
|
-
if href == expected_href:
|
|
63
|
-
filename = logo["filename"]
|
|
64
|
-
logo_file: Path = service.contest_package_dir / "organizations" / organization_id / filename
|
|
65
|
-
if logo_file.exists():
|
|
66
|
-
mime_type = logo["mime"]
|
|
67
|
-
return FileResponse(path=logo_file, media_type=mime_type, filename=filename)
|
|
68
|
-
except Exception as e:
|
|
69
|
-
raise HTTPException(
|
|
70
|
-
status_code=404, detail=f"Logo file not found. [organization_id={organization_id}] [err={e}]"
|
|
71
|
-
)
|
|
49
|
+
file_attr = service.get_organization_logo(contest_id, organization_id)
|
|
50
|
+
return FileResponse(path=file_attr.path, media_type=file_attr.media_type, filename=file_attr.name)
|
|
@@ -1,8 +1,7 @@
|
|
|
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
|
|
|
@@ -47,23 +46,5 @@ async def get_problem_statement(
|
|
|
47
46
|
problem_id: str = FastAPIPath(..., description="Problem identifier"),
|
|
48
47
|
service: ContestServiceDep = None,
|
|
49
48
|
) -> FileResponse:
|
|
50
|
-
service.
|
|
51
|
-
|
|
52
|
-
problem: Dict = service.problems_by_id.get(problem_id)
|
|
53
|
-
if not problem:
|
|
54
|
-
raise HTTPException(status_code=404, detail=f"Problem {problem_id} not found")
|
|
55
|
-
|
|
56
|
-
expected_href = f"contests/{contest_id}/problems/{problem_id}/statement"
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
statements = problem.get("statement", [])
|
|
60
|
-
for statement in statements:
|
|
61
|
-
href = statement["href"]
|
|
62
|
-
filename = statement["filename"]
|
|
63
|
-
if href == expected_href and filename:
|
|
64
|
-
statement_file: Path = service.contest_package_dir / "problems" / problem_id / filename
|
|
65
|
-
if statement_file.exists():
|
|
66
|
-
mime_type = statement["mime"]
|
|
67
|
-
return FileResponse(path=statement_file, media_type=mime_type, filename=filename)
|
|
68
|
-
except Exception as e:
|
|
69
|
-
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)
|
|
@@ -1,8 +1,7 @@
|
|
|
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
|
|
|
@@ -47,25 +46,5 @@ async def get_submission_files(
|
|
|
47
46
|
submission_id: str = FastAPIPath(..., description="Submission identifier"),
|
|
48
47
|
service: ContestServiceDep = None,
|
|
49
48
|
) -> FileResponse:
|
|
50
|
-
service.
|
|
51
|
-
|
|
52
|
-
submission = service.submissions_by_id.get(submission_id)
|
|
53
|
-
if not submission:
|
|
54
|
-
raise HTTPException(status_code=404, detail=f"Submission {submission_id} not found")
|
|
55
|
-
|
|
56
|
-
expected_href = f"contests/{contest_id}/submissions/{submission_id}/files"
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
files: List[Dict] = submission["files"]
|
|
60
|
-
for file_info in files:
|
|
61
|
-
href = file_info["href"]
|
|
62
|
-
if href == expected_href:
|
|
63
|
-
filename = file_info["filename"]
|
|
64
|
-
submission_file: Path = service.contest_package_dir / "submissions" / submission_id / filename
|
|
65
|
-
if submission_file.exists():
|
|
66
|
-
mime_type = file_info["mime"]
|
|
67
|
-
return FileResponse(path=submission_file, media_type=mime_type, filename=filename)
|
|
68
|
-
except Exception as e:
|
|
69
|
-
raise HTTPException(
|
|
70
|
-
status_code=404, detail=f"Submission files not found. [submission_id={submission_id}] [err={e}]"
|
|
71
|
-
)
|
|
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,8 +1,7 @@
|
|
|
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
|
|
|
@@ -47,23 +46,5 @@ async def get_team_photo(
|
|
|
47
46
|
team_id: str = FastAPIPath(..., description="Team identifier"),
|
|
48
47
|
service: ContestServiceDep = None,
|
|
49
48
|
) -> FileResponse:
|
|
50
|
-
service.
|
|
51
|
-
|
|
52
|
-
team = service.teams_by_id.get(team_id)
|
|
53
|
-
if not team:
|
|
54
|
-
raise HTTPException(status_code=404, detail=f"Team {team_id} not found")
|
|
55
|
-
|
|
56
|
-
expected_href = f"contests/{contest_id}/teams/{team_id}/photo"
|
|
57
|
-
|
|
58
|
-
try:
|
|
59
|
-
photos = team["photo"]
|
|
60
|
-
for photo in photos:
|
|
61
|
-
href = photo["href"]
|
|
62
|
-
if href == expected_href:
|
|
63
|
-
filename = photo["filename"]
|
|
64
|
-
photo_file: Path = service.contest_package_dir / "teams" / team_id / filename
|
|
65
|
-
if photo_file.exists():
|
|
66
|
-
mime_type = photo["mime"]
|
|
67
|
-
return FileResponse(path=photo_file, media_type=mime_type, filename=filename)
|
|
68
|
-
except Exception as e:
|
|
69
|
-
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)
|