page update

This commit is contained in:
2026-03-12 14:09:06 +01:00
parent 17a72af5f2
commit 0b9014dcbf
17 changed files with 634 additions and 196 deletions

View File

@@ -104,6 +104,43 @@ $ssoStatusTiles = [
'tone' => $ssoCredentialSource === 'shared' ? 'info' : 'neutral',
],
];
$allowedDomainsList = preg_split('/[\s,;]+/', strtolower($allowedDomains), -1, PREG_SPLIT_NO_EMPTY);
$allowedDomainsList = is_array($allowedDomainsList) ? array_values(array_unique($allowedDomainsList)) : [];
$allowedDomainsCount = count($allowedDomainsList);
$syncFieldCount = count($syncProfileFields);
$ssoSetupBadgeVariant = $microsoftEnabled ? 'success' : 'neutral';
$ssoSetupBadgeLabel = sprintf(
'%s: %s',
t('Microsoft login'),
$microsoftEnabled ? t('Active') : t('Inactive')
);
$ssoShowConfigBadge = $microsoftEnabled;
$ssoConfigBadgeVariant = $microsoftEnabled ? ($ssoConfigComplete ? 'success' : 'warning') : 'neutral';
$ssoConfigBadgeLabel = sprintf(
'%s: %s',
t('Configuration status'),
$ssoConfigComplete ? t('Complete') : t('Incomplete')
);
$ssoPolicyBadgeVariant = match ($ssoPasswordMode) {
'microsoft_only' => 'warning',
'local_and_microsoft' => 'info',
default => 'neutral',
};
$ssoSyncBadgeVariant = $syncProfileOnLogin ? 'info' : 'neutral';
$ssoSyncBadgeLabel = $syncProfileOnLogin ? t('Active') : t('Inactive');
$ssoDomainsBadgeVariant = $allowedDomainsCount > 0 ? 'info' : 'neutral';
$ssoDomainsBadgeLabel = $allowedDomainsCount > 0
? sprintf('%d %s', $allowedDomainsCount, t('Allowed email domains'))
: t('No domain restrictions');
$ssoCredentialsBadgeVariant = $ssoCredentialSource === 'shared' ? 'info' : 'warning';
$ssoCredentialsBadgeLabel = $ssoCredentialSourceLabel;
$openSetupCard = $detailsOpenAll || !$microsoftEnabled || ($microsoftEnabled && !$ssoConfigComplete);
$openPolicyCard = $detailsOpenAll || ($microsoftEnabled && $microsoftEnforce);
$openAccessCard = $detailsOpenAll || ($microsoftEnabled && ($allowedDomainsCount > 0 || $syncProfileOnLogin));
$openOverrideCard = $detailsOpenAll;
?>
<form id="<?php e($formId); ?>" method="post" data-standard-detail-form="1">
@@ -446,137 +483,188 @@ $ssoStatusTiles = [
?>
<?php endforeach; ?>
</div>
<?php if ($microsoftEnabled && !$ssoConfigComplete && $ssoConfigErrorLabel !== ''): ?>
<small class="muted"><?php e($ssoConfigErrorLabel); ?></small>
<?php if ($microsoftEnabled && !$ssoConfigComplete): ?>
<blockquote data-variant="warning">
<strong><?php e(t('SSO setup is incomplete')); ?></strong><br>
<?php if ($ssoConfigErrorLabel !== ''): ?>
<?php e($ssoConfigErrorLabel); ?>
<?php else: ?>
<?php e(t('Complete the required Microsoft configuration before enforcing Microsoft-only login.')); ?>
<?php endif; ?>
</blockquote>
<?php endif; ?>
<fieldset>
<legend><small><?php e(t('Required Microsoft configuration')); ?></small></legend>
<label class="app-field">
<input
type="checkbox"
role="switch"
name="microsoft_enabled"
value="1"
data-tenant-sso-enabled
<?php e($microsoftEnabled ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Enable Microsoft login for this tenant')); ?></span>
</label>
<small class="muted"><?php e(t('Required for Microsoft login.')); ?></small>
<hr>
<label>
<span><?php e(t('Entra tenant ID (tid)')); ?></span>
<input
type="text"
name="entra_tenant_id"
value="<?php e($entraTenantId); ?>"
placeholder="00000000-0000-0000-0000-000000000000"
<?php e($readonlyAttr); ?>>
</label>
<label class="app-field">
<input
type="checkbox"
role="switch"
name="enforce_microsoft_login"
value="1"
<?php e($microsoftEnforce ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Disable password login for this tenant login')); ?></span>
</label>
<small class="muted"><?php e(t('Microsoft-only login requires a complete configuration')); ?></small>
</fieldset>
<fieldset data-tenant-sso-when-enabled>
<legend><small><?php e(t('Optional restrictions')); ?></small></legend>
<label>
<span><?php e(t('Allowed email domains')); ?></span>
<textarea name="allowed_domains" rows="3" placeholder="example.com&#10;partner.com" <?php e($readonlyAttr); ?>><?php e($allowedDomains); ?></textarea>
<small><?php e(t('Optional allow-list, comma or newline separated (example.com).')); ?></small>
</label>
</fieldset>
<fieldset data-tenant-sso-when-enabled>
<legend><small><?php e(t('Login persistence')); ?></small></legend>
<label class="app-field">
<span><?php e(t('Microsoft Auto-Remember')); ?></span>
<select name="microsoft_auto_remember_mode" <?php e($readonlyAttr); ?>>
<option value="inherit" <?php if (($form['auto_remember_mode'] ?? null) === null) echo 'selected'; ?>><?php e(t('Inherit global default')); ?></option>
<option value="1" <?php if (($form['auto_remember_mode'] ?? null) === 1 || ($form['auto_remember_mode'] ?? null) === '1') echo 'selected'; ?>><?php e(t('Force on')); ?></option>
<option value="0" <?php if (($form['auto_remember_mode'] ?? null) === 0 || ($form['auto_remember_mode'] ?? null) === '0') echo 'selected'; ?>><?php e(t('Force off')); ?></option>
</select>
<small class="muted"><?php e(t('Controls whether Microsoft logins automatically persist a remember-me token.')); ?></small>
</label>
</fieldset>
<fieldset data-tenant-sso-when-enabled>
<legend><small><?php e(t('Profile sync (optional)')); ?></small></legend>
<label class="app-field">
<input
type="checkbox"
role="switch"
name="sync_profile_on_login"
value="1"
data-tenant-sso-sync-toggle
<?php e($syncProfileOnLogin ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Profile sync on Microsoft login')); ?></span>
</label>
<small class="muted"><?php e(t('User profile fields are global and affect all tenants of this user')); ?></small>
<div data-tenant-sso-sync-fields>
<hr>
<label><span><?php e(t('Sync fields')); ?></span></label>
<div class="grid grid-1-1">
<?php foreach ($syncFieldOptions as $syncFieldKey => $syncFieldLabel): ?>
<label class="app-field">
<input
type="checkbox"
name="sync_profile_fields[]"
value="<?php e($syncFieldKey); ?>"
<?php e(in_array($syncFieldKey, $syncProfileFields, true) ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t($syncFieldLabel)); ?></span>
</label>
<?php endforeach; ?>
</div>
<?php if ($ssoSyncNeedsGraph): ?>
<details class="app-details-card" name="tenant-sso-setup" <?php e($openSetupCard ? 'open' : ''); ?>>
<summary>
<span class="app-details-card-summary-title"><?php e(t('Required Microsoft configuration')); ?></span>
<span class="app-details-card-summary-meta">
<span class="badge" data-variant="<?php e($ssoSetupBadgeVariant); ?>"><?php e($ssoSetupBadgeLabel); ?></span>
<?php if ($ssoShowConfigBadge): ?>
<span class="badge" data-variant="<?php e($ssoConfigBadgeVariant); ?>"><?php e($ssoConfigBadgeLabel); ?></span>
<?php endif; ?>
</span>
</summary>
<div class="app-details-card-container">
<label class="app-field">
<input
type="checkbox"
role="switch"
name="microsoft_enabled"
value="1"
data-tenant-sso-enabled
<?php e($microsoftEnabled ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Enable Microsoft login for this tenant')); ?></span>
</label>
<small class="muted"><?php e(t('Required for Microsoft login.')); ?></small>
<div data-tenant-sso-when-enabled>
<hr>
<small class="muted"><?php e(t('Phone/mobile/avatar sync requires Microsoft Graph (User.Read)')); ?></small>
<?php endif; ?>
<label>
<span><?php e(t('Entra tenant ID (tid)')); ?></span>
<input
type="text"
name="entra_tenant_id"
value="<?php e($entraTenantId); ?>"
placeholder="00000000-0000-0000-0000-000000000000"
<?php e($readonlyAttr); ?>>
</label>
</div>
</div>
</fieldset>
</details>
<details data-tenant-sso-override-details data-remember-state="admin-tenant-sso-override">
<summary><?php e(t('Advanced app override')); ?></summary>
<hr>
<label class="app-field" data-tenant-sso-when-enabled>
<input type="hidden" name="use_shared_app" value="0">
<input
type="checkbox"
role="switch"
name="use_shared_app"
value="1"
data-tenant-sso-shared-toggle
<?php e($useSharedApp ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Use shared app credentials from settings')); ?></span>
</label>
<small class="muted"><?php e(t('Override only if this tenant needs a separate Entra app.')); ?></small>
<div class="grid" data-tenant-sso-override-fields>
<label>
<span><?php e(t('Client ID override')); ?></span>
<input type="text" name="client_id_override" value="<?php e($clientIdOverride); ?>" <?php e($readonlyAttr); ?>>
<details class="app-details-card" name="tenant-sso-policy" data-tenant-sso-when-enabled <?php e($openPolicyCard ? 'open' : ''); ?>>
<summary>
<span class="app-details-card-summary-title"><?php e(t('Login policy')); ?></span>
<span class="app-details-card-summary-meta">
<span class="badge" data-variant="<?php e($ssoPolicyBadgeVariant); ?>"><?php e($ssoPasswordModeLabel); ?></span>
</span>
</summary>
<div class="app-details-card-container">
<label class="app-field">
<input
type="checkbox"
role="switch"
name="enforce_microsoft_login"
value="1"
<?php e($microsoftEnforce ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Allow Microsoft-only login (disable local password login)')); ?></span>
</label>
<label>
<span><?php e(t('Client secret override')); ?></span>
<input type="password" name="client_secret_override" value="" autocomplete="new-password" <?php e($readonlyAttr); ?>>
<small><?php e(t('Write-only. Leave empty to keep current secret.')); ?></small>
<small class="muted"><?php e(t('Microsoft-only login requires a complete configuration')); ?></small>
<hr>
<label class="app-field">
<span><?php e(t('Remember login after Microsoft sign-in')); ?></span>
<select name="microsoft_auto_remember_mode" <?php e($readonlyAttr); ?>>
<option value="inherit" <?php if (($form['auto_remember_mode'] ?? null) === null) echo 'selected'; ?>><?php e(t('Inherit global default')); ?></option>
<option value="1" <?php if (($form['auto_remember_mode'] ?? null) === 1 || ($form['auto_remember_mode'] ?? null) === '1') echo 'selected'; ?>><?php e(t('Force on')); ?></option>
<option value="0" <?php if (($form['auto_remember_mode'] ?? null) === 0 || ($form['auto_remember_mode'] ?? null) === '0') echo 'selected'; ?>><?php e(t('Force off')); ?></option>
</select>
<small class="muted"><?php e(t('Controls whether Microsoft logins automatically persist a remember-me token.')); ?></small>
</label>
</div>
</details>
<details class="app-details-card" name="tenant-sso-access-sync" data-tenant-sso-when-enabled <?php e($openAccessCard ? 'open' : ''); ?>>
<summary>
<span class="app-details-card-summary-title"><?php e(t('Access and profile sync')); ?></span>
<span class="app-details-card-summary-meta">
<span class="badge" data-variant="<?php e($ssoDomainsBadgeVariant); ?>"><?php e($ssoDomainsBadgeLabel); ?></span>
<span class="badge" data-variant="<?php e($ssoSyncBadgeVariant); ?>">
<?php e(t('Profile sync')); ?>: <?php e($ssoSyncBadgeLabel); ?>
</span>
<?php if ($syncProfileOnLogin): ?>
<span class="badge" data-variant="info">
<?php e(t('Sync fields')); ?>: <?php e((string) $syncFieldCount); ?>
</span>
<?php endif; ?>
</span>
</summary>
<div class="app-details-card-container">
<label>
<span><?php e(t('Allowed email domains')); ?></span>
<textarea name="allowed_domains" rows="3" placeholder="example.com&#10;partner.com" <?php e($readonlyAttr); ?>><?php e($allowedDomains); ?></textarea>
<small><?php e(t('Optional allow-list, comma or newline separated (example.com).')); ?></small>
</label>
<hr>
<label class="app-field">
<input
type="checkbox"
role="switch"
name="sync_profile_on_login"
value="1"
data-tenant-sso-sync-toggle
<?php e($syncProfileOnLogin ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Profile sync on Microsoft login')); ?></span>
</label>
<small class="muted"><?php e(t('User profile fields are global and affect all tenants of this user')); ?></small>
<div data-tenant-sso-sync-fields>
<hr>
<label><span><?php e(t('Sync fields')); ?></span></label>
<div class="grid grid-1-1">
<?php foreach ($syncFieldOptions as $syncFieldKey => $syncFieldLabel): ?>
<label class="app-field">
<input
type="checkbox"
name="sync_profile_fields[]"
value="<?php e($syncFieldKey); ?>"
<?php e(in_array($syncFieldKey, $syncProfileFields, true) ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t($syncFieldLabel)); ?></span>
</label>
<?php endforeach; ?>
</div>
<?php if ($ssoSyncNeedsGraph): ?>
<hr>
<small class="muted"><?php e(t('Phone/mobile/avatar sync requires Microsoft Graph (User.Read)')); ?></small>
<?php endif; ?>
</div>
</div>
</details>
<details
class="app-details-card"
name="tenant-sso-advanced"
data-tenant-sso-override-details
data-tenant-sso-when-enabled
data-remember-state="admin-tenant-sso-override"
<?php e($openOverrideCard ? 'open' : ''); ?>>
<summary>
<span class="app-details-card-summary-title"><?php e(t('App credentials (advanced)')); ?></span>
<span class="app-details-card-summary-meta">
<span class="badge" data-variant="<?php e($ssoCredentialsBadgeVariant); ?>"><?php e($ssoCredentialsBadgeLabel); ?></span>
</span>
</summary>
<div class="app-details-card-container">
<label class="app-field">
<input type="hidden" name="use_shared_app" value="0">
<input
type="checkbox"
role="switch"
name="use_shared_app"
value="1"
data-tenant-sso-shared-toggle
<?php e($useSharedApp ? 'checked' : ''); ?>
<?php e($disabledAttr); ?>>
<span><?php e(t('Use shared app credentials from settings')); ?></span>
</label>
<small class="muted"><?php e(t('Override only if this tenant needs a separate Entra app.')); ?></small>
<div class="grid" data-tenant-sso-override-fields>
<label>
<span><?php e(t('Client ID override')); ?></span>
<input type="text" name="client_id_override" value="<?php e($clientIdOverride); ?>" <?php e($readonlyAttr); ?>>
</label>
<label>
<span><?php e(t('Client secret override')); ?></span>
<input type="password" name="client_secret_override" value="" autocomplete="new-password" <?php e($readonlyAttr); ?>>
<small><?php e(t('Write-only. Leave empty to keep current secret.')); ?></small>
</label>
</div>
<label class="app-field" data-tenant-sso-override-fields>
<input type="checkbox" name="clear_client_secret_override" value="1" <?php e($disabledAttr); ?>>
<span><?php e(t('Clear override secret')); ?></span>
</label>
</div>
<label class="app-field" data-tenant-sso-override-fields>
<input type="checkbox" name="clear_client_secret_override" value="1" <?php e($disabledAttr); ?>>
<span><?php e(t('Clear override secret')); ?></span>
</label>
</details>
</div>
<?php endif; ?>
@@ -698,4 +786,4 @@ $ssoStatusTiles = [
<?php Session::getCsrfInput(); ?>
</form>
<?php endforeach; ?>
<?php endif; ?>
<?php endif; ?>

View File

@@ -4,6 +4,8 @@ use MintyPHP\Http\Request;
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\I18n;
use MintyPHP\Router;
use MintyPHP\Service\Access\SettingsAuthorizationPolicy;
use MintyPHP\Service\Access\UiAccessService;
use MintyPHP\Service\Content\PageService;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
@@ -18,8 +20,18 @@ if ($currentUserId <= 0) {
Router::redirect('login');
}
$return = Request::safeReturnTarget((string) (requestInput()->bodyAll()['return'] ?? ''));
$canEdit = app(UiAccessService::class)->allow(
$currentUserId,
SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_UPDATE
);
if (!$canEdit) {
http_response_code(403);
Flash::error(t('You are not allowed to edit this page'), $return, 'page_forbidden');
Router::redirect($return !== '' ? $return : '');
}
if (!Session::checkCsrfToken()) {
$return = Request::safeReturnTarget((string) (requestInput()->bodyAll()['return'] ?? ''));
Flash::error(t('Form expired, please try again'), $return, 'page_csrf');
Router::redirect($return !== '' ? $return : '');
}
@@ -28,7 +40,6 @@ $slug = trim((string) (requestInput()->bodyAll()['slug'] ?? ''));
$fromLocale = trim((string) (requestInput()->bodyAll()['from_locale'] ?? (I18n::$locale ?? '')));
$toLocale = trim((string) (requestInput()->bodyAll()['to_locale'] ?? ''));
$return = Request::safeReturnTarget((string) (requestInput()->bodyAll()['return'] ?? ''));
if ($return === '' && $slug !== '') {
$return = 'page/' . $slug;
}

View File

@@ -5,6 +5,8 @@ use MintyPHP\Http\Request;
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\I18n;
use MintyPHP\Router;
use MintyPHP\Service\Access\SettingsAuthorizationPolicy;
use MintyPHP\Service\Access\UiAccessService;
use MintyPHP\Service\Content\PageService;
use MintyPHP\Session;
use MintyPHP\Support\Flash;
@@ -28,7 +30,10 @@ if ($notFound) {
$user = $session['user'] ?? [];
$currentUserId = (int) ($user['id'] ?? 0);
$canEdit = $currentUserId > 0;
$canEdit = app(UiAccessService::class)->allow(
$currentUserId,
SettingsAuthorizationPolicy::ABILITY_ADMIN_SETTINGS_UPDATE
);
$returnPath = Request::path();
if ($returnPath === '') {
$returnPath = 'page/' . $slug;

View File

@@ -0,0 +1,113 @@
<?php
/**
* @var array|null $page
* @var bool $canEdit
* @var bool $editMode
* @var string $contentJson
* @var string $slug
*/
?>
<div class="app-details-container app-page">
<section>
<?php if (!$page): ?>
<p><?php e(t('Page not found')); ?></p>
<?php else: ?>
<form method="post" action="<?php e($formAction ?? ''); ?>" class="page-editor" id="page-editor" data-page-editor
data-can-edit="<?php e($canEdit ? '1' : '0'); ?>" data-edit-mode="<?php e($editMode ? 'edit' : 'view'); ?>"
data-placeholder="<?php e(t('Start writing...')); ?>" data-header-placeholder="<?php e(t('Heading')); ?>">
<?php MintyPHP\Session::getCsrfInput(); ?>
<input type="hidden" name="return" value="<?php e($returnPath ?? ''); ?>">
<textarea name="content" id="page-content" hidden><?php e($contentJson); ?></textarea>
<div data-editor-holder></div>
</form>
<?php if (file_exists('web/vendor/editorjs/tools/header.umd.js')): ?>
<script src="<?php e(assetVersion('vendor/editorjs/tools/header.umd.js')); ?>"></script>
<?php endif; ?>
<?php if (file_exists('web/vendor/editorjs/tools/list.umd.js')): ?>
<script src="<?php e(assetVersion('vendor/editorjs/tools/list.umd.js')); ?>"></script>
<?php endif; ?>
<?php if (file_exists('web/vendor/editorjs/tools/checklist.umd.js')): ?>
<script src="<?php e(assetVersion('vendor/editorjs/tools/checklist.umd.js')); ?>"></script>
<?php endif; ?>
<?php if (file_exists('web/vendor/editorjs/tools/table.umd.js')): ?>
<script src="<?php e(assetVersion('vendor/editorjs/tools/table.umd.js')); ?>"></script>
<?php endif; ?>
<?php if (file_exists('web/vendor/editorjs/tools/columns.js')): ?>
<script src="<?php e(assetVersion('vendor/editorjs/tools/columns.js')); ?>"></script>
<?php endif; ?>
<?php if (file_exists('web/vendor/editorjs/tools/marker.umd.js')): ?>
<script src="<?php e(assetVersion('vendor/editorjs/tools/marker.umd.js')); ?>"></script>
<?php endif; ?>
<script type="module" src="<?php e(assetVersion('js/components/app-page-editor.js')); ?>"></script>
<?php endif; ?>
</section>
<?php if ($canEdit): ?>
<aside id="app-details-aside-section">
<div class="app-details-aside-section app-page-action-card">
<div class="grid">
<button type="button" class="secondary outline" data-tooltip-pos="top"
data-tooltip="<?php e($editMode ? t('View') : t('Edit')); ?>" data-editor-toggle
data-edit-label="<?php e(t('Edit')); ?>" data-view-label="<?php e(t('View')); ?>">
<?php if ($editMode): ?>
<i class="bi bi-eye-fill" data-editor-icon aria-hidden="true"></i>
<?php else: ?>
<i class="bi bi-pencil-square" data-editor-icon aria-hidden="true"></i>
<?php endif; ?>
</button>
<button type="submit" form="page-editor" class="primary" data-editor-save>
<?php e(t('Save')); ?>
</button>
</div>
<?php if (isset($locales, $currentLocale) && is_array($locales) && count($locales) > 1): ?>
<hr>
<details>
<summary><?php e(t('Copy')); ?></summary>
<hr>
<form method="post" action="page/copy-language" class="app-page-copy">
<?php MintyPHP\Session::getCsrfInput(); ?>
<input type="hidden" name="slug" value="<?php e($slug ?? ''); ?>">
<input type="hidden" name="from_locale" value="<?php e($currentLocale); ?>">
<input type="hidden" name="return" value="<?php e($returnPath ?? ''); ?>">
<label class="app-field">
<span>
<?php e(t('Copy content to')); ?>
</span>
<div role="group">
<select name="to_locale" required>
<?php foreach ($locales as $locale): ?>
<?php if ($locale === $currentLocale) {
continue;
} ?>
<option value="<?php e($locale); ?>">
<?php
$label = strtoupper($locale);
if ($locale === 'de') {
$label = t('German');
} elseif ($locale === 'en') {
$label = t('English');
}
e($label);
?>
</option>
<?php endforeach; ?>
</select>
<button type="submit" class="secondary outline">
<?php e(t('Copy')); ?>
</button>
</div>
</label>
</form>
<small>
<?php e(t('Existing content in the target language will be overwritten')); ?>
</small>
</details>
<hr>
<?php endif; ?>
</div>
</aside>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,47 @@
<?php
use MintyPHP\Buffer;
use MintyPHP\Http\Request;
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\I18n;
use MintyPHP\Router;
use MintyPHP\Service\Content\PageService;
$sessionStore = app(SessionStoreInterface::class);
$session = $sessionStore->all();
$slug = trim((string) ($slug ?? ''));
if ($slug === '') {
Router::redirect('');
}
$currentUserId = (int) (($session['user']['id'] ?? 0));
if ($currentUserId > 0) {
Router::redirect(Request::withLocale('page/' . $slug, I18n::$locale ?? I18n::$defaultLocale));
}
$pageBundle = PageService::findBySlugWithLocale($slug, I18n::$locale ?? null);
$page = $pageBundle['page'] ?? null;
$pageContent = $pageBundle['content'] ?? null;
$notFound = $page === null;
if ($notFound) {
http_response_code(404);
Buffer::set('title', t('Page not found'));
}
$returnPath = Request::path();
if ($returnPath === '') {
$returnPath = $slug;
}
$formAction = '/' . ltrim($returnPath, '/');
$contentJson = '';
if (is_array($pageContent) && isset($pageContent['content'])) {
$contentJson = (string) $pageContent['content'];
}
if ($contentJson === '') {
$contentJson = json_encode(['blocks' => []], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
$canEdit = false;
$editMode = false;