From e6da7207c83681a56191f1676f2b921ba2d432a4 Mon Sep 17 00:00:00 2001 From: GeoJulien Date: Wed, 23 Oct 2024 15:43:56 +0200 Subject: [PATCH 1/4] feature(integration): support social cards for blog plugin posts --- .../theme_material_social_plugin.py | 96 ++++++++++++++++--- tests/fixtures/docs/blog/.authors.yml | 15 +++ tests/fixtures/docs/blog/index.md | 2 + tests/fixtures/docs/blog/posts/firstpost.md | 32 +++++++ tests/fixtures/docs/blog/posts/secondpost.md | 32 +++++++ .../mkdocs_item_image_social_cards_blog.yml | 14 +++ ...test_integrations_material_social_cards.py | 17 ++++ 7 files changed, 197 insertions(+), 11 deletions(-) create mode 100644 tests/fixtures/docs/blog/.authors.yml create mode 100644 tests/fixtures/docs/blog/index.md create mode 100644 tests/fixtures/docs/blog/posts/firstpost.md create mode 100644 tests/fixtures/docs/blog/posts/secondpost.md create mode 100644 tests/fixtures/mkdocs_item_image_social_cards_blog.yml diff --git a/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py b/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py index 07914a3..6526976 100644 --- a/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py +++ b/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py @@ -21,9 +21,13 @@ # conditional try: from material import __version__ as material_version + from material.plugins.blog.plugin import BlogPlugin + from pymdownx.slugs import slugify + except ImportError: material_version = None + # ############################################################################ # ########## Globals ############# # ################################ @@ -38,6 +42,7 @@ class IntegrationMaterialSocialCards: # attributes IS_ENABLED: bool = True + IS_BLOG_PLUGIN_ENABLED: bool = True IS_SOCIAL_PLUGIN_ENABLED: bool = True IS_SOCIAL_PLUGIN_CARDS_ENABLED: bool = True IS_THEME_MATERIAL: bool = False @@ -53,6 +58,7 @@ def __init__(self, mkdocs_config: MkDocsConfig, switch_force: bool = True) -> No it to False to disable it even if Social Cards are enabled in Mkdocs configuration. Defaults to True. """ + self.mkdocs_config = mkdocs_config # check if the integration can be enabled or not self.IS_SOCIAL_PLUGIN_CARDS_ENABLED = ( self.is_social_plugin_and_cards_enabled_mkdocs(mkdocs_config=mkdocs_config) @@ -85,6 +91,7 @@ def __init__(self, mkdocs_config: MkDocsConfig, switch_force: bool = True) -> No self.social_cards_cache_dir = self.get_social_cards_cache_dir( mkdocs_config=mkdocs_config ) + self.is_blog_plugin_enabled_mkdocs(mkdocs_config=mkdocs_config) if self.is_mkdocs_theme_material_insiders(): self.load_cache_cards_manifest() @@ -123,6 +130,36 @@ def is_mkdocs_theme_material_insiders(self) -> Optional[bool]: self.IS_INSIDERS = False return False + def is_blog_plugin_enabled_mkdocs(self, mkdocs_config: MkDocsConfig) -> bool: + """Check if blog plugin is installed and enabled. + + Args: + mkdocs_config (MkDocsConfig): Mkdocs website configuration object. + + Returns: + bool: True if the theme material and the plugin blog is enabled. + """ + if not self.is_mkdocs_theme_material(mkdocs_config=mkdocs_config): + logger.debug("Installed theme is not 'material'. Integration disabled.") + return False + + if not mkdocs_config.plugins.get("material/blog"): + logger.debug("Material blog plugin is not listed in configuration.") + return False + + self.blog_plugin_cfg: BlogPlugin | None = mkdocs_config.plugins.get( + "material/blog" + ) + + if not self.blog_plugin_cfg.config.enabled: + logger.debug("Material blog plugin is installed but disabled.") + self.IS_BLOG_PLUGIN_ENABLED = False + return False + + logger.debug("Material blog plugin is enabled in Mkdocs configuration.") + self.IS_SOCIAL_PLUGIN_CARDS_ENABLED = True + return True + def is_social_plugin_enabled_mkdocs(self, mkdocs_config: MkDocsConfig) -> bool: """Check if social plugin is installed and enabled. @@ -274,18 +311,29 @@ def get_social_card_build_path_for_page( if mkdocs_site_dir is None and self.mkdocs_site_build_dir: mkdocs_site_dir = self.mkdocs_site_build_dir - expected_built_card_path = Path( - f"{mkdocs_site_dir}/{self.social_cards_assets_dir}/" - f"{Path(mkdocs_page.file.src_uri).with_suffix('.png')}" - ) + # if page is a blog post + if self.IS_BLOG_PLUGIN_ENABLED and Path( + mkdocs_page.file.src_uri + ).is_relative_to(self.blog_plugin_cfg.config.blog_dir): + expected_built_card_path = Path( + f"{mkdocs_site_dir}/{self.social_cards_assets_dir}/" + f"{Path(mkdocs_page.file.dest_uri).parent}.png" + ) + else: + expected_built_card_path = Path( + f"{mkdocs_site_dir}/{self.social_cards_assets_dir}/" + f"{Path(mkdocs_page.file.src_uri).with_suffix('.png')}" + ) if expected_built_card_path.is_file(): logger.debug( - f"Social card file found in cache folder: {expected_built_card_path}" + f"Social card file found in build folder: {expected_built_card_path}" ) return expected_built_card_path else: - logger.debug(f"Not found: {expected_built_card_path}") + logger.debug( + f"Social card not found in build folder: {expected_built_card_path}" + ) return None def get_social_card_cache_path_for_page(self, mkdocs_page: Page) -> Optional[Path]: @@ -305,16 +353,28 @@ def get_social_card_cache_path_for_page(self, mkdocs_page: Page) -> Optional[Pat Path: path to the image in local cache folder if it exists """ if self.IS_INSIDERS: - expected_cached_card_path = self.social_cards_cache_dir.joinpath( - f"assets/images/social/{Path(mkdocs_page.file.src_uri).with_suffix('.png')}" - ) + + # if page is a blog post + if self.IS_BLOG_PLUGIN_ENABLED and Path( + mkdocs_page.file.src_uri + ).is_relative_to(self.blog_plugin_cfg.config.blog_dir): + expected_cached_card_path = self.social_cards_cache_dir.joinpath( + f"assets/images/social/{Path(mkdocs_page.file.dest_uri).parent}.png" + ) + else: + expected_cached_card_path = self.social_cards_cache_dir.joinpath( + f"assets/images/social/{Path(mkdocs_page.file.src_uri).with_suffix('.png')}" + ) + if expected_cached_card_path.is_file(): logger.debug( f"Social card file found in cache folder: {expected_cached_card_path}" ) return expected_cached_card_path else: - logger.debug(f"Not found: {expected_cached_card_path}") + logger.debug( + f"Social card not found in cache folder: {expected_cached_card_path}" + ) else: if "description" in mkdocs_page.meta: @@ -362,4 +422,18 @@ def get_social_card_url_for_page( if mkdocs_site_url is None and self.mkdocs_site_url: mkdocs_site_url = self.mkdocs_site_url - return f"{mkdocs_site_url}assets/images/social/{Path(mkdocs_page.file.src_uri).with_suffix('.png')}" + # if page is a blog post + if self.IS_BLOG_PLUGIN_ENABLED and Path( + mkdocs_page.file.src_uri + ).is_relative_to(self.blog_plugin_cfg.config.blog_dir): + page_social_card = ( + f"{mkdocs_site_url}assets/images/social/" + f"{Path(mkdocs_page.file.dest_uri).parent}.png" + ) + else: + page_social_card = ( + f"{mkdocs_site_url}assets/images/social/" + f"{Path(mkdocs_page.file.src_uri).with_suffix('.png')}" + ) + + return page_social_card diff --git a/tests/fixtures/docs/blog/.authors.yml b/tests/fixtures/docs/blog/.authors.yml new file mode 100644 index 0000000..17b0e05 --- /dev/null +++ b/tests/fixtures/docs/blog/.authors.yml @@ -0,0 +1,15 @@ +authors: + squidfunk: + name: Martin Donath + description: Creator + avatar: https://github.com/squidfunk.png + alexvoss: + name: Alex Voss + description: Weltenwanderer + avatar: https://github.com/alexvoss.png + guts: + avatar: https://cdn.geotribu.fr/img/internal/contributeurs/jmou.jfif + description: GIS Watchman + name: Julien Moura + slug: julien-moura + url: https://geotribu.fr/team/julien-moura/ diff --git a/tests/fixtures/docs/blog/index.md b/tests/fixtures/docs/blog/index.md new file mode 100644 index 0000000..c58f16c --- /dev/null +++ b/tests/fixtures/docs/blog/index.md @@ -0,0 +1,2 @@ +# Blog + diff --git a/tests/fixtures/docs/blog/posts/firstpost.md b/tests/fixtures/docs/blog/posts/firstpost.md new file mode 100644 index 0000000..5cdcd8c --- /dev/null +++ b/tests/fixtures/docs/blog/posts/firstpost.md @@ -0,0 +1,32 @@ +--- +authors: + - alexvoss +date: 2023-10-11 +categories: + - meta +--- + +# My first blog post + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec +maximus ex. Sed consequat, nulla quis malesuada dapibus, elit metus vehicula +erat, ut egestas tellus eros at risus. In hac habitasse platea dictumst. +Phasellus id lacus pulvinar erat consequat pretium. Morbi malesuada arcu mauris +Nam vel justo sem. Nam placerat purus non varius luctus. Integer pretium leo in +sem rhoncus, quis gravida orci mollis. Proin id aliquam est. Vivamus in nunc ac +metus tristique pellentesque. Suspendisse viverra urna in accumsan aliquet. + + + +Donec volutpat, elit ac volutpat laoreet, turpis dolor semper nibh, et dictum +massa ex pulvinar elit. Curabitur commodo sit amet dolor sed mattis. Etiam +tempor odio eu nisi gravida cursus. Maecenas ante enim, fermentum sit amet +molestie nec, mollis ac libero. Vivamus sagittis suscipit eros ut luctus. + +Nunc vehicula sagittis condimentum. Cras facilisis bibendum lorem et feugiat. +In auctor accumsan ligula, at consectetur erat commodo quis. Morbi ac nunc +pharetra, pellentesque risus in, consectetur urna. Nulla id enim facilisis +arcu tincidunt pulvinar. Vestibulum laoreet risus scelerisque porta congue. +In velit purus, dictum quis neque nec, molestie viverra risus. Nam pellentesque +tellus id elit ultricies, vel finibus erat cursus. + diff --git a/tests/fixtures/docs/blog/posts/secondpost.md b/tests/fixtures/docs/blog/posts/secondpost.md new file mode 100644 index 0000000..352d997 --- /dev/null +++ b/tests/fixtures/docs/blog/posts/secondpost.md @@ -0,0 +1,32 @@ +--- +authors: + - squidfunk +date: 2023-10-12 +categories: + - hello +--- + +# A second post + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec +maximus ex. Sed consequat, nulla quis malesuada dapibus, elit metus vehicula +erat, ut egestas tellus eros at risus. In hac habitasse platea dictumst. +Phasellus id lacus pulvinar erat consequat pretium. Morbi malesuada arcu mauris +Nam vel justo sem. Nam placerat purus non varius luctus. Integer pretium leo in +sem rhoncus, quis gravida orci mollis. Proin id aliquam est. Vivamus in nunc ac +metus tristique pellentesque. Suspendisse viverra urna in accumsan aliquet. + + + +Donec volutpat, elit ac volutpat laoreet, turpis dolor semper nibh, et dictum +massa ex pulvinar elit. Curabitur commodo sit amet dolor sed mattis. Etiam +tempor odio eu nisi gravida cursus. Maecenas ante enim, fermentum sit amet +molestie nec, mollis ac libero. Vivamus sagittis suscipit eros ut luctus. + +Nunc vehicula sagittis condimentum. Cras facilisis bibendum lorem et feugiat. +In auctor accumsan ligula, at consectetur erat commodo quis. Morbi ac nunc +pharetra, pellentesque risus in, consectetur urna. Nulla id enim facilisis +arcu tincidunt pulvinar. Vestibulum laoreet risus scelerisque porta congue. +In velit purus, dictum quis neque nec, molestie viverra risus. Nam pellentesque +tellus id elit ultricies, vel finibus erat cursus. + diff --git a/tests/fixtures/mkdocs_item_image_social_cards_blog.yml b/tests/fixtures/mkdocs_item_image_social_cards_blog.yml new file mode 100644 index 0000000..26fe268 --- /dev/null +++ b/tests/fixtures/mkdocs_item_image_social_cards_blog.yml @@ -0,0 +1,14 @@ +site_name: Test RSS Plugin +site_description: Test social cards support in RSS with blog plugin also enabled +site_url: https://guts.github.io/mkdocs-rss-plugin + +plugins: + - blog: + blog_dir: blog + - rss + - social: + enabled: true + cards: true + +theme: + name: material diff --git a/tests/test_integrations_material_social_cards.py b/tests/test_integrations_material_social_cards.py index 4bde30a..64d4782 100644 --- a/tests/test_integrations_material_social_cards.py +++ b/tests/test_integrations_material_social_cards.py @@ -117,6 +117,23 @@ def test_plugin_config_social_plugin_enabled_but_cards_disabled(self): self.assertFalse(integration_social_cards.IS_SOCIAL_PLUGIN_CARDS_ENABLED) self.assertFalse(integration_social_cards.IS_ENABLED) + def test_plugin_config_social_cards_enabled_with_blog_plugin(self): + # default reference + cfg_mkdocs = load_config( + str( + Path("tests/fixtures/mkdocs_item_image_social_cards_blog.yml").resolve() + ) + ) + + integration_social_cards = IntegrationMaterialSocialCards( + mkdocs_config=cfg_mkdocs + ) + self.assertTrue(integration_social_cards.IS_THEME_MATERIAL) + self.assertTrue(integration_social_cards.IS_SOCIAL_PLUGIN_ENABLED) + self.assertTrue(integration_social_cards.IS_SOCIAL_PLUGIN_CARDS_ENABLED) + self.assertTrue(integration_social_cards.IS_BLOG_PLUGIN_ENABLED) + self.assertTrue(integration_social_cards.IS_ENABLED) + def test_simple_build(self): with tempfile.TemporaryDirectory() as tmpdirname: cli_result = self.build_docs_setup( From 470d409579bfd44b9ee11ae9d8a9b2b9c2fd45b3 Mon Sep 17 00:00:00 2001 From: GeoJulien Date: Thu, 24 Oct 2024 18:17:02 +0200 Subject: [PATCH 2/4] fix(integration): IS8BLOG_PLUGIN_ENABLED was not correctly use --- .../integrations/theme_material_social_plugin.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py b/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py index 6526976..1382d03 100644 --- a/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py +++ b/mkdocs_rss_plugin/integrations/theme_material_social_plugin.py @@ -91,7 +91,9 @@ def __init__(self, mkdocs_config: MkDocsConfig, switch_force: bool = True) -> No self.social_cards_cache_dir = self.get_social_cards_cache_dir( mkdocs_config=mkdocs_config ) - self.is_blog_plugin_enabled_mkdocs(mkdocs_config=mkdocs_config) + self.IS_BLOG_PLUGIN_ENABLED = self.is_blog_plugin_enabled_mkdocs( + mkdocs_config=mkdocs_config + ) if self.is_mkdocs_theme_material_insiders(): self.load_cache_cards_manifest() @@ -145,6 +147,7 @@ def is_blog_plugin_enabled_mkdocs(self, mkdocs_config: MkDocsConfig) -> bool: if not mkdocs_config.plugins.get("material/blog"): logger.debug("Material blog plugin is not listed in configuration.") + self.IS_BLOG_PLUGIN_ENABLED = False return False self.blog_plugin_cfg: BlogPlugin | None = mkdocs_config.plugins.get( @@ -157,7 +160,7 @@ def is_blog_plugin_enabled_mkdocs(self, mkdocs_config: MkDocsConfig) -> bool: return False logger.debug("Material blog plugin is enabled in Mkdocs configuration.") - self.IS_SOCIAL_PLUGIN_CARDS_ENABLED = True + self.IS_BLOG_PLUGIN_ENABLED = True return True def is_social_plugin_enabled_mkdocs(self, mkdocs_config: MkDocsConfig) -> bool: From 0e90d914b125336e723449ea1dec581a80be3891 Mon Sep 17 00:00:00 2001 From: GeoJulien Date: Thu, 24 Oct 2024 18:21:19 +0200 Subject: [PATCH 3/4] fix(test): add blog as exception --- tests/test_build.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_build.py b/tests/test_build.py index a312fbf..7f07e47 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -398,8 +398,13 @@ def test_simple_build_item_length_unlimited(self): if feed_item.title not in ( "Page without meta with short text", "Blog sample", + "Blog", ): - self.assertGreater(len(feed_item.description), 150, feed_item.title) + self.assertGreater( + len(feed_item.description), + 150, + f"Failed item title: {feed_item.title}", + ) def test_simple_build_item_delimiter(self): with tempfile.TemporaryDirectory() as tmpdirname: From 8bb75c549dc5d4c6ecca7cdab7f1e7a9c1c60f82 Mon Sep 17 00:00:00 2001 From: GeoJulien Date: Thu, 24 Oct 2024 18:23:36 +0200 Subject: [PATCH 4/4] fix(test): exclude .authors.yml file from mkdocs config fixtures file --- tests/test_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_config.py b/tests/test_config.py index 47b9f68..9c4cd69 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -41,7 +41,7 @@ class TestConfig(BaseTest): @classmethod def setUpClass(cls): """Executed when module is loaded before any test.""" - cls.config_files = sorted(Path("tests/fixtures/").glob("**/*.yml")) + cls.config_files = sorted(Path("tests/fixtures/").glob("**/mkdocs_*.yml")) cls.feed_image = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Feed-icon.svg/128px-Feed-icon.svg.png" def setUp(self):