diff --git a/.gitignore b/.gitignore index c929565..24690c6 100644 --- a/.gitignore +++ b/.gitignore @@ -30,11 +30,22 @@ public/themes/ # Temporary files *.tmp *.temp +.bak/ # Local configuration & credentials config.json +config.*.json +!config.json.example admin/config/admin.json -# No content +# No content (per-domain content dirs included) content/ +content-*/ !content/.gitkeep + +# Test results +pentest_results.* +accessibility-test-results.* +enhanced-test-results.* +cli/test/functional/test-report*.md +cli/test/functional/function-test.md diff --git a/AGENTS.md b/AGENTS.md index 197b4ce..4ec3c92 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,155 +1,74 @@ # Agent Instructions for CodePress CMS ## AI Model -- **Huidig model**: GLM-5.2 max (Ollama cloud) +- **Huidig model**: `claude-opus-4-6` (OpenCode / `opencode/claude-opus-4-6`) - Sessie gestart: 16 feb 2026 ## Build & Run - **Run Server**: `php -S localhost:8080 cms/router.php` (router nodig voor clean URLs) -- **Lint PHP**: `find . -name "*.php" -not -path "./vendor/*" -not -path "./var/*" -exec php -l {} \;` +- **Lint PHP**: `find . -name "*.php" -not -path "./vendor/*" -exec php -l {} \;` - **Dependencies**: Composer vereist voor CommonMark, Twig en scssphp. Geen NPM. -- **Admin Console**: Toegankelijk op `/admin` (standaard login: `admin` / `admin`) +- **Admin Console**: Toegankelijk op `/admin.php` (standaard login: `admin` / `admin`) ## Project Structuur ``` codepress/ -├── cms/ # Core CMS engine +├── cms/ # Core CMS engine │ ├── core/ │ │ ├── class/ -│ │ │ ├── CodePressCMS.php # Hoofd CMS class (routing, rendering, breadcrumb, guide) -│ │ │ ├── ThemeManager.php # Thema-resolver + Twig render + SCSS compile -│ │ │ ├── ContentAPI.php # Read-only API voor PHP content bestanden -│ │ │ ├── ContentSecurityPolicy.php # CSP header management -│ │ │ ├── Analytics.php # Bezoekersstatistieken -│ │ │ ├── BotGuard.php # Bot/AI detectie -│ │ │ ├── Cache.php # Cache systeem -│ │ │ ├── GeoIP.php # GeoIP lookup (land, vlag) -│ │ │ ├── Logger.php # Basis logging -│ │ │ ├── LogManager.php # Dynamisch logging systeem (SQLite/syslog) -│ │ │ ├── RateLimiter.php # Rate limiting per IP -│ │ │ ├── RequestLogger.php # Request logging + visitor info -│ │ │ ├── SearchEngine.php # Volledige tekst zoekfunctie -│ │ │ ├── SimpleTemplate.php # Legacy Mustache-style engine (niet meer gebruikt) -│ │ │ └── AccessibilityManager.php # Accessibility features +│ │ │ ├── CodePressCMS.php # Hoofd CMS class +│ │ │ ├── ThemeManager.php # Thema-resolver + Twig render + SCSS compile +│ │ │ └── Logger.php # Logging systeem │ │ ├── plugin/ -│ │ │ ├── PluginManager.php # Plugin loader (laadt, hooks, filters, sidebar) -│ │ │ └── CMSAPI.php # API voor plugins (getPage, getConfig, etc.) -│ │ ├── config.php # Config loader (leest config.json) -│ │ └── index.php # Bootstrap (autoloader, requires) -│ ├── lang/ # Taalbestanden (nl.php, en.php) -│ └── router.php # PHP dev server router (serveert themes/, admin/assets/, plugins/assets/) -├── themes/ # Dynamische thema's (volledig zelfstandig) -│ ├── default/ # Standaard thema -│ │ ├── theme.json # { title, config.default_template, template: layout→.twig mapping } -│ │ ├── base.twig # Hoofd layout (head, header, nav, breadcrumb, footer) -│ │ ├── full_content.twig # Layout: volledige breedte -│ │ ├── left_sidebar.twig # Layout: sidebar links -│ │ ├── right_sidebar.twig # Layout: sidebar rechts -│ │ ├── custom1.twig # Layout: custom -│ │ ├── guide.twig # Layout: handleiding met sidebar (Navigation plugin) -│ │ ├── partials/ # header.twig, navigation.twig, footer.twig -│ │ └── assets/ -│ │ ├── scss/theme.scss # SCSS bron (runtime gecompileerd) -│ │ ├── css/theme.css # Gecompileerde CSS -│ │ ├── css/style.css # Extra CSS (search fix, etc.) -│ │ ├── css/bootstrap.min.css # Bootstrap 5 -│ │ ├── css/bootstrap-icons.css # Bootstrap Icons -│ │ ├── css/mobile.css # Mobile styles -│ │ ├── js/app.js # Thema JavaScript -│ │ ├── js/bootstrap.bundle.min.js -│ │ ├── fonts/ # bootstrap-icons.woff, woff2 -│ │ └── img/ # favicon, icon, world-map -│ └── demo/ # Demo thema (zelfde structuur, andere look) -├── admin/ # Admin paneel +│ │ │ ├── PluginManager.php # Plugin loader +│ │ │ └── CMSAPI.php # API voor plugins +│ │ ├── config.php # Config loader (leest config.json) +│ │ └── index.php # Bootstrap (autoloader, requires) +│ └── router.php # PHP dev server router (serveert ook /themes/) +├── language/ # Taalbestanden (nl/, en/, de/ — elk met site.php + admin.php) +├── themes/ # Dynamische thema's (volledig zelfstandig) +│ ├── default/ # Standaard thema +│ │ ├── theme.json # { title, default_layout, layout→.twig mapping, kleuren } +│ │ ├── base.twig # Hoofd layout (head, header, nav, footer) +│ │ ├── full_content.twig # Layout: volledige breedte +│ │ ├── left_sidebar.twig # Layout: sidebar links +│ │ ├── right_sidebar.twig # Layout: sidebar rechts +│ │ ├── custom1.twig # Layout: custom +│ │ ├── guide.twig # Layout: handleiding +│ │ ├── partials/ # header.twig, navigation.twig, footer.twig +│ │ ├── assets/scss/theme.scss # SCSS bron (runtime gecompileerd) +│ │ └── assets/js/ # app.js, bootstrap.bundle.min.js +│ ├── demo/ # Demo thema (zelfde structuur, andere look) +├── admin/ # Admin paneel │ ├── config/ -│ │ ├── app.php # Admin app configuratie (paths, config_json, etc.) -│ │ └── admin.json # Gebruikers & security (file-based, .gitignore'd) +│ │ ├── app.php # Admin app configuratie +│ │ ├── admin.json # Gebruikers & security (file-based, gitignored) +│ │ └── admin.json.example # Voorbeeld met placeholder-wachtwoord │ ├── src/ -│ │ └── AdminAuth.php # Authenticatie (sessies, bcrypt, CSRF, lockout, RBAC) -│ ├── theme/default/ # Admin thema -│ │ ├── theme.json # Admin thema configuratie -│ │ ├── assets/ -│ │ │ ├── css/ -│ │ │ │ ├── style.css # Admin styles (code blocks, guide nav) -│ │ │ │ ├── editor.css # CodeMirror editor styles -│ │ │ │ ├── bootstrap.min.css -│ │ │ │ └── bootstrap-icons.css -│ │ │ ├── js/ -│ │ │ │ ├── app.js -│ │ │ │ ├── editor-toolbar.js # CodeMirror toolbar + shortcuts -│ │ │ │ ├── keyboard-navigation.js -│ │ │ │ └── bootstrap.bundle.min.js -│ │ │ ├── codemirror/ # CodeMirror editor (modes, addons) -│ │ │ ├── fonts/ # bootstrap-icons.woff, woff2 -│ │ │ └── img/ # favicon, world-map -│ │ └── views/ -│ │ ├── login.twig # Login pagina -│ │ ├── layouts/ -│ │ │ └── admin.twig # Admin layout met sidebar (role-based zichtbaarheid) -│ │ └── pages/ -│ │ ├── dashboard.twig # Dashboard (role-based inhoud) -│ │ ├── content.twig # Content beheer -│ │ ├── content-edit.twig # Content bewerken (layout select, plugins, CodeMirror) -│ │ ├── content-new.twig # Nieuwe content -│ │ ├── content-move-form.twig # Content verplaatsen -│ │ ├── content-dir-form.twig # Map hernoemen -│ │ ├── config.twig # Site configuratie -│ │ ├── security.twig # Beveiliging instellingen -│ │ ├── theme.twig # Thema beheer -│ │ ├── theme-new.twig # Nieuw thema -│ │ ├── plugins.twig # Plugin beheer (beschermd: essentiële plugins) -│ │ ├── plugins-edit.twig # Plugin bewerken (CodeMirror) -│ │ ├── plugins-new.twig # Nieuwe plugin -│ │ ├── plugin-config.twig # Plugin configuratie -│ │ ├── users.twig # Gebruikersbeheer (rollen, wachtwoord) -│ │ ├── statistics.twig # Statistieken -│ │ ├── logs.twig # Log viewer -│ │ ├── media.twig # Media beheer -│ │ ├── guide.twig # Handleiding (met Navigation sidebar) -│ │ ├── update.twig # Update pagina -│ │ └── error.twig # 403/404 fout pagina -│ └── storage/ # Logs, cache, geoip -├── plugins/ # CMS plugins -│ ├── Navigation/ # Essentiële navigatie plugin (beschermd) -│ │ ├── Navigation.php # Plugin code (guide + content navigatie) -│ │ ├── plugin.json # Plugin metadata -│ │ ├── assets/ -│ │ │ ├── scss/navigation.scss # SCSS bron -│ │ │ └── css/navigation.css # Gecompileerde CSS -│ │ └── views/ # Plugin Twig templates (toekomstig) -│ └── HTMLBlock/ # Voorbeeld sidebar plugin -│ └── HTMLBlock.php -├── content/ # Website content (.md, .php, .html) -├── public/ # Web root -│ ├── index.php # Website entry point -│ ├── admin.php # Admin entry point + routing -│ ├── favicon.ico -│ └── robots.txt -├── guide/ # Handleidingen (nl/en, gesplitst in mappen) -│ ├── nl/ # Nederlandse handleidingen -│ │ ├── index.md # Index (verwijst naar onderwerpen) -│ │ ├── admin-beheerder.md # Admin handleiding (inleiding) -│ │ ├── admin-beheerder/ # Sub-onderdelen -│ │ ├── content-beheerder.md -│ │ ├── content-beheerder/ -│ │ ├── codepress-developer.md -│ │ ├── codepress-developer/ -│ │ ├── theme-developer.md -│ │ └── theme-developer/ -│ ├── en/ # Engelse handleidingen (zelfde structuur als nl/) -│ └── README.md -├── cli/ # CLI scripts & tests +│ │ └── AdminAuth.php # Authenticatie (sessies, bcrypt, CSRF, lockout) +│ ├── theme/default/views/ # Twig templates +│ │ ├── login.twig # Login pagina +│ │ ├── layouts/admin.twig # Admin layout met sidebar +│ │ └── pages/ # dashboard, content, content-edit, config, plugins, theme, users, statistics, logs, security, update, guide, media, etc. +│ └── storage/logs/ # Admin logs (gedeeld met front-end) +├── cli/ # CLI scripts & tests │ └── test/ -│ ├── accessibility.sh # WCAG 2.1 AA test suite -│ ├── enhanced-suite.sh # Enhanced test suite -│ ├── functional/ # Functionele testen -│ └── pentest/ # Penetratietesten -├── var/ # Cache (twig) — .gitignore'd -├── config.json # Site configuratie — .gitignore'd -├── composer.json # PHP dependencies -├── version.php # Versie informatie (huidige: 2.5.2) -├── .gitignore # Negeert: var/, config.json, admin/config/admin.json, content/ -└── AGENTS.md # Dit bestand +│ ├── accessibility.sh # WCAG 2.1 AA test suite +│ ├── enhanced-suite.sh # Enhanced test suite +│ ├── functional/ # Functionele testen +│ └── pentest/ # Penetratietesten +├── plugins/ # CMS plugins +│ ├── HTMLBlock/ +│ └── Navigation/ +├── public/ # Web root +│ ├── assets/css/js/ +│ ├── index.php # Website entry point +│ └── admin.php # Admin entry point + router +├── content/ # Content bestanden +├── guide/ # Handleidingen (nl/en) +├── docs/ # Documentatie +├── config.json # Site configuratie +└── AGENTS.md # Dit bestand ``` ## Code Style & Conventions @@ -161,50 +80,23 @@ codepress/ - Configuration loaded from `config.json` via `cms/core/config.php` - Public website entry point: `public/index.php` - Admin entry point + routing: `public/admin.php` - - Admin authentication + RBAC: `admin/src/AdminAuth.php` - - Admin theme: `admin/theme/default/` (views + assets) - - Plugin assets: `plugins//assets/` (served via router `/plugins//assets/`) + - Admin authenticatie: `admin/src/AdminAuth.php` - **Content**: Stored in `content/`. Supports `.md` (Markdown), `.php` (Dynamic), `.html` (Static). -- **Templating**: Twig templates in `themes//`. `ThemeManager` rendert via Twig en compileert `assets/scss/theme.scss` runtime naar `assets/css_compiled/theme.css` via scssphp. Layout gekozen via frontmatter `layout:` key; onbekende layouts vallen terug op `config.default_template` in `theme.json`. -- **Plugin CSS**: Plugins hebben eigen `assets/scss/` en `assets/css/`. Plugin CSS wordt automatisch geladen na theme CSS (in `base.twig`), zodat thema's plugin styling kunnen overschrijven. Plugin assets worden geserveerd via `cms/router.php` op URL `/plugins//assets/...`. -- **Navigation**: Auto-generated from directory structure. Folders require an index file to be clickable in breadcrumbs. Breadcrumb is dynamisch: Home > [submappen] > [pagina]. Homepage toont altijd het pad. +- **Templating**: Twig templates in `themes//`. `ThemeManager` rendert via Twig en compileert `assets/scss/theme.scss` runtime naar `public/themes//theme.css`. Layout gekozen via frontmatter `layout:` key; onbekende layouts vallen terug op `default_layout` in `theme.json`. +- **Navigation**: Auto-generated from directory structure. Folders require an index file to be clickable in breadcrumbs. - **Security**: - Always use `htmlspecialchars()` for outputting user/content data - Use `realpath()` + prefix-check for path traversal prevention - Admin forms require CSRF tokens via `AdminAuth::verifyCsrf()` - - Passwords stored as bcrypt hashes in `admin/config/admin.json` - - Role-based access control (RBAC) via `AdminAuth::hasPermission()` + - Passwords stored as bcrypt hashes in `admin.json` - **Git**: `main` is the clean CMS core. `development` is de actieve development branch. `e.noorlander` bevat persoonlijke content. Niet mixen. ## Admin Console - **File-based**: Geen database. Gebruikers opgeslagen in `admin/config/admin.json` -- **Routing**: Via clean URLs `/admin/` (omgezet naar `?route=` door `cms/router.php`) -- **Routes**: `login`, `logout`, `dashboard`, `content`, `content-edit`, `content-new`, `content-delete`, `content-dir-create`, `content-dir-rename`, `content-dir-delete`, `content-move`, `config`, `security`, `theme`, `theme-new`, `plugins`, `plugins-new`, `plugins-edit`, `plugins-config`, `plugins-toggle`, `plugins-delete`, `users`, `statistics`, `logs`, `media`, `guide`, `update` +- **Routing**: Via `?route=` parameter in `public/admin.php` +- **Routes**: `login`, `logout`, `dashboard`, `content`, `content-edit`, `content-new`, `content-delete`, `content-dir-create`, `content-dir-rename`, `content-dir-delete`, `content-move`, `config`, `plugins`, `plugins-new`, `plugins-edit`, `plugins-config`, `plugins-toggle`, `plugins-delete`, `theme`, `theme-new`, `users`, `security`, `statistics`, `logs`, `guide`, `media`, `update` - **Auth**: Session-based. `AdminAuth` class handelt login, logout, CSRF, brute-force lockout af -- **Templates**: Twig templates in `admin/theme/default/views/pages/`. Layout in `admin/theme/default/views/layouts/admin.twig` -- **Essentiële plugins**: Gedefinieerd in `getProtectedPlugins()` in `public/admin.php`. Deze plugins kunnen niet worden gedeactiveerd, bewerkt of verwijderd. Huidige essentiële plugins: `Navigation`. - -## Gebruikersrollen (RBAC) -Gedefinieerd in `AdminAuth::ROLE_PERMISSIONS` als een mapping van rol → toegestane routes. - -| Rol | Label | Permissies | -|-----|-------|-----------| -| `admin` | Admin | Alles (`*`) | -| `content-manager` | Content Beheerder | Content beheer, handleiding | -| `bi-manager` | BI Beheerder | Statistieken, logs, handleiding | -| `site-admin` | Site Admin | Thema, plugins, statistieken, logs, update, handleiding | - -- Sidebar items worden conditioneel getoond via `has_permission()` Twig function -- Dashboard inhoud is role-based (statistieken, content stats, systeem info, quick actions) -- Route access control in `public/admin.php`: onbevoegde routes geven 403 error - -## Guide Systeem -- Handleidingen in `guide//` met sub-onderdelen in aparte mappen -- NL en EN hebben identieke structuur (bestandsnamen zijn gelijk voor fallback) -- `getGuidePage()` in `CodePressCMS.php` laadt guide content en injecteert `plugins: Navigation` in metadata -- Navigation plugin genereert zijbalk navigatie vanuit de mapstructuur (guide + content) -- Guide titles worden uit H1 van markdown bestanden gehaald (via `getTitleFromFile()`) -- Admin guide laadt Navigation plugin direct in `handleGuide()` in `public/admin.php` +- **Templates**: Twig templates in `admin/theme/default/views/`. Layout in `layouts/admin.twig` ## Important: Title vs File/Directory Name Logic - **CRITICAL**: When user asks for "title" corrections, they usually mean **FILE/DIRECTORY NAME WITHOUT LANGUAGE PREFIX AND EXTENSIONS**, not the HTML title from content! @@ -219,76 +111,5 @@ Gedefinieerd in `AdminAuth::ROLE_PERMISSIONS` als een mapping van rol → toeges ## Bekende aandachtspunten - LSP errors over "Undefined function" in PHP files zijn vals-positief (standaard PHP functies worden niet herkend door de LSP). Negeer deze. - Zie `TODO.md` voor alle openstaande verbeteringen en nieuwe features. -- `vendor/` map bevat Composer dependencies (CommonMark, Twig, scssphp). Niet handmatig wijzigen. +- `vendor/` map bevat Composer dependencies (CommonMark, Twig, scssphp, GeoIP2). Niet handmatig wijzigen. - `admin/config/admin.json` bevat wachtwoord-hashes. Niet committen met echte productie-wachtwoorden. -- `config.json` staat in `.gitignore`. Niet committen. -- `var/` (Twig cache) staat in `.gitignore`. Kan veilig worden gewist: `rm -rf var/cache/twig/*` -- `content/` staat in `.gitignore`. Content wordt lokaal beheerd. -- Pad-referenties vanuit `public/admin.php`: gebruik `__DIR__ . "/../themes/..."` (één niveau omhoog), NIET `../../` (twee niveaus). - -## CRITICAL: SCSS is de enige CSS bron — NIET handmatig CSS aanpassen -- **NOOIT** `themes//assets/css/theme.css` handmatig aanpassen. Dit bestand mag niet bestaan. -- **ALTIJD** `themes//assets/scss/theme.scss` aanpassen. scssphp compileert dit automatisch naar `assets/css_compiled/theme.css`. -- **ALTIJD** `themes//assets/css_compiled/theme.css` verwijderen na SCSS wijzigingen: `rm themes//assets/css_compiled/theme.css themes//assets/css_compiled/.mtime` -- **REDEN**: `ThemeManager::getCssUrl()` heeft prioriteit: 1) `assets/css/theme.css` (handmatig), 2) `assets/css_compiled/theme.css` (gecompileerd). Als `theme.css` bestaat, wordt de SCSS negeren en worden SCSS wijzigingen NIET zichtbaar. -- **Plugin CSS**: Plugin SCSS in `plugins//assets/scss/` wordt nog niet automatisch gecompileerd. Plugin CSS in `plugins//assets/css/` is handmatig te onderhouden. -- **Bootstrap CSS**: `themes//assets/css/bootstrap.min.css` is een externe dependency. NIET aanpassen. - -## CRITICAL: Bootstrap 5 overrides — alle CSS variabelen EN properties overschrijven -- Bootstrap 5 gebruikt CSS custom properties (variables) op `:root` en op component niveau. Deze overschrijven met alleen `!important` op properties is NIET voldoende. -- **ALTIJD** zowel de Bootstrap CSS variabelen als de properties overschrijven: - - `.nav-tabs`: set `--bs-nav-tabs-border-width`, `--bs-nav-tabs-border-color`, `--bs-nav-tabs-border-radius` EN `border`, `border-radius`, `border-bottom` - - `.dropdown-menu`: set `--bs-dropdown-min-width`, `--bs-dropdown-border-width`, `--bs-dropdown-border-radius`, `--bs-dropdown-box-shadow`, `--bs-dropdown-padding-x/y` EN `border`, `border-radius`, `padding`, `margin`, `min-width`, `box-shadow` - - `.nav-link`: set `border`, `border-top-left-radius`, `border-top-right-radius`, `border-bottom-left-radius`, `border-bottom-right-radius` (alle vier de hoeken!) -- **NOOIT** aannemen dat een enkele `border: none !important` voldoende is. Bootstrap zet `border-top-left-radius` en `border-top-right-radius` apart op `.nav-tabs .nav-link`. - -## CRITICAL: Pad-referenties vanuit public/admin.php -- `__DIR__` in `public/admin.php` is `public/`. -- Gebruik `__DIR__ . "/../themes/..."` (één niveau omhoog naar project root). -- **NOOIT** `__DIR__ . "/../../themes/..."` (twee niveaus — dit gaat naar de parent van het project). -- Dit geldt voor alle paden naar `themes/`, `plugins/`, `guide/`, `admin/`. - -## CRITICAL: Twig syntaxis — geen PHP functions in Twig -- Twig heeft geen `dirname` filter. Gebruik PHP `dirname()` in de handler en geef het resultaat als aparte variabele door aan Twig. -- Twig `??` (null coalescing) werkt NIET op filter expressies zoals `(stats.pages|length ?? 0)`. Gebruik `|default(0)` in plaats daarvan. -- Twig `??` werkt WEL op simpele variable access zoals `(config.value ?? 'default')`. - -## CRITICAL: CodeMirror mode laadvolgorde -- CodeMirror modes hebben dependencies. De laadvolgorde in `admin.twig` moet zijn: - 1. `codemirror.min.js` (core) - 2. `xml.min.js` (basis voor htmlmixed) - 3. `css.min.js` (dependency van htmlmixed) - 4. `javascript.min.js` (dependency van htmlmixed) - 5. `htmlmixed.min.js` (dependency van php) - 6. `php.min.js` (gebruikt htmlmixed) - 7. `clike.min.js` - 8. `markdown.min.js` -- **NOOIT** `php.min.js` laden vóór `htmlmixed.min.js` — dit veroorzaakt `c.indent is not a function` errors. - -## CRITICAL: Plugin bestandsnaam conventie -- Plugin PHP bestanden heten `.php` (bijv. `Navigation.php`, `HTMLBlock.php`), NIET `plugin.php`. -- `PluginManager` laadt `$pluginDir . '/' . $pluginName . '.php'` (regel 46 in PluginManager.php). -- `handlePluginsEdit` in `admin.php` moet `$pluginDir . '/' . $plugin . '.php'` gebruiken, NIET `$pluginDir . '/plugin.php'`. -- `handlePluginsNew` moet het bestand aanmaken als `.php`, NIET `plugin.php`. - -## CRITICAL: Plugin types (content vs systeem) -- `plugin.json` heeft een `type` veld: `"type": "content"` of `"type": "system"`. -- **Content plugins** (type=content): Verschijnen in de sidebar en in de plugin selectie op content-edit paginas. -- **Systeem plugins** (type=system): Worden geladen door PluginManager (voor API/hooks) maar verschijnen NIET in de sidebar. Bieden functionaliteit aan via de CMSAPI. -- `PluginManager::isPluginViewable()` checkt `type === 'system'` -> niet viewable in sidebar. -- `handleContentEdit` toont alleen content-plugins in de plugin selectie. -- De admin plugins pagina toont een "Content" of "Systeem" badge. -- Bij geen `type` veld in plugin.json wordt default `content` aangenomen. - -## CRITICAL: Essentiële plugins beschermen -- Essentiële plugins gedefinieerd in `getProtectedPlugins()` in `public/admin.php` (huidige: `Navigation`). -- Deze plugins kunnen NIET worden: gedeactiveerd (`handlePluginsToggle`), verwijderd (`handlePluginsDelete`), bewerkt (`handlePluginsEdit`). -- De `plugins.twig` template toont een "Essentieel" badge i.p.v. de actieknoppen. -- **ALTIJD** de `isProtectedPlugin()` check toevoegen aan nieuwe plugin handlers. - -## CRITICAL: Live server (Apache) — asset serving -- Op de live server (Apache) staan themes, plugins en admin assets buiten de webroot (`public/`). -- `public/.htaccess` stuurt `/themes/`, `/admin/assets/`, `/plugins/` URLs door naar `public/asset.php`. -- `public/asset.php` serveert de bestanden vanuit de juiste mappen met het juiste MIME-type. -- **NOOIT** aannemen dat de PHP dev server router (`cms/router.php`) op de live server draait. -- Na wijzigingen aan assets: commit EN deploy naar live server. diff --git a/README.en.md b/README.en.md index 639716f..97eb303 100644 --- a/README.en.md +++ b/README.en.md @@ -63,8 +63,8 @@ codepress/ ├── cms/ # Core CMS engine │ ├── core/class/ # CMS classes (CodePressCMS, ThemeManager, etc.) │ ├── core/plugin/ # Plugin system (PluginManager, CMSAPI) -│ ├── lang/ # Translation files (nl.php, en.php) │ └── router.php # PHP dev server router (clean URLs) +├── language/ # Translation files (nl/, en/, de/ — each with site.php + admin.php) ├── admin/ # Admin console │ ├── config/ # Admin configuration (admin.json) │ ├── src/AdminAuth.php # Authentication, roles, permissions diff --git a/README.md b/README.md index 3bc7353..4ecb308 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ codepress/ ├── cms/ # Core CMS engine │ ├── core/class/ # CMS classes (CodePressCMS, ThemeManager, etc.) │ ├── core/plugin/ # Plugin systeem (PluginManager, CMSAPI) -│ ├── lang/ # Taalbestanden (nl.php, en.php) │ └── router.php # PHP dev server router (schone URLs) +├── language/ # Taalbestanden (nl/, en/, de/ — elk met site.php + admin.php) ├── admin/ # Admin console │ ├── config/ # Admin configuratie (admin.json) │ ├── src/AdminAuth.php # Authenticatie, rollen, permissies diff --git a/TODO.md b/TODO.md index 5b8d080..adb2c50 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,56 @@ # TODO -- [ ] Pentest controles uitvoeren +## Voor elke versie verhoging. Deze nooit weghalen. +- [ ] Pentest controles uitgevoerd - [ ] WCAG 2.1 AA accessibility tests -- [ ] Multidomein implenmenteren. -- [ ] Ontwikkel proces verbeteren -- [ ] Code controlleren en functie omschrijvingen verduidelijken +- [ ] Volledige git commit maken. +- [ ] Verslag maken voor opdrcht gever +- [ ] Na convormatie versie verhogen +- [ ] Bij Voltooid versie ophoging aanmaken en deze allemaal unvinken voor volgende ronde. +## Te doen ⏳ + +- [ ] Multidomein implementeren (elk domein = eigen thema + content, één admin + site name) + - [ ] Fase 1: Config-resolutie + - [ ] For apache instants domein settings /public/noorlander.info/ or /public/mycode.name/ + - [ ] config.domains.json (registry: host, aliases, redirect, config) + .example + - [ ] cms/core/domain.php: normalizeHost/getDomainRegistry/resolveDomain/loadSiteConfigForHost + - [ ] cms/core/config.php refactor → herbruikbare functie, compatibel blijven + - [ ] Per-domein config-bestanden (content_dir, active_theme) in the main content dir. like: /content/domain1 /content/domain2 os /content/noorlander.info/ /content/mycode.name/ + - [ ] Fase 2: Front-end + - [ ] cms/router.php: taal-prefix dynamisch uit actieve config + - [ ] public/.htaccess: generieke `([a-z]{2})` taalregel + - [ ] CodePressCMS::getCurrentLanguage(): validatie via config['language']['available'] + - [ ] getInternalHosts(): registry-hosts toevoegen (cross-domein links = intern) + - [ ] public/index.php: /-media/ en /-assets/ via actieve content_dir + - [ ] Fase 3: Admin (domeinbeheer + switch) + - [ ] admin/config/app.php: domains_json pad + - [ ] public/admin.php: $_SESSION['admin_domain'] + routes domains/domain-switch + - [ ] domains.twig + sidebar-item/badge in admin.twig + - [ ] Bestaande handlers laten werken op actief domein (config_json/content_dir patchen) + - [ ] Fase 4: Housekeeping + - [ ] .gitignore: config.*.json, content-*/ + - [ ] AGENTS.md + config.json.example bijwerken + - [ ] Verificatie: php -l, curl met Host-header, domein-switch in admin testen + +## Voltooid ✅ + +- [x] Admin code en niet gebruikte mappen/bestanden opschonen +- [x] version.php changelog verwijderen (staat in git) +- [x] Guide mappenstructuur reorganiseren (NL/EN → rollen) +- [x] README.md compacter maken met verwijzingen naar guide +- [x] Admin dashboard template check — Twig-commentaren `{# ... #}` verwijderd uit Dashboard.php +- [x] Plugins — zichtbaar verschil tussen system en content plugins (badge + border + icoon in plugins.twig) +- [x] Plugins — alleen actieve plugins zichtbaar in sidebar (PluginManager laadt alleen enabled plugins) +- [x] Plugins — dubbele enabled_plugins config opgelost (plugins.enabled verwijderd, alleen enabled_plugins op top-level) +- [x] Admin config — Analytics & Logging toggles verwijderd van config-pagina +- [x] Handleidingen gecontroleerd en bijgewerkt (20 bestanden NL+EN: configuratie, plugins, plugin-development, core-classes, theme-json, layouts, scss-styling, admin-beheerder, nieuw-thema, architectuur) +- [x] Content backup/restore optie + content-git repository integratie (ContentBackup class, content-backup.twig, ZIP backup/restore, git init/commit/log/restore) +- [x] Pentest controles uitgevoerd (30/30 tests geslaagd — 0 vulnerabilities) +- [x] WCAG 2.1 AA accessibility tests (25/25 tests geslaagd — 100% compliance, test-script verbeterd met min/max checks en grep -E) + +## v2.6.0 (2026-08-15) ✅ +- [x] Pentest controles uitgevoerd (30/30) +- [x] WCAG 2.1 AA accessibility tests (25/25) +- [x] Verslag gemaakt (docs/release-notes/v2.6.0.md) +- [x] Versie verhoogd naar 2.6.0 diff --git a/admin/src/AdminAuth.php b/admin/src/AdminAuth.php index a5fdf22..a1e862d 100644 --- a/admin/src/AdminAuth.php +++ b/admin/src/AdminAuth.php @@ -16,7 +16,7 @@ class AdminAuth */ public const ROLE_PERMISSIONS = [ 'admin' => ['*'], - 'content-manager' => ['dashboard', 'content', 'content-edit', 'content-new', 'content-delete', 'content-dir-create', 'content-dir-rename', 'content-dir-delete', 'content-move', 'guide', 'logout'], + 'content-manager' => ['dashboard', 'content', 'content-edit', 'content-new', 'content-delete', 'content-dir-create', 'content-dir-rename', 'content-dir-delete', 'content-move', 'content-backup', 'content-restore', 'content-git-init', 'content-git-commit', 'content-git-restore', 'guide', 'logout'], 'bi-manager' => ['dashboard', 'statistics', 'logs', 'guide', 'logout'], 'site-admin' => ['dashboard', 'theme', 'theme-new', 'plugins', 'plugins-new', 'plugins-edit', 'plugins-config', 'plugins-toggle', 'plugins-delete', 'statistics', 'logs', 'update', 'guide', 'logout'], ]; @@ -28,7 +28,7 @@ class AdminAuth 'admin' => 'Admin', 'content-manager' => 'Content Beheerder', 'bi-manager' => 'BI Beheerder', - 'site-admin' => ' Site Admin', + 'site-admin' => 'Site Admin', ]; public function __construct(array $appConfig) @@ -170,10 +170,19 @@ class AdminAuth if (!$this->isAuthenticated()) { return null; } - return [ - 'username' => $_SESSION['admin_user'], + $username = $_SESSION['admin_user']; + $userData = [ + 'username' => $username, 'role' => $_SESSION['admin_role'] ?? 'admin' ]; + // Enrich with profile fields from admin.json + $userEntry = $this->findUser($username); + if ($userEntry) { + $userData['email'] = $userEntry['email'] ?? ''; + $userData['author_name'] = $userEntry['author_name'] ?? ''; + $userData['author_email'] = $userEntry['author_email'] ?? ''; + } + return $userData; } /** @@ -244,13 +253,16 @@ class AdminAuth 'username' => $u['username'], 'role' => $role, 'role_label' => self::getRoleLabel($role), - 'created' => $u['created'] ?? '' + 'created' => $u['created'] ?? '', + 'email' => $u['email'] ?? '', + 'author_name' => $u['author_name'] ?? '', + 'author_email' => $u['author_email'] ?? '', ]; } return $users; } - public function addUser(string $username, string $password, string $role = 'admin'): array + public function addUser(string $username, string $password, string $role = 'admin', string $email = '', string $authorName = '', string $authorEmail = ''): array { if ($this->findUser($username)) { return ['success' => false, 'message' => 'Gebruiker bestaat al.']; @@ -266,6 +278,9 @@ class AdminAuth 'username' => $username, 'password_hash' => password_hash($password, PASSWORD_DEFAULT), 'role' => $role, + 'email' => $email, + 'author_name' => $authorName, + 'author_email' => $authorEmail, 'created' => date('Y-m-d') ]; $this->saveAdminConfig(); @@ -273,6 +288,24 @@ class AdminAuth return ['success' => true, 'message' => 'Gebruiker aangemaakt.']; } + /** + * Update the profile (email, author_name, author_email) of a user. + */ + public function updateUserProfile(string $username, string $email = '', string $authorName = '', string $authorEmail = ''): array + { + foreach ($this->adminConfig['users'] as &$userEntry) { + if ($userEntry['username'] === $username) { + $userEntry['email'] = $email; + $userEntry['author_name'] = $authorName; + $userEntry['author_email'] = $authorEmail; + $this->saveAdminConfig(); + $this->log('info', "Profiel bijgewerkt: {$username}"); + return ['success' => true, 'message' => 'Profiel opgeslagen.']; + } + } + return ['success' => false, 'message' => 'Gebruiker niet gevonden.']; + } + /** * Change the role of an existing user. */ diff --git a/admin/theme/default/views/layouts/admin.twig b/admin/theme/default/views/layouts/admin.twig index ab491cc..1417104 100644 --- a/admin/theme/default/views/layouts/admin.twig +++ b/admin/theme/default/views/layouts/admin.twig @@ -1,10 +1,9 @@ - + - {% block title %}CodePress Admin{% endblock %} - + {% block title %}{{ ta.admin_title|default('CodePress Admin') }}{% endblock %} @@ -38,109 +37,95 @@