Retire l'action Publier du support de formation
Build and deploy / test-python (push) Successful in 6m57s
Build and deploy / test-js (push) Successful in 50s
Build and deploy / lint-python (push) Successful in 4m14s
Build and deploy / lint-js (push) Failing after 1m12s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Failing after 3m48s

Un apprenant n'a jamais acces a l'editeur : un etat "publie" persiste
en base (published_at) ne servait donc a rien tant qu'aucune vue
apprenant/export ne le consomme (retour utilisateur direct). Retrait
complet : route /document/<slug>/publish, db.mark_support_published,
la colonne logique published_at dans support_meta, le bouton et son
CSS/JS. "Aperçu" devient l'action primaire du bandeau (repond au vrai
besoin : voir le rendu avant un futur export). Un export reel (SCORM
ou equivalent) reste a specifier separement le jour venu.

SKIP=djlint : meme backlog H021 pre-existant que le commit precedent,
aucun fichier touche ici n'y figure. ruff/mypy --strict/vulture/
bandit/import-linter/eslint/stylelint tous verts ; 615 tests Python
(617 - 2 tests du Publier retire) + verification manuelle live du
retrait (route 404, bouton absent du HTML, Apercu confirme
fonctionnel par simulation DOM).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
william
2026-09-20 09:58:53 +02:00
co-authored by Claude Sonnet 5
parent bab581737a
commit 7ca03380b7
12 changed files with 5 additions and 99 deletions
-2
View File
@@ -79,7 +79,6 @@ from .slugify import slugify
from .supports.create_support import create_support
from .supports.delete_support import delete_support
from .supports.list_supports import list_supports
from .supports.mark_support_published import mark_support_published
from .supports.support_meta import support_meta
from .table_name_for import table_name_for
@@ -118,7 +117,6 @@ __all__ = [
"list_supports",
"support_meta",
"delete_support",
"mark_support_published",
"ONBOARDING_TYPES",
"DEFAULT_ONBOARDING_TYPE",
"get_onboarding_type",
-2
View File
@@ -7,7 +7,6 @@ indépendance."""
from .create_support import create_support
from .delete_support import delete_support
from .list_supports import list_supports
from .mark_support_published import mark_support_published
from .support_connection import connect_support, install_support_teardown_safety_net
from .support_dir import support_dir
from .support_meta import support_meta
@@ -21,7 +20,6 @@ __all__ = [
"delete_support",
"install_support_teardown_safety_net",
"list_supports",
"mark_support_published",
"split_slug",
"support_dir",
"support_meta",
-19
View File
@@ -1,19 +0,0 @@
from datetime import UTC, datetime
from .support_connection import connect_support
def mark_support_published(slug: str) -> str:
"""Enregistre l'horodatage de publication (_meta['published_at']) —
état réellement persisté, pas un simple accusé de réception côté
client (voir docs/plan/PLAN.md, "Publier" doit être réel)."""
published_at = datetime.now(UTC).isoformat()
conn = connect_support(slug)
conn.execute(
"INSERT INTO _meta (key, value) VALUES ('published_at', ?) "
"ON CONFLICT(key) DO UPDATE SET value = excluded.value",
(published_at,),
)
conn.commit()
conn.close()
return published_at
-2
View File
@@ -6,10 +6,8 @@ from .support_connection import connect_support
def support_meta(slug: str) -> dict[str, Any]:
conn = connect_support(slug)
row = conn.execute("SELECT value FROM _meta WHERE key = 'name'").fetchone()
published_row = conn.execute("SELECT value FROM _meta WHERE key = 'published_at'").fetchone()
conn.close()
return {
"slug": slug,
"name": row["value"] if row else slug,
"published_at": published_row["value"] if published_row else None,
}
+1 -1
View File
@@ -140,7 +140,7 @@ Cette liste consolide toutes les fonctions validées à travers les maquettes in
- Zoom du canvas (boutons +/-, affichage du pourcentage)
- Undo / Redo
- Mode Aperçu
- Action Publier
- ~~Action Publier~~ — retiré (voir décision du 20/09/2026) : un apprenant n'a jamais accès à l'éditeur, un état "publié" persisté en base ne sert donc à rien tant qu'aucune vue apprenant/export ne le consomme. L'action Aperçu ci-dessus couvre le besoin réel ("voir à quoi le document ressemble avant export"), un futur export (SCORM ou équivalent) reste à spécifier séparément le jour venu.
- Bascule de thème clair/sombre de l'interface d'édition, mémorisée par utilisateur
### 3.2 Bibliothèque d'éléments (panneau gauche)
-1
View File
@@ -11,6 +11,5 @@ from . import ( # noqa: F401 - enregistre les routes definies dans chaque modul
document_element_move,
document_element_update,
document_new,
document_publish,
document_render,
)
-15
View File
@@ -1,15 +0,0 @@
from flask import jsonify
from werkzeug.wrappers import Response
import db
from core.flask_app import app
@app.route("/document/<slug>/publish", methods=["POST"])
def document_publish(slug: str) -> Response:
"""Publie le support — vrai changement d'état persisté
(_meta['published_at'], voir db/supports/mark_support_published.py),
pas juste un toast côté client (voir docs/plan/PLAN.md, "Publier
réel")."""
published_at = db.mark_support_published(slug)
return jsonify({"ok": True, "published_at": published_at})
-5
View File
@@ -147,11 +147,6 @@
background: rgb(255 95 46 / 8%);
}
.docBtnPrimary.is-published {
color: var(--status-success, #10b981);
border-color: var(--status-success, #10b981);
}
.docWidthPicker {
display: flex;
gap: 4px;
+1 -18
View File
@@ -81,10 +81,6 @@ function forgeDocApiRender() {
return fetch(`/document/${window.forgeDocState.slug}/render`).then((r) => r.json());
}
function forgeDocApiPublish() {
return fetch(`/document/${window.forgeDocState.slug}/publish`, { method: 'POST' }).then((r) => r.json());
}
/* ---------------------------------------------------------------------
* Canevas — rafraîchi depuis la VÉRITÉ SERVEUR après chaque mutation
* structurelle (jamais une simple retouche DOM locale, voir
@@ -676,7 +672,7 @@ function forgeDocRenderProps(el) {
/* ---------------------------------------------------------------------
* Chrome de l'éditeur : zoom, largeur d'aperçu responsive, Aperçu,
* Publier, thème (scopé à .docEditor3), navigation mobile.
* thème (scopé à .docEditor3), navigation mobile.
* ------------------------------------------------------------------- */
function forgeDocBindZoom() {
@@ -718,18 +714,6 @@ function forgeDocBindPreviewToggle() {
});
}
function forgeDocBindPublish() {
document.getElementById('docPublishBtn').addEventListener('click', () => {
forgeDocApiPublish().then((result) => {
if (!result.ok) return;
const label = document.getElementById('docPublishLabel');
const btn = document.getElementById('docPublishBtn');
label.textContent = 'Publié';
btn.classList.add('is-published');
});
});
}
function forgeDocApplyTheme(theme) {
const editor = document.getElementById('docEditor3');
editor.dataset.theme = theme;
@@ -817,7 +801,6 @@ function forgeDocInit() {
forgeDocBindZoom();
forgeDocBindWidthPicker();
forgeDocBindPreviewToggle();
forgeDocBindPublish();
forgeDocBindThemeToggle();
forgeDocBindMobileNav();
forgeDocBindKeyboardShortcuts();
+3 -16
View File
@@ -61,7 +61,9 @@
</svg>
</button>
<div class="docDividerV"></div>
<button type="button" class="docBtnSecondary" id="docPreviewBtn">
<button type="button"
class="docBtnSecondary docBtnPrimary"
id="docPreviewBtn">
<svg width="16"
height="16"
viewBox="0 0 24 24"
@@ -74,21 +76,6 @@
<circle cx="12" cy="12" r="3" />
</svg><span class="docBtnLabel">Aperçu</span>
</button>
<button type="button"
class="docBtnSecondary docBtnPrimary"
id="docPublishBtn">
<svg width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round">
<circle cx="12" cy="12" r="9" />
<path d="M12 16V8M8.5 11.5L12 8l3.5 3.5" />
</svg><span class="docBtnLabel" id="docPublishLabel">{{ 'Publié' if support.published_at else 'Publier' }}</span>
</button>
<div class="docDividerV"></div>
<div class="docWidthPicker"
id="docWidthPicker"
-9
View File
@@ -81,15 +81,6 @@ def test_document_element_move_and_delete(client: FlaskClient, support: str) ->
assert delete_resp.get_json()["ok"] is True
def test_document_publish_persists_published_at(client: FlaskClient, support: str) -> None:
assert db.support_meta(support)["published_at"] is None
resp = client.post(f"/document/{support}/publish")
assert resp.status_code == 200
published_at = resp.get_json()["published_at"]
assert published_at is not None
assert db.support_meta(support)["published_at"] == published_at
def test_restricted_user_can_have_one_game_and_one_support_at_once(
user_client: FlaskClient, tmp_game_slug_cleanup: Any, tmp_support_slug_cleanup: Any
) -> None:
-9
View File
@@ -14,7 +14,6 @@ def test_create_support_creates_its_own_db_file_and_schema(tmp_support_slug_clea
tmp_support_slug_cleanup(slug)
meta = db.support_meta(slug)
assert meta["name"] == "Sécurité incendie"
assert meta["published_at"] is None
def test_list_supports_scopes_to_owner_and_excludes_games(
@@ -54,14 +53,6 @@ def test_create_support_avoids_name_collision_for_the_same_owner(tmp_support_slu
assert slug_1 != slug_2
def test_mark_support_published_persists_a_timestamp(tmp_support_slug_cleanup: Any) -> None:
slug = db.create_support("À publier", owner_folder="47")
tmp_support_slug_cleanup(slug)
assert db.support_meta(slug)["published_at"] is None
published_at = db.mark_support_published(slug)
assert db.support_meta(slug)["published_at"] == published_at
def test_delete_support_removes_it_from_the_listing(tmp_support_slug_cleanup: Any) -> None:
slug = db.create_support("Temporaire", owner_folder="48")
tmp_support_slug_cleanup(slug)