Move some methods from Panel to controllers

This commit is contained in:
Giuseppe Criscione 2022-11-28 23:05:44 +01:00
parent f55d09c34d
commit ddf9b749ca
19 changed files with 218 additions and 220 deletions

View File

@ -10,8 +10,10 @@ use Formwork\Formwork;
use Formwork\Parsers\JSON;
use Formwork\Parsers\PHP;
use Formwork\Pages\Site;
use Formwork\Response\RedirectResponse;
use Formwork\Utils\Date;
use Formwork\Utils\HTTPRequest;
use Formwork\Utils\Uri;
use Formwork\View\View;
abstract class AbstractController extends BaseAbstractController
@ -37,6 +39,55 @@ abstract class AbstractController extends BaseAbstractController
return Formwork::instance()->site();
}
/**
* Redirect to a given route
*
* @param int $code HTTP redirect status code
*/
protected function redirect(string $route, int $code = 302): RedirectResponse
{
return new RedirectResponse($this->panel()->uri($route), $code);
}
/**
* Redirect to the site index page
*
* @param int $code HTTP redirect status code
*/
protected function redirectToSite(int $code = 302): RedirectResponse
{
return new RedirectResponse($this->site()->uri(), $code);
}
/**
* Redirect to the administration panel
*
* @param int $code HTTP redirect status code
*/
protected function redirectToPanel(int $code = 302): RedirectResponse
{
return $this->redirect('/', $code);
}
/**
* Redirect to the referer page
*
* @param int $code HTTP redirect status code
* @param string $default Default route if HTTP referer is not available
*/
protected function redirectToReferer(int $code = 302, string $default = '/'): RedirectResponse
{
if (HTTPRequest::validateReferer($this->panel()->uri('/')) && HTTPRequest::referer() !== Uri::current()) {
return new RedirectResponse(HTTPRequest::referer(), $code);
}
return new RedirectResponse($this->panel()->uri($default), $code);
}
protected function translate(...$arguments)
{
return Formwork::instance()->translations()->getCurrent()->translate(...$arguments);
}
/*
* Return default data passed to views
*
@ -45,6 +96,7 @@ abstract class AbstractController extends BaseAbstractController
{
return [
'location' => $this->name,
'site' => $this->site(),
'panel' => $this->panel(),
'csrfToken' => CSRFToken::get(),
'modals' => implode('', $this->modals),
@ -56,20 +108,20 @@ abstract class AbstractController extends BaseAbstractController
'format' => Date::formatToPattern(Formwork::instance()->config()->get('date.format') . ' ' . Formwork::instance()->config()->get('date.time_format')),
'time' => true,
'labels' => [
'today' => $this->panel()->translate('date.today'),
'weekdays' => ['long' => $this->panel()->translate('date.weekdays.long'), 'short' => $this->panel()->translate('date.weekdays.short')],
'months' => ['long' => $this->panel()->translate('date.months.long'), 'short' => $this->panel()->translate('date.months.short')]
'today' => $this->translate('date.today'),
'weekdays' => ['long' => $this->translate('date.weekdays.long'), 'short' => $this->translate('date.weekdays.short')],
'months' => ['long' => $this->translate('date.months.long'), 'short' => $this->translate('date.months.short')]
]
],
'DurationInput' => [
'labels' => [
'years' => $this->panel()->translate('date.duration.years'),
'months' => $this->panel()->translate('date.duration.months'),
'weeks' => $this->panel()->translate('date.duration.weeks'),
'days' => $this->panel()->translate('date.duration.days'),
'hours' => $this->panel()->translate('date.duration.hours'),
'minutes' => $this->panel()->translate('date.duration.minutes'),
'seconds' => $this->panel()->translate('date.duration.seconds')
'years' => $this->translate('date.duration.years'),
'months' => $this->translate('date.duration.months'),
'weeks' => $this->translate('date.duration.weeks'),
'days' => $this->translate('date.duration.days'),
'hours' => $this->translate('date.duration.hours'),
'minutes' => $this->translate('date.duration.minutes'),
'seconds' => $this->translate('date.duration.seconds')
]
]
])

View File

@ -29,20 +29,20 @@ class AuthenticationController extends AbstractController
if ($limiter->hasReachedLimit()) {
$minutes = round(Formwork::instance()->config()->get('panel.login_reset_time') / 60);
return $this->error($this->panel()->translate('panel.login.attempt.too-many', $minutes));
return $this->error($this->translate('panel.login.attempt.too-many', $minutes));
}
switch (HTTPRequest::method()) {
case 'GET':
if (Session::has('FORMWORK_USERNAME')) {
return $this->panel()->redirectToPanel();
return $this->redirectToPanel();
}
// Always generate a new CSRF token
CSRFToken::generate();
return new Response($this->view('authentication.login', [
'title' => $this->panel()->translate('panel.login.login')
'title' => $this->translate('panel.login.login')
], true));
break;
@ -55,7 +55,7 @@ class AuthenticationController extends AbstractController
// Ensure no required data is missing
if (!$data->hasMultiple(['username', 'password'])) {
$this->error($this->panel()->translate('panel.login.attempt.failed'));
$this->error($this->translate('panel.login.attempt.failed'));
}
$limiter->registerAttempt();
@ -82,13 +82,13 @@ class AuthenticationController extends AbstractController
if (($destination = Session::get('FORMWORK_REDIRECT_TO')) !== null) {
Session::remove('FORMWORK_REDIRECT_TO');
return $this->panel()->redirect($destination);
return $this->redirect($destination);
}
return $this->panel()->redirectToPanel();
return $this->redirectToPanel();
}
return $this->error($this->panel()->translate('panel.login.attempt.failed'), [
return $this->error($this->translate('panel.login.attempt.failed'), [
'username' => $data->get('username'),
'error' => true
]);
@ -107,10 +107,10 @@ class AuthenticationController extends AbstractController
Session::destroy();
if (Formwork::instance()->config()->get('panel.logout_redirect') === 'home') {
return $this->panel()->redirectToSite();
return $this->redirectToSite();
}
$this->panel()->notify($this->panel()->translate('panel.login.logged-out'), 'info');
return $this->panel()->redirectToPanel();
$this->panel()->notify($this->translate('panel.login.logged-out'), 'info');
return $this->redirectToPanel();
}
/**
@ -124,7 +124,7 @@ class AuthenticationController extends AbstractController
// Ensure CSRF token is re-generated
CSRFToken::generate();
$defaults = ['title' => $this->panel()->translate('panel.login.login')];
$defaults = ['title' => $this->translate('panel.login.login')];
$this->panel()->notify($message, 'error');
return new Response($this->view('authentication.login', array_merge($defaults, $data), true));
}

View File

@ -24,10 +24,10 @@ class BackupController extends AbstractController
try {
$file = $backupper->backup();
} catch (TranslatedException $e) {
return JSONResponse::error($this->panel()->translate('panel.backup.error.cannot-make', $e->getTranslatedMessage()), 500);
return JSONResponse::error($this->translate('panel.backup.error.cannot-make', $e->getTranslatedMessage()), 500);
}
$filename = basename($file);
return JSONResponse::success($this->panel()->translate('panel.backup.ready'), 200, [
return JSONResponse::success($this->translate('panel.backup.ready'), 200, [
'filename' => $filename,
'uri' => $this->panel()->uri('/backup/download/' . urlencode(base64_encode($filename)) . '/')
]);
@ -44,10 +44,10 @@ class BackupController extends AbstractController
if (FileSystem::isFile($file, false)) {
return new FileResponse($file, true);
}
throw new RuntimeException($this->panel()->translate('panel.backup.error.cannot-download.invalid-filename'));
throw new RuntimeException($this->translate('panel.backup.error.cannot-download.invalid-filename'));
} catch (TranslatedException $e) {
$this->panel()->notify($this->panel()->translate('panel.backup.error.cannot-download', $e->getTranslatedMessage()), 'error');
return $this->panel()->redirectToReferer(302, '/dashboard/');
$this->panel()->notify($this->translate('panel.backup.error.cannot-download', $e->getTranslatedMessage()), 'error');
return $this->redirectToReferer(302, '/dashboard/');
}
}
}

View File

@ -16,6 +16,6 @@ class CacheController extends AbstractController
if (Formwork::instance()->config()->get('cache.enabled')) {
Formwork::instance()->cache()->clear();
}
return JSONResponse::success($this->panel()->translate('panel.cache.cleared'));
return JSONResponse::success($this->translate('panel.cache.cleared'));
}
}

View File

@ -25,7 +25,7 @@ class DashboardController extends AbstractController
$this->modal('deletePage');
return new Response($this->view('dashboard.index', [
'title' => $this->panel()->translate('panel.dashboard.dashboard'),
'title' => $this->translate('panel.dashboard.dashboard'),
'lastModifiedPages' => $this->view('pages.list', [
'pages' => $this->site()->descendants()->sortBy('lastModifiedTime', direction: SORT_DESC)->slice(0, 5),
'subpages' => false,

View File

@ -16,7 +16,7 @@ class ErrorsController extends AbstractController
{
return $this->makeErrorResponse(404, 'not-found', [
'href' => $this->panel()->uri('/dashboard/'),
'label' => $this->panel()->translate('panel.errors.action.return-to-dashboard')
'label' => $this->translate('panel.errors.action.return-to-dashboard')
]);
}
@ -27,7 +27,7 @@ class ErrorsController extends AbstractController
{
return $this->makeErrorResponse(500, 'internal-server-error', [
'href' => $this->makeGitHubIssueUri($exception),
'label' => $this->panel()->translate('panel.errors.action.report-to-github')
'label' => $this->translate('panel.errors.action.report-to-github')
]);
}
@ -38,7 +38,7 @@ class ErrorsController extends AbstractController
{
return $this->makeErrorResponse(403, 'forbidden', [
'href' => $this->panel()->uri('/dashboard/'),
'label' => $this->panel()->translate('panel.errors.action.return-to-dashboard')
'label' => $this->translate('panel.errors.action.return-to-dashboard')
]);
}
@ -53,11 +53,11 @@ class ErrorsController extends AbstractController
{
HTTPResponse::cleanOutputBuffers();
return new Response($this->view('errors.error', [
'title' => $this->panel()->translate('panel.errors.error.' . $name . '.status'),
'title' => $this->translate('panel.errors.error.' . $name . '.status'),
'code' => $status,
'status' => $this->panel()->translate('panel.errors.error.' . $name . '.status'),
'heading' => $this->panel()->translate('panel.errors.error.' . $name . '.heading'),
'description' => $this->panel()->translate('panel.errors.error.' . $name . '.description'),
'status' => $this->translate('panel.errors.error.' . $name . '.status'),
'heading' => $this->translate('panel.errors.error.' . $name . '.heading'),
'description' => $this->translate('panel.errors.error.' . $name . '.description'),
'action' => $action
], true), $status);
}

View File

@ -26,7 +26,7 @@ class OptionsController extends AbstractController
public function index(): RedirectResponse
{
$this->ensurePermission('options.system');
return $this->panel()->redirect('/options/system/');
return $this->redirect('/options/system/');
}
/**
@ -52,8 +52,8 @@ class OptionsController extends AbstractController
FileSystem::touch(Formwork::instance()->config()->get('content.path'));
}
$this->panel()->notify($this->panel()->translate('panel.options.updated'), 'success');
return $this->panel()->redirect('/options/system/');
$this->panel()->notify($this->translate('panel.options.updated'), 'success');
return $this->redirect('/options/system/');
}
$fields->validate(Formwork::instance()->config());
@ -61,7 +61,7 @@ class OptionsController extends AbstractController
$this->modal('changes');
return new Response($this->view('options.system', [
'title' => $this->panel()->translate('panel.options.options'),
'title' => $this->translate('panel.options.options'),
'tabs' => $this->view('options.tabs', [
'tabs' => $this->tabs,
'current' => 'system'
@ -92,8 +92,8 @@ class OptionsController extends AbstractController
FileSystem::touch(Formwork::instance()->config()->get('content.path'));
}
$this->panel()->notify($this->panel()->translate('panel.options.updated'), 'success');
return $this->panel()->redirect('/options/site/');
$this->panel()->notify($this->translate('panel.options.updated'), 'success');
return $this->redirect('/options/site/');
}
$fields->validate($this->site()->data());
@ -101,7 +101,7 @@ class OptionsController extends AbstractController
$this->modal('changes');
return new Response($this->view('options.site', [
'title' => $this->panel()->translate('panel.options.options'),
'title' => $this->translate('panel.options.options'),
'tabs' => $this->view('options.tabs', [
'tabs' => $this->tabs,
'current' => 'site'
@ -118,7 +118,7 @@ class OptionsController extends AbstractController
$this->ensurePermission('options.updates');
return new Response($this->view('options.updates', [
'title' => $this->panel()->translate('panel.options.updates'),
'title' => $this->translate('panel.options.updates'),
'tabs' => $this->view('options.tabs', [
'tabs' => $this->tabs,
'current' => 'updates'
@ -228,7 +228,7 @@ class OptionsController extends AbstractController
ksort($data['HTTP Response Headers']);
return new Response($this->view('options.info', [
'title' => $this->panel()->translate('panel.options.options'),
'title' => $this->translate('panel.options.options'),
'tabs' => $this->view('options.tabs', [
'tabs' => $this->tabs,
'current' => 'info'

View File

@ -52,7 +52,7 @@ class PagesController extends AbstractController
$this->modal('deletePage');
return new Response($this->view('pages.index', [
'title' => $this->panel()->translate('panel.pages.pages'),
'title' => $this->translate('panel.pages.pages'),
'pagesList' => $this->view('pages.list', [
'pages' => $this->site()->pages(),
'subpages' => true,
@ -76,13 +76,13 @@ class PagesController extends AbstractController
// Let's create the page
try {
$page = $this->createPage($data);
$this->panel()->notify($this->panel()->translate('panel.pages.page.created'), 'success');
$this->panel()->notify($this->translate('panel.pages.page.created'), 'success');
} catch (TranslatedException $e) {
$this->panel()->notify($e->getTranslatedMessage(), 'error');
return $this->panel()->redirectToReferer(302, '/pages/');
return $this->redirectToReferer(302, '/pages/');
}
return $this->panel()->redirect('/pages/' . trim($page->route(), '/') . '/edit/');
return $this->redirect('/pages/' . trim($page->route(), '/') . '/edit/');
}
/**
@ -95,20 +95,20 @@ class PagesController extends AbstractController
$page = $this->site()->findPage($params->get('page'));
if ($page === null) {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-edit.page-not-found'), 'error');
return $this->panel()->redirectToReferer(302, '/pages/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-edit.page-not-found'), 'error');
return $this->redirectToReferer(302, '/pages/');
}
if ($params->has('language')) {
if (empty(Formwork::instance()->config()->get('languages.available'))) {
return $this->panel()->redirect('/pages/' . trim($page->route(), '/') . '/edit/');
return $this->redirect('/pages/' . trim($page->route(), '/') . '/edit/');
}
$language = $params->get('language');
if (!in_array($language, Formwork::instance()->config()->get('languages.available'), true)) {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-edit.invalid-language', $language), 'error');
return $this->panel()->redirect('/pages/' . trim($page->route(), '/') . '/edit/language/' . $this->site()->languages()->default() . '/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-edit.invalid-language', $language), 'error');
return $this->redirect('/pages/' . trim($page->route(), '/') . '/edit/language/' . $this->site()->languages()->default() . '/');
}
if ($page->hasLanguage($language)) {
@ -116,7 +116,7 @@ class PagesController extends AbstractController
}
} elseif ($page->language() !== null) {
// Redirect to proper language
return $this->panel()->redirect('/pages/' . trim($page->route(), '/') . '/edit/language/' . $page->language() . '/');
return $this->redirect('/pages/' . trim($page->route(), '/') . '/edit/language/' . $page->language() . '/');
}
// Load page fields
@ -142,7 +142,7 @@ class PagesController extends AbstractController
// Update the page
try {
$page = $this->updatePage($page, $data, $fields);
$this->panel()->notify($this->panel()->translate('panel.pages.page.edited'), 'success');
$this->panel()->notify($this->translate('panel.pages.page.edited'), 'success');
} catch (TranslatedException $e) {
$this->panel()->notify($e->getTranslatedMessage(), 'error');
}
@ -151,13 +151,13 @@ class PagesController extends AbstractController
try {
$this->processPageUploads($page);
} catch (TranslatedException $e) {
$this->panel()->notify($this->panel()->translate('panel.uploader.error', $e->getTranslatedMessage()), 'error');
$this->panel()->notify($this->translate('panel.uploader.error', $e->getTranslatedMessage()), 'error');
}
}
// Redirect if page route has changed
if ($params->get('page') !== ($route = trim($page->route(), '/'))) {
return $this->panel()->redirect('/pages/' . $route . '/edit/');
return $this->redirect('/pages/' . $route . '/edit/');
}
break;
@ -176,7 +176,7 @@ class PagesController extends AbstractController
$this->modal('deleteFile');
return new Response($this->view('pages.editor', [
'title' => $this->panel()->translate('panel.pages.edit-page', $page->title()),
'title' => $this->translate('panel.pages.edit-page', $page->title()),
'page' => $page,
'fields' => $fields,
'templates' => $this->site()->templates()->keys(),
@ -196,16 +196,16 @@ class PagesController extends AbstractController
$data = HTTPRequest::postData();
if (!$data->hasMultiple(['parent', 'from', 'to'])) {
return JSONResponse::error($this->panel()->translate('panel.pages.page.cannot-move'));
return JSONResponse::error($this->translate('panel.pages.page.cannot-move'));
}
if (!is_numeric($data->get('from')) || !is_numeric($data->get('to'))) {
return JSONResponse::error($this->panel()->translate('panel.pages.page.cannot-move'));
return JSONResponse::error($this->translate('panel.pages.page.cannot-move'));
}
$parent = $this->resolveParent($data->get('parent'));
if ($parent === null || !$parent->hasChildren()) {
return JSONResponse::error($this->panel()->translate('panel.pages.page.cannot-move'));
return JSONResponse::error($this->translate('panel.pages.page.cannot-move'));
}
$pages = $parent->children()->toArray();
@ -229,7 +229,7 @@ class PagesController extends AbstractController
}
}
return JSONResponse::success($this->panel()->translate('panel.pages.page.moved'));
return JSONResponse::success($this->translate('panel.pages.page.moved'));
}
/**
@ -242,8 +242,8 @@ class PagesController extends AbstractController
$page = $this->site()->findPage($params->get('page'));
if ($page === null) {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-delete.page-not-found'), 'error');
return $this->panel()->redirectToReferer(302, '/pages/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-delete.page-not-found'), 'error');
return $this->redirectToReferer(302, '/pages/');
}
if ($params->has('language')) {
@ -251,14 +251,14 @@ class PagesController extends AbstractController
if ($page->hasLanguage($language)) {
$page->setLanguage($language);
} else {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-delete.invalid-language', $language), 'error');
return $this->panel()->redirectToReferer(302, '/pages/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-delete.invalid-language', $language), 'error');
return $this->redirectToReferer(302, '/pages/');
}
}
if (!$page->isDeletable()) {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-delete.not-deletable'), 'error');
return $this->panel()->redirectToReferer(302, '/pages/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-delete.not-deletable'), 'error');
return $this->redirectToReferer(302, '/pages/');
}
// Delete just the content file only if there are more than one language
@ -268,13 +268,13 @@ class PagesController extends AbstractController
FileSystem::delete($page->path(), true);
}
$this->panel()->notify($this->panel()->translate('panel.pages.page.deleted'), 'success');
$this->panel()->notify($this->translate('panel.pages.page.deleted'), 'success');
// Don't redirect to referer if it's to Pages@edit
if (!Str::startsWith(Uri::normalize(HTTPRequest::referer()), Uri::make(['path' => $this->panel()->uri('/pages/' . $params->get('page') . '/edit/')]))) {
return $this->panel()->redirectToReferer(302, '/pages/');
return $this->redirectToReferer(302, '/pages/');
}
return $this->panel()->redirect('/pages/');
return $this->redirect('/pages/');
}
/**
@ -287,21 +287,21 @@ class PagesController extends AbstractController
$page = $this->site()->findPage($params->get('page'));
if ($page === null) {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-upload-file.page-not-found'), 'error');
return $this->panel()->redirectToReferer(302, '/pages/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-upload-file.page-not-found'), 'error');
return $this->redirectToReferer(302, '/pages/');
}
if (HTTPRequest::hasFiles()) {
try {
$this->processPageUploads($page);
} catch (TranslatedException $e) {
$this->panel()->notify($this->panel()->translate('panel.uploader.error', $e->getTranslatedMessage()), 'error');
return $this->panel()->redirect('/pages/' . $params->get('page') . '/edit/');
$this->panel()->notify($this->translate('panel.uploader.error', $e->getTranslatedMessage()), 'error');
return $this->redirect('/pages/' . $params->get('page') . '/edit/');
}
}
$this->panel()->notify($this->panel()->translate('panel.uploader.uploaded'), 'success');
return $this->panel()->redirect('/pages/' . $params->get('page') . '/edit/');
$this->panel()->notify($this->translate('panel.uploader.uploaded'), 'success');
return $this->redirect('/pages/' . $params->get('page') . '/edit/');
}
/**
@ -314,19 +314,19 @@ class PagesController extends AbstractController
$page = $this->site()->findPage($params->get('page'));
if ($page === null) {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-delete-file.page-not-found'), 'error');
return $this->panel()->redirectToReferer(302, '/pages/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-delete-file.page-not-found'), 'error');
return $this->redirectToReferer(302, '/pages/');
}
if (!$page->files()->has($params->get('filename'))) {
$this->panel()->notify($this->panel()->translate('panel.pages.page.cannot-delete-file.file-not-found'), 'error');
return $this->panel()->redirect('/pages/' . $params->get('page') . '/edit/');
$this->panel()->notify($this->translate('panel.pages.page.cannot-delete-file.file-not-found'), 'error');
return $this->redirect('/pages/' . $params->get('page') . '/edit/');
}
FileSystem::delete($page->path() . $params->get('filename'));
$this->panel()->notify($this->panel()->translate('panel.pages.page.file-deleted'), 'success');
return $this->panel()->redirect('/pages/' . $params->get('page') . '/edit/');
$this->panel()->notify($this->translate('panel.pages.page.file-deleted'), 'success');
return $this->redirect('/pages/' . $params->get('page') . '/edit/');
}
/**

View File

@ -19,13 +19,17 @@ class RegisterController extends AbstractController
*/
public function register(): Response
{
if (!$this->panel()->users()->isEmpty()) {
return $this->redirectToReferer();
}
Session::regenerate(false);
CSRFToken::generate();
switch (HTTPRequest::method()) {
case 'GET':
return new Response($this->view('register.register', [
'title' => $this->panel()->translate('panel.register.register')
'title' => $this->translate('panel.register.register')
], true));
break;
@ -34,8 +38,8 @@ class RegisterController extends AbstractController
$data = HTTPRequest::postData();
if (!$data->hasMultiple(['username', 'fullname', 'password', 'language', 'email'])) {
$this->panel()->notify($this->panel()->translate('panel.users.user.cannot-create.var-missing'), 'error');
return $this->panel()->redirectToPanel();
$this->panel()->notify($this->translate('panel.users.user.cannot-create.var-missing'), 'error');
return $this->redirectToPanel();
}
$userData = [
@ -57,7 +61,7 @@ class RegisterController extends AbstractController
$time = $accessLog->log($data->get('username'));
$lastAccessRegistry->set($data->get('username'), $time);
return $this->panel()->redirectToPanel();
return $this->redirectToPanel();
break;
}

View File

@ -21,16 +21,16 @@ class UpdatesController extends AbstractController
try {
$upToDate = $updater->checkUpdates();
} catch (RuntimeException $e) {
return JSONResponse::error($this->panel()->translate('panel.updates.status.cannot-check'), 500, [
'status' => $this->panel()->translate('panel.updates.status.cannot-check')
return JSONResponse::error($this->translate('panel.updates.status.cannot-check'), 500, [
'status' => $this->translate('panel.updates.status.cannot-check')
]);
}
if ($upToDate) {
return JSONResponse::success($this->panel()->translate('panel.updates.status.up-to-date'), 200, [
return JSONResponse::success($this->translate('panel.updates.status.up-to-date'), 200, [
'uptodate' => true
]);
}
return JSONResponse::success($this->panel()->translate('panel.updates.status.found'), 200, [
return JSONResponse::success($this->translate('panel.updates.status.found'), 200, [
'uptodate' => false,
'release' => $updater->latestRelease()
]);
@ -48,23 +48,23 @@ class UpdatesController extends AbstractController
try {
$backupper->backup();
} catch (TranslatedException $e) {
return JSONResponse::error($this->panel()->translate('panel.updates.status.cannot-make-backup'), 500, [
'status' => $this->panel()->translate('panel.updates.status.cannot-make-backup')
return JSONResponse::error($this->translate('panel.updates.status.cannot-make-backup'), 500, [
'status' => $this->translate('panel.updates.status.cannot-make-backup')
]);
}
}
try {
$updater->update();
} catch (RuntimeException $e) {
return JSONResponse::error($this->panel()->translate('panel.updates.status.cannot-install'), 500, [
'status' => $this->panel()->translate('panel.updates.status.cannot-install')
return JSONResponse::error($this->translate('panel.updates.status.cannot-install'), 500, [
'status' => $this->translate('panel.updates.status.cannot-install')
]);
}
if (Formwork::instance()->config()->get('cache.enabled')) {
Formwork::instance()->cache()->clear();
}
return JSONResponse::success($this->panel()->translate('panel.updates.installed'), 200, [
'status' => $this->panel()->translate('panel.updates.status.up-to-date')
return JSONResponse::success($this->translate('panel.updates.installed'), 200, [
'status' => $this->translate('panel.updates.status.up-to-date')
]);
}
}

View File

@ -30,7 +30,7 @@ class UsersController extends AbstractController
$this->modal('deleteUser');
return new Response($this->view('users.index', [
'title' => $this->panel()->translate('panel.users.users'),
'title' => $this->translate('panel.users.users'),
'users' => $this->panel()->users()
], true));
}
@ -46,14 +46,14 @@ class UsersController extends AbstractController
// Ensure no required data is missing
if (!$data->hasMultiple(['username', 'fullname', 'password', 'email', 'language'])) {
$this->panel()->notify($this->panel()->translate('panel.users.user.cannot-create.var-missing'), 'error');
return $this->panel()->redirect('/users/');
$this->panel()->notify($this->translate('panel.users.user.cannot-create.var-missing'), 'error');
return $this->redirect('/users/');
}
// Ensure there isn't a user with the same username
if ($this->panel()->users()->has($data->get('username'))) {
$this->panel()->notify($this->panel()->translate('panel.users.user.cannot-create.already-exists'), 'error');
return $this->panel()->redirect('/users/');
$this->panel()->notify($this->translate('panel.users.user.cannot-create.already-exists'), 'error');
return $this->redirect('/users/');
}
$userData = [
@ -66,8 +66,8 @@ class UsersController extends AbstractController
YAML::encodeToFile($userData, Formwork::instance()->config()->get('panel.paths.accounts') . $data->get('username') . '.yml');
$this->panel()->notify($this->panel()->translate('panel.users.user.created'), 'success');
return $this->panel()->redirect('/users/');
$this->panel()->notify($this->translate('panel.users.user.created'), 'success');
return $this->redirect('/users/');
}
/**
@ -93,7 +93,7 @@ class UsersController extends AbstractController
$this->deleteAvatar($user);
} catch (TranslatedException $e) {
$this->panel()->notify($e->getTranslatedMessage(), 'error');
return $this->panel()->redirectToReferer(302, '/users/');
return $this->redirectToReferer(302, '/users/');
}
$lastAccessRegistry = new Registry(Formwork::instance()->config()->get('panel.paths.logs') . 'lastAccess.json');
@ -101,8 +101,8 @@ class UsersController extends AbstractController
// Remove user last access from registry
$lastAccessRegistry->remove($user->username());
$this->panel()->notify($this->panel()->translate('panel.users.user.deleted'), 'success');
return $this->panel()->redirect('/users/');
$this->panel()->notify($this->translate('panel.users.user.deleted'), 'success');
return $this->redirect('/users/');
}
/**
@ -117,8 +117,8 @@ class UsersController extends AbstractController
$user = $this->panel()->users()->get($params->get('user'));
if ($user === null) {
$this->panel()->notify($this->panel()->translate('panel.users.user.not-found'), 'error');
return $this->panel()->redirect('/users/');
$this->panel()->notify($this->translate('panel.users.user.not-found'), 'error');
return $this->redirect('/users/');
}
// Disable password and/or role fields if they cannot be changed
@ -132,15 +132,15 @@ class UsersController extends AbstractController
$fields->validate($data);
try {
$this->updateUser($user, $data);
$this->panel()->notify($this->panel()->translate('panel.users.user.edited'), 'success');
$this->panel()->notify($this->translate('panel.users.user.edited'), 'success');
} catch (TranslatedException $e) {
$this->panel()->notify($this->panel()->translate($e->getLanguageString(), $user->username()), 'error');
$this->panel()->notify($this->translate($e->getLanguageString(), $user->username()), 'error');
}
} else {
$this->panel()->notify($this->panel()->translate('panel.users.user.cannot-edit', $user->username()), 'error');
$this->panel()->notify($this->translate('panel.users.user.cannot-edit', $user->username()), 'error');
}
return $this->panel()->redirect('/users/' . $user->username() . '/profile/');
return $this->redirect('/users/' . $user->username() . '/profile/');
}
$fields = $fields->validate($user);
@ -150,7 +150,7 @@ class UsersController extends AbstractController
$this->modal('deleteUser');
return new Response($this->view('users.profile', [
'title' => $this->panel()->translate('panel.users.user-profile', $user->username()),
'title' => $this->translate('panel.users.user-profile', $user->username()),
'user' => $user,
'fields' => $fields
], true));
@ -219,7 +219,7 @@ class UsersController extends AbstractController
// Delete old avatar
$this->deleteAvatar($user);
$this->panel()->notify($this->panel()->translate('panel.user.avatar.uploaded'), 'success');
$this->panel()->notify($this->translate('panel.user.avatar.uploaded'), 'success');
return $uploader->uploadedFiles()[0];
}
}

View File

@ -8,8 +8,6 @@ use Formwork\Panel\Users\Users;
use Formwork\Assets;
use Formwork\Formwork;
use Formwork\Languages\LanguageCodes;
use Formwork\Pages\Page;
use Formwork\Response\RedirectResponse;
use Formwork\Utils\FileSystem;
use Formwork\Utils\HTTPRequest;
use Formwork\Utils\Notification;
@ -80,7 +78,7 @@ final class Panel
/**
* Return a URI relative to the request root
*/
public function uri(string $route): string
public function uri(string $route = ''): string
{
return $this->panelUri() . ltrim($route, '/');
}
@ -93,14 +91,6 @@ final class Panel
return HTTPRequest::root() . 'panel/' . ltrim($route, '/');
}
/**
* Get the URI of the site
*/
public function siteUri(): string
{
return HTTPRequest::root();
}
/**
* Return panel root
*/
@ -117,23 +107,6 @@ final class Panel
return HTTPRequest::root() . ltrim($this->panelRoot(), '/');
}
/**
* Return the URI of a page
*
* @param bool|string $includeLanguage
*/
public function pageUri(Page $page, $includeLanguage = true): string
{
$base = $this->siteUri();
if ($includeLanguage) {
$language = is_string($includeLanguage) ? $includeLanguage : $page->language();
if ($language !== null) {
$base .= $language . '/';
}
}
return $base . ltrim($page->route(), '/');
}
/**
* Return current route
*/
@ -142,50 +115,6 @@ final class Panel
return '/' . Str::removeStart(HTTPRequest::uri(), $this->panelRoot());
}
/**
* Redirect to a given route
*
* @param int $code HTTP redirect status code
*/
public function redirect(string $route, int $code = 302): RedirectResponse
{
return new RedirectResponse($this->uri($route), $code);
}
/**
* Redirect to the site index page
*
* @param int $code HTTP redirect status code
*/
public function redirectToSite(int $code = 302): RedirectResponse
{
return new RedirectResponse($this->siteUri(), $code);
}
/**
* Redirect to the administration panel
*
* @param int $code HTTP redirect status code
*/
public function redirectToPanel(int $code = 302): RedirectResponse
{
return $this->redirect('/', $code);
}
/**
* Redirect to the referer page
*
* @param int $code HTTP redirect status code
* @param string $default Default route if HTTP referer is not available
*/
public function redirectToReferer(int $code = 302, string $default = '/'): RedirectResponse
{
if (HTTPRequest::validateReferer($this->uri('/')) && HTTPRequest::referer() !== Uri::current()) {
return new RedirectResponse(HTTPRequest::referer(), $code);
}
return new RedirectResponse($this->uri($default), $code);
}
/**
* Send a notification
*/
@ -202,14 +131,6 @@ final class Panel
return Notification::exists() ? Notification::get() : null;
}
/**
* Get a translation
*/
public function translate(...$arguments)
{
return Formwork::instance()->translations()->getCurrent()->translate(...$arguments);
}
/**
* Get Assets instance
*/

View File

@ -121,7 +121,7 @@ class HTTPRequest
*/
public static function validateReferer(string $path = null): bool
{
$base = Uri::normalize(Uri::base() . '/' . ltrim($path, '/'));
$base = Uri::normalize(Uri::base() . '/' . $path);
return Str::startsWith((string) static::referer(), $base);
}

View File

@ -1,9 +1,10 @@
<?php
use Formwork\Panel\Controllers\RegisterController;
use Formwork\Panel\Security\CSRFToken;
use Formwork\Formwork;
use Formwork\Response\JSONResponse;
use Formwork\Response\RedirectResponse;
use Formwork\Utils\FileSystem;
use Formwork\Utils\HTTPRequest;
use Formwork\Utils\Session;
@ -11,7 +12,7 @@ return [
'routes' => [
'panel.index' => [
'path' => '/',
'action' => fn () => Formwork::instance()->panel()->redirect('/dashboard/')
'action' => fn () => new RedirectResponse(Formwork::instance()->panel()->uri('/dashboard/'))
],
'panel.login' => [
'path' => '/login/',
@ -141,6 +142,11 @@ return [
'action' => 'Formwork\Panel\Controllers\UsersController@profile',
'methods' => ['GET', 'POST']
],
'panel.register' => [
'path' => '/register/',
'action' => 'Formwork\Panel\Controllers\RegisterController@register',
'methods' => ['GET']
],
'panel.errors.notfound' => [
'path' => '/{route}/',
'action' => 'Formwork\Panel\Controllers\ErrorsController@notFound'
@ -149,18 +155,23 @@ return [
'filters' => [
'request.validate-size' => [
'action' => static function () {
// Validate HTTP request Content-Length according to post_max_size directive
if (\Formwork\Utils\HTTPRequest::contentLength() !== null) {
$maxSize = \Formwork\Utils\FileSystem::shorthandToBytes(ini_get('post_max_size'));
if (\Formwork\Utils\HTTPRequest::contentLength() > $maxSize && $maxSize > 0) {
$panel = \Formwork\Formwork::instance()->panel();
$panel->notify($panel->translate('panel.request.error.post-max-size'), 'error');
return $panel->redirectToReferer();
// Validate HTTP request Content-Length according to `post_max_size` directive
if (HTTPRequest::contentLength() !== null) {
$maxSize = FileSystem::shorthandToBytes(ini_get('post_max_size'));
if (HTTPRequest::contentLength() > $maxSize && $maxSize > 0) {
$panel = Formwork::instance()->panel();
$panel->notify(
Formwork::instance()->translations()->getCurrent()->translate('panel.request.error.post-max-size'),
'error'
);
return new RedirectResponse($panel->uri());
}
}
},
'methods' => ['POST']
],
'request.validate-csrf' => [
'action' => static function () {
// Validate CSRF token
@ -169,41 +180,51 @@ return [
} catch (RuntimeException $e) {
CSRFToken::destroy();
Session::remove('FORMWORK_USERNAME');
$panel = \Formwork\Formwork::instance()->panel();
$panel->notify($panel->translate('panel.login.suspicious-request-detected'), 'warning');
$panel = Formwork::instance()->panel();
$panel->notify(
Formwork::instance()->translations()->getCurrent()->translate('panel.login.suspicious-request-detected'),
'warning'
);
if (HTTPRequest::isXHR()) {
return JSONResponse::error('Bad Request: the CSRF token is not valid', 400);
}
return $panel->redirect('/login/');
return new RedirectResponse($panel->uri('/login/'));
}
},
'methods' => ['POST'],
'types' => ['HTTP', 'XHR']
],
'panel.register' => [
'action' => static function () {
$panel = Formwork::instance()->panel();
// Register panel if no user exists
if ($panel->users()->isEmpty()) {
if (!HTTPRequest::isLocalhost()) {
return $panel->redirectToSite();
return new RedirectResponse(Formwork::instance()->site()->uri());
}
if ($panel->route() !== '/') {
return $panel->redirectToPanel();
if ($panel->route() !== '/register/') {
return new RedirectResponse($panel->uri('/register/'));
}
$controller = new RegisterController();
return $controller->register();
}
},
'methods' => ['GET', 'POST']
],
'panel.redirect-to-login' => [
'action' => static function () {
$panel = Formwork::instance()->panel();
// Redirect to login if no user is logged
if (!$panel->isLoggedIn() && $panel->route() !== '/login/') {
if (!$panel->users()->isEmpty() && !$panel->isLoggedIn() && $panel->route() !== '/login/') {
Session::set('FORMWORK_REDIRECT_TO', $panel->route());
return $panel->redirect('/login/');
return new RedirectResponse($panel->uri('/login/'));
}
}
]

View File

@ -6,7 +6,7 @@ foreach ($page->files() as $file):
<div class="files-item">
<?= $this->icon(is_null($file->type()) ? 'file' : 'file-' . $file->type()) ?> <div class="files-item-cell file-name" data-overflow-tooltip="true"><?= $file->name() ?> <span class="file-size">(<?= $file->size() ?>)</span></div>
<div class="files-item-cell file-actions">
<a class="button button-link" role="button" href="<?= $panel->pageUri($page) . $file->name() ?>" target="formwork-preview-file-<?= $file->hash() ?>" title="<?= $this->translate('panel.pages.preview-file') ?>" aria-label="title="<?= $this->translate('panel.pages.preview-file') ?>""><?= $this->icon('eye') ?></a>
<a class="button button-link" role="button" href="<?= $page->uri($file->name(), includeLanguage: false) ?>" target="formwork-preview-file-<?= $file->hash() ?>" title="<?= $this->translate('panel.pages.preview-file') ?>" aria-label="title="<?= $this->translate('panel.pages.preview-file') ?>""><?= $this->icon('eye') ?></a>
<?php
if ($panel->user()->permissions()->has('pages.delete_files')):
?>

View File

@ -26,7 +26,7 @@
<?php $this->insert('partials.sidebar') ?>
<div class="title-bar">
<span class="panel-title"><?= $this->translate('panel.panel') ?></span>
<a href="<?= $panel->siteUri() ?>" class="view-site" target="formwork-view-site"><span class="show-from-xs"><?= $this->translate('panel.view-site') ?></span> <?= $this->icon('arrow-right-up-box') ?></a>
<a href="<?= $site->uri() ?>" class="view-site" target="formwork-view-site"><span class="show-from-xs"><?= $this->translate('panel.view-site') ?></span> <?= $this->icon('arrow-right-up-box') ?></a>
</div>
<main class="main">
<?= $this->content() ?>

View File

@ -17,7 +17,7 @@
<?php
foreach ($page->images() as $image):
?>
<option value="<?= $panel->pageUri($page) . $image ?>"><?= $image ?></option>
<option value="<?= $page->uri($image, includeLanguage: false) ?>"><?= $image ?></option>
<?php
endforeach;
?>

View File

@ -22,7 +22,7 @@
?>
<input type="hidden" name="csrf-token" value="<?= $csrfToken ?>">
<div style="text-align: right;">
<a class="button button-link<?php if (!$page->published() || !$page->routable()): ?> disabled<?php endif; ?>" role="button" <?php if ($page->published() && $page->routable()): ?>href="<?= $panel->pageUri($page, $currentLanguage ?: true) ?>"<?php endif; ?> target="formwork-preview-<?= $page->uid() ?>" title="<?= $this->translate('panel.pages.preview') ?>" aria-label="<?= $this->translate('panel.pages.preview') ?>"><?= $this->icon('eye') ?></a>
<a class="button button-link<?php if (!$page->published() || !$page->routable()): ?> disabled<?php endif; ?>" role="button" <?php if ($page->published() && $page->routable()): ?>href="<?= $page->uri(includeLanguage: $currentLanguage ?: true) ?>"<?php endif; ?> target="formwork-preview-<?= $page->uid() ?>" title="<?= $this->translate('panel.pages.preview') ?>" aria-label="<?= $this->translate('panel.pages.preview') ?>"><?= $this->icon('eye') ?></a>
<?php
if ($panel->user()->permissions()->has('pages.delete')):
?>

View File

@ -56,7 +56,7 @@
<span class="page-status-label" data-overflow-tooltip="true"><?= $this->translate('panel.pages.status.' . $page->status()) ?></span>
</div>
<div class="pages-item-cell page-actions">
<a class="button button-link<?php if (!$page->published() || !$page->routable()): ?> disabled<?php endif; ?>" role="button" <?php if ($page->published() && $page->routable()): ?>href="<?= $panel->pageUri($page) ?>"<?php endif; ?> target="formwork-preview-<?= $page->uid() ?>" title="<?= $this->translate('panel.pages.preview') ?>" aria-label="<?= $this->translate('panel.pages.preview') ?>"><?= $this->icon('eye') ?></a>
<a class="button button-link<?php if (!$page->published() || !$page->routable()): ?> disabled<?php endif; ?>" role="button" <?php if ($page->published() && $page->routable()): ?>href="<?= $page->uri(includeLanguage: false) ?>"<?php endif; ?> target="formwork-preview-<?= $page->uid() ?>" title="<?= $this->translate('panel.pages.preview') ?>" aria-label="<?= $this->translate('panel.pages.preview') ?>"><?= $this->icon('eye') ?></a>
<?php
if ($panel->user()->permissions()->has('pages.delete')):
?>