ctfy.sdk.resources.search

client.search -- global search (#2112), the same read as the web panel.

 1"""``client.search`` -- global search (#2112), the same read as the web panel."""
 2
 3from __future__ import annotations
 4
 5from typing import Any
 6
 7from ctfy.sdk._helpers import _raise_for_status
 8from ctfy.sdk.base import BaseHttpClient
 9from ctfy.server.models import SearchGroupName, SearchResponse, SearchScope
10
11
12class SearchResource:
13    """Find competitions, challenges and teams by name.
14
15    Everything returned is something the caller can open: the server decides
16    it with the same rules as the matching list routes (hidden events, the
17    start gate, anonymous entrants, silent exercises), so an agent sees
18    exactly what its human would.
19    """
20
21    def __init__(self, http: BaseHttpClient) -> None:
22        self._http = http
23
24    def query(
25        self,
26        q: str,
27        *,
28        scope: SearchScope | str = SearchScope.ALL,
29        competition_id: str = "",
30        group: SearchGroupName | str | None = None,
31        limit: int = 4,
32        offset: int = 0,
33    ) -> SearchResponse:
34        """Groups of matches for ``q``, each with at most ``limit`` rows and
35        the ``total`` that match.
36
37        ``scope="competition"`` (with ``competition_id``) searches one event;
38        ``"all"`` searches everywhere, listing ``competition_id``'s
39        challenges first. Name a ``group`` and an ``offset`` to page one
40        section. Challenges match on title, id, tag and category, never on
41        the description.
42        """
43        params: dict[str, Any] = {
44            "q": q,
45            "scope": str(scope),
46            "limit": limit,
47            "offset": offset,
48        }
49        if competition_id:
50            params["competition_id"] = competition_id
51        if group is not None:
52            params["group"] = str(group)
53        resp = self._http.request("GET", "/search", params=params)
54        _raise_for_status(resp)
55        return SearchResponse.model_validate(resp.json())
class SearchResource:
13class SearchResource:
14    """Find competitions, challenges and teams by name.
15
16    Everything returned is something the caller can open: the server decides
17    it with the same rules as the matching list routes (hidden events, the
18    start gate, anonymous entrants, silent exercises), so an agent sees
19    exactly what its human would.
20    """
21
22    def __init__(self, http: BaseHttpClient) -> None:
23        self._http = http
24
25    def query(
26        self,
27        q: str,
28        *,
29        scope: SearchScope | str = SearchScope.ALL,
30        competition_id: str = "",
31        group: SearchGroupName | str | None = None,
32        limit: int = 4,
33        offset: int = 0,
34    ) -> SearchResponse:
35        """Groups of matches for ``q``, each with at most ``limit`` rows and
36        the ``total`` that match.
37
38        ``scope="competition"`` (with ``competition_id``) searches one event;
39        ``"all"`` searches everywhere, listing ``competition_id``'s
40        challenges first. Name a ``group`` and an ``offset`` to page one
41        section. Challenges match on title, id, tag and category, never on
42        the description.
43        """
44        params: dict[str, Any] = {
45            "q": q,
46            "scope": str(scope),
47            "limit": limit,
48            "offset": offset,
49        }
50        if competition_id:
51            params["competition_id"] = competition_id
52        if group is not None:
53            params["group"] = str(group)
54        resp = self._http.request("GET", "/search", params=params)
55        _raise_for_status(resp)
56        return SearchResponse.model_validate(resp.json())

Find competitions, challenges and teams by name.

Everything returned is something the caller can open: the server decides it with the same rules as the matching list routes (hidden events, the start gate, anonymous entrants, silent exercises), so an agent sees exactly what its human would.

SearchResource(http: ctfy.sdk.base.BaseHttpClient)
22    def __init__(self, http: BaseHttpClient) -> None:
23        self._http = http
def query( self, q: str, *, scope: ctfy.server.models.SearchScope | str = <SearchScope.ALL: 'all'>, competition_id: str = '', group: ctfy.server.models.SearchGroupName | str | None = None, limit: int = 4, offset: int = 0) -> ctfy.server.models.SearchResponse:
25    def query(
26        self,
27        q: str,
28        *,
29        scope: SearchScope | str = SearchScope.ALL,
30        competition_id: str = "",
31        group: SearchGroupName | str | None = None,
32        limit: int = 4,
33        offset: int = 0,
34    ) -> SearchResponse:
35        """Groups of matches for ``q``, each with at most ``limit`` rows and
36        the ``total`` that match.
37
38        ``scope="competition"`` (with ``competition_id``) searches one event;
39        ``"all"`` searches everywhere, listing ``competition_id``'s
40        challenges first. Name a ``group`` and an ``offset`` to page one
41        section. Challenges match on title, id, tag and category, never on
42        the description.
43        """
44        params: dict[str, Any] = {
45            "q": q,
46            "scope": str(scope),
47            "limit": limit,
48            "offset": offset,
49        }
50        if competition_id:
51            params["competition_id"] = competition_id
52        if group is not None:
53            params["group"] = str(group)
54        resp = self._http.request("GET", "/search", params=params)
55        _raise_for_status(resp)
56        return SearchResponse.model_validate(resp.json())

Groups of matches for q, each with at most limit rows and the total that match.

scope="competition" (with competition_id) searches one event; "all" searches everywhere, listing competition_id's challenges first. Name a group and an offset to page one section. Challenges match on title, id, tag and category, never on the description.