From 2417d053e3add44cd35cd62a1bf8192ad49547fe Mon Sep 17 00:00:00 2001 From: Eduardo Blancas Date: Mon, 25 Mar 2024 15:23:27 -0600 Subject: [PATCH] utc codes in marketing.url and keeping rendered date --- CHANGELOG.md | 2 ++ src/jupyblog/cli.py | 3 ++- src/jupyblog/md.py | 35 ++++++++++++++++++++++++++++++++--- src/jupyblog/models.py | 4 +++- src/jupyblog/utm.py | 8 ++++++-- 5 files changed, 45 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d673b..94293d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # CHANGELOG ## 0.0.14dev +* [Feature] Keep existing date if the current file has been rendered already +* [Feature] Add utm codes to front matter url (`marketing.url`) ## 0.0.13 (2023-03-14) diff --git a/src/jupyblog/cli.py b/src/jupyblog/cli.py index 48a6d64..15de914 100644 --- a/src/jupyblog/cli.py +++ b/src/jupyblog/cli.py @@ -97,9 +97,11 @@ def _render(local, cfg="jupyblog.yaml", incsource=False, log=None): click.echo("Finished running build.sh\n\n") click.echo("Rendering markdown...") + out_path = Path(cfg.path_to_posts_abs(), (post_name + ".md")) mdr = MarkdownRenderer( path_to_mds=path, + path_to_out=out_path, img_dir=cfg.path_to_static_abs(), img_prefix=cfg.prefix_img, footer_template=cfg.read_footer_template(), @@ -119,7 +121,6 @@ def _render(local, cfg="jupyblog.yaml", incsource=False, log=None): ) out, name = mdr.render(name=name_input, include_source_in_footer=incsource) - out_path = Path(cfg.path_to_posts_abs(), (post_name + ".md")) click.echo(f"Output: {out_path}") # map language in code snippets if needed diff --git a/src/jupyblog/md.py b/src/jupyblog/md.py index e4fcee1..7cf712e 100644 --- a/src/jupyblog/md.py +++ b/src/jupyblog/md.py @@ -3,6 +3,7 @@ * support for requirements.txt * create and destroy env """ + from copy import copy from contextlib import contextmanager from urllib import parse @@ -18,7 +19,7 @@ from jupyblog.execute import ASTExecutor, extract_outputs_from_notebook_cell from jupyblog.expand import expand from jupyblog.exceptions import InvalidFrontMatter, InputPostException -from jupyblog.utm import add_utm_to_all_urls +from jupyblog.utm import add_utm_to_all_urls, add_utm_to_url from jupyblog.ast import MarkdownAST, create_md_parser logger = logging.getLogger(__name__) @@ -190,6 +191,11 @@ class MarkdownRenderer: """ Parameters ---------- + path_to_out : str or pathlib.Path + Path to the rendered version of this markdown file. Currently, it's only + used to extract the date from the file (to prevent overridding it when + rendering a new version) + img_dir : str or pathlib.Path Output path (in the current filesystem) for images. @@ -216,8 +222,10 @@ def __init__( front_matter_template=None, utm_source=None, utm_medium=None, + path_to_out=None, ): self.path = path_to_mds + self.path_to_out = path_to_out self._img_dir = img_dir self._img_prefix = img_prefix or "" self._footer_template = footer_template @@ -249,7 +257,8 @@ def render(self, name, *, include_source_in_footer, metadata=None): md_ast = self.parser(md_raw) - # TODO: replace and use model object + # TODO: parse_metadata validates the schema, we are now using pydantic for + # models, hence, we can use it for validation and remove this if metadata is None: metadata = parse_metadata(md_raw) @@ -303,6 +312,16 @@ def render(self, name, *, include_source_in_footer, metadata=None): if self._front_matter_template: metadata = {**metadata, **self._front_matter_template} + # if this has been rendered before, use the existing date + if self.path_to_out and Path(self.path_to_out).is_file(): + metadata_rendered = parse_metadata( + Path(self.path_to_out).read_text(), validate=False + ) + date_existing = metadata_rendered.get("date", None) + + if date_existing: + metadata["date"] = date_existing + if self._footer_template: md_out = add_footer( md_out, @@ -327,7 +346,17 @@ def render(self, name, *, include_source_in_footer, metadata=None): if path and "images" not in metadata: metadata["images"] = [path] - # TODO: extrac title from front matter and put it as H1 header + # if there is a marketing URL, add utm tags + marketing_url = metadata.get("marketing", dict()).get("url", None) + + if marketing_url: + metadata["marketing"]["url"] = add_utm_to_url( + marketing_url, + source=canonical_name, + medium=self._utm_medium, + ) + + # TODO: extract title from front matter and put it as H1 header md_out = replace_metadata(md_out, metadata) diff --git a/src/jupyblog/models.py b/src/jupyblog/models.py index 5af7413..7462234 100644 --- a/src/jupyblog/models.py +++ b/src/jupyblog/models.py @@ -103,7 +103,9 @@ def load_front_matter_template(self, name): now = _now() rendered = Template(text, undefined=StrictUndefined).render( - now=now, name=name, env=os.environ + now=now, + name=name, + env=os.environ, ) front_matter = yaml.safe_load(rendered) else: diff --git a/src/jupyblog/utm.py b/src/jupyblog/utm.py index 2c2dfb6..ca14516 100644 --- a/src/jupyblog/utm.py +++ b/src/jupyblog/utm.py @@ -1,6 +1,7 @@ """ Process URLs in a markdown file """ + from urllib.parse import urlparse, urlencode, parse_qsl from pathlib import PurePosixPath, Path @@ -15,14 +16,17 @@ def find_urls(text): return list(ast.iter_links()) -def add_utm_to_url(url, source, medium, campaign): +def add_utm_to_url(url, source, medium, campaign=None): if isinstance(url, str): parsed = urlparse(url) else: parsed = url current_params = dict(parse_qsl(parsed.query)) - utm = {"utm_source": source, "utm_medium": medium, "utm_campaign": campaign} + utm = {"utm_source": source, "utm_medium": medium} + + if campaign: + utm["utm_campaign"] = campaign parsed = parsed._replace(query=urlencode({**current_params, **utm}))