ctfy.sdk.admin_resources.competition_applications
client.admin.competition_applications — people asking to be let
into a private competition, and the organisers' answer (plan L2).
1"""``client.admin.competition_applications`` — people asking to be let 2into a private competition, and the organisers' answer (plan L2).""" 3 4from __future__ import annotations 5 6from typing import Any 7 8from ctfy.core.enums import ReviewStatus 9from ctfy.sdk._helpers import PagedList, _extract_items, _raise_for_status 10from ctfy.sdk.base import BaseHttpClient 11from ctfy.server.models import CompetitionApplicationRow 12 13 14class AdminCompetitionApplicationsResource: 15 """Read one competition's applications and rule on them. For its 16 organisers — whoever may invite (global admins and the event's full 17 organisers); a roster reviewer may not, since an approval *is* an 18 invitation.""" 19 20 def __init__(self, http: BaseHttpClient) -> None: 21 self._http = http 22 23 def list( 24 self, 25 competition_id: str, 26 *, 27 status: ReviewStatus | None = None, 28 offset: int = 0, 29 limit: int = 50, 30 ) -> PagedList[CompetitionApplicationRow]: 31 """The queue, oldest first; ``status`` narrows the page and its 32 ``total`` alike. ``invited`` on each row is whether the person 33 holds an invitation *now* — distinct from ``status == "approved"`` 34 once an invitation is revoked.""" 35 params: dict[str, Any] = {"offset": offset, "limit": limit} 36 if status is not None: 37 params["status"] = status 38 resp = self._http.request( 39 "GET", f"/admin/competitions/{competition_id}/applications", params=params 40 ) 41 _raise_for_status(resp) 42 return _extract_items(resp.json(), CompetitionApplicationRow) 43 44 def export_csv(self, competition_id: str) -> bytes: 45 """Every application as CSV (UTF-8 with BOM, #2306): the queue's own 46 columns -- organisation, purpose, contact address among them. The 47 read is recorded as a personal-data export.""" 48 resp = self._http.request("GET", f"/admin/competitions/{competition_id}/application-export") 49 _raise_for_status(resp) 50 return resp.content 51 52 def approve(self, competition_id: str, user_id: str) -> CompetitionApplicationRow: 53 """Let them in: writes their invitation and sends the invitation 54 mail. Once — a second verdict is ``application_already_decided``.""" 55 return self._review(competition_id, user_id, {"status": "approved"}) 56 57 def reject(self, competition_id: str, user_id: str, note: str) -> CompetitionApplicationRow: 58 """Turn them down, saying why. Final for the application — the 59 person cannot send it again, and you can still invite them — so 60 ``note`` is required (``application_review_note_required``).""" 61 return self._review(competition_id, user_id, {"status": "rejected", "note": note}) 62 63 def _review( 64 self, competition_id: str, user_id: str, body: dict[str, str] 65 ) -> CompetitionApplicationRow: 66 resp = self._http.request( 67 "POST", 68 f"/admin/competitions/{competition_id}/applications/{user_id}/review", 69 json=body, 70 ) 71 _raise_for_status(resp) 72 return CompetitionApplicationRow.model_validate(resp.json())
15class AdminCompetitionApplicationsResource: 16 """Read one competition's applications and rule on them. For its 17 organisers — whoever may invite (global admins and the event's full 18 organisers); a roster reviewer may not, since an approval *is* an 19 invitation.""" 20 21 def __init__(self, http: BaseHttpClient) -> None: 22 self._http = http 23 24 def list( 25 self, 26 competition_id: str, 27 *, 28 status: ReviewStatus | None = None, 29 offset: int = 0, 30 limit: int = 50, 31 ) -> PagedList[CompetitionApplicationRow]: 32 """The queue, oldest first; ``status`` narrows the page and its 33 ``total`` alike. ``invited`` on each row is whether the person 34 holds an invitation *now* — distinct from ``status == "approved"`` 35 once an invitation is revoked.""" 36 params: dict[str, Any] = {"offset": offset, "limit": limit} 37 if status is not None: 38 params["status"] = status 39 resp = self._http.request( 40 "GET", f"/admin/competitions/{competition_id}/applications", params=params 41 ) 42 _raise_for_status(resp) 43 return _extract_items(resp.json(), CompetitionApplicationRow) 44 45 def export_csv(self, competition_id: str) -> bytes: 46 """Every application as CSV (UTF-8 with BOM, #2306): the queue's own 47 columns -- organisation, purpose, contact address among them. The 48 read is recorded as a personal-data export.""" 49 resp = self._http.request("GET", f"/admin/competitions/{competition_id}/application-export") 50 _raise_for_status(resp) 51 return resp.content 52 53 def approve(self, competition_id: str, user_id: str) -> CompetitionApplicationRow: 54 """Let them in: writes their invitation and sends the invitation 55 mail. Once — a second verdict is ``application_already_decided``.""" 56 return self._review(competition_id, user_id, {"status": "approved"}) 57 58 def reject(self, competition_id: str, user_id: str, note: str) -> CompetitionApplicationRow: 59 """Turn them down, saying why. Final for the application — the 60 person cannot send it again, and you can still invite them — so 61 ``note`` is required (``application_review_note_required``).""" 62 return self._review(competition_id, user_id, {"status": "rejected", "note": note}) 63 64 def _review( 65 self, competition_id: str, user_id: str, body: dict[str, str] 66 ) -> CompetitionApplicationRow: 67 resp = self._http.request( 68 "POST", 69 f"/admin/competitions/{competition_id}/applications/{user_id}/review", 70 json=body, 71 ) 72 _raise_for_status(resp) 73 return CompetitionApplicationRow.model_validate(resp.json())
Read one competition's applications and rule on them. For its organisers — whoever may invite (global admins and the event's full organisers); a roster reviewer may not, since an approval is an invitation.
24 def list( 25 self, 26 competition_id: str, 27 *, 28 status: ReviewStatus | None = None, 29 offset: int = 0, 30 limit: int = 50, 31 ) -> PagedList[CompetitionApplicationRow]: 32 """The queue, oldest first; ``status`` narrows the page and its 33 ``total`` alike. ``invited`` on each row is whether the person 34 holds an invitation *now* — distinct from ``status == "approved"`` 35 once an invitation is revoked.""" 36 params: dict[str, Any] = {"offset": offset, "limit": limit} 37 if status is not None: 38 params["status"] = status 39 resp = self._http.request( 40 "GET", f"/admin/competitions/{competition_id}/applications", params=params 41 ) 42 _raise_for_status(resp) 43 return _extract_items(resp.json(), CompetitionApplicationRow)
The queue, oldest first; status narrows the page and its
total alike. invited on each row is whether the person
holds an invitation now — distinct from status == "approved"
once an invitation is revoked.
45 def export_csv(self, competition_id: str) -> bytes: 46 """Every application as CSV (UTF-8 with BOM, #2306): the queue's own 47 columns -- organisation, purpose, contact address among them. The 48 read is recorded as a personal-data export.""" 49 resp = self._http.request("GET", f"/admin/competitions/{competition_id}/application-export") 50 _raise_for_status(resp) 51 return resp.content
Every application as CSV (UTF-8 with BOM, #2306): the queue's own columns -- organisation, purpose, contact address among them. The read is recorded as a personal-data export.
53 def approve(self, competition_id: str, user_id: str) -> CompetitionApplicationRow: 54 """Let them in: writes their invitation and sends the invitation 55 mail. Once — a second verdict is ``application_already_decided``.""" 56 return self._review(competition_id, user_id, {"status": "approved"})
Let them in: writes their invitation and sends the invitation
mail. Once — a second verdict is application_already_decided.
58 def reject(self, competition_id: str, user_id: str, note: str) -> CompetitionApplicationRow: 59 """Turn them down, saying why. Final for the application — the 60 person cannot send it again, and you can still invite them — so 61 ``note`` is required (``application_review_note_required``).""" 62 return self._review(competition_id, user_id, {"status": "rejected", "note": note})
Turn them down, saying why. Final for the application — the
person cannot send it again, and you can still invite them — so
note is required (application_review_note_required).