ctfy.sdk.admin_resources.competition_admins

client.admin.competition_admins — per-competition admin grants (admin).

 1"""``client.admin.competition_admins`` — per-competition admin grants (admin)."""
 2
 3from __future__ import annotations
 4
 5from datetime import datetime
 6
 7from ctfy.sdk._helpers import PagedList, _extract_items, _raise_for_status
 8from ctfy.sdk.base import BaseHttpClient
 9from ctfy.server.models import CompetitionAdminInfo
10
11
12class AdminCompetitionAdminsResource:
13    """Grant / revoke the per-competition admin role."""
14
15    def __init__(self, http: BaseHttpClient) -> None:
16        self._http = http
17
18    def list(
19        self, competition_id: str, offset: int = 0, limit: int = 50
20    ) -> PagedList[CompetitionAdminInfo]:
21        """Users granted admin on one competition."""
22        resp = self._http.request(
23            "GET",
24            f"/admin/competitions/{competition_id}/admins",
25            params={"offset": offset, "limit": limit},
26        )
27        _raise_for_status(resp)
28        return _extract_items(resp.json(), CompetitionAdminInfo)
29
30    def grant(
31        self,
32        competition_id: str,
33        *,
34        user_id: str = "",
35        email: str = "",
36        expires_at: datetime | None = None,
37    ) -> CompetitionAdminInfo:
38        """Grant per-competition admin. Identify the target by
39        ``user_id`` or ``email`` (the server accepts either).
40
41        ``expires_at`` (timezone-aware, in the future) makes the grant
42        lapse then (#2429 b); ``None`` is a grant that never lapses.
43        Re-granting writes a new value, so it is also how to renew one."""
44        body: dict[str, str] = {"user_id": user_id, "email": email}
45        if expires_at is not None:
46            body["expires_at"] = expires_at.isoformat()
47        resp = self._http.request(
48            "POST",
49            f"/admin/competitions/{competition_id}/admins",
50            json=body,
51        )
52        _raise_for_status(resp)
53        return CompetitionAdminInfo.model_validate(resp.json())
54
55    def revoke(self, competition_id: str, user_id: str) -> None:
56        """Revoke a user's per-competition admin grant."""
57        resp = self._http.request(
58            "DELETE", f"/admin/competitions/{competition_id}/admins/{user_id}"
59        )
60        _raise_for_status(resp)
class AdminCompetitionAdminsResource:
13class AdminCompetitionAdminsResource:
14    """Grant / revoke the per-competition admin role."""
15
16    def __init__(self, http: BaseHttpClient) -> None:
17        self._http = http
18
19    def list(
20        self, competition_id: str, offset: int = 0, limit: int = 50
21    ) -> PagedList[CompetitionAdminInfo]:
22        """Users granted admin on one competition."""
23        resp = self._http.request(
24            "GET",
25            f"/admin/competitions/{competition_id}/admins",
26            params={"offset": offset, "limit": limit},
27        )
28        _raise_for_status(resp)
29        return _extract_items(resp.json(), CompetitionAdminInfo)
30
31    def grant(
32        self,
33        competition_id: str,
34        *,
35        user_id: str = "",
36        email: str = "",
37        expires_at: datetime | None = None,
38    ) -> CompetitionAdminInfo:
39        """Grant per-competition admin. Identify the target by
40        ``user_id`` or ``email`` (the server accepts either).
41
42        ``expires_at`` (timezone-aware, in the future) makes the grant
43        lapse then (#2429 b); ``None`` is a grant that never lapses.
44        Re-granting writes a new value, so it is also how to renew one."""
45        body: dict[str, str] = {"user_id": user_id, "email": email}
46        if expires_at is not None:
47            body["expires_at"] = expires_at.isoformat()
48        resp = self._http.request(
49            "POST",
50            f"/admin/competitions/{competition_id}/admins",
51            json=body,
52        )
53        _raise_for_status(resp)
54        return CompetitionAdminInfo.model_validate(resp.json())
55
56    def revoke(self, competition_id: str, user_id: str) -> None:
57        """Revoke a user's per-competition admin grant."""
58        resp = self._http.request(
59            "DELETE", f"/admin/competitions/{competition_id}/admins/{user_id}"
60        )
61        _raise_for_status(resp)

Grant / revoke the per-competition admin role.

AdminCompetitionAdminsResource(http: ctfy.sdk.base.BaseHttpClient)
16    def __init__(self, http: BaseHttpClient) -> None:
17        self._http = http
def list( self, competition_id: str, offset: int = 0, limit: int = 50) -> ctfy.sdk._helpers.PagedList[ctfy.server.models.CompetitionAdminInfo]:
19    def list(
20        self, competition_id: str, offset: int = 0, limit: int = 50
21    ) -> PagedList[CompetitionAdminInfo]:
22        """Users granted admin on one competition."""
23        resp = self._http.request(
24            "GET",
25            f"/admin/competitions/{competition_id}/admins",
26            params={"offset": offset, "limit": limit},
27        )
28        _raise_for_status(resp)
29        return _extract_items(resp.json(), CompetitionAdminInfo)

Users granted admin on one competition.

def grant( self, competition_id: str, *, user_id: str = '', email: str = '', expires_at: datetime.datetime | None = None) -> ctfy.server.models.CompetitionAdminInfo:
31    def grant(
32        self,
33        competition_id: str,
34        *,
35        user_id: str = "",
36        email: str = "",
37        expires_at: datetime | None = None,
38    ) -> CompetitionAdminInfo:
39        """Grant per-competition admin. Identify the target by
40        ``user_id`` or ``email`` (the server accepts either).
41
42        ``expires_at`` (timezone-aware, in the future) makes the grant
43        lapse then (#2429 b); ``None`` is a grant that never lapses.
44        Re-granting writes a new value, so it is also how to renew one."""
45        body: dict[str, str] = {"user_id": user_id, "email": email}
46        if expires_at is not None:
47            body["expires_at"] = expires_at.isoformat()
48        resp = self._http.request(
49            "POST",
50            f"/admin/competitions/{competition_id}/admins",
51            json=body,
52        )
53        _raise_for_status(resp)
54        return CompetitionAdminInfo.model_validate(resp.json())

Grant per-competition admin. Identify the target by user_id or email (the server accepts either).

expires_at (timezone-aware, in the future) makes the grant lapse then (#2429 b); None is a grant that never lapses. Re-granting writes a new value, so it is also how to renew one.

def revoke(self, competition_id: str, user_id: str) -> None:
56    def revoke(self, competition_id: str, user_id: str) -> None:
57        """Revoke a user's per-competition admin grant."""
58        resp = self._http.request(
59            "DELETE", f"/admin/competitions/{competition_id}/admins/{user_id}"
60        )
61        _raise_for_status(resp)

Revoke a user's per-competition admin grant.