Source code for indieweb_utils.trackback.send

from urllib.parse import urlparse

import requests
from bs4 import BeautifulSoup, Comment

from ..rsd.discover import rsd_discovery
from ..utils.urls import canonicalize_url


class TrackbackError(Exception):
    """Base class for trackback errors."""

    pass


class ConnectionError(TrackbackError):
    """Raised when a connection error occurs."""

    pass


class InvalidStatusCodeError(TrackbackError):
    """Raised when the server returns an invalid status code."""

    pass


def rsd_trackback_discovery(url: str) -> str:
    """
    Discover the trackback URL from a URL using RSD.

    :param url: The URL to discover the trackback URL from.
    :returns: The trackback URL.

    Example:

    .. code-block:: python

        from indieweb_utils import rsd_trackback_discovery

        rsd_trackback_discovery('http://example.com/post/123')
    """
    return rsd_discovery(url, "trackback:ping")


[docs]def discover_trackback_url(url: str) -> str: """ Discover the trackback URL from a URL. :param url: The URL to discover the trackback URL from. :returns: The trackback URL. Example: .. code-block:: python from indieweb_utils import discover_trackback_url discover_trackback_url('http://example.com/post/123') """ get_trackback_url_request = requests.get(url) if get_trackback_url_request.status_code != 200: raise InvalidStatusCodeError( "The server returned a status code of {}.".format(get_trackback_url_request.status_code) ) soup = BeautifulSoup(get_trackback_url_request.text, "html.parser") # get all comments comments = soup.find_all(string=lambda text: isinstance(text, Comment)) for c in comments: soup = BeautifulSoup(c, "lxml") rdf = soup.find("rdf:description") if not rdf: continue trackback_url = rdf.get("trackback:ping") if not trackback_url: raise TrackbackError("No trackback URL found in RDF.") domain = urlparse(url).netloc return canonicalize_url(trackback_url, domain) trackback_url = rsd_trackback_discovery(url) if trackback_url: return trackback_url return ""
[docs]def send_trackback(target_url, source_url, title: str = None, excerpt: str = None, blog_name: str = None) -> None: """ Send a trackback to a URL. :param target_url: The URL to send the trackback to. :param source_url: The URL of your post. :param title: The title of your post. :param excerpt: An excerpt of your post. :param blog_name: The name of your blog. :returns: The status code and message from the server. :raises ConnectionError: Raised when a connection error occurs. :raises InvalidStatusCodeError: Raised when the server returns an invalid status code. :raises TrackbackError: Raised when the server returns an invalid response. Example: .. code-block:: python from indieweb_utils import send_trackback send_trackback( source_url='http://example.com/post/123#trackback', target_url='http://example.com/post/123', title='My Post', excerpt='This is my post', blog_name='My Blog' ) """ endpoint_url = discover_trackback_url(target_url) try: send_trackback_request = requests.post( endpoint_url, data={"url": source_url, "title": title, "excerpt": excerpt, "blog_name": blog_name}, headers={ "User-Agent": "IndieWeb Utils", "Content-Type": "application/x-www-form-urlencoded; charset=utf-8", }, ) except requests.exceptions.ConnectionError: raise ConnectionError("Could not connect to the server.") if send_trackback_request.status_code != 200: raise InvalidStatusCodeError( "The server returned a status code of {}.".format(send_trackback_request.status_code) ) soup = BeautifulSoup(send_trackback_request.text, "lxml") soup = soup.find("response") if not soup: raise TrackbackError("The server returned an invalid response.") if soup.find("error") and soup.find("error").text != "0": raise TrackbackError("The server returned an error: {}".format(soup.find("message").text))