Files
E.Noorlander 20adea7544 v2.6.0: Content backup/git versioning, plugin type system, docs update
New features:
- ContentBackup class with ZIP backup/restore and git versioning
- Admin backup & restore page (content-backup.twig) with git init/commit/log/restore
- Plugin type system: system (blue) vs content (green) with visual badges
- PluginAPIInterface + AdminPluginAPI for plugin architecture
- Essential plugin flag (cannot edit/deactivate/delete)

Improvements:
- Consolidated enabled_plugins config (removed plugins.enabled)
- Removed Analytics/Logging toggles from admin config page
- Fixed Dashboard plugin Twig comments rendered as text
- Updated 20 guide files (NL+EN): configuratie, plugins, plugin-development,
  core-classes, theme-json, layouts, scss-styling, admin-beheerder, nieuw-thema, architectuur
- Improved accessibility test script (grep -E, min/max checks)

Cleanup:
- Removed unused classes: ARIAComponents, AccessibilityManager, ContentSecurityPolicy, etc.
- Removed vendor packages: mustache/mustache, php-mqtt/client
- Removed old templates: logs.twig, statistics.twig (now plugins)
- Moved language files to language/ directory

Tests:
- Pentest: 30/30 passed, 0 vulnerabilities
- WCAG 2.1 AA: 25/25 passed, 100% compliance
2026-08-15 19:21:04 +02:00

128 lines
6.9 KiB
Twig

{% extends "layouts/admin.twig" %}
{% block title %}{{ ta.backup_restore|default('Backup & Restore') }} - {{ ta.admin_title|default('CodePress Admin') }}{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-archive"></i> {{ ta.backup_restore|default('Backup & Restore') }}</h2>
<a href="/admin/content" class="btn btn-outline-secondary btn-sm">
<i class="bi bi-arrow-left"></i> {{ ta.back_to_content|default('Terug naar content') }}
</a>
</div>
{% if message %}
<div class="alert alert-{{ message_type }} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endif %}
<div class="row g-4">
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-header"><i class="bi bi-file-zip"></i> {{ ta.zip_backup|default('ZIP Backup') }}</div>
<div class="card-body">
<p class="text-muted">{{ ta.zip_backup_help|default('Download de volledige content-map als ZIP bestand.') }}</p>
<form method="POST" action="/admin/content-backup">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="action" value="download_zip">
<button type="submit" class="btn btn-primary">
<i class="bi bi-download"></i> {{ ta.download_zip|default('Download ZIP') }}
</button>
</form>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card shadow-sm">
<div class="card-header"><i class="bi bi-upload"></i> {{ ta.restore_from_zip|default('Herstellen uit ZIP') }}</div>
<div class="card-body">
<p class="text-muted">{{ ta.restore_help|default('Upload een eerder gedownloade ZIP bestand om content te herstellen. De huidige content wordt eerst geback-upt.') }}</p>
<form method="POST" action="/admin/content-restore" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<div class="mb-3">
<label for="zipfile" class="form-label">{{ ta.select_zip|default('ZIP bestand selecteren') }}</label>
<input type="file" class="form-control" id="zipfile" name="zipfile" accept=".zip" required>
</div>
<button type="submit" class="btn btn-warning" onclick="return confirm('{{ ta.confirm_restore|default('Weet je zeker dat je de content wilt herstellen? Huidige content wordt geback-upt.') }}')">
<i class="bi bi-arrow-counterclockwise"></i> {{ ta.restore|default('Herstellen') }}
</button>
</form>
</div>
</div>
</div>
</div>
<hr class="my-4">
<div class="card shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<span><i class="bi bi-git"></i> {{ ta.git_versioning|default('Git Versioning') }}</span>
{% if git_available and not has_git_repo %}
<form method="POST" action="/admin/content-git-init" class="d-inline">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<button type="submit" class="btn btn-sm btn-outline-success">
<i class="bi bi-check2-circle"></i> {{ ta.git_init|default('Git init') }}
</button>
</form>
{% endif %}
</div>
<div class="card-body">
{% if not git_available %}
<div class="alert alert-secondary mb-0">
<i class="bi bi-info-circle"></i> {{ ta.git_not_available|default('Git is niet beschikbaar op deze server. Gebruik de ZIP backup/restore opties hierboven.') }}
</div>
{% elseif not has_git_repo %}
<div class="alert alert-info mb-0">
<i class="bi bi-info-circle"></i> {{ ta.git_not_initialized|default('Geen git repository in content/. Klik op "Git init" om versiebeheer te starten.') }}
</div>
{% else %}
<form method="POST" action="/admin/content-git-commit" class="mb-4">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<div class="input-group">
<input type="text" class="form-control" name="commit_message" placeholder="{{ ta.commit_message_placeholder|default('Commit bericht...') }}" maxlength="200">
<button type="submit" class="btn btn-success">
<i class="bi bi-check-lg"></i> {{ ta.commit|default('Commit') }}
</button>
</div>
</form>
{% if git_commits is empty %}
<p class="text-muted">{{ ta.no_commits|default('Nog geen commits. Maak een eerste commit aan.') }}</p>
{% else %}
<div class="table-responsive">
<table class="table table-sm table-hover">
<thead>
<tr>
<th>{{ ta.commit_short|default('Commit') }}</th>
<th>{{ ta.date|default('Datum') }}</th>
<th>{{ ta.message|default('Bericht') }}</th>
<th>{{ ta.actions|default('Acties') }}</th>
</tr>
</thead>
<tbody>
{% for commit in git_commits %}
<tr>
<td><code>{{ commit.short }}</code></td>
<td class="text-muted small">{{ commit.date }}</td>
<td>{{ commit.message }}</td>
<td>
<form method="POST" action="/admin/content-git-restore" class="d-inline" onsubmit="return confirm('{{ ta.confirm_git_restore|default('Weet je zeker dat je de content wilt herstellen naar deze commit?') }}')">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="commit" value="{{ commit.hash }}">
<button type="submit" class="btn btn-sm btn-outline-warning" title="{{ ta.restore_this|default('Herstellen naar deze commit') }}">
<i class="bi bi-arrow-counterclockwise"></i>
</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endif %}
</div>
</div>
{% endblock %}