feat: licence page, admin pages editor, license types, gradient card placeholders, latest-year home view

- Feature 1: public /licence.php fetches 'licenses' page from DB, renders Markdown
- Feature 1: nav.php adds 'Licence' link with active state
- Feature 2: Database::getPage(), savePage(), getAllPages() methods
- Feature 2: bundled src/Parsedown.php (MIT, zero-dependency)
- Feature 2: apropos.php now renders 'about' page content from DB via Parsedown
- Feature 2: admin/pages.php (list) + admin/pages-edit.php (EasyMDE editor)
- Feature 2: admin/actions/page.php (auth+CSRF+validation+save)
- Feature 2: admin/head.php adds 'Pages statiques' nav link
- Feature 3: storage/schema.sql seeds 8 CC license types
- Feature 3: storage/migrations/003_seed_license_types.sql (applied to live DB)
- Feature 3: Database::getLicenseTypes() / getAllLicenseTypes()
- Feature 3: admin/add.php + formulaire.php: license_id field on add form
- Feature 3: admin/edit.php: license_id field on edit form with raw FK lookup
- Feature 3: tfe.php: shows 'Licence :' meta row when non-null
- Feature 6: main.css: .card__media--gradient styles
- Feature 6: index.php: deterministic HSL gradient placeholder cards
- Feature 6: Database::getLatestYearTheses() + getLatestPublishedYear()
- Feature 6: index.php default home = random latest-year theses with info label
This commit is contained in:
Pontoporeia
2026-03-24 13:12:48 +01:00
parent 86a2082edc
commit d87348c388
20 changed files with 2553 additions and 152 deletions

View File

@@ -115,6 +115,30 @@ class Database {
return $stmt->fetchAll();
}
/**
* Get theses from the latest published year, in random order (per request).
* Used for the default home page view.
*/
public function getLatestYearTheses(int $limit = 24): array {
$sql = "SELECT * FROM v_theses_public
WHERE year = (SELECT MAX(year) FROM theses WHERE is_published = 1)
ORDER BY RANDOM()
LIMIT :limit";
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}
/**
* Get the latest year that has published theses
*/
public function getLatestPublishedYear(): ?int {
$stmt = $this->pdo->query("SELECT MAX(year) FROM theses WHERE is_published = 1");
$val = $stmt->fetchColumn();
return $val ? (int)$val : null;
}
/**
* Count all published theses
*/
@@ -648,6 +672,65 @@ class Database {
return $result ? $result['id'] : null;
}
// ========================================================================
// STATIC PAGES METHODS
// ========================================================================
/**
* Get a static page by slug
* @param string $slug Page slug (e.g. 'about', 'licenses')
* @return array|null
*/
public function getPage(string $slug): ?array {
$stmt = $this->pdo->prepare("SELECT * FROM pages WHERE slug = ?");
$stmt->execute([$slug]);
$row = $stmt->fetch();
return $row ?: null;
}
/**
* Update content for a static page by slug
* @throws Exception if slug not found
*/
public function savePage(string $slug, string $content): void {
$stmt = $this->pdo->prepare("SELECT id FROM pages WHERE slug = ?");
$stmt->execute([$slug]);
if (!$stmt->fetch()) {
throw new Exception("Page slug not found: $slug");
}
$stmt = $this->pdo->prepare(
"UPDATE pages SET content = ?, updated_at = CURRENT_TIMESTAMP WHERE slug = ?"
);
$stmt->execute([$content, $slug]);
}
/**
* Get all static pages
*/
public function getAllPages(): array {
$stmt = $this->pdo->query("SELECT * FROM pages ORDER BY slug");
return $stmt->fetchAll();
}
// ========================================================================
// LICENSE TYPE METHODS
// ========================================================================
/**
* Get all license types ordered by name
*/
public function getLicenseTypes(): array {
$stmt = $this->pdo->query("SELECT * FROM license_types ORDER BY name");
return $stmt->fetchAll();
}
/**
* Alias for form-loading consistency
*/
public function getAllLicenseTypes(): array {
return $this->getLicenseTypes();
}
/**
* Insert a thesis file record
*/

1995
src/Parsedown.php Normal file

File diff suppressed because it is too large Load Diff