diff --git a/.github/workflows/pr_checker_build.yml b/.github/workflows/pr_checker_build.yml index 84f64127c6..4e12fcfc47 100644 --- a/.github/workflows/pr_checker_build.yml +++ b/.github/workflows/pr_checker_build.yml @@ -30,9 +30,18 @@ jobs: if: ${{ github.repository_owner == 'geotribu' }} steps: + - name: Install French locale + id: locale-fr + shell: bash + run: | + sudo locale-gen fr_FR.UTF-8 + sudo update-locale LANG=fr_FR.UTF-8 + - name: Get source code uses: actions/checkout@v4 + + - name: Set up Python uses: actions/setup-python@v5 with: diff --git a/.gitignore b/.gitignore index 6b1e3681a1..18c9324aa2 100644 --- a/.gitignore +++ b/.gitignore @@ -234,3 +234,4 @@ linkchecker_report.html gource.ini avatars/ mkdocs-generated-configuration.yml +latest_content.yml diff --git a/content/articles/.pages b/content/articles/.pages index 0b22b20a83..043117b687 100644 --- a/content/articles/.pages +++ b/content/articles/.pages @@ -1,6 +1,7 @@ title: "📖 Articles" nav: + - "Derniers articles": index.md - "2025" - "2024" - "2023" diff --git a/content/articles/index.md b/content/articles/index.md new file mode 100644 index 0000000000..c4f4f21ee8 --- /dev/null +++ b/content/articles/index.md @@ -0,0 +1,13 @@ +--- +title: "Liste des derniers articles parus" +template: custom_templates/index_articles.html +# theme customizations +hide: + - footer + - navigation + - toc +search: + exclude: true +--- + + diff --git a/content/theme/custom_templates/index_articles.html b/content/theme/custom_templates/index_articles.html new file mode 100644 index 0000000000..9f0cd0e454 --- /dev/null +++ b/content/theme/custom_templates/index_articles.html @@ -0,0 +1,74 @@ +{% extends "base.html" %} + +{% block styles %} +{{ super() }} + + +{% endblock %} + + +{% block tabs %} +{{ super() }} + + +
+
+
+
+

Geotribu

+
+
+ Bannière Geotribu +
+
+

Site collaboratif sur la géomatique libre et ouverte.

+
+
+
+
+ + +
+
+ {% if config.extra.latest %}{% for contenu in config.extra.latest.articles %} +
+
+
+ +

{{ contenu.title | default('Titre') }}

+
+ + {% if contenu.subtitle %}

{{ contenu.subtitle | default('Sous-titre') }}

{% + endif + %} + {% for tag in contenu.tags %} + {{ tag }}{{ ", " if not loop.last else + "" }} + {% endfor %} +
{{ "Publié le {}".format(contenu.date | date_localized ) | + default('vendredi 9 août 1985') }} par {{ contenu.authors | default('Prénom NOM') | join(", ") }}
+

{{ contenu.description | default('Description') }}

+ Lire cet article... +
+ +
+
+ {% endfor %}{% endif %} + +
+
+ + +{% endblock %} diff --git a/hooks/mkdocs/G000_load_subconfigs.py b/hooks/mkdocs/G000_load_subconfigs.py index e5d748a3ea..a5b2819c42 100644 --- a/hooks/mkdocs/G000_load_subconfigs.py +++ b/hooks/mkdocs/G000_load_subconfigs.py @@ -23,6 +23,7 @@ logger = logging.getLogger("mkdocs") log_prefix = f"[{__name__}] " +witness_output = Path("./latest_content.yml") # ########################################################################### # ########## Functions ############# @@ -135,6 +136,11 @@ def on_config(config: MkDocsConfig) -> MkDocsConfig: ) config["extra"]["latest"] = latest_contents + print( + latest_contents, + file=witness_output.open(mode="w", encoding="UTF-8"), + ) logger.info( - log_prefix + "Contenus récents ajoutés à la configuration globale du site." + log_prefix + "Contenus récents ajoutés à la configuration globale du site. " + f"Également écrits dans le fichier témoin : {witness_output.resolve()}" ) diff --git a/hooks/mkdocs/G005_jinja_filters.py b/hooks/mkdocs/G005_jinja_filters.py index 33f6e30170..188d27b731 100644 --- a/hooks/mkdocs/G005_jinja_filters.py +++ b/hooks/mkdocs/G005_jinja_filters.py @@ -1,8 +1,10 @@ # standard library +import datetime import logging # 3rd party import mkdocs.plugins +from babel.dates import format_date from geotribu_cli.utils.slugger import sluggy from jinja2 import Environment from mkdocs.config.defaults import MkDocsConfig @@ -10,6 +12,12 @@ # globals logger = logging.getLogger("mkdocs") +log_prefix = f"[{__name__}] " + + +def date_localized(in_date: datetime.date): + "Localize a date using babel." + return format_date(date=in_date, format="long", locale="fr_FR") @mkdocs.plugins.event_priority(-50) @@ -29,10 +37,12 @@ def on_env(env: Environment, config: MkDocsConfig, files: Files) -> Environment: Returns: Environment: global Jinja Environment """ + env.filters["date_localized"] = date_localized env.filters["slugger"] = sluggy logger.info( - "Jinja2 filters added for templates: slugger (handy filter to slugify a string)" + log_prefix + + "Jinja2 filters added for templates: slugger (handy filter to slugify a string)" ) return env diff --git a/hooks/mkdocs/G006_authors_block.py b/hooks/mkdocs/G006_authors_block.py index 12650ec095..adf925803e 100644 --- a/hooks/mkdocs/G006_authors_block.py +++ b/hooks/mkdocs/G006_authors_block.py @@ -23,7 +23,7 @@ logger = logging.getLogger("mkdocs") - +log_prefix = f"[{__name__}] " dico_contributors = {} exclude_files = [ "confidentialite.md", @@ -64,12 +64,14 @@ def on_page_markdown( ): if ( "articles" in page.file.abs_src_path + and "index" not in page.file.name and "templates" not in page.file.abs_src_path ): page_authors = page.meta.get("authors") if not isinstance(page_authors, list): logger.warning( - f"L'entrée 'authors' de l'en-tête de la page '{page.file.abs_src_path}' est incorrecte." + log_prefix + + f"L'entrée 'authors' de l'en-tête de la page '{page.file.abs_src_path}' est incorrecte." ) return diff --git a/scripts/mkdocs_populate_latest.py b/scripts/mkdocs_populate_latest.py new file mode 100644 index 0000000000..d95ac752fc --- /dev/null +++ b/scripts/mkdocs_populate_latest.py @@ -0,0 +1,117 @@ +#! python3 # noqa: E265 + +"""Script permettant de lister les derniers contenus avec leurs propriétés +dans un fichier YAML. Utilisé pour la page d'accueil et les pages +d'index des derniers contenus publiés. +""" + +# ############################################################################ +# ########## Libraries ############# +# ################################## + +# standard library +import locale +import logging +from datetime import datetime +from pathlib import Path +from typing import Literal +from zoneinfo import ZoneInfo + +# 3rd party +import yaml +from mkdocs.structure.pages import Page +from mkdocs.utils.meta import get_data + +# ########################################################################### +# ########## Global ################ +# ################################## + +# journalisation +logger = logging.getLogger("mkdocs") + +# gestion des dates +config_tz = ZoneInfo("Europe/Paris") +locale.setlocale(locale.LC_TIME, "fr_FR.UTF-8") + +# ########################################################################### +# ########## Functions ############# +# ################################## + + +def format_datetime(in_datetime_string: str, out_format: str = "long") -> str: + """Formatte un datetime au format textuel standard (isocalendar) en version textuelle. + Proche du fonctionnement de 'babel.format_date'. + + :param str in_datetime_string: chaîne de caractères en entrée. Doit être au format ISO. + :param str out_format: format de sortie, defaults to "long" + + :return str: chaîne de caractères formatée + """ + dt = datetime.fromisoformat(in_datetime_string).replace(tzinfo=config_tz) + if out_format == "long": + return dt.strftime("%A %d %B %Y") + + +def get_latest_content( + content_type: Literal["articles", "rdp"], count: int = 10 +) -> list[dict]: + """Liste les X (défini par 'count') derniers contenus d'un certain type + en retournant les métadonnées de chaque contenu, ainsi que quelques + attributs personnalisés. + + :param Literal["articles", "rdp"] content_type: type de contenu à lister + :param int count: nombre de contenus à lister, defaults to 10 + + :return list[dict]: liste des contenus avec leurs attributs + """ + output_contents_list: list[Page] = [] + + if content_type == "articles": + glob_pattern = "202*/202*.md" + elif content_type == "rdp": + glob_pattern = "202*/rdp_202*.md" + + for content in sorted( + Path(f"content/{content_type}/").glob(glob_pattern), reverse=True + )[:count]: + with content.open(encoding="utf-8-sig", errors="strict") as f: + source = f.read() + # markdown, meta = get_data(source) + + # ajout attributs personnalisés + output_contents_list.append( + # ajout URL relative + get_data(source)[1] + | {"url_rel": str(content.relative_to("content/"))[:-3]} + # ajoute la date au format textuel + | { + "date_txt_full": format_datetime( + in_datetime_string=get_data(source)[1].get("date"), + out_format="long", + ) + } + ) + + return output_contents_list + + +# ########################################################################### +# ########## Main ################## +# ################################## + +output_dict = {"latest": {"articles": [], "rdp": []}} +# print(get_latest_content(content_type="articles")) +for k in output_dict.get("latest"): + output_dict["latest"][k] = get_latest_content(content_type=k) + +# écrit le fichier final +with Path("config/extra_latest.yml").open("w", encoding="UTF-8") as out_file: + yaml.safe_dump( + output_dict, + out_file, + allow_unicode=True, + default_flow_style=False, + encoding="UTF8", + # indent=4, + sort_keys=True, + )