From 5acdf749090835464b652ebc66009ea8f8eff6a0 Mon Sep 17 00:00:00 2001 From: florimondmanca Date: Sun, 17 Dec 2023 22:01:59 +0100 Subject: [PATCH] Add h-card and h-entry microformats --- .../web/templates/components/jumbotron.jinja | 10 ++- server/web/templates/views/post/detail.jinja | 13 +-- tests/test_indieweb.py | 42 +++++++++- tests/utils.py | 83 +++++++++++++++++++ 4 files changed, 136 insertions(+), 12 deletions(-) diff --git a/server/web/templates/components/jumbotron.jinja b/server/web/templates/components/jumbotron.jinja index 5622206..8eefdd4 100644 --- a/server/web/templates/components/jumbotron.jinja +++ b/server/web/templates/components/jumbotron.jinja @@ -1,13 +1,17 @@ {% macro Jumbotron() %} -
+
- +
-

Florimond Manca

+

+ + Florimond Manca + +

{{ _('Open Source Developer, Idealist On A Journey') }} diff --git a/server/web/templates/views/post/detail.jinja b/server/web/templates/views/post/detail.jinja index cff0097..3f3eca1 100644 --- a/server/web/templates/views/post/detail.jinja +++ b/server/web/templates/views/post/detail.jinja @@ -21,34 +21,35 @@

{%- endif -%} -
+
{{ PostMeta(post, editable=true) }} -

+

{{ post.name }}

{% if post.abstract -%} -

+

{{ post.abstract }}

{%- endif %}

-

-
+
{{ post.text | safe }}
{{ UtterancesComments() }}
-
+
{% endblock content %} diff --git a/tests/test_indieweb.py b/tests/test_indieweb.py index 99197cd..296cbd5 100644 --- a/tests/test_indieweb.py +++ b/tests/test_indieweb.py @@ -3,12 +3,12 @@ from server import settings -from .utils import find_rel_me_links, find_webmention_url +from .utils import find_rel_me_links, find_webmention_url, parse_hcard, parse_hentry @pytest.mark.asyncio async def test_webmentions_url(client: httpx.AsyncClient) -> None: - url = "https://florimond.dev" + url = "http://florimond.dev" response = await client.get(url) assert response.status_code == 200 html = response.text @@ -19,10 +19,46 @@ async def test_webmentions_url(client: httpx.AsyncClient) -> None: @pytest.mark.asyncio async def test_rel_me_links(client: httpx.AsyncClient) -> None: - url = "https://florimond.dev" + url = "http://florimond.dev" response = await client.get(url) assert response.status_code == 200 html = response.text urls = find_rel_me_links(html) assert urls == [link["href"] for link in settings.SOCIAL_LINKS] + + +@pytest.mark.asyncio +async def test_hcard(client: httpx.AsyncClient) -> None: + url = "http://florimond.dev" + response = await client.get(url) + assert response.status_code == 200 + html = response.text + + hcard = parse_hcard(html) + + assert hcard == { + "p-name": "http://florimond.dev/en/", + "u-url": "http://florimond.dev/en/", + "u-photo": "http://florimond.dev/static/img/me.png", + } + + +@pytest.mark.asyncio +async def test_hentry(client: httpx.AsyncClient) -> None: + url = "http://florimond.dev/en/posts/2018/07/let-the-journey-begin" + response = await client.get(url) + assert response.status_code == 200 + html = response.text + + hentry = parse_hentry(html) + + assert hentry["p-name"].strip() == "Let the Journey begin" + assert hentry["p-summary"].strip() == ( + "Hi! My name is Florimond. " + "I will be your captain for the length of this journey. 👨‍✈️" + ) + assert hentry["p-author"] == "http://florimond.dev/en/" + assert hentry["h-card"] == "http://florimond.dev/en/" + assert hentry["dt-published"] == "2018-07-25" + assert hentry["e-content"].startswith("Welcome to CodeSail!") diff --git a/tests/utils.py b/tests/utils.py index cb9be1d..9b0e30a 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -74,3 +74,86 @@ def find_rel_me_links(html: str) -> list[str]: parser.feed(html) return [href for tag, rel, href in parser.rels if tag == "a" and rel == "me"] + + +class HCardParser(HTMLParser): + def __init__(self) -> None: + super().__init__() + self.hcard: dict = {} + self._in_hcard = False + + def handle_starttag(self, tag: str, attrs: list) -> None: + attr = dict(attrs) + + classattr = attr.get("class", "") + + if "h-card" in classattr: + self._in_hcard = True + + if self._in_hcard: + if tag == "img" and "u-photo" in classattr: + self.hcard["u-photo"] = attr["src"] + + if tag == "a" and "p-name" in classattr: + self.hcard["p-name"] = attr["href"] + + if tag == "a" and "u-url" in classattr: + self.hcard["u-url"] = attr["href"] + + +def parse_hcard(html: str) -> dict: + parser = HCardParser() + parser.feed(html) + return parser.hcard + + +class HEntryParser(HTMLParser): + def __init__(self) -> None: + super().__init__() + self.hentry: dict = {} + self._in_hentry = False + self._field = "" + + def handle_starttag(self, tag: str, attrs: list) -> None: + attr = dict(attrs) + + classattr = attr.get("class", "") + + if tag == "article" and "h-entry" in classattr: + self._in_hentry = True + + if self._in_hentry: + if tag == "h1" and "p-name" in classattr: + assert not self._field + self._field = "p-name" + + if "p-summary" in classattr: + assert not self._field + self._field = "p-summary" + + if tag == "a" and "p-author" in classattr: + self.hentry["p-author"] = attr["href"] + + if tag == "a" and "h-card" in classattr: + self.hentry["h-card"] = attr["href"] + + if tag == "time" and "dt-published" in classattr: + self.hentry["dt-published"] = attr["datetime"] + + if "e-content" in classattr: + assert not self._field + self._field = "e-content" + + def handle_data(self, data: str) -> None: + if self._field: + self.hentry[self._field] = data + + def handle_endtag(self, _: str) -> None: + if self._field: + self._field = "" + + +def parse_hentry(html: str) -> dict: + parser = HEntryParser() + parser.feed(html) + return parser.hentry