Control backend access to static pages on a per-page basis
4
Sometimes you may want to control the backend access to Winter.Pages static pages on a per-page basis; this trick should give you a starting point to achieve the specific goals of your project.
Note: In its current implementation this is not a perfect solution, for instance if you want to give access to a page that's a child of another page then the user will need access to the parent page as well in order for this to work.
<?php
namespace MyAuthor\MyPlugin;
use App;
use Event;
use BackendAuth;
use ApplicationException;
use Cms\Classes\Theme;
use Backend\Controllers\Users;
use Backend\Models\User;
use Backend\Models\UserPreference;
use Winter\Pages\Classes\Page;
use Winter\Pages\Controllers\Index;
use System\Classes\PluginBase;
class Plugin extends PluginBase
{
protected $userPreferenceKey = 'myauthor::content.allowed_static_pages';
public function boot()
{
$this->extendBackendUsersController();
$this->extendBackendUserModel();
$this->extendWinterPagesPageModel();
$this->extendWinterPagesIndexController();
}
/**
* Extends the Backend Users controller to add the field that will be used
* to specify specific pages that the user has access to.
*
* @return void
*/
protected function extendBackendUsersController()
{
// Setup specific page permission functionality
// @TODO: Indicate parent / child page relationships in page picker
Users::extendFormFields(function ($form, $model, $context) {
if (!in_array($context, ['update'])) {
return;
}
$form->addTabFields([
'allowed_static_pages' => [
'tab' => 'backend::lang.user.permissions',
'label' => 'Allowed Static Pages',
'comment' => 'The static pages that the user is allowed to edit',
'type' => 'checkboxlist',
'options' => Page::listInTheme(Theme::getActiveTheme())->pluck('title', 'fileName')->toArray(),
],
]);
});
}
/**
* Extends the Backend User model to make the content permissions data available as a
* dynamic attribute that stores the data as a UserPreference record
*
* @return void
*/
protected function extendBackendUserModel()
{
User::extend(function ($model) {
$model->addDynamicMethod('getAllowedStaticPagesAttribute', function () use ($model) {
return UserPreference::forUser($model)->get($this->userPreferenceKey);
});
// TODO: Warning, users can set this value themselves by including it in the POST data sent by an
// update request on their myaccount page, this is why there is an explicit isSuperuser() check here
$model->addDynamicMethod('setAllowedStaticPagesAttribute', function ($value) use ($model) {
if ($model->exists && BackendAuth::user()->isSuperuser()) {
UserPreference::forUser($model)->set($this->userPreferenceKey, $value);
}
});
});
}
/**
* Extends the Winter.Pages Page model to prevent users from deleting or persisting changes to
* pages that they don't have access to.
*
* @return void
*/
protected function extendWinterPagesPageModel()
{
Page::extend(function ($model) {
if (!App::runningInBackend()) {
return;
}
$allowedPages = UserPreference::forUser()->get($this->userPreferenceKey);
if (empty($allowedPages)) {
return;
}
$model->bindEvent('model.beforeDelete', function () {
throw new ApplicationException("You do not have permission to delete pages.");
});
$model->bindEvent('model.beforeSave', function () use ($model, $allowedPages) {
if (!$model->exists) {
throw new ApplicationException("You do not have permission to create new pages.");
}
if (!in_array($model->fileName, $allowedPages)) {
throw new ApplicationException("You are not permitted to modify {$model->fileName}");
}
});
});
}
/**
* Extends the Winter.Pages Index controller to only allow pages that the user has
* access to to be loaded.
*
* @return void
*/
protected function extendWinterPagesIndexController()
{
Index::extend(function ($controller) {
$allowedPages = UserPreference::forUser()->get($this->userPreferenceKey);
if (empty($allowedPages)) {
return;
}
Event::listen('cms.object.listInTheme', function ($object, $list) use ($allowedPages) {
if (!($object instanceof Page)) {
return;
}
foreach ($list as $index => $page) {
if (!in_array($page->fileName, $allowedPages)) {
$list->forget($index);
}
}
});
});
}
}
There are no comments yet
Be the first one to comment