Refactoring : sécurité (XSS), découpage en modules inc/* et js/admin/*, IDs résolus par slug, perf (caches, cron Gravatar, assets auto-hébergés), tests

This commit is contained in:
2026-06-10 21:30:25 +02:00
parent e6b73df516
commit 9280c3b9ce
44 changed files with 3209 additions and 2907 deletions

View File

@@ -22,13 +22,13 @@
{% if author.avatar_url %}
<div class="author-header">
<div class="author-avatar">
<img src="{{ author.avatar_url }}" alt="{{ author.display_name }}">
<img src="{{ author.avatar_url|esc_url }}" alt="{{ author.display_name|esc_attr }}">
</div>
<div class="author-identity">
<h2><p>{{ author.display_name }}</p></h2>
<h2><p>{{ author.display_name|esc_html }}</p></h2>
{% if author.role_label or author.role_complement or author.affiliation %}
<p class="author-role">
{{ author.role_label }}{% if author.role_complement %} {{ author.role_complement }}{% if author.affiliation %},{% endif %}{% endif %}{% if author.affiliation %} {{ author.affiliation }}{% endif %}
{{ author.role_label|esc_html }}{% if author.role_complement %} {{ author.role_complement|esc_html }}{% if author.affiliation %},{% endif %}{% endif %}{% if author.affiliation %} {{ author.affiliation|esc_html }}{% endif %}
</p>
{% endif %}
<p class="maj">{{ current_language == 'en' ? 'Updated on' : 'Mis à jour le' }} {{ author.user_since }}</p>
@@ -63,10 +63,10 @@
{% if not author.avatar_url %}
<div class="author-identity">
<h2><p>{{ author.display_name }}</p></h2>
<h2><p>{{ author.display_name|esc_html }}</p></h2>
{% if author.role_label or author.role_complement or author.affiliation %}
<p class="author-role">
{{ author.role_label }}{% if author.role_complement %} {{ author.role_complement }}{% if author.affiliation %},{% endif %}{% endif %}{% if author.affiliation %} {{ author.affiliation }}{% endif %}
{{ author.role_label|esc_html }}{% if author.role_complement %} {{ author.role_complement|esc_html }}{% if author.affiliation %},{% endif %}{% endif %}{% if author.affiliation %} {{ author.affiliation|esc_html }}{% endif %}
</p>
{% endif %}
<p class="maj">{{ current_language == 'en' ? 'Updated on' : 'Mis à jour le' }} {{ author.user_since }}</p>

View File

@@ -42,7 +42,7 @@
<ul>
<li data-role="">{{ current_language == 'en' ? 'All statuses' : 'Tous les statuts' }}</li>
{% for role in filter_roles %}
<li data-role="{{ role.name }}">{{ role.name }}</li>
<li data-role="{{ role.name|esc_attr }}">{{ role.name|esc_html }}</li>
{% endfor %}
</ul>
</div>
@@ -81,18 +81,20 @@
</thead>
<tbody>
{% for member in group.members %}
<tr onclick="window.location.href='{{ member.url }}'"
data-name="{{ member.display_name }}"
data-sort-name="{{ member.sort_key }}"
data-roles="{{ member.role_names|join('|') }}"
data-avatar="{{ member.avatar_url }}"
data-status="{{ member.status }}"
data-affiliation="{{ member.affiliation }}"
data-domaines="{{ member.domaines|join(', ') }}"
data-autres-domaines="{{ member.autres_domaines }}">
<td>{{ member.display_name }}</td>
<td>{{ member.status }}</td>
<td>{{ member.affiliation }}</td>
{# data-url + listener délégué (membresFilters.js) au lieu d'un onclick inline ;
tout passe par esc_attr/esc_html : ces valeurs viennent des profils utilisateurs #}
<tr data-url="{{ member.url|esc_url }}"
data-name="{{ member.display_name|esc_attr }}"
data-sort-name="{{ member.sort_key|esc_attr }}"
data-roles="{{ member.role_names|join('|')|esc_attr }}"
data-avatar="{{ member.avatar_url|esc_url }}"
data-status="{{ member.status|esc_attr }}"
data-affiliation="{{ member.affiliation|esc_attr }}"
data-domaines="{{ member.domaines|join(', ')|esc_attr }}"
data-autres-domaines="{{ member.autres_domaines|esc_attr }}">
<td>{{ member.display_name|esc_html }}</td>
<td>{{ member.status|esc_html }}</td>
<td>{{ member.affiliation|esc_html }}</td>
</tr>
{% endfor %}
</tbody>

View File

@@ -20,6 +20,6 @@
{% if type_label %}<span>{{ type_label }}</span>{% endif %}
{% if lieu %}<span>{{ lieu }}</span>{% endif %}
</div>
<p class="agenda-card__title">{{ post.title }}</p>
<p class="agenda-card__title">{{ post.title|bilingual }}</p>
</div>
</a>

View File

@@ -1,18 +1,18 @@
<article class="author-card">
<a href="{{ author.url }}" class="author-card__visual" tabindex="-1" aria-hidden="true">
<a href="{{ author.url|esc_url }}" class="author-card__visual" tabindex="-1" aria-hidden="true">
{% if author.avatar_url %}
<img src="{{ author.avatar_url }}" alt="{{ author.name }}" loading="lazy">
<img src="{{ author.avatar_url|esc_url }}" alt="{{ author.name|esc_attr }}" loading="lazy">
{% else %}
<span class="author-card__initials">{{ author.initials }}</span>
<span class="author-card__initials">{{ author.initials|esc_html }}</span>
{% endif %}
</a>
<div class="author-card__info">
<h2 class="author-card__name"><a href="{{ author.url }}">{{ author.name }}</a></h2>
<h2 class="author-card__name"><a href="{{ author.url|esc_url }}">{{ author.name|esc_html }}</a></h2>
{% if author.role_label %}
<p class="author-card__role">{{ author.role_label }}</p>
<p class="author-card__role">{{ author.role_label|esc_html }}</p>
{% endif %}
{% if author.affiliation %}
<p class="author-card__affiliation">{{ author.affiliation }}</p>
<p class="author-card__affiliation">{{ author.affiliation|esc_html }}</p>
{% endif %}
</div>
</article>

View File

@@ -40,77 +40,3 @@
</h2>
{% endif %}
</article>
{#
<article class="post-card">
{% if card.card_image %}
<div class="post-card__image">
<img src="{{ card.card_image }}" alt="{{ post.title }}" loading="lazy">
</div>
{% endif %}
<div class="post-card__content">
<h3 class="post-card__title">
<a href="{{ post.link }}">{{ post.title }}</a>
</h3>
{% if post.meta('sous-titre') %}
<p class="post-card__subtitle">{{ post.meta('sous-titre') }}</p>
{% endif %}
<time class="post-card__date" datetime="{{ post.date('Y-m-d') }}">{{ post.date('d/m/Y') }}</time>
{% if card.card_membres is not empty or post.meta('autrepersonnes') %}
<div class="post-card__authors">
{% for name in card.card_membres %}
<span class="post-card__author">{{ name }}</span>
{% endfor %}
{% if post.meta('autrepersonnes') %}
<span class="post-card__author post-card__author--external">{{ post.meta('autrepersonnes') }}</span>
{% endif %}
</div>
{% endif %}
{% if post.meta('fonction_auteur') %}
<span class="post-card__role">{{ post.meta('fonction_auteur') }}</span>
{% endif %}
{% if post.meta('editeur') %}
<span class="post-card__publisher">{{ post.meta('editeur') }}</span>
{% endif %}
{% if post.meta('journal') %}
<span class="post-card__journal">{{ post.meta('journal') }}</span>
{% endif %}
{% if card.card_axes is not empty %}
<div class="post-card__axes">
{% for axe in card.card_axes %}
<span class="post-card__axe">{{ axe }}</span>
{% endfor %}
</div>
{% endif %}
{% if card.card_etiquettes is not empty %}
<div class="post-card__tags">
{% for tag in card.card_etiquettes %}
<span class="post-card__tag">{{ tag }}</span>
{% endfor %}
</div>
{% endif %}
<div class="post-card__links">
{% if post.meta('lien_externe_1') %}
<a href="{{ post.meta('lien_externe_1') }}" class="post-card__link" target="_blank" rel="noopener">
{{ post.meta('titre_du_lien_externe_1') ?: post.meta('lien_externe_1') }}
</a>
{% endif %}
{% if post.meta('hal_url') %}
<a href="{{ post.meta('hal_url') }}" class="post-card__link post-card__link--hal" target="_blank" rel="noopener">
HAL
</a>
{% endif %}
</div>
</div>
</article>
#}

View File

@@ -13,9 +13,7 @@
{% if article.category_name and article.category_name != article.parent_name %}
<span class="breadcrumb__separator">&rarr;</span>
<a class="breadcrumb__cat" href="{{ article.category_link }}">{{ article.category_name }}</a>
{% endif %}{#
<span class="breadcrumb__separator">&rarr;</span>
<span class="breadcrumb__current">{{ post.title }}</span> #}
{% endif %}
</nav>
{% if post.edit_link %}
<a href="{{ post.edit_link }}" class="link-button" target="_blank" rel="noopener">