re #25 allow rules edition + assignment

This commit is contained in:
Antonio Ramirez
2017-07-16 02:28:34 +02:00
parent f706ebb4fa
commit 84b009c5f0
17 changed files with 614 additions and 20 deletions

View File

@ -255,7 +255,7 @@ class AdminController extends Controller
$this->trigger(ActiveRecord::EVENT_BEFORE_DELETE, $event);
if ($user->delete()) {
Yii::$app->getSession()->setFlash('success', \Yii::t('usuario', 'User has been deleted'));
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'User has been deleted'));
$this->trigger(ActiveRecord::EVENT_AFTER_DELETE, $event);
} else {
Yii::$app->getSession()->setFlash(

View File

@ -0,0 +1,142 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Controller;
use Da\User\Model\Rule;
use Da\User\Search\RuleSearch;
use Da\User\Service\AuthRuleEditionService;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Validator\AjaxRequestModelValidator;
use Yii;
use yii\filters\VerbFilter;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
class RuleController extends Controller
{
use AuthManagerAwareTrait;
use ContainerAwareTrait;
/**
* @inheritdoc
*/
public function behaviors()
{
return [
[
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['POST'],
],
]
];
}
public function actionIndex()
{
/** @var RuleSearch $searchModel */
$searchModel = $this->make(RuleSearch::class);
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render(
'index',
[
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
]
);
}
public function actionCreate()
{
$model = $this->make(Rule::class, [], ['scenario' => 'create', 'className' => \yii\rbac\Rule::class]);
$this->make(AjaxRequestModelValidator::class, [$model])->validate();
if ($model->load(Yii::$app->request->post())) {
if ($this->make(AuthRuleEditionService::class, [$model])->run()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Authorization rule has been added.'));
return $this->redirect(['index']);
}
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Unable to create new authorization rule.'));
}
return $this->render(
'create',
[
'model' => $model
]
);
}
public function actionUpdate($name)
{
/** @var Rule $model */
$model = $this->make(Rule::class, [], ['scenario' => 'update']);
$rule = $this->findRule($name);
$model->setAttributes(
[
'previousName' => $name,
'name' => $rule->name,
'className' => get_class($rule)
]
);
$this->make(AjaxRequestModelValidator::class, [$model])->validate();
if ($model->load(Yii::$app->request->post())) {
if ($this->make(AuthRuleEditionService::class, [$model])->run()) {
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Authorization rule has been updated.'));
return $this->redirect(['index']);
}
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Unable to update authorization rule.'));
}
return $this->render(
'update',
[
'model' => $model,
]
);
}
public function actionDelete($name)
{
$rule = $this->findRule($name);
$this->getAuthManager()->remove($rule);
$this->getAuthManager()->invalidateCache();
Yii::$app->getSession()->setFlash('success', Yii::t('usuario', 'Authorization rule has been removed.'));
}
/**
* @param $name
*
* @throws NotFoundHttpException
* @return mixed|null|\yii\rbac\Rule
*/
protected function findRule($name)
{
$rule = $this->getAuthManager()->getRule($name);
if (!($rule instanceof \yii\rbac\Rule)) {
throw new NotFoundHttpException(Yii::t('usuario', 'Rule {0} not found.', $name));
}
return $rule;
}
}

View File

@ -13,6 +13,7 @@ namespace Da\User\Model;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Validator\RbacItemsValidator;
use Da\User\Validator\RbacRuleExistsValidator;
use Da\User\Validator\RbacRuleValidator;
use Yii;
use yii\base\Model;
@ -41,7 +42,7 @@ abstract class AbstractAuthItem extends Model
/**
* @var string[]
*/
public $children;
public $children = [];
/**
* @var \yii\rbac\Role|\yii\rbac\Permission
*/
@ -60,7 +61,7 @@ abstract class AbstractAuthItem extends Model
$this->description = $this->item->description;
$this->children = array_keys($this->getAuthManager()->getChildren($this->item->name));
if ($this->item->ruleName !== null) {
$this->rule = get_class($this->getAuthManager()->getRule($this->item->ruleName));
$this->rule = $this->item->ruleName;
}
}
}
@ -111,7 +112,7 @@ abstract class AbstractAuthItem extends Model
},
],
['children', RbacItemsValidator::class],
['rule', RbacRuleValidator::class],
['rule', RbacRuleExistsValidator::class],
];
}

60
src/User/Model/Rule.php Normal file
View File

@ -0,0 +1,60 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Model;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Validator\RbacRuleNameValidator;
use Da\User\Validator\RbacRuleValidator;
use yii\base\Model;
class Rule extends Model
{
use AuthManagerAwareTrait;
/**
* @var string
*/
public $name;
/**
* @var string fully qualified class name. Not to be confused with className() method
*/
public $className;
/**
* @var string holds the name of the rule previous update
*/
public $previousName;
/**
* @inheritdoc
*/
public function scenarios()
{
return [
'create' => ['name', 'className'],
'update' => ['name', 'className', 'previousName'],
];
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['name', 'className'], 'trim'],
[['name', 'className'], 'required'],
[['name', 'previousName'], 'match', 'pattern' => '/^[\w][\w-.:]+[\w]$/'],
[['name'], RbacRuleNameValidator::class, 'previousName' => $this->previousName],
[['className'], RbacRuleValidator::class],
];
}
}

View File

@ -0,0 +1,81 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Search;
use Da\User\Model\Rule;
use Da\User\Traits\ContainerAwareTrait;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use yii\db\Query;
class RuleSearch extends Rule
{
use ContainerAwareTrait;
/**
* @var string
*/
public $created_at;
/**
* @inheritdoc
*/
public function scenarios()
{
return Model::scenarios();
}
/**
* @inheritdoc
*/
public function rules()
{
return [
['name', 'string'],
];
}
/**
* @param array $params
*
* @return ActiveDataProvider
*/
public function search(array $params = [])
{
$query = (new Query())
->select(['name', 'data', 'created_at', 'updated_at'])
->from($this->getAuthManager()->ruleTable)
->orderBy(['name' => SORT_ASC]);
if ($this->load($params)) {
$query->andFilterWhere(['name' => $this->name]);
}
if (!$this->validate()) {
$query->where('0=1');
var_dump($this->load($params));
die();
}
return $this->make(
ActiveDataProvider::class,
[],
[
'query' => $query,
'db' => $this->getAuthManager()->db,
'sort' => [
'attributes' => ['name', 'created_at', 'updated_at']
]
]
);
}
}

View File

@ -46,11 +46,9 @@ class AuthItemEditionService implements ServiceInterface
$item->description = $this->model->description;
if (!empty($this->model->rule)) {
$rule = $this->make($this->model->rule);
if (null === $this->getAuthManager()->getRule($rule->name)) {
$this->getAuthManager()->add($rule);
if (null !== $this->getAuthManager()->getRule($this->model->rule)) {
$item->ruleName = $this->model->rule;
}
$item->ruleName = $rule->name;
} else {
$item->ruleName = null;
}

View File

@ -0,0 +1,53 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Service;
use Da\User\Contracts\ServiceInterface;
use Da\User\Model\Rule;
use Da\User\Traits\AuthManagerAwareTrait;
use Da\User\Traits\ContainerAwareTrait;
use Exception;
class AuthRuleEditionService implements ServiceInterface
{
use AuthManagerAwareTrait;
use ContainerAwareTrait;
protected $model;
public function __construct(Rule $model)
{
$this->model = $model;
}
public function run()
{
if (!$this->model->validate() || (!in_array($this->model->scenario, ['create', 'update']))) {
return false;
}
$rule = $this->make($this->model->className, [], ['name' => $this->model->name]);
try {
if ($this->model->scenario == 'create') {
$this->getAuthManager()->add($rule);
} else {
$this->getAuthManager()->update($this->model->previousName, $rule);
}
$this->getAuthManager()->invalidateCache();
} catch (Exception $e) {
return false;
}
return true;
}
}

View File

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Validator;
use Da\User\Traits\AuthManagerAwareTrait;
use Yii;
use yii\validators\Validator;
class RbacRuleExistsValidator extends Validator
{
use AuthManagerAwareTrait;
protected function validateValue($value)
{
$rule = $this->getAuthManager()->getRule($value);
if (!$rule) {
return [Yii::t('usuario', 'Rule {0} does not exists', $value), []];
}
}
}

View File

@ -0,0 +1,42 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Da\User\Validator;
use Da\User\Traits\AuthManagerAwareTrait;
use Yii;
use yii\rbac\Rule;
use yii\validators\Validator;
class RbacRuleNameValidator extends Validator
{
use AuthManagerAwareTrait;
/**
* @var
*/
public $previousName;
/**
* @inheritdoc
*/
protected function validateValue($value)
{
if ($this->previousName != $value) {
$rule = $this->getAuthManager()->getRule($value);
if ($rule instanceof Rule) {
return [Yii::t('usuario', 'Rule name {0} is already in use', $value), []];
}
}
return null;
}
}

View File

@ -11,26 +11,26 @@
namespace Da\User\Validator;
use Da\User\Traits\ContainerAwareTrait;
use Exception;
use ReflectionClass;
use Yii;
use yii\rbac\Rule;
use yii\validators\Validator;
class RbacRuleValidator extends Validator
{
use ContainerAwareTrait;
protected function validateValue($value)
{
try {
$class = new ReflectionClass($value);
} catch (Exception $e) {
return [Yii::t('usuario', 'Class "{0}" does not exist', $value), []];
}
$rule = $this->make($value);
if ($class->isInstantiable() == false) {
return [Yii::t('usuario', 'Rule class can not be instantiated'), []];
if (!($rule instanceof Rule)) {
return [Yii::t('usuario', 'Rule class must extend "yii\\rbac\\Rule".'), []];
}
if ($class->isSubclassOf('\yii\rbac\Rule') == false) {
return [Yii::t('usuario', 'Rule class must extend "yii\\rbac\\Rule"'), []];
} catch (Exception $e) {
return [Yii::t('usuario', 'Authentication rule class {0} can not be instantiated', $value), []];
}
}
}

View File

@ -10,6 +10,7 @@
*/
use dosamigos\selectize\SelectizeDropDownList;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\widgets\ActiveForm;
@ -32,7 +33,13 @@ use yii\widgets\ActiveForm;
<?= $form->field($model, 'description') ?>
<?= $form->field($model, 'rule') ?>
<?= $form->field($model, 'rule')->widget(SelectizeDropDownList::class, [
'items' => ArrayHelper::map(Yii::$app->getAuthManager()->getRules(), 'name', 'name'),
'options' => [
'prompt' => 'Select rule...'
]
]) ?>
<?= $form->field($model, 'children')->widget(
SelectizeDropDownList::class,

View File

@ -16,6 +16,7 @@
use Da\User\Helper\AuthHelper;
use dosamigos\selectize\SelectizeDropDownList;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
use yii\widgets\ActiveForm;
@ -33,7 +34,12 @@ $unassignedItems = Yii::$container->get(AuthHelper::class)->getUnassignedItems($
<?= $form->field($model, 'description') ?>
<?= $form->field($model, 'rule') ?>
<?= $form->field($model, 'rule')->widget(SelectizeDropDownList::class, [
'items' => ArrayHelper::map(Yii::$app->getAuthManager()->getRules(), 'name', 'name'),
'options' => [
'prompt' => 'Select rule...'
]
]) ?>
<?= $form->field($model, 'children')->widget(
SelectizeDropDownList::class,

View File

@ -0,0 +1,27 @@
<?php
/**
* @var $this yii\web\View
* @var $model \Da\User\Model\Rule
*/
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(
[
'enableClientValidation' => false,
'enableAjaxValidation' => true,
]
) ?>
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'className') ?>
<?= Html::submitButton(Yii::t('usuario', 'Save'), ['class' => 'btn btn-success btn-block']) ?>
<?php ActiveForm::end() ?>

View File

@ -0,0 +1,31 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
/**
* @var \Da\User\Model\Role $model
* @var $this yii\web\View
* @var $unassignedItems string[]
*/
$this->title = Yii::t('usuario', 'Create new rule');
$this->params['breadcrumbs'][] = $this->title;
?>
<?php $this->beginContent('@Da/User/resources/views/shared/admin_layout.php') ?>
<?= $this->render(
'_form',
[
'model' => $model,
]
) ?>
<?php $this->endContent() ?>

View File

@ -0,0 +1,76 @@
<?php
use yii\grid\ActionColumn;
use yii\grid\GridView;
use yii\helpers\Url;
use yii\rbac\Rule;
/**
* @var $dataProvider \yii\data\ActiveDataProvider
* @var $searchModel \Da\User\Search\RuleSearch
* @var $this yii\web\View
*/
$this->title = Yii::t('usuario', 'Rules');
$this->params['breadcrumbs'][] = $this->title;
?>
<?php $this->beginContent('@Da/User/resources/views/shared/admin_layout.php') ?>
<?= GridView::widget(
[
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'layout' => "{items}\n{pager}",
'columns' => [
[
'attribute' => 'name',
'label' => Yii::t('usuario', 'Name'),
'options' => [
'style' => 'width: 20%'
],
],
[
'attribute' => 'className',
'label' => Yii::t('usuario', 'Class'),
'value' => function ($row) {
$rule = unserialize($row['data']);
return get_class($rule);
},
'options' => [
'style' => 'width: 20%'
],
],
[
'attribute' => 'created_at',
'label' => Yii::t('usuario', 'Created at'),
'format' => 'datetime',
'options' => [
'style' => 'width: 20%'
],
],
[
'attribute' => 'updated_at',
'label' => Yii::t('usuario', 'Updated at'),
'format' => 'datetime',
'options' => [
'style' => 'width: 20%'
],
],
[
'class' => ActionColumn::className(),
'template' => '{update} {delete}',
'urlCreator' => function ($action, $model) {
return Url::to(['/user/rule/' . $action, 'name' => $model['name']]);
},
'options' => [
'style' => 'width: 5%'
],
]
],
]
) ?>
<?php $this->endContent() ?>

View File

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
/**
* @var \Da\User\Model\Role $model
* @var $this yii\web\View
* @var $unassignedItems string[]
*/
$this->title = Yii::t('usuario', 'Update rule');
$this->params['breadcrumbs'][] = ['label' => Yii::t('usuario', 'Rules'), 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<?php $this->beginContent('@Da/User/resources/views/shared/admin_layout.php') ?>
<?= $this->render(
'_form',
[
'model' => $model,
]
) ?>
<?php $this->endContent() ?>

View File

@ -32,6 +32,10 @@ use yii\bootstrap\Nav;
'label' => Yii::t('usuario', 'Permissions'),
'url' => ['/user/permission/index'],
],
[
'label' => Yii::t('usuario', 'Rules'),
'url' => ['/user/rule/index'],
],
[
'label' => Yii::t('usuario', 'Create'),
'items' => [
@ -47,6 +51,10 @@ use yii\bootstrap\Nav;
'label' => Yii::t('usuario', 'New permission'),
'url' => ['/user/permission/create'],
],
[
'label' => Yii::t('usuario', 'New rule'),
'url' => ['/user/rule/create'],
],
],
],
],