Skip to content

Commit

Permalink
Wenn deployed, dann manche Pages schützen (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
gharlan committed Mar 20, 2018
1 parent 711d4c3 commit 844bdd0
Show file tree
Hide file tree
Showing 5 changed files with 320 additions and 8 deletions.
4 changes: 4 additions & 0 deletions boot.php
Expand Up @@ -10,3 +10,7 @@

rex_extension::register('PAGE_BODY_ATTR', 'rex_ydeploy_handler::addBodyClasses');
rex_extension::register('OUTPUT_FILTER', 'rex_ydeploy_handler::addBadge');

if (rex_ydeploy::factory()->isDeployed()) {
rex_extension::register('PAGES_PREPARED', 'rex_ydeploy_handler::protectPages');
}
54 changes: 54 additions & 0 deletions lib/api_protected_page.php
@@ -0,0 +1,54 @@
<?php

class rex_api_ydeploy_protected_page extends rex_api_function
{
public function execute()
{
if (!rex::getUser()->isAdmin()) {
throw new rex_api_exception('Protected pages can be (un)locked only by admins.');
}

$action = rex_get('action', 'string');

if (!in_array($action, ['lock', 'unlock'], true)) {
throw new rex_api_exception('Supported protected page actions are "lock" and "unlock", but "'.$action.'" given.');
}

$protectedPage = rex_get('protected_page', 'string');

$foundPage = null;
foreach (rex_ydeploy_handler::getProtectedPages() as $page => $subpages) {
// `yform/manager/table_edit` must not match `yform/man`
// so we add slashes to avoid this
if (0 === strpos($protectedPage.'/', $page.'/')) {
$foundPage = $page;

break;
}
}

if (!$foundPage) {
throw new rex_api_exception('The page "'.$protectedPage.'" is not protected.');
}

if ('unlock' === $action) {
rex_ydeploy_handler::unlockPage($foundPage);
} else {
rex_ydeploy_handler::lockPage($foundPage);
}

if ($redirect = rex_get('redirect', 'string')) {
rex_response::sendRedirect($redirect);
}

$result = new rex_api_result(true);
$result->setRequiresReboot(true);

return $result;
}

protected function requiresCsrfProtection()
{
return true;
}
}
108 changes: 108 additions & 0 deletions lib/handler.php
Expand Up @@ -48,4 +48,112 @@ public static function addBadge(rex_extension_point $ep)

return str_replace('</body>', $badge.'</body>', $ep->getSubject());
}

public static function protectPages()
{
$unlockedPages = self::getUnlockedPages();

foreach (self::getProtectedPages() as $page => $subpages) {
$page = rex_be_controller::getPageObject($page);

if (!$page) {
continue;
}

if (isset($unlockedPages[$page->getFullKey()])) {
self::handleUnlockedPage($page, $subpages);

continue;
}

if (!is_array($subpages)) {
self::protectPage($page);

continue;
}

foreach ($subpages as $subpage) {
$subpage = $page->getSubpage($subpage);

if ($subpage) {
self::protectPage($subpage);
}
}
}
}

public static function getProtectedPages(): array
{
return rex_addon::get('ydeploy')->getProperty('config')['protected_pages'];
}

public static function getUnlockedPages(): array
{
return rex_session('ydeploy_unlocked_pages', 'array', []);
}

public static function unlockPage(string $page)
{
$unlockedPages = self::getUnlockedPages();
$unlockedPages[$page] = true;
rex_set_session('ydeploy_unlocked_pages', $unlockedPages);
}

public static function lockPage(string $page)
{
$unlockedPages = self::getUnlockedPages();
unset($unlockedPages[$page]);
rex_set_session('ydeploy_unlocked_pages', $unlockedPages);
}

private static function protectPage(rex_be_page $page)
{
if (rex_be_controller::getCurrentPage() && $page->isActive()) {
rex_be_controller::setCurrentPage('system/ydeploy');
}

$page->setHidden(true);

// If page is first subpage of other page, then the other page must be also hidden
while ($parent = $page->getParent()) {
$subpages = $parent->getSubpages();

if ($page !== reset($subpages)) {
break;
}

$parent->setHidden(true);
$page = $parent;
}
}

private static function handleUnlockedPage(rex_be_page $page, array $subpages = null)
{
if (!rex_be_controller::getCurrentPage() || !$page->isActive()) {
return;
}

if (is_array($subpages)) {
$subpage = substr(rex_be_controller::getCurrentPage(), strlen($page->getFullKey()) + 1);
$subpage = explode('/', $subpage, 2)[0];

if (!in_array($subpage, $subpages, true)) {
return;
}
}

rex_extension::register('PAGE_TITLE_SHOWN', function (rex_extension_point $ep) {
$url = rex_url::backendPage('system/ydeploy', rex_api_ydeploy_protected_page::getUrlParams() + [
'action' => 'lock',
'protected_page' => rex_be_controller::getCurrentPage(),
]);
$error = rex_view::error('
The page <code>'.rex_escape(rex_be_controller::getCurrentPage()).'</code> is protected in deployed instances, but currently unlocked. Changes via this page should be made in development instances only! <br><br>
<a href="'.$url.'">Lock and leave this page</a>
');

return $ep->getSubject().$error;
});
}
}
31 changes: 23 additions & 8 deletions package.yml
Expand Up @@ -11,6 +11,15 @@ conflicts:
packages:
developer: '<3.7'

console_commands:
ydeploy:diff: rex_ydeploy_command_diff
ydeploy:migrate: rex_ydeploy_command_migrate

pages:
system/ydeploy:
title: YDeploy
pjax: false

config:
fixtures:
tables:
Expand All @@ -29,11 +38,17 @@ config:
redactor2_profiles: ~
yform_field: ~
yform_table: ~

console_commands:
ydeploy:diff: rex_ydeploy_command_diff
ydeploy:migrate: rex_ydeploy_command_migrate

pages:
system/ydeploy:
title: YDeploy
protected_pages:
install: ~
markitup: ~
media_manager: ~
metainfo: ~
modules: ~
packages: ~
redactor2: ~
templates: ~
yform/manager:
- table_edit
- table_migrate
- tableset_import
- table_field
131 changes: 131 additions & 0 deletions pages/system.ydeploy.php
Expand Up @@ -29,3 +29,134 @@
$fragment->setVar('title', 'Info');
$fragment->setVar('body', $content, false);
echo $fragment->parse('core/page/section.php');

if (!$ydeploy->isDeployed()) {
return;
}

$apiUrl = function (string $action, string $page, string $redirect = null) {
$params = rex_api_ydeploy_protected_page::getUrlParams();
$params['action'] = $action;
$params['protected_page'] = $page;

if ($redirect) {
$params['redirect'] = $redirect;
}

return rex_url::currentBackendPage($params);
};

$calledPage = rex_request('page', 'string');

if ('system/ydeploy' !== $calledPage) {
$redirect = rex_context::fromGet()->getUrl([], false);
$url = $apiUrl('unlock', $calledPage, $redirect);

echo rex_view::error('
The called page <code>'.rex_escape($calledPage).'</code> is protected in deployed instances because it should be used only in development instances. <br><br>
<a href="'.$url.'">Unlock and open it anyway</a>
');
}

$content = '';

$pages = [];

foreach (rex_ydeploy_handler::getProtectedPages() as $page => $subpages) {
$page = rex_be_controller::getPageObject($page);

if (!$page) {
continue;
}

$icon = $page->getIcon();
$root = $page;
while ($parent = $root->getParent()) {
$root = $parent;
$icon = $icon ?: $parent->getIcon();
}

// create non-hidden fake page
if ($root instanceof rex_be_page_main) {
$fakePage = new rex_be_page_main($root->getBlock(), $page->getFullKey(), $page->getTitle());
$fakePage->setPrio($root->getPrio());
} else {
$fakePage = new rex_be_page($page->getFullKey(), $page->getTitle());
}

// rex_be_navigation does not provide the page keys in navigation items
// so we misuse the href for the page key
$fakePage->setHref($page->getFullKey());
$fakePage->setIcon($icon);

$pages[$root->getKey()][] = $fakePage;
}

$navi = rex_be_navigation::factory();

// add fake pages to navigation, but use original order from rex_be_controller
foreach (rex_be_controller::getPages() as $key => $page) {
if (!isset($pages[$key])) {
continue;
}

foreach ($pages[$key] as $fakePage) {
$navi->addPage($fakePage);
}
}

$unlockedPages = rex_ydeploy_handler::getUnlockedPages();

foreach ($navi->getNavigation() as $block) {
$content .= '
<tr>
<td></td>
<td colspan="4"><b>'.$block['headline']['title'].'</b></td>
</tr>
';

foreach ($block['navigation'] as $page) {
if (isset($unlockedPages[$page['href']])) {
$url = $apiUrl('lock', $page['href']);
$action = '<a class="rex-online" href="'.$url.'"><i class="rex-icon fa-unlock-alt"></i> Unlocked</a>';

$action2 = '<a href="'.rex_url::backendPage($page['href']).'">Open</a>';
} else {
$url = $apiUrl('unlock', $page['href']);
$action = '<a class="rex-offline" href="'.$url.'"><i class="rex-icon fa-lock"></i> Locked</a>';

$url = $apiUrl('unlock', $page['href'], rex_url::backendPage($page['href']));
$action2 = '<a href="'.$url.'">Unlock & open</a>';
}

$content .= '
<tr>
<td class="rex-table-icon"><i class="'.$page['icon'].'"></i></td>
<td><code>'.rex_escape($page['href']).'</code></td>
<td>'.$page['title'].'</td>
<td class="rex-table-action">'.$action.'</td>
<td class="rex-table-action">'.$action2.'</td>
</tr>
';
}
}

$content = '
<table class="table table-hover">
<thead>
<tr>
<th></th>
<th>Key</th>
<th>Title</th>
<th colspan="2"></th>
</tr>
</thead>
<tbody>
'.$content.'
</tbody>
</table>';

$fragment = new rex_fragment();
$fragment->setVar('title', 'Protected Pages');
$fragment->setVar('content', $content, false);
echo $fragment->parse('core/page/section.php');

0 comments on commit 844bdd0

Please sign in to comment.