xnutsive/notoma

View on GitHub
notoma/page.py

Summary

Maintainability
A
55 mins
Test Coverage
from pathlib import Path
from string import Template
from datetime import datetime

import re

from notion.collection import NotionDate, CollectionRowBlock
from notion.block import PageBlock

from .config import Config

"""
Functions that operate on Notion's `PageBlock`.
"""


def page_path(page: PageBlock, dest_dir: Path = Path(".")) -> Path:
    "Build a .md file path in `dest_dir` based on a Notion page metadata."
    fname = __title_to_slug(page.title) + ".md"
    return dest_dir / fname


def __title_to_slug(title: str) -> str:
    return re.sub(r"[^\w\-]", "", re.sub(r"\s+", "-", title)).lower()


def front_matter(page: CollectionRowBlock, config: Config) -> str:
    "Builds and returns a page front matter in a yaml-like format."
    # Start with all the properties from the page, including formulas and rollups.
    all_props = page.get_all_properties()

    # Add the default layout from the config
    # if there's no layout property on the page itself.
    if "layout" not in all_props:
        all_props["layout"] = config.default_layout

    # Add default published_at if there's no specific property for it.
    if "published_at" not in all_props:
        last_edited_time = datetime.utcfromtimestamp(
            int(page.get("last_edited_time")) / 1000
        )
        all_props["published_at"] = last_edited_time

    # Select only properties that are not empty
    renderables = {k: v for k, v in all_props.items() if v != ""}
    return __sanitize_front_matter(renderables)


def __sanitize_front_matter(items: dict) -> dict:
    "Sanitizes and returns front matter items as a dictionary."
    for k, v in items.items():
        if type(v) not in [str, list]:
            if isinstance(v, NotionDate):
                items[k] = v.start
            if isinstance(v, bool):
                items[k] = str(v).lower()
    return items


def page_url_substitutions(page: PageBlock, config: Config) -> dict:
    "Builds and returns a `dict` of substitutions to build URL to this page in the Blog."
    # Start with a dict from `front_m   subs = front_matter(page, config)
    subs = front_matter(page, config)

    # Grab the config baseurl
    subs["baseurl"] = config["baseurl"]

    # FIXME Clean this up into a mapping of callables?
    #
    if "title" in subs:
        subs["title"] = __title_to_slug(subs["title"])

    if "categories" in subs:
        subs["categories"] = "/".join(subs["categories"])
    else:
        subs["categories"] = ""

    if "published_at" in subs:
        subs["year"], subs["month"], subs["day"], *_ = subs["published_at"].timetuple()

    return subs


def build_page_url(page: PageBlock, pattern: Template, config: Config) -> str:
    "Build the URL string for a given URL pattern and returns it as `str`."
    return pattern.substitute(page_url_substitutions(page, config))