Skip to content

bovine.utils

activity_pub_object_id_from_html_body

activity_pub_object_id_from_html_body(
    body: str,
) -> str | None

Determines the object identifier from the html body by parsing it and looking for link tags with rel=”alternate” and type application/activity+json

Source code in bovine/bovine/utils/__init__.py
def activity_pub_object_id_from_html_body(body: str) -> str | None:
    """Determines the object identifier from the html body
    by parsing it and looking for link tags with rel="alternate"
    and type application/activity+json"""

    soup = BeautifulSoup(body, features="lxml")
    element = soup.find(
        "link", attrs={"rel": "alternate", "type": "application/activity+json"}
    )
    if not element:
        return None

    return element.attrs.get("href")

check_max_offset_now

check_max_offset_now(
    dt: datetime, minutes: int = 5
) -> bool

Checks that offset of a datetime to now to be less than minutes

Source code in bovine/bovine/utils/__init__.py
def check_max_offset_now(dt: datetime, minutes: int = 5) -> bool:
    """Checks that offset of a datetime to now to be less than minutes"""

    now = datetime.now(tz=timezone.utc)

    if dt > now + timedelta(minutes=minutes):
        return False

    if dt < now - timedelta(minutes=minutes):
        return False

    return True

get_gmt_now

get_gmt_now() -> str

Returns the current time in UTC as a GMT formatted string as used in the HTTP Date header

Source code in bovine/bovine/utils/__init__.py
def get_gmt_now() -> str:
    """Returns the current time in UTC as a GMT formatted string as used
    in the HTTP Date header"""
    return datetime.now(tz=timezone.utc).strftime(GMT_STRING)

now_isoformat

now_isoformat() -> str

Returns now in Isoformat, e.g. “2023-05-31T18:11:35Z”, to be used as the value of published

Source code in bovine/bovine/utils/__init__.py
def now_isoformat() -> str:
    """Returns now in Isoformat, e.g. "2023-05-31T18:11:35Z", to be used as the value
    of published"""
    return (
        datetime.now(tz=timezone.utc).replace(microsecond=0, tzinfo=None).isoformat()
        + "Z"
    )

parse_fediverse_handle

parse_fediverse_handle(
    account: str,
) -> Tuple[str, Optional[str]]

Splits fediverse handle in name and domain Supported forms are:

  • user@domain -> (user, domain)
  • @user@domain -> (user, domain)
  • acct:user@domain -> (user, domain)
Source code in bovine/bovine/utils/__init__.py
def parse_fediverse_handle(account: str) -> Tuple[str, Optional[str]]:
    """Splits fediverse handle in name and domain Supported forms are:

    * user@domain -> (user, domain)
    * @user@domain -> (user, domain)
    * acct:user@domain -> (user, domain)
    """
    if account[0] == "@":
        account = account[1:]
    account = account.removeprefix("acct:")

    if "@" in account:
        user, domain = account.split("@", 1)
        return user, domain
    return account, None

parse_gmt

parse_gmt(date_string: str) -> datetime

Parses a GMT formatted string as used in HTTP Date header

Source code in bovine/bovine/utils/__init__.py
def parse_gmt(date_string: str) -> datetime:
    """Parses a GMT formatted string as used in HTTP Date header"""
    return datetime.strptime(date_string, GMT_STRING).replace(tzinfo=timezone.utc)

pydantic_to_json

pydantic_to_json(obj) -> dict

Transforms a pydantic object from bovine.models into a dictionary, that can be serialized as json

Source code in bovine/bovine/utils/__init__.py
def pydantic_to_json(obj) -> dict:
    """Transforms a pydantic object from [bovine.models][bovine.models]
    into a dictionary, that can be serialized as json"""
    return obj.model_dump(mode="json", exclude_none=True)

webfinger_response

webfinger_response(account: str, url: str) -> JrdData

Returns the webfinger response a sa JrdData object

>>> webfinger_response("acct:actor@test.example", "http://test.example/actor")
JrdData(subject='acct:actor@test.example',
    expires=None,
    aliases=None,
    properties=None,
    links=[JrdLink(rel='self',
        type='application/activity+json',
        href='http://test.example/actor',
        titles=None,
        properties=None,
        template=None)])

Parameters:

Name Type Description Default
account str

The acct uri

required
url str

The URL of the actor object

required

Returns:

Type Description
JrdData
Source code in bovine/bovine/utils/__init__.py
def webfinger_response(account: str, url: str) -> JrdData:
    """Returns the webfinger response a sa JrdData object


    ```pycon
    >>> webfinger_response("acct:actor@test.example", "http://test.example/actor")
    JrdData(subject='acct:actor@test.example',
        expires=None,
        aliases=None,
        properties=None,
        links=[JrdLink(rel='self',
            type='application/activity+json',
            href='http://test.example/actor',
            titles=None,
            properties=None,
            template=None)])

    ```

    :param account: The acct uri
    :param url: The URL  of the actor object
    :returns:

    """
    return JrdData(
        subject=account,
        links=[JrdLink(href=url, rel="self", type="application/activity+json")],
    )

webfinger_response_json

webfinger_response_json(account: str, url: str) -> dict

helper to generate a webfinger response

>>> webfinger_response_json("acct:actor@test.example", "http://test.example/actor")
{'subject': 'acct:actor@test.example',
    'links': [{'rel': 'self',
        'type': 'application/activity+json',
        'href': 'http://test.example/actor'}]}
Source code in bovine/bovine/utils/__init__.py
def webfinger_response_json(account: str, url: str) -> dict:
    """helper to generate a webfinger response

    ```pycon
    >>> webfinger_response_json("acct:actor@test.example", "http://test.example/actor")
    {'subject': 'acct:actor@test.example',
        'links': [{'rel': 'self',
            'type': 'application/activity+json',
            'href': 'http://test.example/actor'}]}

    ```
    """
    return pydantic_to_json(webfinger_response(account, url))