diff --git a/.github/ISSUE_REPLY_TEMPLATE.md b/.github/ISSUE_REPLY_TEMPLATE.md new file mode 100644 index 00000000..a5054a72 --- /dev/null +++ b/.github/ISSUE_REPLY_TEMPLATE.md @@ -0,0 +1,5 @@ +This project is not being actively maintained and there is no one officially offering support or help. + +Only PRs are being evaluated (there is no deadline for evaluation). + +Read more here: https://github.com/dektrium/yii2-user/issues/903 diff --git a/.github/support.yml b/.github/support.yml new file mode 100644 index 00000000..929458c3 --- /dev/null +++ b/.github/support.yml @@ -0,0 +1,22 @@ +# Configuration for support-requests - https://github.com/dessant/support-requests + +# Label used to mark issues as support requests +supportLabel: support + +# Comment to post on issues marked as support requests, `{issue-author}` is an +# optional placeholder. Set to `false` to disable +supportComment: > + :wave: @{issue-author}, this project is not being actively maintained and there is no one officially offering support or help. + Only PRs are being evaluated (there is no deadline for evaluation). + Read more here: https://github.com/dektrium/yii2-user/issues/903 +# Close issues marked as support requests +close: true + +# Lock issues marked as support requests +lock: false + +# Assign `off-topic` as the reason for locking. Set to `false` to disable +setLockReason: true + +# Repository to extend settings from +# _extends: repo diff --git a/RbacWebModule.php b/RbacWebModule.php index 45ecd915..c39531f9 100644 --- a/RbacWebModule.php +++ b/RbacWebModule.php @@ -19,6 +19,18 @@ */ class RbacWebModule extends BaseModule { + const EVENT_INIT = 'init'; + const EVENT_MENU = 'menu'; + const EVENT_PERMISSION_FORM = 'permissionForm'; + + const MODEL_ASSIGNMENT = 100; + const MODEL_AUTHITEM = 101; + const MODEL_PERMISSION = 102; + const MODEL_ROLE = 103; + const MODEL_RULE = 104; + const MODEL_RULE_SEARCH = 105; + const MODEL_SEARCH = 106; + /** * @var string */ @@ -29,11 +41,19 @@ class RbacWebModule extends BaseModule */ public $admins = []; - /** + /** * @var string The Administrator permission name. */ public $adminPermission; + /** + * @var array the model settings for the module. The keys will be one of the `self::MODEL_` constants + * and the value will be the model class names you wish to set. + * + * @see `setConfig()` method for the default settings + */ + public $modelSettings = []; + /** @inheritdoc */ public function behaviors() { @@ -50,6 +70,26 @@ public function behaviors() ], ]; } + + public function init() + { + parent::init(); + $this->setConfig(); + $this->trigger(self::EVENT_INIT); + } + + public function setConfig() + { + $this->modelSettings = array_replace_recursive([ + self::MODEL_ASSIGNMENT => 'dektrium\rbac\models\Assignment', + self::MODEL_AUTHITEM => 'dektrium\rbac\models\AuthItem', + self::MODEL_PERMISSION => 'dektrium\rbac\models\Permission', + self::MODEL_ROLE => 'dektrium\rbac\models\Role', + self::MODEL_RULE => 'dektrium\rbac\models\Rule', + self::MODEL_RULE_SEARCH => 'dektrium\rbac\models\RuleSearch', + self::MODEL_SEARCH => 'dektrium\rbac\models\Search', + ], $this->modelSettings); + } /** * Checks access. @@ -63,9 +103,14 @@ public function checkAccess() if (method_exists($user, 'getIsAdmin')) { return $user->getIsAdmin(); } else if ($this->adminPermission) { - return $this->adminPermission ? \Yii::$app->user->can($this->adminPermission) : false; + return \Yii::$app->user->can($this->adminPermission); } else { return isset($user->username) ? in_array($user->username, $this->admins) : false; } } + + public function getModelClass($m) + { + return $this->modelSettings[$m]; + } } diff --git a/controllers/AssignmentController.php b/controllers/AssignmentController.php index 88b48d9c..470ca68f 100644 --- a/controllers/AssignmentController.php +++ b/controllers/AssignmentController.php @@ -1,54 +1,55 @@ - - * - * For the full copyright and license information, please view the LICENSE.md - * file that was distributed with this source code. - */ - -namespace dektrium\rbac\controllers; - -use dektrium\rbac\models\Assignment; -use Yii; -use yii\web\Controller; - -/** - * @author Dmitry Erofeev - */ -class AssignmentController extends Controller -{ - /** - * Show form with auth items for user. - * - * @param int $id - */ - public function actionAssign($id) - { - $model = Yii::createObject([ - 'class' => Assignment::className(), - 'user_id' => $id, - ]); - - if ($model->load(\Yii::$app->request->post()) && $model->updateAssignments()) { - } - - return \dektrium\rbac\widgets\Assignments::widget([ - 'model' => $model, - ]); - /*$model = Yii::createObject([ - 'class' => Assignment::className(), - 'user_id' => $id, - ]); - - if ($model->load(Yii::$app->request->post()) && $model->updateAssignments()) { - - } - - return $this->render('assign', [ - 'model' => $model, - ]);*/ - } + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +namespace dektrium\rbac\controllers; + +use dektrium\rbac\RbacWebModule as Module; +use Yii; +use yii\web\Controller; + +/** + * @author Dmitry Erofeev + */ +class AssignmentController extends Controller +{ + protected $modelClass = Module::MODEL_ASSIGNMENT; + /** + * Show form with auth items for user. + * + * @param int $id + */ + public function actionAssign($id) + { + $model = Yii::createObject([ + 'class' => $this->module->getModelClass($this->modelClass), + 'user_id' => $id, + ]); + + if ($model->load(\Yii::$app->request->post()) && $model->updateAssignments()) { + } + + return \dektrium\rbac\widgets\Assignments::widget([ + 'model' => $model, + ]); + /*$model = Yii::createObject([ + 'class' => Assignment::className(), + 'user_id' => $id, + ]); + + if ($model->load(Yii::$app->request->post()) && $model->updateAssignments()) { + + } + + return $this->render('assign', [ + 'model' => $model, + ]);*/ + } } \ No newline at end of file diff --git a/controllers/ItemControllerAbstract.php b/controllers/ItemControllerAbstract.php index 375529f0..400d4b6e 100644 --- a/controllers/ItemControllerAbstract.php +++ b/controllers/ItemControllerAbstract.php @@ -76,7 +76,7 @@ public function actionCreate() { /** @var \dektrium\rbac\models\Role|\dektrium\rbac\models\Permission $model */ $model = \Yii::createObject([ - 'class' => $this->modelClass, + 'class' => $this->module->getModelClass($this->modelClass), 'scenario' => 'create', ]); @@ -103,11 +103,11 @@ public function actionUpdate($name) /** @var \dektrium\rbac\models\Role|\dektrium\rbac\models\Permission $model */ $item = $this->getItem($name); $model = \Yii::createObject([ - 'class' => $this->modelClass, + 'class' => $this->module->getModelClass($this->modelClass), 'scenario' => 'update', 'item' => $item, ]); - + $this->performAjaxValidation($model); if ($model->load(\Yii::$app->request->post()) && $model->save()) { @@ -141,7 +141,7 @@ protected function performAjaxValidation(Model $model) { if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) { \Yii::$app->response->format = Response::FORMAT_JSON; - echo json_encode(ActiveForm::validate($model)); + \Yii::$app->response->data = json_encode(ActiveForm::validate($model)); \Yii::$app->end(); } } diff --git a/controllers/PermissionController.php b/controllers/PermissionController.php index adf8d0d3..cc8aca59 100644 --- a/controllers/PermissionController.php +++ b/controllers/PermissionController.php @@ -1,40 +1,41 @@ - - * - * For the full copyright and license information, please view the LICENSE.md - * file that was distributed with this source code. - */ - -namespace dektrium\rbac\controllers; - -use yii\rbac\Permission; -use yii\web\NotFoundHttpException; -use yii\rbac\Item; - -/** - * @author Dmitry Erofeev - */ -class PermissionController extends ItemControllerAbstract -{ - /** @var string */ - protected $modelClass = 'dektrium\rbac\models\Permission'; - - /** @var int */ - protected $type = Item::TYPE_PERMISSION; - - /** @inheritdoc */ - protected function getItem($name) - { - $role = \Yii::$app->authManager->getPermission($name); - - if ($role instanceof Permission) { - return $role; - } - - throw new NotFoundHttpException; - } + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +namespace dektrium\rbac\controllers; + +use yii\rbac\Permission; +use yii\web\NotFoundHttpException; +use yii\rbac\Item; +use dektrium\rbac\RbacWebModule as Module; + +/** + * @author Dmitry Erofeev + */ +class PermissionController extends ItemControllerAbstract +{ + /** @var string */ + protected $modelClass = Module::MODEL_PERMISSION; + + /** @var int */ + protected $type = Item::TYPE_PERMISSION; + + /** @inheritdoc */ + protected function getItem($name) + { + $role = \Yii::$app->authManager->getPermission($name); + + if ($role instanceof Permission) { + return $role; + } + + throw new NotFoundHttpException; + } } \ No newline at end of file diff --git a/controllers/RoleController.php b/controllers/RoleController.php index 148459ae..69f2976f 100644 --- a/controllers/RoleController.php +++ b/controllers/RoleController.php @@ -1,39 +1,40 @@ - - * - * For the full copyright and license information, please view the LICENSE.md - * file that was distributed with this source code. - */ - -namespace dektrium\rbac\controllers; - -use yii\rbac\Role; -use yii\web\NotFoundHttpException; -use yii\rbac\Item; - -/** - * @author Dmitry Erofeev - */ -class RoleController extends ItemControllerAbstract -{ - /** @var string */ - protected $modelClass = 'dektrium\rbac\models\Role'; - - protected $type = Item::TYPE_ROLE; - - /** @inheritdoc */ - protected function getItem($name) - { - $role = \Yii::$app->authManager->getRole($name); - - if ($role instanceof Role) { - return $role; - } - - throw new NotFoundHttpException; - } + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +namespace dektrium\rbac\controllers; + +use yii\rbac\Role; +use yii\web\NotFoundHttpException; +use yii\rbac\Item; +use dektrium\rbac\RbacWebModule as Module; + +/** + * @author Dmitry Erofeev + */ +class RoleController extends ItemControllerAbstract +{ + /** @var string */ + protected $modelClass = Module::MODEL_ROLE; + + protected $type = Item::TYPE_ROLE; + + /** @inheritdoc */ + protected function getItem($name) + { + $role = \Yii::$app->authManager->getRole($name); + + if ($role instanceof Role) { + return $role; + } + + throw new NotFoundHttpException; + } } \ No newline at end of file diff --git a/controllers/RuleController.php b/controllers/RuleController.php index e73affad..cd599fd4 100644 --- a/controllers/RuleController.php +++ b/controllers/RuleController.php @@ -1,203 +1,205 @@ - - * - * For the full copyright and license information, please view the LICENSE.md - * file that was distributed with this source code. - */ - -namespace dektrium\rbac\controllers; - -use dektrium\rbac\components\DbManager; -use dektrium\rbac\models\Rule; -use dektrium\rbac\models\RuleSearch; -use yii\di\Instance; -use yii\filters\VerbFilter; -use yii\web\Controller; -use yii\web\NotFoundHttpException; -use yii\web\Response; -use yii\widgets\ActiveForm; - -/** - * Controller for managing rules. - * - * @author Dmitry Erofeev - */ -class RuleController extends Controller -{ - /** - * @var string|DbManager The auth manager component ID. - */ - public $authManager = 'authManager'; - - /** - * This method will set [[authManager]] to be the 'authManager' application component, if it is `null`. - */ - public function init() - { - parent::init(); - - $this->authManager = Instance::ensure($this->authManager, DbManager::className()); - } - - /** - * @return array - */ - public function behaviors() - { - return [ - 'verbFilter' => [ - 'class' => VerbFilter::className(), - 'actions' => [ - 'delete' => ['POST'], - ], - ], - ]; - } - - /** - * Shows list of created rules. - * - * @return string - * @throws \yii\base\InvalidConfigException - */ - public function actionIndex() - { - $searchModel = $this->getSearchModel(); - $dataProvider = $searchModel->search(\Yii::$app->request->queryParams); - - return $this->render('index', [ - 'searchModel' => $searchModel, - 'dataProvider' => $dataProvider, - ]); - } - - /** - * Shows page where new rule can be added. - * - * @return array|string - */ - public function actionCreate() - { - $model = $this->getModel(Rule::SCENARIO_CREATE); - - if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) { - \Yii::$app->response->format = Response::FORMAT_JSON; - return ActiveForm::validate($model); - } - - if ($model->load(\Yii::$app->request->post()) && $model->create()) { - \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Rule has been added')); - return $this->redirect(['index']); - } - - return $this->render('create', [ - 'model' => $model, - ]); - } - - /** - * Updates existing auth rule. - * @param string $name - * @return array|string|Response - * @throws NotFoundHttpException - */ - public function actionUpdate($name) - { - $model = $this->getModel(Rule::SCENARIO_UPDATE); - $rule = $this->findRule($name); - - $model->setOldName($name); - $model->setAttributes([ - 'name' => $rule->name, - 'class' => get_class($rule), - ]); - - if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) { - \Yii::$app->response->format = Response::FORMAT_JSON; - return ActiveForm::validate($model); - } - - if ($model->load(\Yii::$app->request->post()) && $model->update()) { - \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Rule has been updated')); - return $this->redirect(['index']); - } - - return $this->render('update', [ - 'model' => $model, - ]); - } - - /** - * Removes rule. - * - * @param string $name - * @return string - * @throws NotFoundHttpException - */ - public function actionDelete($name) - { - $rule = $this->findRule($name); - - $this->authManager->remove($rule); - $this->authManager->invalidateCache(); - - \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Rule has been removed')); - - return $this->redirect(['index']); - } - - /** - * Searches for rules. - * - * @param string|null $q - * @return array - */ - public function actionSearch($q = null) - { - \Yii::$app->response->format = Response::FORMAT_JSON; - - return ['results' => $this->getSearchModel()->getRuleNames($q)]; - } - - /** - * @param string $scenario - * @return Rule - * @throws \yii\base\InvalidConfigException - */ - private function getModel($scenario) - { - return \Yii::createObject([ - 'class' => Rule::className(), - 'scenario' => $scenario, - ]); - } - - /** - * @return RuleSearch - * @throws \yii\base\InvalidConfigException - */ - private function getSearchModel() - { - return \Yii::createObject(RuleSearch::className()); - } - - /** - * @param string $name - * @return mixed|null|\yii\rbac\Rule - * @throws NotFoundHttpException - */ - private function findRule($name) - { - $rule = $this->authManager->getRule($name); - - if ($rule instanceof \yii\rbac\Rule) { - return $rule; - } - - throw new NotFoundHttpException(\Yii::t('rbac', 'Not found')); - } + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +namespace dektrium\rbac\controllers; + +use dektrium\rbac\components\DbManager; +use dektrium\rbac\models\Rule; +use dektrium\rbac\models\RuleSearch; +use dektrium\rbac\RbacWebModule as Module; +use yii\di\Instance; +use yii\filters\VerbFilter; +use yii\web\Controller; +use yii\web\NotFoundHttpException; +use yii\web\Response; +use yii\widgets\ActiveForm; + +/** + * Controller for managing rules. + * + * @author Dmitry Erofeev + */ +class RuleController extends Controller +{ + protected $modelClass = Module::MODEL_RULE; + /** + * @var string|DbManager The auth manager component ID. + */ + public $authManager = 'authManager'; + + /** + * This method will set [[authManager]] to be the 'authManager' application component, if it is `null`. + */ + public function init() + { + parent::init(); + + $this->authManager = Instance::ensure($this->authManager, DbManager::className()); + } + + /** + * @return array + */ + public function behaviors() + { + return [ + 'verbFilter' => [ + 'class' => VerbFilter::className(), + 'actions' => [ + 'delete' => ['POST'], + ], + ], + ]; + } + + /** + * Shows list of created rules. + * + * @return string + * @throws \yii\base\InvalidConfigException + */ + public function actionIndex() + { + $searchModel = $this->getSearchModel(); + $dataProvider = $searchModel->search(\Yii::$app->request->queryParams); + + return $this->render('index', [ + 'searchModel' => $searchModel, + 'dataProvider' => $dataProvider, + ]); + } + + /** + * Shows page where new rule can be added. + * + * @return array|string + */ + public function actionCreate() + { + $model = $this->getModel(Rule::SCENARIO_CREATE); + + if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) { + \Yii::$app->response->format = Response::FORMAT_JSON; + return ActiveForm::validate($model); + } + + if ($model->load(\Yii::$app->request->post()) && $model->create()) { + \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Rule has been added')); + return $this->redirect(['index']); + } + + return $this->render('create', [ + 'model' => $model, + ]); + } + + /** + * Updates existing auth rule. + * @param string $name + * @return array|string|Response + * @throws NotFoundHttpException + */ + public function actionUpdate($name) + { + $model = $this->getModel(Rule::SCENARIO_UPDATE); + $rule = $this->findRule($name); + + $model->setOldName($name); + $model->setAttributes([ + 'name' => $rule->name, + 'class' => get_class($rule), + ]); + + if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) { + \Yii::$app->response->format = Response::FORMAT_JSON; + return ActiveForm::validate($model); + } + + if ($model->load(\Yii::$app->request->post()) && $model->update()) { + \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Rule has been updated')); + return $this->redirect(['index']); + } + + return $this->render('update', [ + 'model' => $model, + ]); + } + + /** + * Removes rule. + * + * @param string $name + * @return string + * @throws NotFoundHttpException + */ + public function actionDelete($name) + { + $rule = $this->findRule($name); + + $this->authManager->remove($rule); + $this->authManager->invalidateCache(); + + \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Rule has been removed')); + + return $this->redirect(['index']); + } + + /** + * Searches for rules. + * + * @param string|null $q + * @return array + */ + public function actionSearch($q = null) + { + \Yii::$app->response->format = Response::FORMAT_JSON; + + return ['results' => $this->getSearchModel()->getRuleNames($q)]; + } + + /** + * @param string $scenario + * @return Rule + * @throws \yii\base\InvalidConfigException + */ + private function getModel($scenario) + { + return \Yii::createObject([ + 'class' => $this->module->getModelClass(MODULE::MODEL_RULE), + 'scenario' => $scenario, + ]); + } + + /** + * @return RuleSearch + * @throws \yii\base\InvalidConfigException + */ + private function getSearchModel() + { + return \Yii::createObject($this->module->getModelClass(MODULE::MODEL_RULE_SEARCH)); + } + + /** + * @param string $name + * @return mixed|null|\yii\rbac\Rule + * @throws NotFoundHttpException + */ + private function findRule($name) + { + $rule = $this->authManager->getRule($name); + + if ($rule instanceof \yii\rbac\Rule) { + return $rule; + } + + throw new NotFoundHttpException(\Yii::t('rbac', 'Not found')); + } } \ No newline at end of file diff --git a/events/MenuEvent.php b/events/MenuEvent.php new file mode 100644 index 00000000..f2ca5204 --- /dev/null +++ b/events/MenuEvent.php @@ -0,0 +1,8 @@ + - * - * For the full copyright and license information, please view the LICENSE.md - * file that was distributed with this source code. - */ - -namespace dektrium\rbac\models; - -use yii\base\InvalidConfigException; -use yii\base\InvalidParamException; -use yii\base\Model; -use yii\helpers\Json; -use yii\rbac\Item; -use dektrium\rbac\validators\RbacValidator; - -/** - * @author Dmitry Erofeev - */ -abstract class AuthItem extends Model -{ - /** - * @var string - */ - public $name; - - /** - * @var string - */ - public $description; - - /** - * @var string - */ - public $rule; - - /** - * @var string - */ - public $data; - - /** - * @var bool - */ - public $dataCannotBeDecoded = false; - - /** - * @var string[] - */ - public $children = []; - - /** - * @var \yii\rbac\Role|\yii\rbac\Permission - */ - public $item; - - /** - * @var \dektrium\rbac\components\DbManager - */ - protected $manager; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - $this->manager = \Yii::$app->authManager; - if ($this->item instanceof Item) { - $this->name = $this->item->name; - $this->description = $this->item->description; - $this->children = array_keys($this->manager->getChildren($this->item->name)); - - try { - if (is_object($this->item->data)) { - $this->dataCannotBeDecoded = true; - } else if ($this->item->data !== null) { - $this->data = Json::encode($this->item->data); - } - } catch (InvalidParamException $e) { - $this->dataCannotBeDecoded = true; - } - - if ($this->item->ruleName !== null) { - $this->rule = get_class($this->manager->getRule($this->item->ruleName)); - } - } - } - - /** - * @inheritdoc - */ - public function attributeLabels() - { - return [ - 'name' => \Yii::t('rbac', 'Name'), - 'description' => \Yii::t('rbac', 'Description'), - 'children' => \Yii::t('rbac', 'Children'), - 'rule' => \Yii::t('rbac', 'Rule'), - ]; - } - - /** - * @inheritdoc - */ - public function scenarios() - { - return [ - 'create' => ['name', 'description', 'children', 'rule', 'data'], - 'update' => ['name', 'description', 'children', 'rule', 'data'], - ]; - } - - /** - * @inheritdoc - */ - public function rules() - { - return [ - ['name', 'required'], - [['name', 'description', 'rule'], 'trim'], - ['name', function () { - if ($this->manager->getItem($this->name) !== null) { - $this->addError('name', \Yii::t('rbac', 'Auth item with such name already exists')); - } - }, 'when' => function () { - return $this->scenario == 'create' || $this->item->name != $this->name; - }], - ['children', RbacValidator::className()], - ['rule', function () { - $rule = $this->manager->getRule($this->rule); - - if (!$rule) { - $this->addError('rule', \Yii::t('rbac', 'Rule {0} does not exist', $this->rule)); - } - }], - ['data', function () { - try { - Json::decode($this->data); - } catch (InvalidParamException $e) { - $this->addError('data', \Yii::t('rbac', 'Data must be type of JSON ({0})', $e->getMessage())); - } - }], - ]; - } - - /** - * Saves item. - * - * @return bool - */ - public function save() - { - if ($this->validate() == false) { - return false; - } - - if ($isNewItem = ($this->item === null)) { - $this->item = $this->createItem($this->name); - } else { - $oldName = $this->item->name; - } - - $this->item->name = $this->name; - $this->item->description = $this->description; - $this->item->data = $this->data == null ? null : Json::decode($this->data); - $this->item->ruleName = empty($this->rule) ? null : $this->rule; - - if ($isNewItem) { - \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Item has been created')); - $this->manager->add($this->item); - } else { - \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Item has been updated')); - $this->manager->update($oldName, $this->item); - } - - $this->updateChildren(); - - $this->manager->invalidateCache(); - - return true; - } - - /** - * Updated items children. - */ - protected function updateChildren() - { - $children = $this->manager->getChildren($this->item->name); - $childrenNames = array_keys($children); - - if (is_array($this->children)) { - // remove children that - foreach (array_diff($childrenNames, $this->children) as $item) { - $this->manager->removeChild($this->item, $children[$item]); - } - // add new children - foreach (array_diff($this->children, $childrenNames) as $item) { - $this->manager->addChild($this->item, $this->manager->getItem($item)); - } - } else { - $this->manager->removeChildren($this->item); - } - } - - /** - * @return array An array of unassigned items. - */ - abstract public function getUnassignedItems(); - - /** - * @param string $name - * @return \yii\rbac\Item - */ - abstract protected function createItem($name); -} + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +namespace dektrium\rbac\models; + +use yii\base\InvalidConfigException; +use yii\base\InvalidParamException; +use yii\base\Model; +use yii\helpers\Json; +use yii\rbac\Item; +use dektrium\rbac\validators\RbacValidator; + +/** + * @author Dmitry Erofeev + */ +abstract class AuthItem extends Model +{ + /** + * @var string + */ + public $name; + + /** + * @var string + */ + public $description; + + /** + * @var string + */ + public $rule; + + /** + * @var string + */ + public $data; + + /** + * @var bool + */ + public $dataCannotBeDecoded = false; + + /** + * @var string[] + */ + public $children = []; + + /** + * @var \yii\rbac\Role|\yii\rbac\Permission + */ + public $item; + + /** + * @var \dektrium\rbac\components\DbManager + */ + protected $manager; + + /** + * @inheritdoc + */ + public function init() + { + parent::init(); + $this->manager = \Yii::$app->authManager; + if ($this->item instanceof Item) { + $this->name = $this->item->name; + $this->description = $this->item->description; + $this->children = array_keys($this->manager->getChildren($this->item->name)); + + try { + if (is_object($this->item->data)) { + $this->dataCannotBeDecoded = true; + } else if ($this->item->data !== null) { + $this->data = Json::encode($this->item->data); + } + } catch (InvalidParamException $e) { + $this->dataCannotBeDecoded = true; + } + + if ($this->item->ruleName !== null) { + $this->rule = get_class($this->manager->getRule($this->item->ruleName)); + } + } + } + + /** + * @inheritdoc + */ + public function attributeLabels() + { + return [ + 'name' => \Yii::t('rbac', 'Name'), + 'description' => \Yii::t('rbac', 'Description'), + 'children' => \Yii::t('rbac', 'Children'), + 'rule' => \Yii::t('rbac', 'Rule'), + ]; + } + + /** + * @inheritdoc + */ + public function scenarios() + { + return [ + 'create' => ['name', 'description', 'children', 'rule', 'data'], + 'update' => ['name', 'description', 'children', 'rule', 'data'], + ]; + } + + /** + * @inheritdoc + */ + public function rules() + { + return [ + ['name', 'required'], + [['name', 'description', 'rule'], 'trim'], + ['name', function () { + if ($this->manager->getItem($this->name) !== null) { + $this->addError('name', \Yii::t('rbac', 'Auth item with such name already exists')); + } + }, 'when' => function () { + return $this->scenario == 'create' || $this->item->name != $this->name; + }], + ['children', RbacValidator::className()], + ['rule', function () { + $rule = $this->manager->getRule($this->rule); + + if (!$rule) { + $this->addError('rule', \Yii::t('rbac', 'Rule {0} does not exist', $this->rule)); + } + }], + ['data', function () { + try { + Json::decode($this->data); + } catch (InvalidParamException $e) { + $this->addError('data', \Yii::t('rbac', 'Data must be type of JSON ({0})', $e->getMessage())); + } + }], + ]; + } + + /** + * Saves item. + * + * @return bool + */ + public function save() + { + if ($this->validate() == false) { + return false; + } + + if ($isNewItem = ($this->item === null)) { + $this->item = $this->createItem($this->name); + } else { + $oldName = $this->item->name; + } + + $this->item->name = $this->name; + $this->item->description = $this->description; + $this->item->data = $this->data == null ? null : Json::decode($this->data); + $this->item->ruleName = empty($this->rule) ? null : $this->rule; + + if ($isNewItem) { + \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Item has been created')); + $this->manager->add($this->item); + } else { + \Yii::$app->session->setFlash('success', \Yii::t('rbac', 'Item has been updated')); + $this->manager->update($oldName, $this->item); + } + + $this->updateChildren(); + + $this->manager->invalidateCache(); + + $this->afterSave($isNewItem); + + return true; + } + + /** + * Run after saving + * @param type $isNewItem + */ + public function afterSave($isNewItem) + { + + } + + /** + * Updated items children. + */ + protected function updateChildren() + { + $children = $this->manager->getChildren($this->item->name); + $childrenNames = array_keys($children); + + if (is_array($this->children)) { + // remove children that + foreach (array_diff($childrenNames, $this->children) as $item) { + $this->manager->removeChild($this->item, $children[$item]); + } + // add new children + foreach (array_diff($this->children, $childrenNames) as $item) { + $this->manager->addChild($this->item, $this->manager->getItem($item)); + } + } else { + $this->manager->removeChildren($this->item); + } + } + + /** + * @return array An array of unassigned items. + */ + abstract public function getUnassignedItems(); + + /** + * @param string $name + * @return \yii\rbac\Item + */ + abstract protected function createItem($name); +} diff --git a/views/permission/_form.php b/views/permission/_form.php index f086a8d9..3fee435b 100644 --- a/views/permission/_form.php +++ b/views/permission/_form.php @@ -1,67 +1,82 @@ - - * - * For the full copyright and license information, please view the LICENSE.md - * file that was distributed with this source code. - */ - -/** - * @var $this yii\web\View - * @var $model dektrium\rbac\models\Role - */ - -use kartik\select2\Select2; -use yii\helpers\Url; -use yii\web\JsExpression; -use yii\widgets\ActiveForm; -use yii\helpers\Html; - -?> - - false, - 'enableAjaxValidation' => true, -]) ?> - -field($model, 'name') ?> - -field($model, 'description')->textarea() ?> - -field($model, 'rule')->widget(Select2::className(), [ - 'options' => [ - 'placeholder' => Yii::t('rbac', 'Select rule'), - ], - 'pluginOptions' => [ - 'ajax' => [ - 'url' => Url::to(['/rbac/rule/search']), - 'data' => new JsExpression('function(params) { return {q:params.term}; }') - ], - 'allowClear' => true, - ], -]) ?> - -dataCannotBeDecoded): ?> -
- -
- - field($model, 'data')->textarea([ - 'rows' => 3 - ]) ?> - - -field($model, 'children')->widget(Select2::className(), [ - 'data' => $model->getUnassignedItems(), - 'options' => [ - 'id' => 'children', - 'multiple' => true - ], -]) ?> - - 'btn btn-success btn-block']) ?> - + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +/** + * @var $this yii\web\View + * @var $model dektrium\rbac\models\Role + */ + +use dektrium\rbac\events\PermissionFormEvent; +use dektrium\rbac\RbacWebModule; +use kartik\select2\Select2; +use yii\helpers\Html; +use yii\helpers\Url; +use yii\web\JsExpression; +use yii\widgets\ActiveForm; + + +$event = new PermissionFormEvent(); + +?> + + false, + 'enableAjaxValidation' => true, +]) ?> + +field($model, 'name') ?> + +field($model, 'description')->textarea() ?> + +field($model, 'rule')->widget(Select2::className(), [ + 'options' => [ + 'placeholder' => Yii::t('rbac', 'Select rule'), + ], + 'pluginOptions' => [ + 'ajax' => [ + 'url' => Url::to(['/rbac/rule/search']), + 'data' => new JsExpression('function(params) { return {q:params.term}; }') + ], + 'allowClear' => true, + ], +]) ?> + +dataCannotBeDecoded): ?> +
+ +
+ + field($model, 'data')->textarea([ + 'rows' => 3 + ]) ?> + + +field($model, 'children')->widget(Select2::className(), [ + 'data' => $model->getUnassignedItems(), + 'options' => [ + 'id' => 'children', + 'multiple' => true + ], +]) ?> + +context->module->trigger(RbacWebModule::EVENT_PERMISSION_FORM, $event); + +if (!empty($event->renderViews)) { + foreach ($event->renderViews as $view) { + echo $this->render($view, ['form' => $form, 'model' => $model]); + } +} +?> + + 'btn btn-success btn-block']) ?> + \ No newline at end of file diff --git a/widgets/Menu.php b/widgets/Menu.php index c48cb631..2a26a428 100644 --- a/widgets/Menu.php +++ b/widgets/Menu.php @@ -1,82 +1,95 @@ - - * - * For the full copyright and license information, please view the LICENSE.md - * file that was distributed with this source code. - */ - -namespace dektrium\rbac\widgets; - -use yii\bootstrap\Nav; - -/** - * Menu widget. - * - * @author Dmitry Erofeev - */ -class Menu extends Nav -{ - /** - * @inheritdoc - */ - public $options = [ - 'class' => 'nav-tabs' - ]; - - /** - * @inheritdoc - */ - public function init() - { - parent::init(); - - $userModuleClass = 'dektrium\user\Module'; - $isUserModuleInstalled = \Yii::$app->getModule('user') instanceof $userModuleClass; - - $this->items = [ - [ - 'label' => \Yii::t('rbac', 'Users'), - 'url' => ['/user/admin/index'], - 'visible' => $isUserModuleInstalled, - ], - [ - 'label' => \Yii::t('rbac', 'Roles'), - 'url' => ['/rbac/role/index'], - ], - [ - 'label' => \Yii::t('rbac', 'Permissions'), - 'url' => ['/rbac/permission/index'], - ], - [ - 'label' => \Yii::t('rbac', 'Rules'), - 'url' => ['/rbac/rule/index'], - ], - [ - 'label' => \Yii::t('rbac', 'Create'), - 'items' => [ - [ - 'label' =>\ Yii::t('rbac', 'New user'), - 'url' => ['/user/admin/create'], - 'visible' => $isUserModuleInstalled, - ], - [ - 'label' => \Yii::t('rbac', 'New role'), - 'url' => ['/rbac/role/create'] - ], - [ - 'label' => \Yii::t('rbac', 'New permission'), - 'url' => ['/rbac/permission/create'] - ], - [ - 'label' => \Yii::t('rbac', 'New rule'), - 'url' => ['/rbac/rule/create'] - ] - ] - ], - ]; - } + + * + * For the full copyright and license information, please view the LICENSE.md + * file that was distributed with this source code. + */ + +namespace dektrium\rbac\widgets; + +use dektrium\rbac\events\MenuEvent; +use dektrium\rbac\RbacWebModule as Module; +use Yii; +use yii\bootstrap\Nav; + +/** + * Menu widget. + * + * @author Dmitry Erofeev + */ +class Menu extends Nav +{ + /** + * @inheritdoc + */ + public $options = [ + 'class' => 'nav-tabs' + ]; + + /** + * @inheritdoc + */ + public function init() + { + parent::init(); + + $userModuleClass = 'dektrium\user\Module'; + $isUserModuleInstalled = Yii::$app->getModule('user') instanceof $userModuleClass; + + $create = [ + 'label' => Yii::t('rbac', 'Create'), + 'items' => [ + [ + 'label' => Yii::t('rbac', 'New user'), + 'url' => ['/user/admin/create'], + 'visible' => $isUserModuleInstalled, + ], + [ + 'label' => Yii::t('rbac', 'New role'), + 'url' => ['/rbac/role/create'] + ], + [ + 'label' => Yii::t('rbac', 'New permission'), + 'url' => ['/rbac/permission/create'] + ], + [ + 'label' => Yii::t('rbac', 'New rule'), + 'url' => ['/rbac/rule/create'] + ] + ] + ]; + + $this->items = [ + [ + 'label' => Yii::t('rbac', 'Users'), + 'url' => ['/user/admin/index'], + 'visible' => $isUserModuleInstalled, + ], + [ + 'label' => Yii::t('rbac', 'Roles'), + 'url' => ['/rbac/role/index'], + ], + [ + 'label' => Yii::t('rbac', 'Permissions'), + 'url' => ['/rbac/permission/index'], + ], + [ + 'label' => Yii::t('rbac', 'Rules'), + 'url' => ['/rbac/rule/index'], + ], + ]; + + $event = new MenuEvent(); + + $this->view->context->module->trigger(Module::EVENT_MENU, $event); + + if (!empty($event->items)) { + array_push($this->items, $event->items); + } + array_push($this->items, $create); + } } \ No newline at end of file