Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 53dbce5bb0 | |||
| 7737edf402 | |||
| 6d159e7dda | |||
| 331e9c9ecd | |||
| 0280ef3ca1 | |||
| eddde2165a | |||
| 07d004b3f0 | |||
| 5cb0e854fd | |||
| 8f6c17f0f2 | |||
| 5452fb4927 |
@@ -11,5 +11,4 @@ Thumbs.db
|
||||
# Données des sites (articles, config, cache) — propres à chaque workspace
|
||||
data/*
|
||||
!data/.gitkeep
|
||||
!data/site/
|
||||
_cache/
|
||||
|
||||
@@ -9,6 +9,47 @@ Format : [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) — versionnag
|
||||
|
||||
---
|
||||
|
||||
## [1.6.2] - 2026-05-15
|
||||
|
||||
### Corrigé
|
||||
- `oidc/start.php` : garde explicite après `session_start()` — erreur 500 immédiate si `session.save_path` est inaccessible, évite un flux OIDC condamné à l'échec silencieux
|
||||
- `oidc/callback.php` : même garde de session ; `error_log` en cas d'échec du contrôle de state pour faciliter le diagnostic
|
||||
- `consignes.md` : règle ajoutée — pool PHP-FPM avec `user = www-data`, pas le compte admin personnel
|
||||
|
||||
---
|
||||
|
||||
## [1.6.1] - 2026-05-15
|
||||
|
||||
### Corrigé
|
||||
- `login/index.php`, `login/magic.php`, `logout.php` : ordre de chargement corrigé (`config.php` avant `bootstrap.php`) pour que `SESSION_NAME` soit défini avant `session_start()`
|
||||
- `data/site/` retiré du suivi git du moteur (contenu site-spécifique) ; `.gitignore` mis à jour
|
||||
|
||||
---
|
||||
|
||||
## [1.6.0] - 2026-05-15
|
||||
|
||||
### Ajouté
|
||||
- Admin → Dashboard : bouton unique **Mettre à jour** (git pull + migrations SQL + migrations contenu) remplace les boutons séparés
|
||||
- Branche `dev` : branche d'intégration permanente pour le développement quotidien
|
||||
|
||||
### Corrigé
|
||||
- `run_engine_update` : vérifie que le remote git `origin` correspond à `FOLIO_REPO_URL` avant tout `git pull` (évite le pull sur le mauvais dépôt)
|
||||
|
||||
---
|
||||
|
||||
## [1.5.0] - 2026-05-15
|
||||
|
||||
### Ajouté
|
||||
- Admin → Site : configuration de l'URL du dépôt Folio et de la branche suivie pour les mises à jour, sans modifier le `.env` (`folio_repo_url`, `folio_update_branch` dans `site_settings.json`)
|
||||
- `APP_TIMEZONE` : fuseau horaire configurable via `.env` (défaut `Europe/Paris`), appliqué globalement dans `bootstrap.php`
|
||||
|
||||
### Corrigé
|
||||
- Bouton « Vérifier » masqué avec message explicatif si `FOLIO_REPO_URL` n'est pas configuré (ni dans `.env` ni dans l'admin)
|
||||
- `FOLIO_REPO_URL` et `FOLIO_UPDATE_BRANCH` documentés dans `.env.example`
|
||||
- `scripts/push.sh` : ne pousse plus directement sur `main` — pousse sur la branche courante pour forcer le passage par une PR
|
||||
|
||||
---
|
||||
|
||||
## [1.4.0] - 2026-05-15
|
||||
|
||||
### Ajouté
|
||||
|
||||
@@ -11,40 +11,64 @@ Il contient uniquement le code du moteur — pas de données, pas de credentials
|
||||
| Répertoire local | Site distant | Rôle |
|
||||
|-----------------|-------------|------|
|
||||
| `~/Projects/folio/` | — | Copie du dépôt Folio (branche DEV). On code ici. |
|
||||
| `~/Projects/varlog/` | varlog.a5l.fr | Sync bidirectionnelle des articles varlog. Sert de site de test pour le moteur. |
|
||||
| `~/Projects/fr.abonnel.www/` | www.abonnel.fr | Sync bidirectionnelle des articles abonnel.fr. A aussi servi au déploiement initial. |
|
||||
| `~/Projects/varlog/` | varlog.a5l.fr | Workspace varlog (scripts de déploiement/sync). Sert de site de test pour le moteur. |
|
||||
| `~/Projects/varlog-data/` | varlog.a5l.fr | Articles de varlog. Sync bidirectionnelle. |
|
||||
| `~/Projects/fr.abonnel.www/` | www.abonnel.fr | Workspace abonnel.fr (scripts de déploiement/sync). |
|
||||
| `~/Projects/fr.abonnel.www-data/` | www.abonnel.fr | Articles de abonnel.fr. Sync bidirectionnelle. |
|
||||
|
||||
**abonnel.fr** utilise Folio mais se met à jour seul via son UpdateChecker interne (vérifie `version.txt` sur Gitea). Aucune action manuelle nécessaire côté serveur.
|
||||
|
||||
## Articles (`data/`)
|
||||
|
||||
Les articles ne sont pas versionnés dans ce dépôt. Ils ont leur propre git local dans chaque workspace site (`~/Projects/varlog/data/`, `~/Projects/fr.abonnel.www/data/`), synchronisé de façon bidirectionnelle avec le serveur distant.
|
||||
Les articles ne sont pas versionnés dans ce dépôt. Ils ont leur propre dépôt git (`~/Projects/varlog-data/`, `~/Projects/fr.abonnel.www-data/`), synchronisé de façon bidirectionnelle avec le serveur distant.
|
||||
|
||||
## Modifier le moteur
|
||||
|
||||
Pour toute correction ou fonctionnalité : **créer un ticket et une PR**.
|
||||
### Branches
|
||||
|
||||
1. Coder ici dans `~/Projects/folio/` (branche feature)
|
||||
2. **Tester sur varlog.a5l.fr** :
|
||||
| Branche | Rôle |
|
||||
|---------|------|
|
||||
| `dev` | Branche d'intégration permanente. **Tout le développement courant se fait ici.** |
|
||||
| `main` | Branche de production. **Jamais de commit direct.** |
|
||||
| `feat/*` | Branches feature optionnelles pour du travail isolé, mergées dans `dev`. |
|
||||
|
||||
### Workflow
|
||||
|
||||
1. Toujours travailler sur `dev` (ou une branche feature mergée dans `dev`) :
|
||||
```bash
|
||||
git checkout dev
|
||||
```
|
||||
2. **Tester sur varlog.a5l.fr** à chaque itération (rsync des fichiers locaux, DB persistante) :
|
||||
```bash
|
||||
~/Projects/varlog/scripts/sync.sh
|
||||
# puis tester sur http://varlog.acegrp.lan
|
||||
```
|
||||
3. Une fois validé, ouvrir une PR sur Gitea. Le commit doit inclure :
|
||||
- `public/version.txt` (bump semver)
|
||||
- `CHANGELOG.md` (entrée `### Ajouté / Corrigé / Modifié`)
|
||||
3. Quand `dev` est stable et prête pour la production :
|
||||
- Bumper `public/version.txt` (semver)
|
||||
- Ajouter une entrée `CHANGELOG.md` (`### Ajouté / Corrigé / Modifié`)
|
||||
- Ouvrir une **PR `dev` → `main`** sur Gitea
|
||||
4. Merger la PR → abonnel.fr se met à jour automatiquement.
|
||||
|
||||
**Règle absolue : ne jamais commiter directement sur `main`.** Le script `scripts/push.sh` bloque cette action.
|
||||
|
||||
### Pourquoi `dev` et non des branches feature à la volée
|
||||
|
||||
- La DB de varlog (test) accumule les migrations au fil du temps — changer de branche ne fait pas reculer les migrations.
|
||||
- Travailler toujours sur `dev` évite toute désynchronisation entre le code rsyncé et la DB.
|
||||
|
||||
## Données articles (`DATA_PATH`)
|
||||
|
||||
Les articles sont stockés dans un répertoire **hors du dépôt Folio**, configurable via `DATA_PATH` dans `.env`.
|
||||
Les articles sont stockés dans un répertoire **hors du dépôt Folio**, configurable via `DATA_PATH` dans `.env` (défaut production : `/srv/data/folio`).
|
||||
|
||||
| Environnement | Chemin local | Chemin serveur |
|
||||
|--------------|-------------|----------------|
|
||||
| varlog | `~/Projects/varlog-data/` | `/srv/data/folio` |
|
||||
| abonnel.fr | `~/Projects/fr.abonnel.www-data/` | `/srv/data/folio` |
|
||||
| Environnement | Dépôt local articles | Dépôt Gitea | Serveur |
|
||||
|--------------|---------------------|------------|---------|
|
||||
| varlog | `~/Projects/varlog-data/` | `cedricAbonnel/varlog` | `varlog:/srv/data/folio` |
|
||||
| abonnel.fr | `~/Projects/fr.abonnel.www-data/` | `cedricAbonnel/abonnel-www` | `abonnel-wiki:/srv/data/folio` |
|
||||
|
||||
Les scripts de sync (`pull-data.sh`, `push-data.sh`, `sync.sh`) utilisent `DATA_DIR` (overridable via env) pointant vers ces chemins locaux.
|
||||
Sync bidirectionnelle via **git** (pas rsync). Scripts dans `~/Projects/varlog/scripts/` et `~/Projects/fr.abonnel.www/scripts/` :
|
||||
- `pull-data.sh` : commit auto serveur + git pull local
|
||||
- `push-data.sh` : git commit local + git push + git pull serveur
|
||||
- `sync.sh` : moteur (rsync) + articles (git bidirectionnel)
|
||||
|
||||
## Asymétrie de déploiement moteur
|
||||
|
||||
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
# Consignes — Folio
|
||||
|
||||
## Architecture
|
||||
|
||||
**Folio** est un moteur de blog PHP.
|
||||
|
||||
### Dépôts et rôles
|
||||
|
||||
| Répertoire local | Rôle | Remote Gitea |
|
||||
|-----------------|------|-------------|
|
||||
| `~/Projects/folio/` | Copie du moteur Folio, branche `dev`. **Tout le développement se fait ici.** | `git.abonnel.fr/cedricAbonnel/folio` |
|
||||
| `~/Projects/varlog/` | Workspace du site varlog (scripts, config). | — |
|
||||
| `~/Projects/varlog-data/` | Articles de varlog.a5l.fr. Sync bidirectionnelle. | `cedricAbonnel/varlog` |
|
||||
| `~/Projects/fr.abonnel.www/` | Workspace du site abonnel.fr (scripts, config). | — |
|
||||
| `~/Projects/fr.abonnel.www-data/` | Articles de www.abonnel.fr. Sync bidirectionnelle. | `cedricAbonnel/abonnel-www` |
|
||||
|
||||
### Environnements
|
||||
|
||||
| Site | Rôle | Mise à jour moteur | Articles |
|
||||
|------|------|--------------------|---------|
|
||||
| varlog.a5l.fr | Test | rsync depuis `~/Projects/folio/` | `varlog-data/` ↔ `varlog:/srv/data/folio` |
|
||||
| www.abonnel.fr | Production | Auto (UpdateChecker vérifie `version.txt` sur Gitea) | `fr.abonnel.www-data/` ↔ `abonnel-wiki:/srv/data/folio` |
|
||||
|
||||
### Articles (`DATA_PATH`)
|
||||
|
||||
Les articles ne sont **jamais** dans le dépôt folio. Ils vivent dans un répertoire séparé, configurable via `DATA_PATH` dans le `.env` de chaque instance.
|
||||
|
||||
- Serveur varlog : `DATA_PATH=/srv/data/folio`
|
||||
- Serveur abonnel.fr : `DATA_PATH=/srv/data/folio`
|
||||
- En local pour tester : pointer `DATA_PATH` vers `~/Projects/varlog-data/`
|
||||
|
||||
La sync des articles se fait via git (pas rsync) avec les scripts `pull-data.sh` et `push-data.sh`.
|
||||
|
||||
---
|
||||
|
||||
## Workflow moteur
|
||||
|
||||
1. Travailler sur `dev` dans `~/Projects/folio/`
|
||||
2. Tester sur varlog.a5l.fr :
|
||||
```bash
|
||||
~/Projects/varlog/scripts/sync.sh
|
||||
# puis vérifier sur http://varlog.acegrp.lan (ou varlog.a5l.fr)
|
||||
```
|
||||
3. Quand `dev` est stable :
|
||||
- Bumper `public/version.txt` (semver)
|
||||
- Ajouter une entrée dans `CHANGELOG.md`
|
||||
- Ouvrir une **PR `dev` → `main`** sur Gitea
|
||||
4. Merger la PR → abonnel.fr se met à jour automatiquement.
|
||||
|
||||
**Règle absolue : jamais de commit direct sur `main`.**
|
||||
|
||||
---
|
||||
|
||||
## Mise à jour du moteur (varlog)
|
||||
|
||||
Le poste local n'a pas de base de données. Tout ce qui touche à la DB ou au contenu s'exécute **sur le serveur varlog** via SSH — les scripts locaux ne font qu'ouvrir une connexion SSH et lancer le PHP distant.
|
||||
|
||||
**Cycle de développement :**
|
||||
1. Modifier le code dans `~/Projects/folio/` (local)
|
||||
2. Déployer et tester :
|
||||
|
||||
```bash
|
||||
# Rsync moteur (folio → varlog) + sync articles bidirectionnel
|
||||
~/Projects/varlog/scripts/sync.sh
|
||||
# puis tester sur http://varlog.acegrp.lan
|
||||
```
|
||||
|
||||
3. Si des migrations de schéma BDD sont nécessaires :
|
||||
```bash
|
||||
~/Projects/varlog/scripts/db-migrate.sh # exécute le PHP sur varlog via SSH
|
||||
```
|
||||
|
||||
4. Si des migrations de contenu sont nécessaires :
|
||||
```bash
|
||||
~/Projects/varlog/scripts/content-migrate.sh # exécute le PHP sur varlog via SSH
|
||||
```
|
||||
|
||||
**Déploiement complet en une commande (lint + rsync + DB + contenu + commit serveur) :**
|
||||
```bash
|
||||
~/Projects/varlog/scripts/deploy.sh "message de commit"
|
||||
```
|
||||
|
||||
Chemin serveur : `varlog:/var/www/lan.acegrp.varlog/`
|
||||
|
||||
---
|
||||
|
||||
## Mise à jour manuelle du moteur (abonnel.fr)
|
||||
|
||||
À utiliser uniquement si l'UpdateChecker échoue :
|
||||
|
||||
```bash
|
||||
cp /var/www/lan.acegrp.abonnel-www/.env /tmp/.env.bak
|
||||
sudo rm -rf /var/www/lan.acegrp.abonnel-www
|
||||
git clone --depth=1 https://git.abonnel.fr/cedricAbonnel/folio.git /var/www/lan.acegrp.abonnel-www
|
||||
cp /tmp/.env.bak /var/www/lan.acegrp.abonnel-www/.env
|
||||
cd /var/www/lan.acegrp.abonnel-www && composer install --no-dev --optimize-autoloader
|
||||
php database/migrate.php
|
||||
git -C /var/www/lan.acegrp.abonnel-www config user.email 'cedric@abonnel.fr'
|
||||
git -C /var/www/lan.acegrp.abonnel-www config user.name 'Cédrix'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Règles à respecter
|
||||
|
||||
- Ne **jamais** écraser le `.env` serveur (ni scp, ni réécriture). Indiquer les variables à l'utilisateur pour qu'il les saisisse lui-même.
|
||||
- Ne **jamais** versionner `data/`, `.env`, ou `vendor/` dans le dépôt folio.
|
||||
- Toujours bumper la version **et** mettre à jour le changelog dans le même commit que la PR.
|
||||
- Dans les pools PHP-FPM, toujours utiliser `user = www-data` / `group = www-data`. `cedrix` est un admin ordinaire, pas un compte de service.
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"uuid": "a3d8f2c1-7b4e-4f9a-8c3d-2e5a9b6f1d4c",
|
||||
"slug": "about",
|
||||
"title": "À propos",
|
||||
"author": "cedric@abonnel.fr",
|
||||
"published": true,
|
||||
"published_at": "2021-01-16 04:02:40",
|
||||
"created_at": "2021-01-16 04:02:40",
|
||||
"updated_at": "2026-05-13 00:00:00",
|
||||
"revisions": [],
|
||||
"cover": "",
|
||||
"files_meta": [],
|
||||
"external_links": [],
|
||||
"seo_title": "",
|
||||
"seo_description": "",
|
||||
"og_image": "",
|
||||
"category": ""
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
# À propos
|
||||
|
||||
Qui se cache derrière varlog ?
|
||||
|
||||
Je m'appelle **Cédric**. Passionné d'informatique depuis longtemps, je gère un **HomeLab** à la maison — un petit laboratoire personnel où je fais tourner des serveurs, expérimente des configs réseau et casse des choses pour mieux les comprendre.
|
||||
|
||||
varlog est mon carnet de bord technique. J'y documente ce que je fais, ce que j'apprends, et parfois ce qui tourne mal — les incidents sont souvent les meilleures leçons.
|
||||
|
||||
Le blog a été lancé publiquement aux **JDLL 2025** (Journées Du Logiciel Libre), à Lyon.
|
||||
|
||||
## Ce dont je parle ici
|
||||
|
||||
### HomeLab & infrastructure
|
||||
|
||||
Proxmox, virtualisation, domotique (Zigbee, MQTT, Home Assistant), supervision avec Uptime Kuma, auto-hébergement de services (Gitea, Keycloak…), incidents réseau et leurs post-mortems.
|
||||
|
||||
### Réseaux & télécom
|
||||
|
||||
Passionné par les réseaux mobiles (3G/4G/5G/6G), la fibre optique (50G-PON), les stratégies des opérateurs et les infrastructures qui font fonctionner tout ça sans qu'on y pense.
|
||||
|
||||
### Linux & développement
|
||||
|
||||
Debian au quotidien, scripts, administration système, et un peu de PHP — dont ce blog lui-même, développé maison sous le nom de code *Folio*.
|
||||
|
||||
### Numérique & société
|
||||
|
||||
Souveraineté numérique, données personnelles, IA et plateformes qui monétisent nos contenus — des sujets qui m'intéressent autant qu'ils m'inquiètent.
|
||||
|
||||
### Le reste
|
||||
|
||||
Bricolage, travaux, anecdotes techniques, lectures, liseuses Kobo, et quelques billets qui n'entrent dans aucune case. La vie ne se range pas en catégories.
|
||||
|
||||
## Contact
|
||||
|
||||
Vous pouvez me joindre via le [formulaire de contact](/contact). Je lis tous les messages, même si je ne réponds pas toujours vite.
|
||||
|
||||
---
|
||||
|
||||
Le contenu de ce blog est publié sous licence [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) sauf mention contraire. Le moteur *Folio* est distribué sous [licence MIT](/LICENSE).
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"uuid": "b2c7e1f4-4a3d-4e8b-9f2a-1d6c8e3f5a7b",
|
||||
"slug": "legal",
|
||||
"title": "Mentions légales",
|
||||
"author": "cedric@abonnel.fr",
|
||||
"published": true,
|
||||
"published_at": "2021-01-16 04:02:40",
|
||||
"created_at": "2021-01-16 04:02:40",
|
||||
"updated_at": "2026-05-13 00:00:00",
|
||||
"revisions": [],
|
||||
"cover": "",
|
||||
"files_meta": [],
|
||||
"external_links": [],
|
||||
"seo_title": "",
|
||||
"seo_description": "",
|
||||
"og_image": "",
|
||||
"category": ""
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
# Mentions légales
|
||||
|
||||
Conformément à la loi n° 2004-575 du 21 juin 2004 pour la confiance dans l'économie numérique (LCEN).
|
||||
|
||||
## Éditeur du site
|
||||
|
||||
**Responsable de publication :** Cédric Abonnel
|
||||
**Qualité :** Particulier — site personnel non commercial
|
||||
**Contact :** [formulaire de contact](/contact)
|
||||
|
||||
## Hébergement
|
||||
|
||||
**Type :** Auto-hébergement sur infrastructure personnelle (HomeLab)
|
||||
**Exploitant :** Cédric Abonnel
|
||||
**Fournisseur d'accès à internet :** Infrastructure personnelle auto-hébergée
|
||||
|
||||
## Propriété intellectuelle
|
||||
|
||||
Le **contenu éditorial** de ce site (articles, textes, images produites par l'auteur) est publié sous licence [Creative Commons Attribution 4.0 International (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/), sauf mention contraire.
|
||||
|
||||
Le **moteur du site** (*Folio*) est un logiciel libre distribué sous [licence MIT](/LICENSE).
|
||||
|
||||
Les composants tiers (Bootstrap, PHPMailer, police Inter…) sont soumis à leurs licences respectives, détaillées sur la [page des licences](/licenses).
|
||||
|
||||
## Données personnelles (RGPD)
|
||||
|
||||
Ce site est un blog personnel **sans publicité, sans pistage, sans système de commentaires** ni inscription publique.
|
||||
|
||||
Les seules données traitées automatiquement sont les **journaux de connexion du serveur web** (adresse IP, horodatage, page demandée), conservés conformément aux obligations légales (article L34-1 du Code des postes et des communications électroniques — durée maximale : 1 an).
|
||||
|
||||
Ces données ne sont ni vendues, ni transmises à des tiers, ni utilisées à des fins commerciales.
|
||||
|
||||
Conformément au RGPD (règlement UE 2016/679), vous disposez d'un droit d'accès, de rectification et de suppression des données vous concernant. Pour exercer ces droits : [formulaire de contact](/contact).
|
||||
|
||||
## Cookies
|
||||
|
||||
Ce site utilise uniquement un **cookie de session technique**, nécessaire au fonctionnement de l'authentification. Il n'est déposé que lors d'une connexion au compte d'administration et n'est pas utilisé à des fins de suivi ou de profilage. Aucun cookie tiers n'est déposé.
|
||||
|
||||
## Responsabilité
|
||||
|
||||
L'éditeur s'efforce de maintenir les informations publiées à jour et exactes, mais ne peut garantir l'exhaustivité ou l'absence d'erreurs du contenu.
|
||||
|
||||
Les liens vers des sites tiers sont fournis à titre informatif. L'éditeur n'est pas responsable du contenu de ces sites externes.
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"uuid": "fdff8ad3-d369-4bd7-bbb9-e14d433868d7",
|
||||
"slug": "licenses",
|
||||
"title": "Licences",
|
||||
"author": "cedric@abonnel.fr",
|
||||
"published": true,
|
||||
"published_at": "2021-01-16 04:02:40",
|
||||
"created_at": "2021-01-16 04:02:40",
|
||||
"updated_at": "2021-01-16 04:02:40",
|
||||
"revisions": [],
|
||||
"cover": "",
|
||||
"files_meta": [],
|
||||
"external_links": [],
|
||||
"seo_title": "",
|
||||
"seo_description": "",
|
||||
"og_image": "",
|
||||
"category": ""
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
# Licences
|
||||
|
||||
Composants logiciels utilisés par ce site et leurs licences.
|
||||
|
||||
## Ce site
|
||||
|
||||
| Composant | Licence | Usage |
|
||||
|-----------|---------|-------|
|
||||
| **Folio** — moteur de blog PHP | MIT | Moteur de ce blog — par Cédric Abonnel ([voir la licence](/LICENSE)) |
|
||||
| **Contenu éditorial** | CC BY 4.0 | Articles et textes du blog — [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/) |
|
||||
|
||||
## Bibliothèques (production)
|
||||
|
||||
| Composant | Version | Licence | Usage |
|
||||
|-----------|---------|---------|-------|
|
||||
| **Bootstrap** | 5.3.3 | MIT | Framework CSS/JS — auto-hébergé ([voir la licence](/assets/css/LICENSE-Bootstrap.txt)) |
|
||||
| **PHPMailer** | 6.12.0 | LGPL-2.1 | Envoi d'e-mails SMTP |
|
||||
| **phpdotenv** | 5.6.2 | BSD-3-Clause | Variables d'environnement |
|
||||
| **openid-connect-php** | 1.0.2 | Apache-2.0 | Authentification SSO (OIDC) |
|
||||
| **Police Inter** | v20 | OFL-1.1 | Typographie — auto-hébergée ([voir la licence](/assets/fonts/LICENSE-Inter.txt)) |
|
||||
|
||||
## Outils de développement
|
||||
|
||||
| Composant | Version | Licence | Usage |
|
||||
|-----------|---------|---------|-------|
|
||||
| **PHPStan** | 1.12.32 | MIT | Analyse statique PHP |
|
||||
| **PHP-CS-Fixer** | 3.89.1 | MIT | Formatage du code |
|
||||
| **Claude Code CLI** | — | Commercial | Outil de développement (Anthropic) — [Conditions d'utilisation](https://www.anthropic.com/legal/aup) |
|
||||
|
||||
## Infrastructure
|
||||
|
||||
| Composant | Licence | Usage |
|
||||
|-----------|---------|-------|
|
||||
| **PHP 8.3** | PHP License v3.01 | Langage côté serveur |
|
||||
| **PostgreSQL** | PostgreSQL License | Base de données relationnelle |
|
||||
| **Apache HTTP Server** | Apache-2.0 | Serveur web |
|
||||
|
||||
|
||||
+78
-1
@@ -45,7 +45,7 @@ $action = $_GET['action'] ?? 'list';
|
||||
$uuid = $_GET['uuid'] ?? '';
|
||||
$slug = $_GET['slug'] ?? '';
|
||||
|
||||
$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site', 'not_found', 'add_feed', 'delete_feed', 'add_link', 'delete_link', 'reorder_links', 'react', 'comment', 'verify_comment', 'comment_moderate', 'comment_delete', 'comment_resend', 'create_tag_type', 'delete_tag_type', 'edit_tags', 'book_save', 'book_delete', 'admin_save_as_groups', 'admin_save_folio_config'];
|
||||
$_noindexActions = ['create', 'edit', 'admin', 'categories', 'diff', 'add_files', 'import_image', 'import_image_step2', 'sources', 'profile', 'delete_file', 'delete_external_link', 'rename_category', 'delete_category', 'toggle_private_category', 'admin_save_site', 'not_found', 'add_feed', 'delete_feed', 'add_link', 'delete_link', 'reorder_links', 'react', 'comment', 'verify_comment', 'comment_moderate', 'comment_delete', 'comment_resend', 'create_tag_type', 'delete_tag_type', 'edit_tags', 'book_save', 'book_delete', 'admin_save_as_groups', 'admin_save_folio_config', 'run_engine_update'];
|
||||
$metaRobots = in_array($action, $_noindexActions, true) ? 'noindex, nofollow' : null;
|
||||
unset($_noindexActions);
|
||||
|
||||
@@ -2816,6 +2816,83 @@ switch ($action) {
|
||||
header('Location: /admin?tab=dashboard¬ice=' . ($_cmErrors ? 'migration_error' : 'migrated'));
|
||||
exit;
|
||||
|
||||
case 'run_engine_update':
|
||||
requireAuth();
|
||||
if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(403);
|
||||
exit;
|
||||
}
|
||||
|
||||
// 1. git pull — vérifier que origin pointe vers le dépôt folio configuré
|
||||
$_folioRepo = rtrim(folioRepoUrl(), '/');
|
||||
exec('git -C ' . escapeshellarg(BASE_PATH) . ' remote get-url origin 2>&1', $_originOut, $_originCode);
|
||||
$_originUrl = rtrim(trim(implode('', $_originOut)), '/');
|
||||
// Normaliser : supprimer les credentials éventuels de l'URL (token@host → host)
|
||||
$_originNorm = preg_replace('#https?://[^@]+@#', 'https://', $_originUrl);
|
||||
$_repoNorm = preg_replace('#https?://[^@]+@#', 'https://', $_folioRepo);
|
||||
if ($_originCode !== 0 || $_originNorm !== $_repoNorm) {
|
||||
$_SESSION['_update_log'] = "Le remote git 'origin' (" . $_originUrl . ") ne correspond pas à FOLIO_REPO_URL (" . $_folioRepo . "). git pull annulé.";
|
||||
header('Location: /admin?tab=dashboard¬ice=update_git_error');
|
||||
exit;
|
||||
}
|
||||
exec('cd ' . escapeshellarg(BASE_PATH) . ' && git pull origin main 2>&1', $_gitOut, $_gitCode);
|
||||
if ($_gitCode !== 0) {
|
||||
$_SESSION['_update_log'] = implode("\n", $_gitOut);
|
||||
header('Location: /admin?tab=dashboard¬ice=update_git_error');
|
||||
exit;
|
||||
}
|
||||
|
||||
// 2. composer install (non-bloquant si absent)
|
||||
exec('which composer 2>/dev/null', $_composerPath);
|
||||
if (!empty($_composerPath)) {
|
||||
exec('cd ' . escapeshellarg(BASE_PATH) . ' && composer install --no-dev --optimize-autoloader -q 2>&1');
|
||||
}
|
||||
|
||||
// 3. Migrations SQL
|
||||
$pdo->exec('CREATE TABLE IF NOT EXISTS schema_migrations (name TEXT NOT NULL PRIMARY KEY, applied_at TIMESTAMP NOT NULL DEFAULT NOW())');
|
||||
$_sqlApplied = array_flip($pdo->query('SELECT name FROM schema_migrations ORDER BY name')->fetchAll(PDO::FETCH_COLUMN));
|
||||
$_sqlFiles = glob(BASE_PATH . '/database/migration_*.sql') ?: [];
|
||||
sort($_sqlFiles);
|
||||
foreach ($_sqlFiles as $_sqlFile) {
|
||||
$_sqlName = basename($_sqlFile);
|
||||
if (isset($_sqlApplied[$_sqlName])) {
|
||||
continue;
|
||||
}
|
||||
$pdo->exec((string) file_get_contents($_sqlFile));
|
||||
$pdo->prepare('INSERT INTO schema_migrations (name) VALUES (:n)')->execute([':n' => $_sqlName]);
|
||||
}
|
||||
|
||||
// 4. Migrations de contenu
|
||||
$_cmDataDir = DATA_PATH;
|
||||
$_cmTrack = $_cmDataDir . '/.content_migrations.json';
|
||||
$_cmFlag = $_cmDataDir . '/.maintenance';
|
||||
$_cmApplied = file_exists($_cmTrack) ? (json_decode((string) file_get_contents($_cmTrack), true) ?? []) : [];
|
||||
$_cmFiles = glob(BASE_PATH . '/scripts/content/migration_*.php') ?: [];
|
||||
sort($_cmFiles);
|
||||
$_cmPending = array_values(array_filter($_cmFiles, fn ($f) => !isset($_cmApplied[basename($f)])));
|
||||
$_cmErrors = 0;
|
||||
if (!empty($_cmPending)) {
|
||||
file_put_contents($_cmFlag, date('Y-m-d H:i:s'));
|
||||
$dataDir = $_cmDataDir;
|
||||
foreach ($_cmPending as $_cmFile) {
|
||||
try {
|
||||
require $_cmFile;
|
||||
$_cmApplied[basename($_cmFile)] = date('Y-m-d H:i:s');
|
||||
file_put_contents($_cmTrack, json_encode($_cmApplied, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n");
|
||||
} catch (Throwable $_cmEx) {
|
||||
$_cmErrors++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (file_exists($_cmFlag)) {
|
||||
unlink($_cmFlag);
|
||||
}
|
||||
}
|
||||
|
||||
$_updateChecker->clearCache();
|
||||
header('Location: /admin?tab=dashboard¬ice=' . ($_cmErrors ? 'update_content_error' : 'engine_updated'));
|
||||
exit;
|
||||
|
||||
case 'force_update_check':
|
||||
requireAuth();
|
||||
if (!isAdmin() || $_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
|
||||
@@ -35,9 +35,12 @@ if (!function_exists('url')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined('BASE_PATH')) {
|
||||
define('BASE_PATH', dirname(__DIR__, 2));
|
||||
}
|
||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/bootstrap.php';
|
||||
require_once dirname(__DIR__, 2) . '/config/config.php';
|
||||
require_once dirname(__DIR__, 2) . '/bootstrap.php';
|
||||
require_once dirname(__DIR__, 2) . '/src/SiteSettings.php';
|
||||
require_once dirname(__DIR__, 2) . '/src/mailer.php';
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
// version : 20251011
|
||||
declare(strict_types=1);
|
||||
|
||||
if (!defined('BASE_PATH')) {
|
||||
define('BASE_PATH', dirname(__DIR__, 2));
|
||||
}
|
||||
require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/bootstrap.php';
|
||||
require_once dirname(__DIR__, 2) . '/config/config.php';
|
||||
require_once dirname(__DIR__, 2) . '/bootstrap.php';
|
||||
|
||||
// si tu as un service pour ouvrir une session
|
||||
|
||||
|
||||
+3
-5
@@ -4,12 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
define('BASE_PATH', realpath(__DIR__ . '/../'));
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
require_once BASE_PATH . '/src/auth.php';
|
||||
require_once BASE_PATH . '/vendor/autoload.php';
|
||||
require_once BASE_PATH . '/config/config.php';
|
||||
require_once BASE_PATH . '/bootstrap.php';
|
||||
require_once BASE_PATH . '/src/auth.php';
|
||||
|
||||
$logoutUrl = ssoLogoutUrl();
|
||||
|
||||
|
||||
@@ -39,7 +39,15 @@ if (!$OIDC_ISSUER || !$OIDC_CLIENT_ID || !$OIDC_REDIRECT_URI) {
|
||||
$tokenEndpoint = $OIDC_ISSUER . '/protocol/openid-connect/token';
|
||||
$userInfoEndpoint = $OIDC_ISSUER . '/protocol/openid-connect/userinfo';
|
||||
|
||||
if (session_status() !== PHP_SESSION_ACTIVE) {
|
||||
error_log('[OIDC/callback] session_start() a échoué — vérifier session.save_path');
|
||||
http_response_code(500);
|
||||
echo $debug ? 'Erreur de session (session.save_path inaccessible ?).' : 'Erreur interne.';
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($_GET['state'], $_SESSION['oidc_state']) || !hash_equals((string)$_SESSION['oidc_state'], (string)$_GET['state'])) {
|
||||
error_log('[OIDC/callback] State invalide — GET:' . ($_GET['state'] ?? 'absent') . ' SESSION:' . (isset($_SESSION['oidc_state']) ? 'présent' : 'absent') . ' session_id:' . session_id());
|
||||
http_response_code(400);
|
||||
echo $debug ? 'State invalide.' : 'Requête invalide.';
|
||||
exit;
|
||||
|
||||
@@ -9,6 +9,13 @@ require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/config/config.php';
|
||||
require_once dirname(__DIR__, 2) . '/bootstrap.php';
|
||||
|
||||
if (session_status() !== PHP_SESSION_ACTIVE) {
|
||||
error_log('[OIDC/start] session_start() a échoué — vérifier session.save_path');
|
||||
http_response_code(500);
|
||||
echo 'Erreur de session. Contactez l\'administrateur.';
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!function_exists('env')) {
|
||||
function env(string $key, ?string $default = null): ?string
|
||||
{
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.4.0
|
||||
1.6.2
|
||||
|
||||
+12
-3
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pousse le code Folio vers git.abonnel.fr/cedricAbonnel/folio
|
||||
# Pousse la branche courante vers git.abonnel.fr/cedricAbonnel/folio
|
||||
# Ne pousse JAMAIS directement sur main — passer par une PR.
|
||||
# Usage : ./scripts/push.sh "message de commit"
|
||||
set -euo pipefail
|
||||
|
||||
@@ -20,6 +21,13 @@ if [ ! -d .git ]; then
|
||||
echo "→ Dépôt git initialisé"
|
||||
fi
|
||||
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
if [[ "$BRANCH" == "main" ]]; then
|
||||
echo "✗ Refus de pousser directement sur main."
|
||||
echo " Travailler sur 'dev' ou une branche feature : git checkout dev"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extraire la version depuis CHANGELOG.md (première entrée ## [X.Y.Z])
|
||||
FOLIO_VERSION=$(grep -m1 '^\#\# \[[0-9]' CHANGELOG.md | sed 's/.*\[\([^]]*\)\].*/\1/')
|
||||
if [[ -z "$FOLIO_VERSION" ]]; then
|
||||
@@ -32,5 +40,6 @@ echo "→ Version : $FOLIO_VERSION"
|
||||
git add -A
|
||||
git diff --cached --quiet && echo "(rien à committer)" && exit 0
|
||||
git commit -m "$MSG"
|
||||
git push origin main
|
||||
echo "✓ Poussé vers folio"
|
||||
git push origin "$BRANCH"
|
||||
echo "✓ Poussé vers folio (branche $BRANCH)"
|
||||
echo " → Ouvrir une PR sur https://git.abonnel.fr/cedricAbonnel/folio/pulls/new/$BRANCH"
|
||||
|
||||
+24
-24
@@ -126,13 +126,17 @@ function adminStatusBadge(array $a, int $now): string
|
||||
<tr>
|
||||
<th class="text-muted fw-normal ps-0 pe-2 text-nowrap">Dernière version disponible</th>
|
||||
<td class="d-flex align-items-center gap-2 flex-wrap">
|
||||
<span><?= htmlspecialchars($_remoteLabel) ?><?= $_remoteLabel !== '—' && $_remoteLabel !== $_deployedLabel ? ' <span class="badge bg-warning text-dark ms-1">Mise à jour disponible</span>' : '' ?></span>
|
||||
<?php if ($_repoConfigured): ?>
|
||||
<form method="POST" action="/?action=force_update_check" class="d-inline">
|
||||
<button type="submit" class="btn btn-outline-secondary btn-sm py-0">Vérifier</button>
|
||||
</form>
|
||||
<span><?= htmlspecialchars($_remoteLabel) ?></span>
|
||||
<?php if ($_remoteLabel !== '—' && $_remoteLabel !== $_deployedLabel): ?>
|
||||
<form method="POST" action="/?action=run_engine_update" class="d-inline">
|
||||
<button type="submit" class="btn btn-primary btn-sm">Mettre à jour vers v<?= htmlspecialchars($_remoteLabel) ?></button>
|
||||
</form>
|
||||
<?php elseif ($_repoConfigured): ?>
|
||||
<form method="POST" action="/?action=force_update_check" class="d-inline">
|
||||
<button type="submit" class="btn btn-outline-secondary btn-sm py-0">Vérifier</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<span class="text-muted small">(<code>FOLIO_REPO_URL</code> non configuré)</span>
|
||||
<span class="text-muted small">(<code>FOLIO_REPO_URL</code> non configuré)</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -140,24 +144,20 @@ function adminStatusBadge(array $a, int $now): string
|
||||
<th class="text-muted fw-normal ps-0 pe-2 text-nowrap">Branche suivie</th>
|
||||
<td><code><?= htmlspecialchars($_branch) ?></code><?= $_lastChecked !== null ? ' <span class="text-muted ms-2">· vérifié le ' . date('d/m/Y à H:i', $_lastChecked) . '</span>' : '' ?></td>
|
||||
</tr>
|
||||
<?php if (!empty($_notices)): ?>
|
||||
<tr>
|
||||
<th class="text-muted fw-normal ps-0 pe-2 align-top">Actions requises</th>
|
||||
<td class="d-flex flex-wrap gap-2 align-items-center">
|
||||
<?php foreach ($_notices as $_n): ?>
|
||||
<?php if ($_n['type'] === 'warning'): ?>
|
||||
<form method="POST" action="/?action=run_content_migrations">
|
||||
<button type="submit" class="btn btn-warning btn-sm">Mettre à jour le contenu</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php if (($_GET['notice'] ?? '') === 'migrated'): ?>
|
||||
<tr><td colspan="2"><div class="alert alert-success py-1 mb-0 small">Migrations appliquées avec succès.</div></td></tr>
|
||||
<?php elseif (($_GET['notice'] ?? '') === 'migration_error'): ?>
|
||||
<tr><td colspan="2"><div class="alert alert-danger py-1 mb-0 small">Une erreur est survenue pendant la migration.</div></td></tr>
|
||||
<?php if (($_GET['notice'] ?? '') === 'engine_updated'): ?>
|
||||
<tr><td colspan="2"><div class="alert alert-success py-1 mb-0 small">Moteur mis à jour avec succès (code, base de données, contenu).</div></td></tr>
|
||||
<?php elseif (($_GET['notice'] ?? '') === 'update_git_error'): ?>
|
||||
<tr><td colspan="2">
|
||||
<div class="alert alert-danger py-1 mb-0 small">
|
||||
Erreur git pull — vérifiez les droits d'accès au dépôt.
|
||||
<?php if (!empty($_SESSION['_update_log'])): ?>
|
||||
<pre class="mt-1 mb-0 small"><?= htmlspecialchars($_SESSION['_update_log']) ?></pre>
|
||||
<?php unset($_SESSION['_update_log']); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td></tr>
|
||||
<?php elseif (($_GET['notice'] ?? '') === 'update_content_error'): ?>
|
||||
<tr><td colspan="2"><div class="alert alert-warning py-1 mb-0 small">Code et base de données mis à jour, mais une migration de contenu a échoué.</div></td></tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user