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
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
|
|
@@ -8,6 +8,7 @@ from fastapi import APIRouter
|
|
|
8
8
|
|
|
9
9
|
from . import (
|
|
10
10
|
access,
|
|
11
|
+
accounts,
|
|
11
12
|
awards,
|
|
12
13
|
clarifications,
|
|
13
14
|
contests,
|
|
@@ -30,6 +31,7 @@ def create_router() -> APIRouter:
|
|
|
30
31
|
|
|
31
32
|
# Include all route modules
|
|
32
33
|
router.include_router(access.router, tags=["Access"])
|
|
34
|
+
router.include_router(accounts.router, tags=["Accounts"])
|
|
33
35
|
router.include_router(awards.router, tags=["Awards"])
|
|
34
36
|
router.include_router(clarifications.router, tags=["Clarifications"])
|
|
35
37
|
router.include_router(contests.router, tags=["Contests"])
|
|
@@ -11,10 +11,8 @@ logger = logging.getLogger(__name__)
|
|
|
11
11
|
|
|
12
12
|
@router.get(
|
|
13
13
|
"/contests/{contest_id}/access",
|
|
14
|
-
summary="Get
|
|
15
|
-
description="Get access capabilities and visible endpoints for current client",
|
|
14
|
+
summary="Get access information",
|
|
16
15
|
response_model=Dict[str, Any],
|
|
17
16
|
)
|
|
18
17
|
async def get_access(contest_id: str, service: ContestServiceDep) -> Dict[str, Any]:
|
|
19
|
-
|
|
20
|
-
return service.get_access_info(contest_id)
|
|
18
|
+
return service.get_access(contest_id)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Dict, List
|
|
3
|
+
|
|
4
|
+
from fastapi import APIRouter
|
|
5
|
+
from fastapi import Path as FastAPIPath
|
|
6
|
+
|
|
7
|
+
from ..dependencies import ContestServiceDep
|
|
8
|
+
|
|
9
|
+
router = APIRouter()
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@router.get(
|
|
14
|
+
"/contests/{contest_id}/accounts",
|
|
15
|
+
summary="Get all the accounts",
|
|
16
|
+
response_model=List[Dict[str, Any]],
|
|
17
|
+
)
|
|
18
|
+
async def get_accounts(
|
|
19
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
20
|
+
service: ContestServiceDep = None,
|
|
21
|
+
) -> List[Dict[str, Any]]:
|
|
22
|
+
return service.get_accounts(contest_id)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@router.get(
|
|
26
|
+
"/contests/{contest_id}/accounts/{account_id}",
|
|
27
|
+
summary="Get the given account",
|
|
28
|
+
response_model=Dict[str, Any],
|
|
29
|
+
)
|
|
30
|
+
async def get_account(
|
|
31
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
32
|
+
account_id: str = FastAPIPath(..., description="Account identifier"),
|
|
33
|
+
service: ContestServiceDep = None,
|
|
34
|
+
) -> Dict[str, Any]:
|
|
35
|
+
return service.get_account(contest_id, account_id)
|
|
@@ -3,7 +3,6 @@ from typing import Any, Dict, List
|
|
|
3
3
|
|
|
4
4
|
from fastapi import APIRouter, Path
|
|
5
5
|
|
|
6
|
-
from ...model import Award, Awards
|
|
7
6
|
from ..dependencies import ContestServiceDep
|
|
8
7
|
|
|
9
8
|
router = APIRouter()
|
|
@@ -12,27 +11,23 @@ logger = logging.getLogger(__name__)
|
|
|
12
11
|
|
|
13
12
|
@router.get(
|
|
14
13
|
"/contests/{contest_id}/awards",
|
|
15
|
-
summary="Get
|
|
16
|
-
|
|
17
|
-
response_model=Awards,
|
|
14
|
+
summary="Get all the awards standings for this contest",
|
|
15
|
+
response_model=List[Dict[str, Any]],
|
|
18
16
|
)
|
|
19
17
|
async def get_awards(
|
|
20
18
|
contest_id: str = Path(..., description="Contest identifier"), service: ContestServiceDep = None
|
|
21
19
|
) -> List[Dict[str, Any]]:
|
|
22
|
-
"""Get all awards"""
|
|
23
20
|
return service.get_awards(contest_id)
|
|
24
21
|
|
|
25
22
|
|
|
26
23
|
@router.get(
|
|
27
24
|
"/contests/{contest_id}/awards/{award_id}",
|
|
28
|
-
summary="Get
|
|
29
|
-
|
|
30
|
-
response_model=Award,
|
|
25
|
+
summary="Get the specific award for this contest",
|
|
26
|
+
response_model=Dict[str, Any],
|
|
31
27
|
)
|
|
32
28
|
async def get_award(
|
|
33
29
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
34
30
|
award_id: str = Path(..., description="Award identifier"),
|
|
35
31
|
service: ContestServiceDep = None,
|
|
36
32
|
) -> Dict[str, Any]:
|
|
37
|
-
"""Get specific award information"""
|
|
38
33
|
return service.get_award(contest_id, award_id)
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any, Dict, List
|
|
2
|
+
from typing import Any, Dict, List
|
|
3
3
|
|
|
4
|
-
from fastapi import APIRouter, Path
|
|
4
|
+
from fastapi import APIRouter, Path
|
|
5
5
|
|
|
6
|
-
from ...model import Clarification, Clarifications
|
|
7
6
|
from ..dependencies import ContestServiceDep
|
|
8
7
|
|
|
9
8
|
router = APIRouter()
|
|
@@ -12,31 +11,24 @@ logger = logging.getLogger(__name__)
|
|
|
12
11
|
|
|
13
12
|
@router.get(
|
|
14
13
|
"/contests/{contest_id}/clarifications",
|
|
15
|
-
summary="Get
|
|
16
|
-
|
|
17
|
-
response_model=Clarifications,
|
|
14
|
+
summary="Get all the clarifications for this contest",
|
|
15
|
+
response_model=List[Dict[str, Any]],
|
|
18
16
|
)
|
|
19
17
|
async def get_clarifications(
|
|
20
18
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
21
|
-
from_team_id: Optional[str] = Query(None, description="Filter by sender team ID (empty string for null)"),
|
|
22
|
-
to_team_id: Optional[str] = Query(None, description="Filter by recipient team ID (empty string for null)"),
|
|
23
|
-
problem_id: Optional[str] = Query(None, description="Filter by problem ID (empty string for null)"),
|
|
24
19
|
service: ContestServiceDep = None,
|
|
25
20
|
) -> List[Dict[str, Any]]:
|
|
26
|
-
|
|
27
|
-
return service.get_clarifications(contest_id, from_team_id, to_team_id, problem_id)
|
|
21
|
+
return service.get_clarifications(contest_id)
|
|
28
22
|
|
|
29
23
|
|
|
30
24
|
@router.get(
|
|
31
25
|
"/contests/{contest_id}/clarifications/{clarification_id}",
|
|
32
|
-
summary="Get
|
|
33
|
-
|
|
34
|
-
response_model=Clarification,
|
|
26
|
+
summary="Get the given clarifications for this contest",
|
|
27
|
+
response_model=Dict[str, Any],
|
|
35
28
|
)
|
|
36
29
|
async def get_clarification(
|
|
37
30
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
38
31
|
clarification_id: str = Path(..., description="Clarification identifier"),
|
|
39
32
|
service: ContestServiceDep = None,
|
|
40
33
|
) -> Dict[str, Any]:
|
|
41
|
-
"""Get specific clarification information"""
|
|
42
34
|
return service.get_clarification(contest_id, clarification_id)
|
|
@@ -1,74 +1,90 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
|
-
from
|
|
3
|
-
from typing import Any, Dict, List
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
4
|
|
|
5
|
-
from fastapi import APIRouter,
|
|
5
|
+
from fastapi import APIRouter, Query
|
|
6
6
|
from fastapi import Path as FastAPIPath
|
|
7
|
-
from fastapi.responses import FileResponse
|
|
7
|
+
from fastapi.responses import FileResponse, StreamingResponse
|
|
8
8
|
|
|
9
|
-
from ...model import Contest, State
|
|
10
9
|
from ..dependencies import ContestServiceDep
|
|
11
10
|
|
|
12
11
|
router = APIRouter()
|
|
13
12
|
logger = logging.getLogger(__name__)
|
|
14
13
|
|
|
15
14
|
|
|
16
|
-
@router.get(
|
|
15
|
+
@router.get(
|
|
16
|
+
"/contests",
|
|
17
|
+
summary="Get all the contests",
|
|
18
|
+
response_model=List[Dict[str, Any]],
|
|
19
|
+
)
|
|
17
20
|
async def get_contests(service: ContestServiceDep) -> List[Dict[str, Any]]:
|
|
18
|
-
"""Get all contests"""
|
|
19
21
|
return service.get_contests()
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
@router.get(
|
|
23
25
|
"/contests/{contest_id}",
|
|
24
|
-
summary="Get
|
|
25
|
-
|
|
26
|
-
response_model=Contest,
|
|
26
|
+
summary="Get the given contest",
|
|
27
|
+
response_model=Dict[str, Any],
|
|
27
28
|
)
|
|
28
29
|
async def get_contest(
|
|
29
|
-
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
30
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
31
|
+
service: ContestServiceDep = None,
|
|
30
32
|
) -> Dict[str, Any]:
|
|
31
|
-
"""Get specific contest information"""
|
|
32
33
|
return service.get_contest(contest_id)
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
@router.get(
|
|
36
37
|
"/contests/{contest_id}/state",
|
|
37
|
-
summary="Get
|
|
38
|
-
|
|
39
|
-
response_model=State,
|
|
38
|
+
summary="Get the current contest state",
|
|
39
|
+
response_model=Dict[str, Any],
|
|
40
40
|
)
|
|
41
41
|
async def get_state(
|
|
42
|
-
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
42
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
43
|
+
service: ContestServiceDep = None,
|
|
43
44
|
) -> Dict[str, Any]:
|
|
44
|
-
"""Get contest state"""
|
|
45
45
|
return service.get_contest_state(contest_id)
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
@router.get(
|
|
49
|
-
"/contests/{contest_id}/
|
|
50
|
-
summary="Get
|
|
51
|
-
description="Get banner image for the contest",
|
|
49
|
+
"/contests/{contest_id}/banner",
|
|
50
|
+
summary="Get the banner for the given contest",
|
|
52
51
|
response_class=FileResponse,
|
|
53
52
|
)
|
|
54
53
|
async def get_contest_banner(
|
|
55
|
-
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
54
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
55
|
+
service: ContestServiceDep = None,
|
|
56
56
|
) -> FileResponse:
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@router.get(
|
|
62
|
+
"/contests/{contest_id}/problemset",
|
|
63
|
+
summary="Get the problemset document for the given contest",
|
|
64
|
+
response_class=FileResponse,
|
|
65
|
+
)
|
|
66
|
+
async def get_contest_problem_set(
|
|
67
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
68
|
+
service: ContestServiceDep = None,
|
|
69
|
+
) -> FileResponse:
|
|
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)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@router.get(
|
|
75
|
+
"/contests/{contest_id}/event-feed",
|
|
76
|
+
summary="Get event feed for contest",
|
|
77
|
+
description="Get events for the contest in NDJSON format. Each line contains a single event object.",
|
|
78
|
+
)
|
|
79
|
+
async def get_event_feed(
|
|
80
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
81
|
+
stream: bool = Query(False, description="Whether to stream the output or stop immediately"),
|
|
82
|
+
since_token: Optional[str] = Query(None, description="Return events after this token"),
|
|
83
|
+
service: ContestServiceDep = None,
|
|
84
|
+
) -> StreamingResponse:
|
|
85
|
+
async def generate():
|
|
86
|
+
events = service.get_event_feed(contest_id, since_token)
|
|
87
|
+
for event in events:
|
|
88
|
+
yield json.dumps(event, ensure_ascii=False, separators=(",", ":")) + "\n"
|
|
89
|
+
|
|
90
|
+
return StreamingResponse(generate(), media_type="application/x-ndjson")
|
|
@@ -13,17 +13,18 @@ logger = logging.getLogger(__name__)
|
|
|
13
13
|
@router.get(
|
|
14
14
|
"/",
|
|
15
15
|
summary="API Information",
|
|
16
|
-
description="Get API version and provider information",
|
|
17
16
|
response_model=Dict[str, Any],
|
|
18
17
|
)
|
|
19
18
|
async def get_api_info(service: ContestServiceDep) -> Dict[str, Any]:
|
|
20
|
-
"""Get API information and provider details"""
|
|
21
19
|
return service.get_api_info()
|
|
22
20
|
|
|
23
21
|
|
|
24
|
-
@router.get(
|
|
22
|
+
@router.get(
|
|
23
|
+
"/health",
|
|
24
|
+
summary="Health Check",
|
|
25
|
+
response_model=Dict[str, Any],
|
|
26
|
+
)
|
|
25
27
|
async def health_check(service: ContestServiceDep) -> Dict[str, Any]:
|
|
26
|
-
"""Health check endpoint"""
|
|
27
28
|
return {
|
|
28
29
|
"status": "healthy",
|
|
29
30
|
"timestamp": datetime.now().isoformat(),
|
|
@@ -3,10 +3,6 @@ from typing import Any, Dict, List
|
|
|
3
3
|
|
|
4
4
|
from fastapi import APIRouter, Path
|
|
5
5
|
|
|
6
|
-
from ...model import (
|
|
7
|
-
Group,
|
|
8
|
-
Groups,
|
|
9
|
-
)
|
|
10
6
|
from ..dependencies import ContestServiceDep
|
|
11
7
|
|
|
12
8
|
router = APIRouter()
|
|
@@ -15,27 +11,24 @@ logger = logging.getLogger(__name__)
|
|
|
15
11
|
|
|
16
12
|
@router.get(
|
|
17
13
|
"/contests/{contest_id}/groups",
|
|
18
|
-
summary="Get
|
|
19
|
-
|
|
20
|
-
response_model=Groups,
|
|
14
|
+
summary="Get all the groups for this contest",
|
|
15
|
+
response_model=List[Dict[str, Any]],
|
|
21
16
|
)
|
|
22
17
|
async def get_groups(
|
|
23
|
-
contest_id: str = Path(..., description="Contest identifier"),
|
|
18
|
+
contest_id: str = Path(..., description="Contest identifier"),
|
|
19
|
+
service: ContestServiceDep = None,
|
|
24
20
|
) -> List[Dict[str, Any]]:
|
|
25
|
-
"""Get all groups"""
|
|
26
21
|
return service.get_groups(contest_id)
|
|
27
22
|
|
|
28
23
|
|
|
29
24
|
@router.get(
|
|
30
25
|
"/contests/{contest_id}/groups/{group_id}",
|
|
31
|
-
summary="Get
|
|
32
|
-
|
|
33
|
-
response_model=Group,
|
|
26
|
+
summary="Get the given group for this contest",
|
|
27
|
+
response_model=Dict[str, Any],
|
|
34
28
|
)
|
|
35
29
|
async def get_group(
|
|
36
30
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
37
31
|
group_id: str = Path(..., description="Group identifier"),
|
|
38
32
|
service: ContestServiceDep = None,
|
|
39
33
|
) -> Dict[str, Any]:
|
|
40
|
-
"""Get specific group information"""
|
|
41
34
|
return service.get_group(contest_id, group_id)
|
|
@@ -3,10 +3,6 @@ from typing import Any, Dict, List
|
|
|
3
3
|
|
|
4
4
|
from fastapi import APIRouter, Path
|
|
5
5
|
|
|
6
|
-
from ...model import (
|
|
7
|
-
JudgementType,
|
|
8
|
-
JudgementTypes,
|
|
9
|
-
)
|
|
10
6
|
from ..dependencies import ContestServiceDep
|
|
11
7
|
|
|
12
8
|
router = APIRouter()
|
|
@@ -15,27 +11,24 @@ logger = logging.getLogger(__name__)
|
|
|
15
11
|
|
|
16
12
|
@router.get(
|
|
17
13
|
"/contests/{contest_id}/judgement-types",
|
|
18
|
-
summary="Get
|
|
19
|
-
|
|
20
|
-
response_model=JudgementTypes,
|
|
14
|
+
summary="Get all the judgement types for this contest",
|
|
15
|
+
response_model=List[Dict[str, Any]],
|
|
21
16
|
)
|
|
22
17
|
async def get_judgement_types(
|
|
23
|
-
contest_id: str = Path(..., description="Contest identifier"),
|
|
18
|
+
contest_id: str = Path(..., description="Contest identifier"),
|
|
19
|
+
service: ContestServiceDep = None,
|
|
24
20
|
) -> List[Dict[str, Any]]:
|
|
25
|
-
"""Get all judgement types"""
|
|
26
21
|
return service.get_judgement_types(contest_id)
|
|
27
22
|
|
|
28
23
|
|
|
29
24
|
@router.get(
|
|
30
25
|
"/contests/{contest_id}/judgement-types/{judgement_type_id}",
|
|
31
|
-
summary="Get
|
|
32
|
-
|
|
33
|
-
response_model=JudgementType,
|
|
26
|
+
summary="Get the given judgement type for this contest",
|
|
27
|
+
response_model=Dict[str, Any],
|
|
34
28
|
)
|
|
35
29
|
async def get_judgement_type(
|
|
36
30
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
37
31
|
judgement_type_id: str = Path(..., description="Judgement type identifier"),
|
|
38
32
|
service: ContestServiceDep = None,
|
|
39
33
|
) -> Dict[str, Any]:
|
|
40
|
-
"""Get specific judgement type information"""
|
|
41
34
|
return service.get_judgement_type(contest_id, judgement_type_id)
|
|
@@ -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 Judgement, Judgements
|
|
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}/judgements",
|
|
15
|
-
summary="Get
|
|
16
|
-
|
|
17
|
-
response_model=Judgements,
|
|
14
|
+
summary="Get all the judgements for this contest",
|
|
15
|
+
response_model=List[Dict[str, Any]],
|
|
18
16
|
)
|
|
19
17
|
async def get_judgements(
|
|
20
18
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
21
19
|
submission_id: Optional[str] = Query(None, description="Filter judgements by submission ID"),
|
|
22
20
|
service: ContestServiceDep = None,
|
|
23
21
|
) -> List[Dict[str, Any]]:
|
|
24
|
-
"""Get all judgements, optionally filtered by submission"""
|
|
25
22
|
return service.get_judgements(contest_id, submission_id)
|
|
26
23
|
|
|
27
24
|
|
|
28
25
|
@router.get(
|
|
29
26
|
"/contests/{contest_id}/judgements/{judgement_id}",
|
|
30
|
-
summary="Get
|
|
31
|
-
|
|
32
|
-
response_model=Judgement,
|
|
27
|
+
summary="Get the given judgement for this contest",
|
|
28
|
+
response_model=Dict[str, Any],
|
|
33
29
|
)
|
|
34
30
|
async def get_judgement(
|
|
35
31
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
36
32
|
judgement_id: str = Path(..., description="Judgement identifier"),
|
|
37
33
|
service: ContestServiceDep = None,
|
|
38
34
|
) -> Dict[str, Any]:
|
|
39
|
-
"""Get specific judgement information"""
|
|
40
35
|
return service.get_judgement(contest_id, judgement_id)
|
|
@@ -3,10 +3,6 @@ from typing import Any, Dict, List
|
|
|
3
3
|
|
|
4
4
|
from fastapi import APIRouter, Path
|
|
5
5
|
|
|
6
|
-
from ...model import (
|
|
7
|
-
Language,
|
|
8
|
-
Languages,
|
|
9
|
-
)
|
|
10
6
|
from ..dependencies import ContestServiceDep
|
|
11
7
|
|
|
12
8
|
router = APIRouter()
|
|
@@ -15,27 +11,24 @@ logger = logging.getLogger(__name__)
|
|
|
15
11
|
|
|
16
12
|
@router.get(
|
|
17
13
|
"/contests/{contest_id}/languages",
|
|
18
|
-
summary="Get
|
|
19
|
-
|
|
20
|
-
response_model=Languages,
|
|
14
|
+
summary="Get all the languages for this contest",
|
|
15
|
+
response_model=List[Dict[str, Any]],
|
|
21
16
|
)
|
|
22
17
|
async def get_languages(
|
|
23
|
-
contest_id: str = Path(..., description="Contest identifier"),
|
|
18
|
+
contest_id: str = Path(..., description="Contest identifier"),
|
|
19
|
+
service: ContestServiceDep = None,
|
|
24
20
|
) -> List[Dict[str, Any]]:
|
|
25
|
-
"""Get all programming languages"""
|
|
26
21
|
return service.get_languages(contest_id)
|
|
27
22
|
|
|
28
23
|
|
|
29
24
|
@router.get(
|
|
30
25
|
"/contests/{contest_id}/languages/{language_id}",
|
|
31
|
-
summary="Get
|
|
32
|
-
|
|
33
|
-
response_model=Language,
|
|
26
|
+
summary="Get the given language for this contest",
|
|
27
|
+
response_model=Dict[str, Any],
|
|
34
28
|
)
|
|
35
29
|
async def get_language(
|
|
36
30
|
contest_id: str = Path(..., description="Contest identifier"),
|
|
37
31
|
language_id: str = Path(..., description="Language identifier"),
|
|
38
32
|
service: ContestServiceDep = None,
|
|
39
33
|
) -> Dict[str, Any]:
|
|
40
|
-
"""Get specific language information"""
|
|
41
34
|
return service.get_language(contest_id, language_id)
|
|
@@ -1,15 +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 (
|
|
10
|
-
Organization,
|
|
11
|
-
Organizations,
|
|
12
|
-
)
|
|
13
8
|
from ..dependencies import ContestServiceDep
|
|
14
9
|
|
|
15
10
|
router = APIRouter()
|
|
@@ -18,36 +13,32 @@ logger = logging.getLogger(__name__)
|
|
|
18
13
|
|
|
19
14
|
@router.get(
|
|
20
15
|
"/contests/{contest_id}/organizations",
|
|
21
|
-
summary="Get
|
|
22
|
-
|
|
23
|
-
response_model=Organizations,
|
|
16
|
+
summary="Get all the organizations for this contest",
|
|
17
|
+
response_model=List[Dict[str, Any]],
|
|
24
18
|
)
|
|
25
19
|
async def get_organizations(
|
|
26
|
-
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
20
|
+
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
21
|
+
service: ContestServiceDep = None,
|
|
27
22
|
) -> List[Dict[str, Any]]:
|
|
28
|
-
"""Get all organizations"""
|
|
29
23
|
return service.get_organizations(contest_id)
|
|
30
24
|
|
|
31
25
|
|
|
32
26
|
@router.get(
|
|
33
27
|
"/contests/{contest_id}/organizations/{organization_id}",
|
|
34
|
-
summary="Get
|
|
35
|
-
|
|
36
|
-
response_model=Organization,
|
|
28
|
+
summary="Get the given organization for this contest",
|
|
29
|
+
response_model=Dict[str, Any],
|
|
37
30
|
)
|
|
38
31
|
async def get_organization(
|
|
39
32
|
contest_id: str = FastAPIPath(..., description="Contest identifier"),
|
|
40
33
|
organization_id: str = FastAPIPath(..., description="Organization identifier"),
|
|
41
34
|
service: ContestServiceDep = None,
|
|
42
35
|
) -> Dict[str, Any]:
|
|
43
|
-
"""Get specific organization information"""
|
|
44
36
|
return service.get_organization(contest_id, organization_id)
|
|
45
37
|
|
|
46
38
|
|
|
47
39
|
@router.get(
|
|
48
40
|
"/contests/{contest_id}/organizations/{organization_id}/logo",
|
|
49
41
|
summary="Get Organization Logo",
|
|
50
|
-
description="Get logo file for a specific organization",
|
|
51
42
|
response_class=FileResponse,
|
|
52
43
|
)
|
|
53
44
|
async def get_organization_logo(
|
|
@@ -55,28 +46,5 @@ async def get_organization_logo(
|
|
|
55
46
|
organization_id: str = FastAPIPath(..., description="Organization identifier"),
|
|
56
47
|
service: ContestServiceDep = None,
|
|
57
48
|
) -> FileResponse:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# Get organization from indexed data
|
|
62
|
-
org = service.organizations_by_id.get(organization_id)
|
|
63
|
-
if not org:
|
|
64
|
-
raise HTTPException(status_code=404, detail=f"Organization {organization_id} not found")
|
|
65
|
-
|
|
66
|
-
# Expected href pattern for this endpoint
|
|
67
|
-
expected_href = f"contests/{contest_id}/organizations/{organization_id}/logo"
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
logos = org["logo"]
|
|
71
|
-
for logo in logos:
|
|
72
|
-
href = logo["href"]
|
|
73
|
-
if href == expected_href:
|
|
74
|
-
filename = logo["filename"]
|
|
75
|
-
logo_file: Path = service.contest_package_dir / "organizations" / organization_id / filename
|
|
76
|
-
if logo_file.exists():
|
|
77
|
-
mime_type = logo["mime"]
|
|
78
|
-
return FileResponse(path=logo_file, media_type=mime_type, filename=filename)
|
|
79
|
-
except Exception as e:
|
|
80
|
-
raise HTTPException(
|
|
81
|
-
status_code=404, detail=f"Logo file not found. [organization_id={organization_id}] [err={e}]"
|
|
82
|
-
)
|
|
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)
|