This commit is contained in:
2026-02-04 23:31:53 +01:00
commit cd59ccd99b
2401 changed files with 56808 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
<?php
/**
* @var array $values
* @var string|null $formId
* @var bool $detailsOpenAll
* @var bool $isReadOnly
*/
use MintyPHP\Session;
$values = $values ?? [];
$formId = $formId ?? 'permission-form';
$detailsOpenAll = $detailsOpenAll ?? false;
$isReadOnly = $isReadOnly ?? false;
$detailsOpenAttr = $detailsOpenAll ? 'open' : '';
$readonlyAttr = $isReadOnly ? 'readonly' : '';
?>
<form id="<?php e($formId); ?>" method="post">
<details name="basic-data" <?php e($detailsOpenAttr); ?>>
<summary>Stammdaten</summary>
<hr>
<div class="grid">
<label for="permission-description">
<span><?php e(t('Description')); ?></span>
<input type="text" name="description" id="permission-description"
value="<?php e($values['description'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
<label for="permission-key">
<span><?php e(t('Permission key')); ?></span>
<input required type="text" name="key" id="permission-key" value="<?php e($values['key'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
</div>
</details>
<hr>
<?php Session::getCsrfInput(); ?>
</form>

View File

@@ -0,0 +1,42 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::PERMISSIONS_CREATE);
$errors = [];
$form = [
'key' => '',
'description' => '',
];
if (isset($_POST['key'])) {
$result = PermissionService::createFromAdmin($_POST);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
if ($result['ok'] ?? false) {
$action = (string) ($_POST['action'] ?? 'create');
if ($action === 'create_close') {
Flash::success('Permission created', 'admin/permissions', 'permission_created');
Router::redirect('admin/permissions');
} else {
$id = (int) ($result['id'] ?? 0);
if ($id > 0) {
$target = "admin/permissions/edit/{$id}";
Flash::success('Permission created', $target, 'permission_created');
Router::redirect($target);
} else {
Flash::success('Permission created', 'admin/permissions', 'permission_created');
Router::redirect('admin/permissions');
}
}
}
}
Buffer::set('title', t('Create permission'));

View File

@@ -0,0 +1,44 @@
<?php
/**
* @var array<int, string> $errors
* @var array $form
*/
?>
<div class="app-details-container">
<section>
<div class="app-breadcrumb">
<a href="/admin">Startseite</a><i class="bi bi-chevron-right"></i><a
href="/admin/permissions"><?php e(t('Permissions')); ?></a><i class="bi bi-chevron-right"></i><?php e(t('Create permission')); ?>
</div>
<div class="app-details-titlebar">
<h1>
<a href="admin/permissions" title="<?php e(t('Cancel')); ?>"><i class="bi bi-arrow-left"></i></a>
<?php e(t('Create permission')); ?>
</h1>
<div class="app-details-titlebar-actions">
<button type="submit" form="permission-form" name="action" value="create" class="secondary outline">
<?php e(t('Create')); ?>
</button>
<button type="submit" form="permission-form" name="action" value="create_close" class="primary">
<?php e(t('Create & close')); ?>
</button>
</div>
</div>
<?php if (!empty($errors)): ?>
<div class="notice" data-variant="error">
<ul>
<?php foreach ($errors as $error): ?>
<li><?php e($error); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php
$values = $form ?? [];
$detailsOpenAll = true;
require __DIR__ . '/_form.phtml';
?>
</section>
</div>

View File

@@ -0,0 +1,41 @@
<?php
use MintyPHP\Router;
use MintyPHP\Support\Guard;
use MintyPHP\Service\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::PERMISSIONS_VIEW);
if (!isset($_SESSION['user'])) {
http_response_code(401);
Router::json(['data' => [], 'total' => 0]);
}
$limit = (int) ($_GET['limit'] ?? 10);
$offset = (int) ($_GET['offset'] ?? 0);
$search = trim((string) ($_GET['search'] ?? ''));
$order = (string) ($_GET['order'] ?? 'key');
$dir = (string) ($_GET['dir'] ?? 'asc');
$result = PermissionService::listPaged([
'limit' => $limit,
'offset' => $offset,
'search' => $search,
'order' => $order,
'dir' => $dir,
]);
$rows = [];
foreach ($result['data'] ?? [] as $row) {
$rows[] = [
'id' => $row['id'] ?? null,
'key' => $row['key'] ?? '',
'description' => $row['description'] ?? '',
'created' => dt($row['created'] ?? ''),
];
}
Router::json([
'data' => $rows,
'total' => $result['total'] ?? 0,
]);

View File

@@ -0,0 +1,23 @@
<?php
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Service\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::PERMISSIONS_DELETE);
$id = (int) ($id ?? 0);
if ($id <= 0) {
Router::redirect('admin/permissions');
}
$result = PermissionService::deleteById($id);
if (!($result['ok'] ?? false)) {
Flash::error('Permission not found', 'admin/permissions', 'permission_not_found');
Router::redirect('admin/permissions');
}
Flash::success('Permission deleted', 'admin/permissions', 'permission_deleted');
Router::redirect('admin/permissions');

View File

@@ -0,0 +1,64 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
use MintyPHP\Router;
use MintyPHP\Repository\RolePermissionRepository;
use MintyPHP\Repository\RoleRepository;
use MintyPHP\Service\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::PERMISSIONS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
}
$id = (int) ($id ?? 0);
$permission = $id > 0 ? PermissionService::find($id) : null;
if (!$permission) {
Flash::error('Permission not found', 'admin/permissions', 'permission_not_found');
Router::redirect('admin/permissions');
}
$errors = [];
$form = $permission;
$roles = RoleRepository::list();
$selectedRoleIds = RolePermissionRepository::listRoleIdsByPermissionId($id);
if (isset($_POST['key'])) {
if (!PermissionService::userHas($currentUserId, PermissionService::PERMISSIONS_UPDATE)) {
Flash::error('Permission denied', "admin/permissions/edit/{$id}", 'permission_denied');
Router::redirect("admin/permissions/edit/{$id}");
return;
}
$result = PermissionService::updateFromAdmin($id, $_POST);
$form = $result['form'] ?? $form;
$errors = $result['errors'] ?? [];
$selectedRoleIds = $_POST['role_ids'] ?? $selectedRoleIds;
if (!is_array($selectedRoleIds)) {
$selectedRoleIds = [$selectedRoleIds];
}
$selectedRoleIds = array_values(array_unique(array_map('intval', $selectedRoleIds)));
if ($result['ok'] ?? false) {
$roleIds = $_POST['role_ids'] ?? [];
if (!is_array($roleIds)) {
$roleIds = [$roleIds];
}
$roleIds = array_values(array_unique(array_map('intval', $roleIds)));
RolePermissionRepository::replaceForPermission($id, $roleIds);
$action = (string) ($_POST['action'] ?? 'save');
if ($action === 'save_close') {
Flash::success('Permission updated', 'admin/permissions', 'permission_updated');
Router::redirect('admin/permissions');
} else {
Flash::success('Permission updated', "admin/permissions/edit/{$id}", 'permission_updated');
Router::redirect("admin/permissions/edit/{$id}");
}
}
}
Buffer::set('title', t('Edit permission'));

View File

@@ -0,0 +1,79 @@
<?php
/**
* @var array<int, string> $errors
* @var array $form
* @var array $permission
*/
?>
<div class="app-details-container">
<section>
<div class="app-breadcrumb">
<a href="/admin">Startseite</a><i class="bi bi-chevron-right"></i><a
href="/admin/permissions"><?php e(t('Permissions')); ?></a><i
class="bi bi-chevron-right"></i><?php e(t('Edit permission')); ?>
</div>
<div class="app-details-titlebar">
<h1>
<a href="admin/permissions" title="<?php e(t('Cancel')); ?>"><i class="bi bi-arrow-left"></i></a>
<?php e(t('Edit permission')); ?>
</h1>
<div class="app-details-titlebar-actions">
<?php if (can('permissions.delete')): ?>
<details class="dropdown">
<summary role="button" class="outline secondary"><i class="bi bi-three-dots"></i></summary>
<ul dir="rtl">
<li>
<form method="post" action="admin/permissions/delete/<?php e((string) ($permission['id'] ?? '')); ?>"
onsubmit="return confirm('<?php e(t('Delete this permission?')); ?>');">
<?php MintyPHP\Session::getCsrfInput(); ?>
<button type="submit" class="transparent">
<?php e(t('Delete')); ?>
</button>
</form>
</li>
</ul>
</details>
<?php endif; ?>
<?php if (can('permissions.update')): ?>
<button type="submit" form="permission-form" name="action" value="save" class="secondary outline">
<?php e(t('Save')); ?>
</button>
<button type="submit" form="permission-form" name="action" value="save_close" class="primary">
<?php e(t('Save & close')); ?>
</button>
<?php endif; ?>
</div>
</div>
<?php if (!empty($errors)): ?>
<div class="notice" data-variant="error">
<ul>
<?php foreach ($errors as $error): ?>
<li><?php e($error); ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<?php
$values = $form ?? $permission ?? [];
$isReadOnly = !can('permissions.update');
$detailsOpenAll = true;
$isReadOnly = $isReadOnly ?? false;
require __DIR__ . '/_form.phtml';
?>
</section>
<aside id="app-details-aside-section">
<div class="app-details-aside-section">
<hgroup>
<h2><?php e($values['key'] ?? ''); ?></h2>
<p><?php e(t('Permission')); ?></p>
</hgroup>
<hr>
<?php if (!empty($roles)): ?>
<?php multiSelectForm('permission-roles', 'role_ids', 'Assigned roles', 'Select roles', $roles, $selectedRoleIds ?? [], $isReadOnly, 'description', 'permission-form'); ?>
<?php endif; ?>
</div>
</aside>
</div>

View File

@@ -0,0 +1,23 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Support\Guard;
use MintyPHP\Session;
use MintyPHP\Service\PermissionService;
Guard::requireLogin();
Guard::requirePermission(PermissionService::PERMISSIONS_VIEW);
$currentUserId = (int) ($_SESSION['user']['id'] ?? 0);
if ($currentUserId > 0) {
PermissionService::getUserPermissions($currentUserId);
}
Buffer::set('title', t('Permissions'));
Buffer::set('grid_lang', json_encode(gridLang(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$csrfKey = Session::$csrfSessionKey;
$csrfToken = $_SESSION[$csrfKey] ?? '';
Buffer::set(
'grid_csrf',
json_encode(['key' => $csrfKey, 'token' => $csrfToken], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);

View File

@@ -0,0 +1,121 @@
<?php
use MintyPHP\Router;
$canCreatePermissions = can('permissions.create');
$canUpdatePermissions = can('permissions.update');
$canDeletePermissions = can('permissions.delete');
?>
<div class="app-breadcrumb">
<a href="/admin">Startseite</a><i class="bi bi-chevron-right"></i><?php e(t('Permissions')); ?>
</div>
<div class="app-list-titlebar">
<h1><?php e(t('Permissions')); ?></h1>
<div class="app-list-titlebar-actions">
<button
class="outline secondary"
type="button"
data-toolbar-toggle
data-toolbar-target="#permissions-toolbar"
data-toolbar-text-show="<?php e(t('Show filters')); ?>"
data-toolbar-text-hide="<?php e(t('Hide filters')); ?>"
>
<i class="bi bi-funnel-fill"></i> <span data-toolbar-label><?php e(t('Hide filters')); ?></span>
</button>
<?php if ($canCreatePermissions): ?>
<a role="button" class="primary" href="admin/permissions/create">
<i class="bi bi-plus"></i> <?php e(t('Create permission')); ?>
</a>
<?php endif; ?>
</div>
</div>
<div class="app-list-toolbar" id="permissions-toolbar">
<input type="search" id="permission-search" placeholder="<?php e(t('Search...')); ?>">
</div>
<div class="app-list-table">
<div id="permissions-grid"></div>
</div>
<?php $gridFactoryVersion = @filemtime('web/js/core/app-grid-factory.js') ?: time(); ?>
<script src="<?php e(asset('vendor/gridjs/gridjs.umd.js')); ?>"></script>
<script type="module">
import { initToolbarToggles } from "<?php e(asset('js/components/app-toggle-toolbar.js')); ?>";
import { createServerGrid } from "<?php e(asset('js/core/app-grid-factory.js?v=' . $gridFactoryVersion)); ?>";
import { buildUrl, postAction, badgeHtml } from "<?php e(asset('js/pages/app-list-utils.js')); ?>";
initToolbarToggles();
const appBase = "<?php e(localeBase()); ?>";
const csrf = <?php MintyPHP\Buffer::get('grid_csrf'); ?>;
const deleteConfirm = "<?php e(t('Delete this permission?')); ?>";
const buildActionUrl = (action, id) => buildUrl(appBase, `admin/permissions/${action}/${id}`);
const initPermissionsGrid = () => {
const gridConfig = createServerGrid({
gridjs: window.gridjs,
container: '#permissions-grid',
dataUrl: 'admin/permissions/data',
appBase,
columns: [
{ name: "<?php e(t('Description')); ?>", sort: true },
{ name: "<?php e(t('Permission key')); ?>", sort: true },
{ name: "<?php e(t('Created')); ?>", sort: true, formatter: (cell) => badgeHtml(gridjs, cell) },
{ name: 'ID', hidden: true }
],
sortColumns: ['description', 'key', 'created', null],
paginationLimit: 10,
language: <?php MintyPHP\Buffer::get('grid_lang'); ?>,
mapData: (data) => data.data.map((row) => [
row.description,
row.key,
row.created,
row.id
]),
actions: {
enabled: true,
label: "<?php e(t('Actions')); ?>",
getRowId: (row) => row?.cells?.[3]?.data,
items: [
{
key: 'edit',
type: 'link',
label: "<i class=\"bi bi-pencil-fill\"></i>",
href: ({ id }) => buildActionUrl('edit', id)
},
<?php if ($canDeletePermissions): ?>
{
key: 'delete',
label: "<i class=\"bi bi-trash3-fill\"></i>",
className: 'danger outline',
confirm: deleteConfirm
}
<?php endif; ?>
],
onAction: async ({ action, id, grid }) => {
if (action !== 'delete') return;
const url = buildActionUrl('delete', id);
const response = await postAction(url, csrf);
if (response.ok) {
grid.forceRender();
} else {
window.location.href = new URL('admin/permissions', appBase).toString();
}
}
},
rowDblClick: {
getUrl: (row) => {
const id = row?.cells?.[3]?.data;
return id ? buildActionUrl('edit', id) : '';
}
},
search: {
input: '#permission-search',
param: 'search',
debounce: 250
}
});
return gridConfig;
};
initPermissionsGrid();
</script>