Skip to content

Resources

Base classes

Resource(http)

Base for every resource binding.

Concrete resources set :attr:path and :attr:model as class-level constants and compose any subset of the :class:_ListOps, :class:_GetOps, :class:_CreateOps, :class:_UpdateOps, :class:_DeleteOps mixins to expose the operations that the CTFd API actually supports for that resource.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

_ListOps(http)

Bases: Resource

Mixin: GET /<path> collection listing and pagination.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

_GetOps(http)

Bases: Resource

Mixin: GET /<path>/{id} single-resource retrieval.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

_CreateOps(http)

Bases: Resource

Mixin: POST /<path> resource creation.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

_UpdateOps(http)

Bases: Resource

Mixin: PATCH /<path>/{id} partial update.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

_DeleteOps(http)

Bases: Resource

Mixin: DELETE /<path>/{id}.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

Awards

AwardsResource(http)

Bases: _ListOps[Award], _GetOps[Award], _CreateOps[Award], _DeleteOps

/awards — list, retrieve, create, delete (CTFd does not expose PATCH).

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Brackets

BracketsResource(http)

Bases: _ListOps[Bracket], _CreateOps[Bracket], _UpdateOps[Bracket], _DeleteOps

/brackets — no single-bracket GET endpoint is exposed by CTFd.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Challenges

ChallengesResource(http)

Bases: _ListOps[Challenge], _GetOps[Challenge], _CreateOps[Challenge], _UpdateOps[Challenge], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

attempt(challenge_id, submission) async

Submit an attempt against a challenge (POST /challenges/attempt).

Source code in ctfd/resources/challenges.py
async def attempt(self, challenge_id: int, submission: str) -> dict[str, Any]:
    """Submit an attempt against a challenge (``POST /challenges/attempt``)."""

    payload = await self._http.post_json(
        '/challenges/attempt',
        json={'challenge_id': challenge_id, 'submission': submission},
    )
    result = _data(payload)
    return result if isinstance(result, dict) else {}

types() async

List the challenge types registered on the server.

Source code in ctfd/resources/challenges.py
async def types(self) -> dict[str, Any]:
    """List the challenge types registered on the server."""

    payload = await self._http.get_json('/challenges/types')
    result = _data(payload)
    return result if isinstance(result, dict) else {}

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Comments

CommentsResource(http)

Bases: _ListOps[Comment], _CreateOps[Comment], _DeleteOps

/comments — collection list/create + per-id delete. CTFd exposes no GET-by-id or PATCH.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Configs

ConfigsResource(http)

Bases: Resource

/configs — keyed by string (not integer id), plus the /configs/fields sub-resource.

The collection endpoint also accepts PATCH for bulk updates, which has no equivalent in the generic CRUD mixins.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

bulk_update(body) async

Update multiple configuration keys in one call (PATCH /configs).

Source code in ctfd/resources/configs.py
async def bulk_update(self, body: dict[str, Any]) -> dict[str, Any]:
    """Update multiple configuration keys in one call (``PATCH /configs``)."""

    payload = await self._http.patch_json('/configs', json=_serialize(body))
    result = _data(payload)
    return result if isinstance(result, dict) else {}

fields() async

List configurable user/team profile fields (GET /configs/fields).

Source code in ctfd/resources/configs.py
async def fields(self) -> builtins.list[dict[str, Any]]:
    """List configurable user/team profile fields (``GET /configs/fields``)."""

    payload = await self._http.get_json('/configs/fields')
    return [item for item in _data_list(payload) if isinstance(item, dict)]

Exports

ExportsResource(http)

Bases: Resource

Bindings for the /exports/raw endpoint.

The endpoint streams a ZIP archive of the entire CTFd instance, so the methods exposed here return raw bytes rather than parsed models.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

raw() async

Download the export archive and return it entirely in memory.

Source code in ctfd/resources/exports.py
async def raw(self) -> bytes:
    """Download the export archive and return it entirely in memory."""

    response = await self._http.request('POST', '/exports/raw')
    return response.content

stream(chunk_size=DEFAULT_CHUNK_SIZE) async

Stream the export archive in chunks of chunk_size bytes.

Source code in ctfd/resources/exports.py
async def stream(self, chunk_size: int = DEFAULT_CHUNK_SIZE) -> AsyncIterator[bytes]:
    """Stream the export archive in chunks of ``chunk_size`` bytes."""

    response = await self._http.request('POST', '/exports/raw')
    async for chunk in response.aiter_bytes(chunk_size):
        yield chunk

Files

FilesResource(http)

Bases: _ListOps[File], _GetOps[File], _DeleteOps, Resource

/files — list, retrieve, delete, plus multipart upload and raw download.

Per the CTFd swagger, POST /files is multipart and uses the file form field (singular) plus optional type, location, challenge_id, page_id and solution_id companions; it is exposed as :meth:upload rather than create because the return type is a list of created records, not a single one.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

upload(file, *, type=None, location=None, challenge_id=None, page_id=None, solution_id=None) async

Upload a file and return the created :class:File records.

file accepts any value supported by httpx's files= argument: a raw bytes blob, a binary file-like object, or a (filename, content, content_type) tuple.

Source code in ctfd/resources/files.py
async def upload(  # noqa: PLR0913
    self,
    file: IO[bytes] | bytes | tuple[str, IO[bytes] | bytes, str | None],
    *,
    type: str | None = None,  # noqa: A002
    location: str | None = None,
    challenge_id: int | None = None,
    page_id: int | None = None,
    solution_id: int | None = None,
) -> list[File]:
    """Upload a file and return the created :class:`File` records.

    ``file`` accepts any value supported by httpx's ``files=`` argument:
    a raw bytes blob, a binary file-like object, or a ``(filename, content,
    content_type)`` tuple.
    """

    data = _drop_none(
        {
            'type': type,
            'location': location,
            'challenge_id': challenge_id,
            'page_id': page_id,
            'solution_id': solution_id,
        }
    )
    response = await self._http.request('POST', self.path, files={'file': file}, data=data)
    payload = response.json() if response.content else {}
    return [File.model_validate(item) for item in _data_list(payload)]

download(file_id) async

Download the raw bytes of a stored file.

Fetches the file record to resolve its location, then requests the site-root URL {site}/files/{location} (CTFd serves uploads outside of /api/v1).

Source code in ctfd/resources/files.py
async def download(self, file_id: int) -> bytes:
    """Download the raw bytes of a stored file.

    Fetches the file record to resolve its ``location``, then requests the
    site-root URL ``{site}/files/{location}`` (CTFd serves uploads outside
    of ``/api/v1``).
    """

    meta_payload = await self._http.get_json(f'/files/{file_id}')
    meta = _data(meta_payload)
    location = meta.get('location') if isinstance(meta, dict) else None
    if not isinstance(location, str) or not location:
        msg = f'File {file_id} has no downloadable location'
        raise ValueError(msg)
    return await self._http.get_bytes(f'{self._http.site_root}/files/{location}')

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Flags

FlagsResource(http)

Bases: _ListOps[Flag], _GetOps[Flag], _CreateOps[Flag], _UpdateOps[Flag], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

types() async

List the registered flag types (GET /flags/types).

Source code in ctfd/resources/flags.py
async def types(self) -> dict[str, Any]:
    """List the registered flag types (``GET /flags/types``)."""

    payload = await self._http.get_json('/flags/types')
    result = _data(payload)
    return result if isinstance(result, dict) else {}

type(type_name) async

Fetch the definition of a single flag type (GET /flags/types/{name}).

Source code in ctfd/resources/flags.py
async def type(self, type_name: str) -> dict[str, Any]:
    """Fetch the definition of a single flag type (``GET /flags/types/{name}``)."""

    payload = await self._http.get_json(f'/flags/types/{type_name}')
    result = _data(payload)
    return result if isinstance(result, dict) else {}

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Hints

HintsResource(http)

Bases: _ListOps[Hint], _GetOps[Hint], _CreateOps[Hint], _UpdateOps[Hint], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Notifications

NotificationsResource(http)

Bases: _ListOps[Notification], _GetOps[Notification], _CreateOps[Notification], _DeleteOps

/notifications — list, retrieve, create, delete.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Pages

PagesResource(http)

Bases: _ListOps[Page], _GetOps[Page], _CreateOps[Page], _UpdateOps[Page], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Scoreboard

ScoreboardResource(http)

Bases: Resource

/scoreboard — public scoreboard listings (no per-id endpoints).

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list() async

Return the full scoreboard (GET /scoreboard).

Source code in ctfd/resources/scoreboard.py
async def list(self) -> list[ScoreboardEntry]:
    """Return the full scoreboard (``GET /scoreboard``)."""

    payload = await self._http.get_json('/scoreboard')
    return [ScoreboardEntry.model_validate(item) for item in _data_list(payload)]

top(count) async

Return the top count entries (GET /scoreboard/top/{count}).

CTFd returns this endpoint as a mapping keyed by position (e.g. "1": {...}, "2": {...}); the mapping is preserved here.

Source code in ctfd/resources/scoreboard.py
async def top(self, count: int) -> dict[str, ScoreboardEntry]:
    """Return the top ``count`` entries (``GET /scoreboard/top/{count}``).

    CTFd returns this endpoint as a mapping keyed by position (e.g.
    ``"1": {...}, "2": {...}``); the mapping is preserved here.
    """

    payload = await self._http.get_json(f'/scoreboard/top/{count}')
    data = payload.get('data', {}) if isinstance(payload, dict) else {}
    if not isinstance(data, dict):
        return {}
    return {key: ScoreboardEntry.model_validate(value) for key, value in data.items()}

Shares

SharesResource(http)

Bases: _CreateOps[Share]

/shares — creation only.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

Solutions

SolutionsResource(http)

Bases: _ListOps[Solution], _GetOps[Solution], _CreateOps[Solution], _UpdateOps[Solution], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Statistics

StatisticsResource(http)

Bases: Resource

/statistics/* — aggregate counters and matrices.

These endpoints return heterogeneous payloads (per-category counters, percentages, time-series matrices, ...), so they are exposed as raw mappings rather than strongly-typed models.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

Submissions

SubmissionsResource(http)

Bases: _ListOps[Submission], _GetOps[Submission], _CreateOps[Submission], _UpdateOps[Submission], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Tags

TagsResource(http)

Bases: _ListOps[Tag], _GetOps[Tag], _CreateOps[Tag], _UpdateOps[Tag], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Teams

TeamsResource(http)

Bases: _ListOps[Team], _GetOps[Team], _CreateOps[Team], _UpdateOps[Team], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Tokens

TokensResource(http)

Bases: _ListOps[Token], _GetOps[Token], _CreateOps[Token], _DeleteOps

/tokens — list, retrieve, create, delete (no PATCH on tokens).

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Topics

TopicsResource(http)

Bases: _ListOps[Topic], _GetOps[Topic], _CreateOps[Topic], _DeleteOps

/topics — list, retrieve, create, delete by id, plus unlink on the collection.

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

Detach a topic from a target (challenge, page, ...).

Maps to DELETE /topics?type=...&target_id=...; the topic record itself is preserved.

Source code in ctfd/resources/topics.py
async def unlink(self, *, target_id: int, type: str) -> None:  # noqa: A002
    """Detach a topic from a target (challenge, page, ...).

    Maps to ``DELETE /topics?type=...&target_id=...``; the topic record
    itself is preserved.
    """

    await self._http.delete_json(self.path, params={'target_id': target_id, 'type': type})

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Unlocks

UnlocksResource(http)

Bases: _ListOps[Unlock], _CreateOps[Unlock]

/unlocks — list and create only (no per-id endpoints).

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))

Users

UsersResource(http)

Bases: _ListOps[User], _GetOps[User], _CreateOps[User], _UpdateOps[User], _DeleteOps

Source code in ctfd/resources/_base.py
def __init__(self, http: AsyncHTTPClient) -> None:
    self._http = http

email(user_id, body) async

Send an email to a user (POST /users/{id}/email).

Source code in ctfd/resources/users.py
async def email(self, user_id: int, body: dict[str, Any]) -> dict[str, Any]:
    """Send an email to a user (``POST /users/{id}/email``)."""

    payload = await self._http.post_json(f'/users/{user_id}/email', json=_serialize(body))
    result = _data(payload)
    return result if isinstance(result, dict) else {}

list(**params) async

Fetch the first page of the collection as a list.

Source code in ctfd/resources/_base.py
async def list(self, **params: Any) -> list[T]:
    """Fetch the first page of the collection as a list."""

    payload = await self._http.get_json(self.path, params=params)
    return [cast('T', self.model.model_validate(item)) for item in _data_list(payload)]

iter(**params)

Return an async iterator that walks every page of the collection.

Source code in ctfd/resources/_base.py
def iter(self, **params: Any) -> AsyncPaginator[T]:
    """Return an async iterator that walks every page of the collection."""

    return cast('AsyncPaginator[T]', AsyncPaginator(self._http, self.path, self.model, params=params))