ctfy.sdk.admin_resources.series

client.admin.series — recurring contests.

 1"""``client.admin.series`` — recurring contests."""
 2
 3from __future__ import annotations
 4
 5import builtins
 6
 7from ctfy.sdk._helpers import _raise_for_status
 8from ctfy.sdk.base import BaseHttpClient
 9from ctfy.server.models import (
10    CompetitionSeriesConfig,
11    CompetitionSeriesInfo,
12    SeriesPreview,
13)
14
15
16class AdminSeriesResource:
17    """A schedule that creates competitions on its own.
18
19    The thing to know before enabling one: it publishes onto a public
20    listing without anybody pressing a button, so the two reads matter
21    more than the writes. :meth:`preview` is how you check a cadence
22    without waiting a week, and ``spawn_job_enabled`` on every read is
23    how you notice that the job which does the work is paused.
24    """
25
26    def __init__(self, http: BaseHttpClient) -> None:
27        self._http = http
28
29    def list(self) -> builtins.list[CompetitionSeriesInfo]:
30        resp = self._http.request("GET", "/admin/series")
31        _raise_for_status(resp)
32        return [CompetitionSeriesInfo.model_validate(r) for r in resp.json()]
33
34    def get(self, series_id: str) -> CompetitionSeriesInfo:
35        resp = self._http.request("GET", f"/admin/series/{series_id}")
36        _raise_for_status(resp)
37        return CompetitionSeriesInfo.model_validate(resp.json())
38
39    def create(self, config: CompetitionSeriesConfig) -> CompetitionSeriesInfo:
40        resp = self._http.request("POST", "/admin/series", json=config.model_dump(mode="json"))
41        _raise_for_status(resp)
42        return CompetitionSeriesInfo.model_validate(resp.json())
43
44    def update(self, series_id: str, config: CompetitionSeriesConfig) -> CompetitionSeriesInfo:
45        """Full replace of the editable half.
46
47        The creation audit is not part of ``config`` and cannot be
48        rewritten — a schedule that then acts on its own must keep an
49        honest record of who set it up.
50        """
51        resp = self._http.request(
52            "PUT", f"/admin/series/{series_id}", json=config.model_dump(mode="json")
53        )
54        _raise_for_status(resp)
55        return CompetitionSeriesInfo.model_validate(resp.json())
56
57    def delete(self, series_id: str) -> None:
58        """Retire a schedule. **Its competitions are kept.**
59
60        They are ordinary competitions with teams, solves and boards;
61        deleting a schedule cannot reasonably mean deleting the finished
62        events it produced.
63        """
64        resp = self._http.request("DELETE", f"/admin/series/{series_id}")
65        _raise_for_status(resp)
66
67    def preview(self, series_id: str) -> SeriesPreview:
68        """What this series would do, without doing it.
69
70        Projects past the spawn lead window on purpose: the mistake worth
71        catching is a pool that covers three weeks of a schedule meant to
72        run indefinitely, and that is only visible at the fourth.
73        """
74        resp = self._http.request("GET", f"/admin/series/{series_id}/preview")
75        _raise_for_status(resp)
76        return SeriesPreview.model_validate(resp.json())
class AdminSeriesResource:
17class AdminSeriesResource:
18    """A schedule that creates competitions on its own.
19
20    The thing to know before enabling one: it publishes onto a public
21    listing without anybody pressing a button, so the two reads matter
22    more than the writes. :meth:`preview` is how you check a cadence
23    without waiting a week, and ``spawn_job_enabled`` on every read is
24    how you notice that the job which does the work is paused.
25    """
26
27    def __init__(self, http: BaseHttpClient) -> None:
28        self._http = http
29
30    def list(self) -> builtins.list[CompetitionSeriesInfo]:
31        resp = self._http.request("GET", "/admin/series")
32        _raise_for_status(resp)
33        return [CompetitionSeriesInfo.model_validate(r) for r in resp.json()]
34
35    def get(self, series_id: str) -> CompetitionSeriesInfo:
36        resp = self._http.request("GET", f"/admin/series/{series_id}")
37        _raise_for_status(resp)
38        return CompetitionSeriesInfo.model_validate(resp.json())
39
40    def create(self, config: CompetitionSeriesConfig) -> CompetitionSeriesInfo:
41        resp = self._http.request("POST", "/admin/series", json=config.model_dump(mode="json"))
42        _raise_for_status(resp)
43        return CompetitionSeriesInfo.model_validate(resp.json())
44
45    def update(self, series_id: str, config: CompetitionSeriesConfig) -> CompetitionSeriesInfo:
46        """Full replace of the editable half.
47
48        The creation audit is not part of ``config`` and cannot be
49        rewritten — a schedule that then acts on its own must keep an
50        honest record of who set it up.
51        """
52        resp = self._http.request(
53            "PUT", f"/admin/series/{series_id}", json=config.model_dump(mode="json")
54        )
55        _raise_for_status(resp)
56        return CompetitionSeriesInfo.model_validate(resp.json())
57
58    def delete(self, series_id: str) -> None:
59        """Retire a schedule. **Its competitions are kept.**
60
61        They are ordinary competitions with teams, solves and boards;
62        deleting a schedule cannot reasonably mean deleting the finished
63        events it produced.
64        """
65        resp = self._http.request("DELETE", f"/admin/series/{series_id}")
66        _raise_for_status(resp)
67
68    def preview(self, series_id: str) -> SeriesPreview:
69        """What this series would do, without doing it.
70
71        Projects past the spawn lead window on purpose: the mistake worth
72        catching is a pool that covers three weeks of a schedule meant to
73        run indefinitely, and that is only visible at the fourth.
74        """
75        resp = self._http.request("GET", f"/admin/series/{series_id}/preview")
76        _raise_for_status(resp)
77        return SeriesPreview.model_validate(resp.json())

A schedule that creates competitions on its own.

The thing to know before enabling one: it publishes onto a public listing without anybody pressing a button, so the two reads matter more than the writes. preview() is how you check a cadence without waiting a week, and spawn_job_enabled on every read is how you notice that the job which does the work is paused.

AdminSeriesResource(http: ctfy.sdk.base.BaseHttpClient)
27    def __init__(self, http: BaseHttpClient) -> None:
28        self._http = http
def list(self) -> list[ctfy.server.models.CompetitionSeriesInfo]:
30    def list(self) -> builtins.list[CompetitionSeriesInfo]:
31        resp = self._http.request("GET", "/admin/series")
32        _raise_for_status(resp)
33        return [CompetitionSeriesInfo.model_validate(r) for r in resp.json()]
def get(self, series_id: str) -> ctfy.server.models.CompetitionSeriesInfo:
35    def get(self, series_id: str) -> CompetitionSeriesInfo:
36        resp = self._http.request("GET", f"/admin/series/{series_id}")
37        _raise_for_status(resp)
38        return CompetitionSeriesInfo.model_validate(resp.json())
40    def create(self, config: CompetitionSeriesConfig) -> CompetitionSeriesInfo:
41        resp = self._http.request("POST", "/admin/series", json=config.model_dump(mode="json"))
42        _raise_for_status(resp)
43        return CompetitionSeriesInfo.model_validate(resp.json())
def update( self, series_id: str, config: ctfy.server.models.CompetitionSeriesConfig) -> ctfy.server.models.CompetitionSeriesInfo:
45    def update(self, series_id: str, config: CompetitionSeriesConfig) -> CompetitionSeriesInfo:
46        """Full replace of the editable half.
47
48        The creation audit is not part of ``config`` and cannot be
49        rewritten — a schedule that then acts on its own must keep an
50        honest record of who set it up.
51        """
52        resp = self._http.request(
53            "PUT", f"/admin/series/{series_id}", json=config.model_dump(mode="json")
54        )
55        _raise_for_status(resp)
56        return CompetitionSeriesInfo.model_validate(resp.json())

Full replace of the editable half.

The creation audit is not part of config and cannot be rewritten — a schedule that then acts on its own must keep an honest record of who set it up.

def delete(self, series_id: str) -> None:
58    def delete(self, series_id: str) -> None:
59        """Retire a schedule. **Its competitions are kept.**
60
61        They are ordinary competitions with teams, solves and boards;
62        deleting a schedule cannot reasonably mean deleting the finished
63        events it produced.
64        """
65        resp = self._http.request("DELETE", f"/admin/series/{series_id}")
66        _raise_for_status(resp)

Retire a schedule. Its competitions are kept.

They are ordinary competitions with teams, solves and boards; deleting a schedule cannot reasonably mean deleting the finished events it produced.

def preview(self, series_id: str) -> ctfy.server.models.SeriesPreview:
68    def preview(self, series_id: str) -> SeriesPreview:
69        """What this series would do, without doing it.
70
71        Projects past the spawn lead window on purpose: the mistake worth
72        catching is a pool that covers three weeks of a schedule meant to
73        run indefinitely, and that is only visible at the fourth.
74        """
75        resp = self._http.request("GET", f"/admin/series/{series_id}/preview")
76        _raise_for_status(resp)
77        return SeriesPreview.model_validate(resp.json())

What this series would do, without doing it.

Projects past the spawn lead window on purpose: the mistake worth catching is a pool that covers three weeks of a schedule meant to run indefinitely, and that is only visible at the fourth.