Content: publish/hide chapters, sections and articles

- migration V5 adds published flag (default true) to chapters/sections/articles
- ContentService: tree(includeHidden) filters, treeAll(), findArticle(includeHidden),
  set*Published; public tree/article expose only published items
- admin API: GET /tree/all, GET /all/{chapter}/{section}/{article}, PUT
  /{chapters|sections|articles}/{id}/published
- web: learn pages for admins load the full tree, show "скрыто" badges and
  publish/hide buttons for every chapter, section and article; hidden articles
  open in preview for admins, guests get "not found"; article view carries
  published flag
This commit is contained in:
2026-09-16 18:29:44 +03:00
parent aa1fb5c791
commit 30b8064718
13 changed files with 225 additions and 26 deletions

View File

@@ -10,14 +10,20 @@
<span class="nav-sep">/</span>
<span th:text="${section.title}">Раздел</span>
</nav>
<h1 class="page-title" th:text="${section.title}">Раздел</h1>
<h1 class="page-title">
<span th:text="${section.title}">Раздел</span>
<span th:if="${!section.published}" class="badge badge-warn ml-2">скрыто</span>
</h1>
<div class="card card-flush">
<table>
<thead><tr><th>Статья</th></tr></thead>
<tbody>
<tr th:each="article : ${section.articles}">
<td><a th:href="@{/learn/{c}/{s}/{a}(c=${chapter.slug}, s=${section.slug}, a=${article.slug})}"
th:text="${article.title}">—</a></td>
<td>
<a th:href="@{/learn/{c}/{s}/{a}(c=${chapter.slug}, s=${section.slug}, a=${article.slug})}"
th:text="${article.title}">—</a>
<span th:if="${!article.published}" class="badge badge-warn ml-1">скрыто</span>
</td>
</tr>
<tr th:if="${#lists.isEmpty(section.articles)}"><td class="empty">Статей пока нет.</td></tr>
</tbody>