// site/models/role-manager.php
use Kirby\Cms\Page;
use Kirby\Http\Response;
class RoleManagerPage extends Page
{
/**
* Gathers all permissions from all urole pages and returns them
* as a downloadable JSON file.
*/
public function backupRoles()
{
// --- DEBUGGING TEST ---
// If this method is being called, the script will stop and show this message.
die('SUCCESS: The backupRoles() method was called.');
$backupData = [];
// Find all children of this page that use the 'urole' template.
$rolePages = $this->children()->filterBy('intendedTemplate', 'urole');
// Loop through each role page to gather its rules.
foreach ($rolePages as $rolePage) {
$roleId = $rolePage->slug();
$rules = $rolePage->rules()->toStructure();
// Prepare the data for this role, converting structure items to arrays.
$backupData[$roleId] = $rules->map(function ($rule) {
return [
'permission_name' => $rule->permission_name()->value(),
'scope_type' => $rule->scope_type()->value(),
'scope_target_text' => $rule->scope_target_text()->value(),
'scope_target_page' => $rule->scope_target_page()->yaml(), // Store as YAML for easy import
'allowed' => $rule->allowed()->value(),
];
})->data();
}
// Generate a filename with the current date.
$filename = 'padeltime-permissions-backup-' . date('Y-m-d') . '.json';
// Use Kirby's Response class to force a file download.
return Response::download(json_encode($backupData, JSON_PRETTY_PRINT), $filename);
}
}
not yet as I have not figured out a way to make the current vue viewbutton code of janitor aware of the model (aka do queries). the field can get parameters a bit easier. but i am planing to add that eventually.
This partially worked but it returned a black browser screen with the json succes message while my models function was executed and the backups were present…
To clarify, my custom backup button makes a backup of some files.
Second setup:
Use js to call the route, this works but i’d rather not use this and call my models function from within my .yml file and display an informational after execution of the function. If you’ve got a better idea feel free…
code below:
in .yml
buttons:
status: true
mybbakupbtn:
icon: download
text: Backup Roles
# THE FIX: We give the button an ID for our JavaScript to find.
# The link is a dummy link to make it render as a button.
id: backup-permissions-button
link: "#"
my plugin index.php with the api registration:
'api' => [
'routes' => [
// Route for the backup functionality
[
'pattern' => 'backup',
'auth' => false,
'action' => function () {
// Check if a user is logged into the panel before proceeding.
if (!kirby()->user()) {
return ['status' => 'error', 'message' => 'Authentication required.'];
}
$roleManagerPage = page('role-manager');
if ($roleManagerPage) {
return $roleManagerPage->backupRoles();
}
return null;
}
]
]
],
in my model:
<?php
use Kirby\Cms\Page;
use Kirby\Toolkit\F;
class RoleManagerPage extends Page
{
public function backupRoles()
{
$backupData = [];
$backupDir = kirby()->root('site') . '/backups/permissions';
$filename = 'permissions-backup-' . date('Y-m-d-His') . '.json';
$filePath = $backupDir . '/' . $filename;
$json = json_encode($backupData, JSON_PRETTY_PRINT);
try {
Dir::make($backupDir);
if (F::write($filePath, $json) === true) {
return [
'status' => 'ok',
'message' => 'Backup created successfully at: ' . $filePath
];
} else {
throw new Exception('The backup file could not be written.');
}
} catch (Exception $e) {
return [
'status' => 'error',
'message' => $e->getMessage()
];
}
}
}
my js:
async function handleBackup(event) {
event.preventDefault();
if (confirm("Do you really want to create a new permission backup on the server?")) {
try {
const response = await fetch('/api/backup');
const result = await response.json();
if (response.ok && result.status === 'ok') {
panel.notification.success(result.message);
panel.view.reload();
} else {
panel.notification.error(result.message || "An unknown error occurred.");
}
} catch (error) {
panel.notification.error("Failed to connect to the backup API.");
}
}
}
document.body.addEventListener('click', function(event) {
if (event.target.closest('#backup-permissions-button')) {
handleBackup(event);
}
});