mirror of
https://github.com/humhub/humhub.git
synced 2025-01-16 21:58:17 +01:00
ControllerAccess
This commit is contained in:
parent
7da8715f57
commit
03fdb7a5df
@ -22,6 +22,7 @@
|
||||
"yiisoft/yii2-imagine": "~2.0.0",
|
||||
"raoul2000/yii2-jcrop-widget": "*",
|
||||
"kartik-v/yii2-widgets": "*",
|
||||
"phpoffice/phpexcel": "*",
|
||||
"cebe/markdown": "1.0.2",
|
||||
"yiisoft/yii2-jui": "~2.0.0",
|
||||
"zendframework/zend-http": "*",
|
||||
@ -52,7 +53,7 @@
|
||||
"bower-asset/imagesloaded": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"yiisoft/yii2-codeception": "~2.0.0",
|
||||
"codeception/codeception": "*",
|
||||
"yiisoft/yii2-debug": "~2.0.0",
|
||||
"yiisoft/yii2-gii": "~2.0.0",
|
||||
"yiisoft/yii2-faker": "~2.0.0",
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
namespace humhub\compat;
|
||||
|
||||
use humhub\widgets\MarkdownField;
|
||||
use humhub\widgets\MultiSelectField;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
@ -234,7 +236,7 @@ class HForm extends \yii\base\Component
|
||||
}
|
||||
return $field;
|
||||
case 'multiselectdropdown':
|
||||
return \humhub\widgets\MultiSelectField::widget([
|
||||
return MultiSelectField::widget([
|
||||
'form' => $this->form,
|
||||
'model' => $model,
|
||||
'attribute' => $name,
|
||||
@ -289,8 +291,7 @@ class HForm extends \yii\base\Component
|
||||
]);
|
||||
case 'markdown':
|
||||
$options['id'] = $name;
|
||||
$returnField = $this->form->field($model, $name)->textarea($options);
|
||||
$returnField .= \humhub\widgets\MarkdownEditor::widget(array('fieldId' => $name));
|
||||
$returnField = $this->form->field($model, $name)->widget(MarkdownField::class, $options);
|
||||
return $returnField;
|
||||
default:
|
||||
return "Field Type " . $definition['type'] . " not supported by Compat HForm";
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
namespace humhub\components;
|
||||
|
||||
use humhub\components\access\ControllerAccess;
|
||||
use humhub\components\behaviors\AccessControl;
|
||||
use Yii;
|
||||
use yii\helpers\Url;
|
||||
@ -49,36 +50,10 @@ class Controller extends \yii\web\Controller
|
||||
public $prependActionTitles = true;
|
||||
|
||||
/**
|
||||
* @var string[] defines the allowed actions for guests if $strictGuestMode is set to true.
|
||||
* @var string defines the ControllerAccess class for this controller responsible for managing access rules
|
||||
* @see self::getAccess()
|
||||
*/
|
||||
public $guestActions = [];
|
||||
|
||||
/**
|
||||
* @var bool if set to true will only allow actions defined in $guestActions, otherwise the controller has to handle its own guest handling
|
||||
*/
|
||||
public $strictGuestMode = false;
|
||||
|
||||
/**
|
||||
* @var bool if set to true only (space/profile/system) admins are allowed to access any controller action
|
||||
*/
|
||||
protected $adminOnly = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
|
||||
return [
|
||||
'acl' => [
|
||||
'class' => AccessControl::className(),
|
||||
'adminOnly' => $this->adminOnly,
|
||||
'guestAllowedActions' => $this->guestActions,
|
||||
'loggedInOnly' => $this->strictGuestMode,
|
||||
'rules' => $this->getAccessRules()
|
||||
]
|
||||
];
|
||||
}
|
||||
protected $access = ControllerAccess::class;
|
||||
|
||||
/**
|
||||
* Returns access rules for the standard access control behavior.
|
||||
@ -91,6 +66,18 @@ class Controller extends \yii\web\Controller
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|ControllerAccess returns an ControllerAccess instance
|
||||
*/
|
||||
public function getAccess()
|
||||
{
|
||||
if(!$this->access) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Yii::createObject($this->access);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -100,6 +87,16 @@ class Controller extends \yii\web\Controller
|
||||
$this->trigger(self::EVENT_INIT);
|
||||
}
|
||||
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'acl' => [
|
||||
'class' => AccessControl::class,
|
||||
'rules' => $this->getAccessRules()
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
217
protected/humhub/components/access/AccessValidator.php
Normal file
217
protected/humhub/components/access/AccessValidator.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 30.07.2017
|
||||
* Time: 03:07
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\base\Object;
|
||||
|
||||
/**
|
||||
* AccessValidators are responsible for validating a given set of rules.
|
||||
*
|
||||
* Rules consist of an array with at leas an rule name and optional further rule settings.
|
||||
* If only a rule name is given, the rule is considered global, otherwise it may be restricted to specific actions by
|
||||
* providing an action setting e.g.:
|
||||
*
|
||||
* ```
|
||||
* // Global myRule
|
||||
* ['myRule']
|
||||
*
|
||||
* // MyRule restricted to action1 and action2
|
||||
* ['myRule' => ['action1', 'action2']]
|
||||
*
|
||||
* // Alternative action configuration
|
||||
* ['myRule', 'actions' => ['action1', 'action2']]
|
||||
* ```
|
||||
*
|
||||
* A Validator has an unique name which is used to detect related rules and can filter out non related rules by
|
||||
* means of the `filterRelatedRules()` function.
|
||||
*
|
||||
* Subclasses have to overwrite the `run()` function, which holds the actual validation logic.
|
||||
*
|
||||
* AccessValidators have access to a ControllerAccess instance, which holds the ruleset and validation state.
|
||||
*
|
||||
* This abstract validator class furthermore provides some helper functions as:
|
||||
*
|
||||
* - `isActionRelated()`: Checks if a given rule is related to the current action
|
||||
* - `extractActions()`: Extracts the action settings from a given rule array
|
||||
* - `getRuleName()`: Extracts the rule name from a given rule array
|
||||
*
|
||||
* @package humhub\components\access
|
||||
*/
|
||||
abstract class AccessValidator extends Object
|
||||
{
|
||||
/**
|
||||
* @var string the name of the valdiator
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var int http error code used in case the validation failes
|
||||
*/
|
||||
public $code = 403;
|
||||
|
||||
/**
|
||||
* @var string validator error message
|
||||
*/
|
||||
public $reason;
|
||||
|
||||
/**
|
||||
* @var ControllerAccess access instance
|
||||
*/
|
||||
public $access;
|
||||
|
||||
/**
|
||||
* @var bool determines if this validator is only interested in action related rules or all validator related rules
|
||||
*/
|
||||
public $actionFilter = true;
|
||||
|
||||
public function init()
|
||||
{
|
||||
if(!$this->name) {
|
||||
$this->name = static::class;
|
||||
}
|
||||
|
||||
if(empty($this->reason)) {
|
||||
$this->reason = Yii::t('error', 'You are not permitted to access this section.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for validating the given ruleset.
|
||||
* Related rules may be filtered by means of the `filterRelatedRules()` function.
|
||||
* The whole rule set can be retrieved by calling `$this->access->rules`.
|
||||
*
|
||||
*
|
||||
* @return boolean true if validation passed otherwise true
|
||||
*/
|
||||
abstract function run();
|
||||
|
||||
/**
|
||||
* Filters out all rules which are not related to this validator.
|
||||
*
|
||||
* @param $rules
|
||||
* @return array
|
||||
*/
|
||||
protected function filterRelatedRules($rules = null)
|
||||
{
|
||||
if($rules === null) {
|
||||
$rules = $this->access->getRules();
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($rules as $rule) {
|
||||
$ruleName = $this->getRuleName($rule);
|
||||
|
||||
if($this->name === $ruleName) {
|
||||
$result[] = $rule;
|
||||
}
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current action is contained in the given $rule.
|
||||
* This is the case either if the current action is contained in the rules action settings or
|
||||
* the rule is global (no action restriction).
|
||||
*
|
||||
* @param array|string $actionArray single action id or array of action ids
|
||||
* @return bool
|
||||
*/
|
||||
protected function isActionRelated($rule)
|
||||
{
|
||||
$actions = $this->extractActions($rule);
|
||||
|
||||
// If no action array is given we consider the rule to be controller global
|
||||
if (empty($actions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_array($actions) && !is_string($actions)) {
|
||||
throw new InvalidParamException('Invalid rule provided!');
|
||||
}
|
||||
|
||||
$actions = is_string($actions) ? [$actions] : $actions;
|
||||
|
||||
return in_array($this->access->action, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts actions settings form a given rule.
|
||||
*
|
||||
* Action rules can be either set like:
|
||||
*
|
||||
* ['ruleName', 'actions' => ['action1', 'action2']]
|
||||
*
|
||||
* or in some cases:
|
||||
*
|
||||
* ['ruleName' => ['action1', 'action2']]
|
||||
*
|
||||
* @param $rule
|
||||
* @return array
|
||||
*/
|
||||
protected function extractActions($rule)
|
||||
{
|
||||
$name = $this->getRuleName($rule);
|
||||
$actions = [];
|
||||
|
||||
if (isset($rule['actions'])) {
|
||||
$actions = $rule['actions'];
|
||||
} else {
|
||||
$actions = isset($rule[$name]) ? $rule[$name] : $actions;
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the ruleName from the given array.
|
||||
*
|
||||
* @param $arr
|
||||
* @return mixed|null
|
||||
*/
|
||||
protected function getRuleName($rule)
|
||||
{
|
||||
if(empty($rule)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstKey = current(array_keys($rule));
|
||||
if(is_string($firstKey)) {
|
||||
return $firstKey;
|
||||
} else {
|
||||
return $rule[$firstKey];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the error message in case the validation fails
|
||||
*/
|
||||
public function getReason()
|
||||
{
|
||||
return $this->reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int http error code used in case the validation fails
|
||||
*/
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
}
|
84
protected/humhub/components/access/ActionAccessValidator.php
Normal file
84
protected/humhub/components/access/ActionAccessValidator.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 28.07.2017
|
||||
* Time: 17:43
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
|
||||
/**
|
||||
* This Validator filters out non action related rules and supports a $strict mode, which will require all validator
|
||||
* related rules to pass.
|
||||
*
|
||||
* If $strict mode is set to false only one of the validator related rules have pass.
|
||||
*
|
||||
* Subclasses of ActionAccessValidator only have to extend the `validate()` function for validating a single rule.
|
||||
*
|
||||
* @package humhub\components\access
|
||||
*/
|
||||
abstract class ActionAccessValidator extends AccessValidator
|
||||
{
|
||||
|
||||
/**
|
||||
* @var bool if set to true (default) all validator related rules have to pass otherwise only one
|
||||
*/
|
||||
public $strict = true;
|
||||
|
||||
/**
|
||||
* Runs the validation against all validator and action related rules.
|
||||
*
|
||||
* This function will return true, if there is no action related rule for this validator.
|
||||
*
|
||||
* @param $rule array
|
||||
* @param $access ControllerAccess
|
||||
* @return boolean
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$rules = $this->filterRelatedRules();
|
||||
|
||||
if(empty($rules)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
$can = $this->validate($rule);
|
||||
if ($can && !$this->strict) {
|
||||
return true;
|
||||
} else if (!$can && $this->strict) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->strict;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters our rules not related to the current validator and action.
|
||||
*
|
||||
* @param array|null $rules
|
||||
* @return array
|
||||
*/
|
||||
protected function filterRelatedRules($rules = null)
|
||||
{
|
||||
$result = [];
|
||||
foreach (parent::filterRelatedRules($rules) as $rule) {
|
||||
if($this->isActionRelated($rule)) {
|
||||
$result[] = $rule;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected abstract function validate($rule);
|
||||
}
|
363
protected/humhub/components/access/ControllerAccess.php
Normal file
363
protected/humhub/components/access/ControllerAccess.php
Normal file
@ -0,0 +1,363 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 26.07.2017
|
||||
* Time: 13:33
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\base\Object;
|
||||
use yii\web\Controller;
|
||||
|
||||
/**
|
||||
* ControllerAccess contains the actual logic to verify if a user can access a given $action.
|
||||
*
|
||||
* By default the AccessCheck will set the current logged in user permission object, if $user is null, we assume a guest
|
||||
* user.
|
||||
*
|
||||
* The guest user access can be verified by calling the `reguiresLogin()` check.
|
||||
*
|
||||
* Inactive users are can be catched by calling `isInActiveUser()`.
|
||||
*
|
||||
* The actual permission rule verification is handled by the `verify()` check, subclasses may overwrite and extend this
|
||||
* function with additional checks.
|
||||
*
|
||||
* Subclasses can extend available validators by calling `registerValidator` and providing a validator setting array as:
|
||||
*
|
||||
* ```
|
||||
* public function init()
|
||||
* {
|
||||
* parent::init();
|
||||
* $this->registerValidator([
|
||||
* self::RULE_MY_CUSTOM_RULE => 'validateCustomRule',
|
||||
* 'reason' => Yii::t('error', 'Guest mode not active, please login first.'),
|
||||
* 'code' => 401]);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The previous example registered an new validator repsonsible for validating $rules with name self::RULE_MY_CUSTOM_RULE and validation
|
||||
* handler function 'validateCustomRule' which defines an handler method within the subclass.
|
||||
*
|
||||
* The validator can be set the following additional settings:
|
||||
*
|
||||
* - **reason**: Reason set if the validaiton fails
|
||||
* - **code**: Http Code e.g. 404, 403, 401
|
||||
* - **actionType**: Defines how to determine if a rule is action related by default an action rule allows the following action settings:
|
||||
* ['myCustomRule' => ['action1', 'action2']] and ['myCustomRule', 'actions' => ['action1', 'action2']] but can be restricted to the second definition only by setting ACTION_SETTING_TYPE_OPTION_ONLY
|
||||
* - **actionFilter**: if set to false the validations handler is always executed even if the action settings do not match with the current action (default true)
|
||||
* - **strict**: if set to false only one rule of a given validator has to pass otherwise all rules have to pass (default true)
|
||||
*
|
||||
* @since 1.2.2
|
||||
*/
|
||||
class ControllerAccess extends Object
|
||||
{
|
||||
/**
|
||||
* Allows the action rule setting only by extra option ['myRule', 'actions' => ['action1', 'action2']]
|
||||
*/
|
||||
const ACTION_SETTING_TYPE_OPTION_ONLY = 0;
|
||||
|
||||
/**
|
||||
* Allows the action rule setting by extra option ['myRule', 'actions' => ['action1', 'action2']] or immediate ['myRule' => ['action1', 'action2']]
|
||||
*/
|
||||
const ACTION_SETTING_TYPE_BOTH = 1;
|
||||
|
||||
const RULE_ADMIN_ONLY = 'admin';
|
||||
const RULE_PERMISSION = 'permission';
|
||||
const RULE_LOGGED_IN_ONLY = 'login';
|
||||
const RULE_GUEST_CUSTOM = 'custom';
|
||||
const RULE_STRICT = 'strict';
|
||||
const RULE_DISABLED_USER = 'disabledUser';
|
||||
const RULE_UNAPPROVED_USER = 'unapprovedUser';
|
||||
const RULE_POST = 'post';
|
||||
const RULE_JSON = 'json';
|
||||
|
||||
/**
|
||||
* @var array fixed rules will always be added to the current rule set
|
||||
*/
|
||||
protected $fixedRules = [
|
||||
[self::RULE_DISABLED_USER],
|
||||
[self::RULE_UNAPPROVED_USER],
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array defines all available validators, this list can be extended by calling `registerValidator()`
|
||||
*/
|
||||
protected $validators = [];
|
||||
|
||||
/**
|
||||
* @var User identity to test against
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* @var string the controller action id to test
|
||||
*/
|
||||
public $action;
|
||||
|
||||
/**
|
||||
* @var array access rule array
|
||||
*/
|
||||
protected $rules = [];
|
||||
|
||||
/**
|
||||
* @var string actual decline message, can be changed in verify checks for specific error messages
|
||||
*/
|
||||
public $reason;
|
||||
|
||||
/**
|
||||
* @var int http code, can be changed in verify checks for specific error codes
|
||||
*/
|
||||
public $code;
|
||||
|
||||
/**
|
||||
* @var Controller owner object of this ControllerAccess the owner is mainly used to find custom validation handler
|
||||
*/
|
||||
public $owner;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->user = Yii::$app->user->getIdentity();
|
||||
|
||||
if (empty($this->action)) {
|
||||
$this->action = Yii::$app->controller->action->id;
|
||||
}
|
||||
|
||||
$this->registerValidator([self::RULE_STRICT => 'validateStrictMode', 'reason' => Yii::t('error', 'Guest mode not active, please login first.'), 'code' => 401]);
|
||||
$this->registerValidator([self::RULE_UNAPPROVED_USER => 'validateUnapprovedUser', 'reason' => Yii::t('error', 'Your user account has not been approved yet, please try again later or contact a network administrator.'), 'code' => 401]);
|
||||
$this->registerValidator([self::RULE_DISABLED_USER => 'validateDisabledUser', 'reason' => Yii::t('error', 'Your user account is inactive, please login with an active account or contact a network administrator.'), 'code' => 401]);
|
||||
$this->registerValidator([self::RULE_LOGGED_IN_ONLY => 'validateLoggedInOnly', 'reason' => Yii::t('error', 'Login required for this section.'), 'code' => 401]);
|
||||
|
||||
// We don't set code 401 since we want to show an error instead of redirecting to login
|
||||
$this->registerValidator(GuestAccessValidator::class);
|
||||
$this->registerValidator([self::RULE_ADMIN_ONLY => 'validateAdminOnly', 'reason' => Yii::t('error', 'You need admin permissions to access this section.')]);
|
||||
$this->registerValidator(PermissionAccessValidator::class);
|
||||
$this->registerValidator(DeprecatedPermissionAccessValidator::class);
|
||||
$this->registerValidator([self::RULE_POST => 'validatePostRequest', 'code' => 405, 'reason' => Yii::t('base', 'Invalid request method!')]);
|
||||
$this->registerValidator([self::RULE_JSON => 'validateJsonResponse']);
|
||||
}
|
||||
|
||||
public function getRules()
|
||||
{
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
public function setRules($rules = [])
|
||||
{
|
||||
$this->rules = array_merge($this->getFixedRules(), $rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new validator to the available validators and sets some default values.
|
||||
*
|
||||
* A validator shoud have the following form
|
||||
*
|
||||
* `['ruleName' => 'handler', 'code' => 401, 'reason' => 'Some message in case the validation failed']`
|
||||
*
|
||||
* to allow other direct settings required by the action validator e.g. direct permission settings.
|
||||
*
|
||||
* @param $setting array validator setting array
|
||||
*/
|
||||
protected function registerValidator($options)
|
||||
{
|
||||
if(is_string($options)) {
|
||||
$options = [
|
||||
'class' => $options,
|
||||
];
|
||||
}
|
||||
|
||||
$options['access'] = $this;
|
||||
|
||||
$name = $this->getName($options);
|
||||
|
||||
if($name == 'class') {
|
||||
$validator = Yii::createObject($options);
|
||||
} else if(class_exists($name)) {
|
||||
unset($options[0]);
|
||||
$options['class'] = $name;
|
||||
$validator = Yii::createObject($options);
|
||||
} else {
|
||||
$handler = $options[$name];
|
||||
unset($options[$name]);
|
||||
$options['name'] = $name;
|
||||
$options['owner'] = $this;
|
||||
$options['handler'] = $handler;
|
||||
$validator = new DelegateAccessValidator($options);
|
||||
}
|
||||
|
||||
$this->validators[$validator->name] = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the current $rule setting against all available validators
|
||||
* @return bool
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$finished = [];
|
||||
|
||||
foreach($this->rules as $rule) {
|
||||
$ruleName = $this->getName($rule);
|
||||
|
||||
// A validator validates all rules of the given $name, so we don't have to rerun the validation here if already handled
|
||||
if(in_array($ruleName, $finished)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$finished[] = $ruleName;
|
||||
|
||||
$validator = $this->findValidator($ruleName);
|
||||
|
||||
if(!$validator->run()) {
|
||||
$this->reason = (!$this->reason) ? $validator->getReason() : $this->reason;
|
||||
$this->code = (!$this->code) ? $validator->getCode(): $this->code;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function findValidator($ruleName)
|
||||
{
|
||||
if(isset($this->validators[$ruleName])) {
|
||||
return $this->validators[$ruleName];
|
||||
}
|
||||
|
||||
return $this->getCustomValidator($ruleName);
|
||||
}
|
||||
|
||||
protected function getCustomValidator($ruleName)
|
||||
{
|
||||
if($this->owner && method_exists($this->owner, $ruleName)) {
|
||||
return new DelegateAccessValidator([
|
||||
'access' => $this,
|
||||
'owner' => $this->owner,
|
||||
'handler' => $ruleName,
|
||||
'name' => $ruleName
|
||||
]);
|
||||
}
|
||||
|
||||
if (class_exists($ruleName)) {
|
||||
return Yii::createObject([
|
||||
'class' => $ruleName,
|
||||
'access' => $this
|
||||
]);
|
||||
}
|
||||
|
||||
throw new InvalidParamException('Invalid validator settings given for rule '.$ruleName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the ruleName from the given $array.
|
||||
*
|
||||
* @param $arr
|
||||
* @return mixed|null
|
||||
*/
|
||||
protected function getName($arr)
|
||||
{
|
||||
if(empty($arr)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$firstKey = current(array_keys($arr));
|
||||
if(is_string($firstKey)) {
|
||||
return $firstKey;
|
||||
} else {
|
||||
return $arr[$firstKey];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array returns array of rules which will always be added to the rule set
|
||||
*/
|
||||
protected function getFixedRules()
|
||||
{
|
||||
return $this->fixedRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool makes sure if the current user is loggedIn
|
||||
*/
|
||||
public function validateLoggedInOnly()
|
||||
{
|
||||
return !$this->isGuest();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool makes sure the current user has administration rights
|
||||
*/
|
||||
public function validateAdminOnly()
|
||||
{
|
||||
return $this->isAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool checks if guest mode is activated for guestaccess
|
||||
*/
|
||||
public function validateStrictMode()
|
||||
{
|
||||
return !$this->isGuest() || Yii::$app->user->isGuestAccessEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed checks if the current request is a post request
|
||||
*/
|
||||
public function validatePostRequest()
|
||||
{
|
||||
return Yii::$app->request->method == 'POST';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool makes sure the response type is json
|
||||
*/
|
||||
public function validateJson()
|
||||
{
|
||||
Yii::$app->response->format = 'json';
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool checks if the current user is a disabled user
|
||||
*/
|
||||
public function validateDisabledUser()
|
||||
{
|
||||
return $this->isGuest() || $this->user->status !== User::STATUS_DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool checks if the current user is an unapproved user
|
||||
*/
|
||||
public function validateUnapprovedUser()
|
||||
{
|
||||
return $this->isGuest() || $this->user->status !== User::STATUS_NEED_APPROVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool Checks if the given $user is set.
|
||||
*/
|
||||
public function isGuest()
|
||||
{
|
||||
return $this->user == null;
|
||||
}
|
||||
|
||||
public function isAdmin()
|
||||
{
|
||||
return !$this->isGuest() && $this->user->isSystemAdmin();
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 30.07.2017
|
||||
* Time: 02:21
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
|
||||
class DelegateAccessValidator extends ActionAccessValidator
|
||||
{
|
||||
public $owner;
|
||||
|
||||
public $handler;
|
||||
|
||||
protected function validate($rule)
|
||||
{
|
||||
$handler = $this->handler;
|
||||
return $this->owner->$handler($rule, $this);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 30.07.2017
|
||||
* Time: 04:04
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidParamException;
|
||||
|
||||
class DeprecatedPermissionAccessValidator extends PermissionAccessValidator
|
||||
{
|
||||
public $name = 'permissions';
|
||||
}
|
51
protected/humhub/components/access/GuestAccessValidator.php
Normal file
51
protected/humhub/components/access/GuestAccessValidator.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 30.07.2017
|
||||
* Time: 03:00
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
|
||||
use Yii;
|
||||
|
||||
class GuestAccessValidator extends AccessValidator
|
||||
{
|
||||
|
||||
public $name = 'guestAccess';
|
||||
|
||||
public $code = 403;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if($this->access->isGuest() && !Yii::$app->user->isGuestAccessEnabled()) {
|
||||
$this->code = 401;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$this->access->isGuest()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there is a guest restriction rule only return true if there is an action related rule
|
||||
foreach ($this->filterRelatedRules() as $rule) {
|
||||
if($this->isActionRelated($rule)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 30.07.2017
|
||||
* Time: 04:04
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
|
||||
use Yii;
|
||||
use yii\base\InvalidParamException;
|
||||
|
||||
class PermissionAccessValidator extends ActionAccessValidator
|
||||
{
|
||||
public $name = 'permission';
|
||||
|
||||
public $strict = false;
|
||||
|
||||
protected function validate($rule)
|
||||
{
|
||||
if (isset($rule[$this->name]) && !empty($rule[$this->name])) {
|
||||
return $this->verifyPermission($rule[$this->name], $rule);
|
||||
}
|
||||
|
||||
throw new InvalidParamException('Invalid permission rule provided for action ' . $this->action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user has the given $permission.
|
||||
*
|
||||
* @param string|string[]|BasePermission $permission
|
||||
* @param array $params
|
||||
* @param array $rule
|
||||
* @return bool true if the given $permission is granted
|
||||
*/
|
||||
protected function verifyPermission($permission, $rule)
|
||||
{
|
||||
return Yii::$app->user->can($permission, $rule);
|
||||
}
|
||||
|
||||
protected function extractActions($rule)
|
||||
{
|
||||
$actions = null;
|
||||
|
||||
if (isset($rule['actions'])) {
|
||||
$actions = $rule['actions'];
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
}
|
33
protected/humhub/components/access/StrictAccess.php
Normal file
33
protected/humhub/components/access/StrictAccess.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 27.07.2017
|
||||
* Time: 23:25
|
||||
*/
|
||||
|
||||
namespace humhub\components\access;
|
||||
|
||||
/**
|
||||
* StrictAccess should be used by all controllers which don't allow guest access if guest mode is inactive.
|
||||
* There are only some controllers which require guest access even if guest mode is active as Login, Registration etc.
|
||||
*
|
||||
* @package humhub\components\access
|
||||
*/
|
||||
class StrictAccess extends ControllerAccess
|
||||
{
|
||||
public function getFixedRules()
|
||||
{
|
||||
$fixed = parent::getFixedRules();
|
||||
$fixed[] = [self::RULE_STRICT];
|
||||
return $fixed;
|
||||
}
|
||||
|
||||
}
|
@ -8,11 +8,10 @@
|
||||
|
||||
namespace humhub\components\behaviors;
|
||||
|
||||
use humhub\modules\content\components\ContentContainerController;
|
||||
use humhub\modules\space\models\Space;
|
||||
use Yii;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\web\ForbiddenHttpException;
|
||||
use humhub\components\access\ControllerAccess;
|
||||
use yii\web\HttpException;
|
||||
|
||||
/**
|
||||
* AccessControl provides basic controller access protection
|
||||
@ -52,13 +51,6 @@ use yii\web\ForbiddenHttpException;
|
||||
class AccessControl extends \yii\base\ActionFilter
|
||||
{
|
||||
|
||||
/**
|
||||
* Action ids which are allowed when Guest Mode is enabled
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $guestAllowedActions = [];
|
||||
|
||||
/**
|
||||
* Rules for access to controller
|
||||
*
|
||||
@ -66,22 +58,32 @@ class AccessControl extends \yii\base\ActionFilter
|
||||
*/
|
||||
public $rules = [];
|
||||
|
||||
/**
|
||||
* Action ids which are allowed when Guest Mode is enabled
|
||||
*
|
||||
* @var array
|
||||
* @deprecated since 1.2.2 use ['guestAccess' => ['action1', 'action2']] rule instead
|
||||
*/
|
||||
public $guestAllowedActions = [];
|
||||
|
||||
/**
|
||||
* Only allow admins access to this controller
|
||||
*
|
||||
* @var boolean
|
||||
* @deprecated since 1.2.2 use ['adminOnly'] rule instead
|
||||
*/
|
||||
public $adminOnly = false;
|
||||
|
||||
/**
|
||||
* Only allow logged in users access to this controller
|
||||
* @deprecated since 1.2.2 use ['loggedInOnly'] rule instead
|
||||
*/
|
||||
public $loggedInOnly = true;
|
||||
public $loggedInOnly = false;
|
||||
|
||||
/**
|
||||
* User groups cache;
|
||||
* @var ControllerAccess instance
|
||||
*/
|
||||
private $_usergroupNames = null;
|
||||
protected $_controllerAccess;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@ -93,200 +95,77 @@ class AccessControl extends \yii\base\ActionFilter
|
||||
return true;
|
||||
}
|
||||
|
||||
$identity = Yii::$app->user->getIdentity();
|
||||
$this->handleDeprecatedSettings();
|
||||
$this->_controllerAccess = $this->getControllerAccess($this->rules);
|
||||
|
||||
if ($identity != null && !$identity->isActive()) {
|
||||
return $this->handleInactiveUser();
|
||||
}
|
||||
|
||||
if (Yii::$app->user->isGuest && !$this->adminOnly) {
|
||||
return $this->handleGuestAccess($action);
|
||||
}
|
||||
|
||||
if ($this->adminOnly && !$this->isAdmin()) {
|
||||
$this->forbidden();
|
||||
}
|
||||
|
||||
if ($this->checkRules()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->loggedInOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Denys access for non active users by performing a logout.
|
||||
* @return boolean always false
|
||||
*/
|
||||
protected function handleInactiveUser()
|
||||
{
|
||||
Yii::$app->user->logout();
|
||||
Yii::$app->response->redirect(['/user/auth/login']);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks access for guest users.
|
||||
*
|
||||
* Guests users are allowed to access an action if either the $loggedInOnly and $adminOnly flags are
|
||||
* set to false or the given controller action is contained in $guestAllowedActions.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
protected function handleGuestAccess($action)
|
||||
{
|
||||
if (!$this->loggedInOnly && !$this->adminOnly) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($action->id, $this->guestAllowedActions) && Yii::$app->getModule('user')->settings->get('auth.allowGuestAccess') == 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Yii::$app->user->loginRequired();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks group and permission rules.
|
||||
* @return boolean
|
||||
*/
|
||||
protected function checkRules()
|
||||
{
|
||||
$result = true;
|
||||
if (!empty($this->rules)) {
|
||||
foreach ($this->rules as $rule) {
|
||||
// If the rule contains an action restriction, which does not match the current controller action we ignore the rule.
|
||||
if(!$this->checkRuleAction($rule)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->checkGroupRule($rule) || $this->checkPermissionRule($rule)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
$this->forbidden();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a given permission rules.
|
||||
*
|
||||
* @param type $rule
|
||||
* @return boolean
|
||||
*/
|
||||
protected function checkPermissionRule($rule)
|
||||
{
|
||||
if (isset($rule['permissions']) && !empty($rule['permissions'])) {
|
||||
$permissionArr = (!is_array($rule['permissions'])) ? [$rule['permissions']] : $rule['permissions'];
|
||||
$params = isset($rule['params']) ? $rule['params'] : [];
|
||||
|
||||
if ($this->isContentContainerController()) {
|
||||
return $this->owner->contentContainer->can($permissionArr, $params) || Yii::$app->user->can($permissionArr, $params);
|
||||
}
|
||||
|
||||
return Yii::$app->user->can($permissionArr, $params);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current controller action against the allowed rule action.
|
||||
* If the rule does not contain any action settings, the rule is allowed for all controller actions.
|
||||
*
|
||||
* @param array $rule
|
||||
* @return boolean true if current action is allowed
|
||||
*/
|
||||
private function checkRuleAction($rule)
|
||||
{
|
||||
if (!empty($rule['actions'])) {
|
||||
$action = Yii::$app->controller->action->id;
|
||||
return in_array($action, $rule['actions']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isContentContainerController()
|
||||
{
|
||||
return $this->owner instanceof ContentContainerController;
|
||||
}
|
||||
|
||||
protected function isAdmin()
|
||||
{
|
||||
if(Yii::$app->user->isGuest) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->isContentContainerController()) {
|
||||
if($this->owner->contentContainer instanceof Space) {
|
||||
return $this->owner->contentContainer->isAdmin();
|
||||
if(!$this->_controllerAccess->run()) {
|
||||
if($this->_controllerAccess->code == 401) {
|
||||
return $this->loginRequired();
|
||||
} else {
|
||||
return $this->owner->contentContainer->isCurrentUser();
|
||||
$this->forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
return Yii::$app->user->isAdmin();
|
||||
}
|
||||
|
||||
private function getControllerSpace()
|
||||
{
|
||||
if ($this->isContentContainerController()) {
|
||||
return $this->owner->getSpace();
|
||||
}
|
||||
|
||||
return null;
|
||||
return parent::beforeAction($action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks specific group access by group names.
|
||||
*
|
||||
* @param type $rule
|
||||
* @return boolean
|
||||
* Compatibility with pre 1.2.2 usage of AccessControl
|
||||
*/
|
||||
protected function checkGroupRule($rule)
|
||||
protected function handleDeprecatedSettings()
|
||||
{
|
||||
if (!empty($rule['groups'])) {
|
||||
$userGroups = $this->getUserGroupNames();
|
||||
$isAllowedAction = $this->checkRuleAction($rule);
|
||||
$allowedGroups = array_map('strtolower', $rule['groups']);
|
||||
foreach ($allowedGroups as $allowedGroup) {
|
||||
if (in_array($allowedGroup, $userGroups) && $isAllowedAction) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if($this->adminOnly) {
|
||||
$this->rules[] = [ControllerAccess::RULE_ADMIN_ONLY];
|
||||
}
|
||||
|
||||
return false;
|
||||
if($this->loggedInOnly) {
|
||||
$this->rules[] = [ControllerAccess::RULE_LOGGED_IN_ONLY];
|
||||
}
|
||||
|
||||
if(!empty($this->guestAllowedActions)) {
|
||||
$this->rules[] = ['guestAccess' => $this->guestAllowedActions];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of strings with all user groups of the current user.
|
||||
* Returns a ControllerAccess instance, controllers are able to overwrite this by implementing an own `getAccess()`
|
||||
* function.
|
||||
*
|
||||
* @return type
|
||||
* @return ControllerAccess
|
||||
*/
|
||||
private function getUserGroupNames()
|
||||
protected function getControllerAccess($rules = [])
|
||||
{
|
||||
if ($this->_userGroupNames == null) {
|
||||
$identity = Yii::$app->user->getIdentity();
|
||||
$this->_userGroupNames = ArrayHelper::getColumn(ArrayHelper::toArray($identity->groups), 'name');
|
||||
$this->_userGroupNames = array_map('strtolower', $this->_userGroupNames);
|
||||
$instance = null;
|
||||
if(method_exists($this->owner, 'getAccess')) {
|
||||
$instance = $this->owner->getAccess();
|
||||
}
|
||||
|
||||
return $this->_userGroupNames;
|
||||
if(!$instance) {
|
||||
$instance = new ControllerAccess();
|
||||
}
|
||||
|
||||
$instance->setRules($rules);
|
||||
$instance->owner = $this->owner;
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws ForbiddenHttpException
|
||||
*/
|
||||
protected function forbidden()
|
||||
{
|
||||
throw new ForbiddenHttpException(Yii::t('error', 'You are not allowed to perform this action.'));
|
||||
throw new HttpException($this->_controllerAccess->code, $this->_controllerAccess->reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool forces user login
|
||||
*/
|
||||
protected function loginRequired()
|
||||
{
|
||||
Yii::$app->user->logout();
|
||||
Yii::$app->user->loginRequired();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,10 @@ HumHub Change Log
|
||||
- Enh: Darkened comment links for better readability
|
||||
- Fix #2582 Userfollow activity click action not working
|
||||
- Enh: Make space membership activities clickable
|
||||
- Enh: Removed `yii2-codeception` dependency
|
||||
|
||||
- Chg: Removed `yii2-codeception` dependency
|
||||
- Chg: Added `phpoffice/phpexcel` dependency
|
||||
- Enh: Added `JsWidget::fadeIn` for smooth widget initialization
|
||||
- Enh: Enhanced `AccessControl` filter with `ControllerAccess` layer for better testability and flexibility
|
||||
|
||||
1.2.1 (June 17, 2017)
|
||||
- Fix: Invite error in french language
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace activity\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -29,6 +29,8 @@ class Controller extends \humhub\components\Controller
|
||||
*/
|
||||
public $adminOnly = true;
|
||||
|
||||
public $loggedInOnly = true;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
@ -0,0 +1,158 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 31.07.2017
|
||||
* Time: 13:25
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\controllers;
|
||||
|
||||
|
||||
use DateTime;
|
||||
use humhub\components\ActiveRecord;
|
||||
use humhub\modules\admin\components\Controller;
|
||||
use humhub\modules\admin\models\PendingRegistrationSearch;
|
||||
use humhub\modules\admin\permissions\ManageGroups;
|
||||
use humhub\modules\admin\permissions\ManageUsers;
|
||||
use PHPExcel;
|
||||
use PHPExcel_Cell;
|
||||
use PHPExcel_IOFactory;
|
||||
use PHPExcel_Shared_Date;
|
||||
use PHPExcel_Style_NumberFormat;
|
||||
use PHPExcel_Writer_Excel2007;
|
||||
use function PHPSTORM_META\type;
|
||||
use Yii;
|
||||
use yii\helpers\ArrayHelper;
|
||||
|
||||
class PendingRegistrationsController extends Controller
|
||||
{
|
||||
public function init()
|
||||
{
|
||||
$this->subLayout = '@admin/views/layouts/user';
|
||||
$this->appendPageTitle(Yii::t('AdminModule.base', 'Pending user registrations'));
|
||||
return parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getAccessRules()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'permission' => [
|
||||
ManageUsers::class,
|
||||
ManageGroups::class,
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function actionIndex($export = false, $format = null)
|
||||
{
|
||||
$searchModel = new PendingRegistrationSearch();
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
|
||||
if($export) {
|
||||
return $this->createCVS($dataProvider, $searchModel, $format);
|
||||
}
|
||||
|
||||
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel,
|
||||
'types' => $this->getTypeMapping()
|
||||
]);
|
||||
}
|
||||
|
||||
public function getTypeMapping()
|
||||
{
|
||||
return [
|
||||
PendingRegistrationSearch::SOURCE_INVITE => Yii::t('AdminModule.base', 'Invite'),
|
||||
PendingRegistrationSearch::SOURCE_SELF => Yii::t('AdminModule.base', 'Sign up'),
|
||||
];
|
||||
}
|
||||
|
||||
public function createCVS($dataProvider, ActiveRecord $model, $format = null)
|
||||
{
|
||||
$columns = [
|
||||
['email'],
|
||||
['originator.username'],
|
||||
['language'],
|
||||
['source'],
|
||||
['created_at', 'type' => 'datetime'],
|
||||
];
|
||||
|
||||
$file = new PHPExcel();
|
||||
$file->getProperties()->setCreator('HumHub');
|
||||
$file->getProperties()->setTitle(Yii::t('AdminModule.base', 'Pending user registrations'));
|
||||
$file->getProperties()->setSubject(Yii::t('AdminModule.base', 'Pending user registrations'));
|
||||
$file->getProperties()->setDescription(Yii::t('AdminModule.base', 'Pending user registrations'));
|
||||
|
||||
$file->setActiveSheetIndex(0);
|
||||
$worksheet = $file->getActiveSheet();
|
||||
|
||||
$worksheet->setTitle(Yii::t('AdminModule.base', 'Pending user registrations'));
|
||||
|
||||
// Creat header
|
||||
$row = 1;
|
||||
$lastColumn = count($columns);
|
||||
for ($column = 0; $column != $lastColumn; $column++) {
|
||||
$columnKey = PHPExcel_Cell::stringFromColumnIndex($column);
|
||||
$worksheet->getColumnDimension($columnKey)->setWidth(30);
|
||||
$worksheet->setCellValueByColumnAndRow($column, $row, $model->getAttributeLabel($columns[$column][0]));
|
||||
}
|
||||
|
||||
$row++;
|
||||
|
||||
// Fill content header
|
||||
foreach($dataProvider->query->all() as $record) {
|
||||
for ($column = 0; $column != $lastColumn; $column++) {
|
||||
$attribute = $columns[$column][0];
|
||||
$value = ArrayHelper::getValue($record,$attribute);
|
||||
|
||||
if(isset($columns[$column]['type']) && $columns[$column]['type'] === 'datetime') {
|
||||
$value = PHPExcel_Shared_Date::PHPToExcel(new DateTime($value));
|
||||
if($format === 'CSV') {
|
||||
$worksheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(Yii::$app->formatter->getDateTimePattern());
|
||||
} else {
|
||||
$worksheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME);
|
||||
}
|
||||
}
|
||||
|
||||
if($attribute === 'source') {
|
||||
$types = $this->getTypeMapping();
|
||||
$value = isset($types[$value]) ? $types[$value] : $value;
|
||||
}
|
||||
|
||||
$worksheet->setCellValueByColumnAndRow($column, $row, $value);
|
||||
}
|
||||
$row++;
|
||||
}
|
||||
|
||||
$filePrefix = 'pur_export_'.time();
|
||||
if($format === 'CSV') {
|
||||
$writer = PHPExcel_IOFactory::createWriter($file, 'CSV');
|
||||
$writer->setDelimiter(';');
|
||||
|
||||
header('Content-Type: application/csv');
|
||||
header('Content-Disposition: attachment;filename="'.$filePrefix.'.csv"');
|
||||
header('Cache-Control: max-age=0');
|
||||
} else {
|
||||
$writer = PHPExcel_IOFactory::createWriter($file, 'Excel2007');
|
||||
header('Content-type: application/vnd.ms-excel');
|
||||
header('Content-Disposition: attachment; filename="'.$filePrefix.'.xlsx"');
|
||||
header('Cache-Control: max-age=0');
|
||||
}
|
||||
|
||||
$writer->save('php://output');
|
||||
}
|
||||
}
|
@ -47,13 +47,14 @@ class UserController extends Controller
|
||||
public function getAccessRules()
|
||||
{
|
||||
return [
|
||||
['permissions' => [
|
||||
ManageUsers::className(),
|
||||
ManageGroups::className()
|
||||
[
|
||||
'permissions' => [
|
||||
ManageUsers::class,
|
||||
ManageGroups::class,
|
||||
]
|
||||
],
|
||||
[
|
||||
'permissions' => ManageSettings::className(),
|
||||
'permissions' => [ManageSettings::class],
|
||||
'actions' => ['index']
|
||||
]
|
||||
];
|
||||
@ -71,7 +72,7 @@ class UserController extends Controller
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel
|
||||
]);
|
||||
} else if (Yii::$app->user->can(new ManageSettings())) {
|
||||
} else if (Yii::$app->user->can(ManageSettings::class)) {
|
||||
$this->redirect(['/admin/authentication']);
|
||||
} else {
|
||||
$this->forbidden();
|
||||
@ -85,9 +86,7 @@ class UserController extends Controller
|
||||
*/
|
||||
public function actionEdit()
|
||||
{
|
||||
$user = UserEditForm::findOne([
|
||||
'id' => Yii::$app->request->get('id')
|
||||
]);
|
||||
$user = UserEditForm::findOne(['id' => Yii::$app->request->get('id')]);
|
||||
$user->initGroupSelection();
|
||||
|
||||
if ($user == null) {
|
||||
|
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\models;
|
||||
|
||||
use humhub\modules\user\models\Invite;
|
||||
use Yii;
|
||||
use yii\data\ActiveDataProvider;
|
||||
|
||||
/**
|
||||
* PendingRegistrationSearch
|
||||
*
|
||||
* @author buddha
|
||||
*/
|
||||
class PendingRegistrationSearch extends Invite
|
||||
{
|
||||
public function attributes()
|
||||
{
|
||||
// add related fields to searchable attributes
|
||||
return array_merge(parent::attributes(), ['originator.username']);
|
||||
}
|
||||
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['id'], 'integer'],
|
||||
[['email', 'created_at', 'originator.username', 'source', 'language'], 'safe'],
|
||||
];
|
||||
}
|
||||
|
||||
public function attributeLabels()
|
||||
{
|
||||
$result = parent::attributeLabels(); // TODO: Change the autogenerated stub
|
||||
$result['originator.username'] = Yii::t('AdminModule.base', 'Invited by');
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates data provider instance with search query applied
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return ActiveDataProvider
|
||||
*/
|
||||
public function search($params = [])
|
||||
{
|
||||
$query = self::find()->joinWith(['originator']);
|
||||
|
||||
$dataProvider = new ActiveDataProvider([
|
||||
'query' => $query,
|
||||
'pagination' => ['pageSize' => 50],
|
||||
]);
|
||||
|
||||
$dataProvider->setSort([
|
||||
'attributes' => [
|
||||
'email',
|
||||
'created_at',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->load($params);
|
||||
|
||||
if (!$this->validate()) {
|
||||
$query->where('0=1');
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
$query->andFilterWhere(['id' => $this->id]);
|
||||
$query->andFilterWhere(['like', 'id', $this->id]);
|
||||
$query->andFilterWhere(['like', 'username', $this->getAttribute('originator.username')]);
|
||||
$query->andFilterWhere(['like', 'user_invite.email', $this->email]);
|
||||
$query->andFilterWhere(['like', 'user_invite.language', $this->language]);
|
||||
$query->andFilterWhere(['like', 'source', $this->source]);
|
||||
|
||||
return $dataProvider;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace admin\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use humhub\widgets\Button;
|
||||
use humhub\widgets\GridView;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Url;
|
||||
?>
|
||||
|
||||
<div class="panel-body">
|
||||
<h4><?= Yii::t('AdminModule.base', 'Pending user registrations'); ?></h4>
|
||||
|
||||
<div class="help-block">
|
||||
<?= Yii::t('AdminModule.views_approval_index', 'The following list contains all pending sign-ups and invites.'); ?>
|
||||
</div>
|
||||
|
||||
<div class="dropdown pull-right">
|
||||
<button class="btn btn-primary btn-sm " type="button" data-toggle="dropdown"><i class="fa fa-download"></i> <?= Yii::t('base', 'Export')?> <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><?= Button::asLink('csv', Url::current(['export' => '1', 'format' => 'CSV']))->pjax(false)->icon('fa-file-code-o')->sm() ?></li>
|
||||
<li><?= Button::asLink('xlsx', Url::current(['export' => '1', 'format' => 'XLSX']))->pjax(false)->icon('fa-file-excel-o')->sm() ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?=
|
||||
GridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
'filterModel' => $searchModel,
|
||||
'columns' => ['email',
|
||||
'originator.username',
|
||||
'language',
|
||||
'created_at',
|
||||
[
|
||||
'attribute' => 'source',
|
||||
'filter' => \yii\helpers\Html::activeDropDownList($searchModel, 'source', array_merge(['' => ''], $types)),
|
||||
'options' => ['width' => '40px'],
|
||||
'format' => 'raw',
|
||||
'value' => function($data) use ($types) {
|
||||
if (isset($types[$data->source])) {
|
||||
return $types[$data->source];
|
||||
}
|
||||
return Html::encode($data->source);
|
||||
},
|
||||
],]
|
||||
]);
|
||||
?>
|
||||
|
||||
</div>
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] b0a7d07ce759b891f3ddfe460849f7a6
|
||||
<?php //[STAMP] 2aea435445801f2b571f53bf6c1759b0
|
||||
namespace comment\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 3f9180251a575519e16ad271d87f69d5
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace comment\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 4620099acaa171d89740a45ce8351624
|
||||
<?php //[STAMP] 7f1a977c3860981721f99092d50a0edb
|
||||
namespace comment\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
use humhub\modules\content\models\Content;
|
||||
use Yii;
|
||||
use humhub\libs\ProfileBannerImage;
|
||||
@ -24,6 +25,8 @@ use humhub\modules\content\models\ContentContainer;
|
||||
* - getUrl()
|
||||
*
|
||||
* @property integer $id
|
||||
* @property integer $visibility
|
||||
*
|
||||
* @since 1.0
|
||||
* @author Luke
|
||||
*/
|
||||
@ -166,37 +169,20 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
return $this->hasOne(ContentContainer::className(), ['pk' => 'id'])
|
||||
->andOnCondition(['class' => self::className()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the permissionManager of this container by default for the current logged in user unsless another $user instance was provided.
|
||||
*
|
||||
* @param User $user
|
||||
* @return ContentContainerPermissionManager
|
||||
*/
|
||||
public function getPermissionManager(User $user = null)
|
||||
{
|
||||
if($user && !$user->is(Yii::$app->user->getIdentity())) {
|
||||
$permissionManager = new ContentContainerPermissionManager;
|
||||
$permissionManager->contentContainer = $this;
|
||||
$permissionManager->subject = $user;
|
||||
return $permissionManager;
|
||||
}
|
||||
|
||||
if ($this->permissionManager !== null) {
|
||||
return $this->permissionManager;
|
||||
}
|
||||
|
||||
$this->permissionManager = new ContentContainerPermissionManager;
|
||||
$this->permissionManager->contentContainer = $this;
|
||||
return $this->permissionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for getPermisisonManager()->can().
|
||||
* Checks if the current user has the given Permission on this ContentContainerActiveRecord.
|
||||
* This is a shortcut for `$this->getPermisisonManager()->can()`.
|
||||
*
|
||||
* The following example will check if the current user has MyPermission on the given $contentContainer
|
||||
*
|
||||
* ```php
|
||||
* $contentContainer->can(MyPermisison::class);
|
||||
* ```
|
||||
*
|
||||
* Note: This method is used to verify ContentContainerPermissions and not GroupPermissions.
|
||||
*
|
||||
* @param mixed $permission
|
||||
* @param string|string[]|BasePermission $permission
|
||||
* @see PermissionManager::can()
|
||||
* @return boolean
|
||||
* @since 1.2
|
||||
@ -206,6 +192,31 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
return $this->getPermissionManager()->can($permission, $params, $allowCaching);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ContentContainerPermissionManager instance for this ContentContainerActiveRecord as permission object
|
||||
* and the given user (or current user if not given) as permission subject.
|
||||
*
|
||||
* @param User $user
|
||||
* @return ContentContainerPermissionManager
|
||||
*/
|
||||
public function getPermissionManager(User $user = null)
|
||||
{
|
||||
if($user && !$user->is(Yii::$app->user->getIdentity())) {
|
||||
return new ContentContainerPermissionManager([
|
||||
'contentContainer' => $this,
|
||||
'subject' => $user
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->permissionManager !== null) {
|
||||
return $this->permissionManager;
|
||||
}
|
||||
|
||||
return $this->permissionManager = new ContentContainerPermissionManager([
|
||||
'contentContainer' => $this
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns user group for the given $user or current logged in user if no $user instance was provided.
|
||||
*
|
||||
@ -245,4 +256,14 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
return Content::VISIBILITY_PRIVATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current visibility setting of this ContentContainerActiveRecord
|
||||
* @param $visibility
|
||||
* @return bool
|
||||
*/
|
||||
public function isVisibleFor($visibility)
|
||||
{
|
||||
return $this->visibility == $visibility;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ class ContentContainerController extends Controller
|
||||
throw new HttpException(405, Yii::t('base', 'Module is not enabled on this content container!'));
|
||||
}
|
||||
|
||||
return parent::init();
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,6 +153,14 @@ class ContentContainerController extends Controller
|
||||
$this->checkAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getAccess()
|
||||
{
|
||||
return new ContentContainerControllerAccess(['contentContainer' => $this->contentContainer]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current module is enabled on this content container.
|
||||
*
|
||||
|
@ -0,0 +1,208 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 26.07.2017
|
||||
* Time: 18:11
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
|
||||
use Yii;
|
||||
use humhub\components\access\StrictAccess;
|
||||
use humhub\modules\space\models\Membership;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\user\models\User;
|
||||
|
||||
/**
|
||||
* Class ContentContainerControllerAccess
|
||||
*
|
||||
* Adds a container permission check to
|
||||
*
|
||||
* @package components
|
||||
*/
|
||||
class ContentContainerControllerAccess extends StrictAccess
|
||||
{
|
||||
const RULE_SPACE_ONLY = 'space';
|
||||
const RULE_PROFILE_ONLY = 'profile';
|
||||
|
||||
const RULE_USER_GROUP_ONLY = 'userGroup';
|
||||
const RULE_CONTAINER_ACCESS = 'containerAccess';
|
||||
|
||||
/**
|
||||
* @var ContentContainerActiveRecord
|
||||
*/
|
||||
public $contentContainer;
|
||||
|
||||
private $_membership = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if (!$this->contentContainer && Yii::$app->controller instanceof ContentContainerController) {
|
||||
$this->contentContainer = Yii::$app->controller->contentContainer;
|
||||
}
|
||||
|
||||
// overwrite default permission validator
|
||||
$this->registerValidator([ContentContainerPermissionAccess::class, 'contentContainer' => $this->contentContainer]);
|
||||
$this->registerValidator([self::RULE_SPACE_ONLY => 'validateSpaceOnlyRule']);
|
||||
$this->registerValidator([self::RULE_PROFILE_ONLY => 'validateProfileOnlyRule']);
|
||||
$this->registerValidator([UserGroupAccessValidator::class, 'contentContainer' => $this->contentContainer]);
|
||||
$this->registerValidator([self::RULE_CONTAINER_ACCESS => 'validateContainerAccess']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the 'userGroup' rule which requires the given $user to be in the given userGroup setting array.
|
||||
* @return bool
|
||||
*/
|
||||
public function validateUserGroupRule($rule)
|
||||
{
|
||||
$userGroup = $this->contentContainer->getUserGroup($this->user);
|
||||
|
||||
if(!in_array($userGroup, $rule[self::RULE_USER_GROUP_ONLY])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool verifies 'spaceOnly' rules
|
||||
*/
|
||||
public function validateSpaceOnlyRule()
|
||||
{
|
||||
return $this->isSpaceController();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool verifies 'userOnly' rules
|
||||
*/
|
||||
public function validateProfileOnlyRule()
|
||||
{
|
||||
return $this->isProfileController();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool Additional ContentContainerActiveRecord specific checks
|
||||
*/
|
||||
public function validateContainerAccess()
|
||||
{
|
||||
if($this->isSpaceController()) {
|
||||
return $this->canAccessSpace();
|
||||
} else {
|
||||
return $this->canAccessUser();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool Space related access checks
|
||||
*/
|
||||
private function canAccessSpace()
|
||||
{
|
||||
if($this->contentContainer->isVisibleFor(Space::VISIBILITY_ALL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// don't allow guests since visibility != VISIBILITY_ALL
|
||||
if($this->isGuest()) {
|
||||
$this->code = 401;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->user->isSystemAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// @see SpaceModelMembership
|
||||
$membership = $this->getSpaceMembership();
|
||||
|
||||
if ($membership) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if($this->isVisibleFor(Space::VISIBILITY_NONE)) {
|
||||
$this->code = 404;
|
||||
$this->reason = Yii::t('ContentModule.base', 'This space is not visible!');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Membership
|
||||
*/
|
||||
private function getSpaceMembership()
|
||||
{
|
||||
if(!$this->isSpaceController() || $this->isGuest()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if($this->_membership === false) {
|
||||
$this->_membership = $this->contentContainer->getMembership($this->user->id);
|
||||
}
|
||||
|
||||
return $this->_membership;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool User related access checks
|
||||
*/
|
||||
private function canAccessUser()
|
||||
{
|
||||
if($this->contentContainer->status == User::STATUS_NEED_APPROVAL) {
|
||||
$this->reason = Yii::t('UserModule.behaviors_ProfileControllerBehavior', 'This user account is not approved yet!');
|
||||
$this->code = 404;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->isGuest() && $this->contentContainer->isVisibleFor(User::VISIBILITY_ALL)) {
|
||||
$this->code = 401;
|
||||
$this->reason = Yii::t('UserModule.behaviors_ProfileControllerBehavior', 'You need to login to view this user profile!');
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO: visibility + friendship check
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function isAdmin()
|
||||
{
|
||||
if(parent::isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->contentContainer instanceof Space) {
|
||||
return $this->contentContainer->isAdmin($this->user);
|
||||
} else if($this->contentContainer instanceof Space) {
|
||||
return $this->user && $this->user->is($this->contentContainer);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isSpaceController()
|
||||
{
|
||||
return $this->contentContainer instanceof Space;
|
||||
}
|
||||
|
||||
protected function isProfileController()
|
||||
{
|
||||
return $this->contentContainer instanceof User;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 30.07.2017
|
||||
* Time: 04:15
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
|
||||
use humhub\components\access\PermissionAccessValidator;
|
||||
|
||||
class ContentContainerPermissionAccess extends PermissionAccessValidator
|
||||
{
|
||||
/**
|
||||
* @var ContentContainerActiveRecord
|
||||
*/
|
||||
public $contentContainer;
|
||||
|
||||
protected function verifyPermission($permission, $rule)
|
||||
{
|
||||
return parent::verifyPermission($permission, $rule) || $this->contentContainer->can($permission, $rule);
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 30.07.2017
|
||||
* Time: 04:04
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
|
||||
use humhub\components\access\ActionAccessValidator;
|
||||
use humhub\libs\BasePermission;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
use yii\base\InvalidParamException;
|
||||
|
||||
class UserGroupAccessValidator extends ActionAccessValidator
|
||||
{
|
||||
public $name = 'userGroup';
|
||||
|
||||
/**
|
||||
* @var ContentContainerActiveRecord
|
||||
*/
|
||||
public $contentContainer;
|
||||
|
||||
public $strict = false;
|
||||
|
||||
private $spaceGroupLevel = [
|
||||
Space::USERGROUP_GUEST,
|
||||
Space::USERGROUP_USER,
|
||||
Space::USERGROUP_MEMBER,
|
||||
Space::USERGROUP_MODERATOR,
|
||||
Space::USERGROUP_ADMIN,
|
||||
Space::USERGROUP_OWNER,
|
||||
];
|
||||
|
||||
private $profileGroupLevel = [
|
||||
User::USERGROUP_GUEST,
|
||||
User::USERGROUP_USER,
|
||||
User::USERGROUP_FRIEND,
|
||||
User::USERGROUP_SELF,
|
||||
];
|
||||
|
||||
protected function validate($rule)
|
||||
{
|
||||
if (isset($rule[$this->name]) && !empty($rule[$this->name])) {
|
||||
$allowedGroups = is_string($rule[$this->name]) ? [$rule[$this->name]] : $rule[$this->name];
|
||||
$userGroup = $this->contentContainer->getUserGroup($this->access->user);
|
||||
|
||||
if(isset($rule['strict']) && $rule['strict'] == true) {
|
||||
return in_array($userGroup, $allowedGroups);
|
||||
}
|
||||
|
||||
foreach ($allowedGroups as $allowedUserGroup) {
|
||||
if($this->getUserGroupLevel($userGroup) >= $this->getUserGroupLevel($allowedUserGroup)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new InvalidParamException('Invalid userGroup rule provided for action ' . $this->action);
|
||||
}
|
||||
|
||||
public function getUserGroupLevel($userGroup)
|
||||
{
|
||||
$userGroupLevelArr = ($this->contentContainer instanceof Space) ? $this->spaceGroupLevel : $this->profileGroupLevel;
|
||||
|
||||
if(!in_array($userGroup, $userGroupLevelArr)) {
|
||||
return PHP_INT_MAX;
|
||||
}
|
||||
|
||||
return array_search($userGroup, $userGroupLevelArr);
|
||||
}
|
||||
|
||||
protected function extractActions($rule)
|
||||
{
|
||||
$actions = null;
|
||||
|
||||
if (isset($rule['actions'])) {
|
||||
$actions = $rule['actions'];
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function getReason()
|
||||
{
|
||||
return Yii::t('error', 'You are not permitted to access this section.');
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace content\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -0,0 +1,430 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 26.07.2017
|
||||
* Time: 16:13
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\unit;
|
||||
|
||||
use humhub\components\access\ControllerAccess;
|
||||
use humhub\modules\content\components\ContentContainerControllerAccess;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\user\models\User;
|
||||
use tests\codeception\_support\HumHubDbTestCase;
|
||||
use Yii;
|
||||
|
||||
class ContentContainerAccessControllerTest extends HumHubDbTestCase
|
||||
{
|
||||
public function testSimpleGlobalGuestAccess()
|
||||
{
|
||||
$space = Space::findOne(1);
|
||||
$this->allowGuestAccess();
|
||||
Yii::$app->getModule('user')->settings->set('auth.allowGuestAccess', 1);
|
||||
|
||||
// Controller global guestAccess
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [
|
||||
['guestAccess']
|
||||
],
|
||||
'action' => 'testAction']);
|
||||
$this->assertTrue($accessCheck->isGuest());
|
||||
|
||||
// GuestAccess given with not matching action setting
|
||||
$accessCheck->rules = [
|
||||
['guestAccess' => ['otherTestAction']]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// GuestAccess given with matching actoin setting
|
||||
$accessCheck->rules = [
|
||||
['guestAccess' => ['otherTestAction', 'testAction']]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// AdminOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
['guestAccess' => ['otherTestAction', 'testAction']],
|
||||
[ControllerAccess::RULE_ADMIN_ONLY]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// AdminOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
['guestAccess' => ['otherTestAction', 'testAction']],
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['testAction']]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// AdminOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
['guestAccess' => ['otherTestAction', 'testAction']],
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['otherTestAction']]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// LoggedInOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['otherTestAction']],
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// LoggedInOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['otherTestAction']],
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY => 'otherTestAction']
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// LoggedInOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['otherTestAction']],
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY => 'testAction'],
|
||||
['guestAccess' => 'testAction']
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// By default guests are allowed without further rules
|
||||
$accessCheck->rules = [];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// Global Permission setting
|
||||
$accessCheck->rules = [
|
||||
['permission' => ContentTestPermission1::class]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Action restricted permission setting
|
||||
$accessCheck->rules = [
|
||||
['permission' => ContentTestPermission1::class, 'actions' => ['otherTestAction']]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// Matching action related permission setting
|
||||
$accessCheck->rules = [
|
||||
['permission' => ContentTestPermission1::class, 'actions' => ['otherTestAction', 'testAction']]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testStrictAccess()
|
||||
{
|
||||
$space = Space::findOne(1);
|
||||
// Controller global guestAccess
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [],
|
||||
'action' => 'testAction']);
|
||||
// Test strict behaviour
|
||||
$this->allowGuestAccess(false);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testSpaceOnlyAccess()
|
||||
{
|
||||
$this->becomeUser('User1');
|
||||
$space = Space::findOne(1);
|
||||
|
||||
// Controller global guestAccess
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [[ContentContainerControllerAccess::RULE_SPACE_ONLY]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck->contentContainer = Yii::$app->user->getIdentity();
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Not related
|
||||
$accessCheck->rules = [
|
||||
[ContentContainerControllerAccess::RULE_SPACE_ONLY => ['otherAction']]
|
||||
];
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck->rules = [
|
||||
[ContentContainerControllerAccess::RULE_SPACE_ONLY => ['otherAction', 'testAction']]
|
||||
];
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testProfileOnlyAccess()
|
||||
{
|
||||
$this->becomeUser('User1');
|
||||
$space = Space::findOne(1);
|
||||
|
||||
// Controller global guestAccess
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => Yii::$app->user->getIdentity(),
|
||||
'rules' => [[ContentContainerControllerAccess::RULE_PROFILE_ONLY]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck->contentContainer = $space;
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Not related
|
||||
$accessCheck->rules = [
|
||||
[ContentContainerControllerAccess::RULE_PROFILE_ONLY => ['otherAction']]
|
||||
];
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck->rules = [
|
||||
[ContentContainerControllerAccess::RULE_PROFILE_ONLY => ['otherAction', 'testAction']]
|
||||
];
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testUserGroupAccess()
|
||||
{
|
||||
$this->allowGuestAccess();
|
||||
|
||||
// Guest is not user
|
||||
$space = Space::findOne(1);
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'action' => 'testAction',
|
||||
'rules' => [
|
||||
['userGroup' => [Space::USERGROUP_USER]]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Guest is allowed
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [['userGroup' => [Space::USERGROUP_GUEST]]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// User 1 is not member of Space1
|
||||
$this->becomeUser('User1');
|
||||
|
||||
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [['userGroup' => [Space::USERGROUP_MEMBER]]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// User 1 is member of Space1
|
||||
$space3 = Space::findOne(3);
|
||||
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space3,
|
||||
'rules' => [['userGroup' => [Space::USERGROUP_MEMBER]]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// Since its leveled member should also be allowed to access user restricted
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space3,
|
||||
'rules' => [['userGroup' => Space::USERGROUP_USER]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space3,
|
||||
'rules' => [['userGroup' => Space::USERGROUP_MODERATOR]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Only non user related group provided
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => Yii::$app->user->getIdentity(),
|
||||
'rules' => [['userGroup' => Space::USERGROUP_MODERATOR]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Also User related group provided
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => Yii::$app->user->getIdentity(),
|
||||
'rules' => [['userGroup' => [Space::USERGROUP_MODERATOR, User::USERGROUP_SELF]]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
$user1 = Yii::$app->user->getIdentity();
|
||||
$this->becomeUser('User2');
|
||||
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $user1,
|
||||
'rules' => [['userGroup' => [User::USERGROUP_SELF]]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $user1,
|
||||
'rules' => [['userGroup' => [User::USERGROUP_GUEST]]],
|
||||
'action' => 'testAction']);
|
||||
|
||||
$this->assertTrue($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testLoggedInOnlyAccess()
|
||||
{
|
||||
$space = Space::findOne(1);
|
||||
$this->allowGuestAccess();
|
||||
|
||||
// Controller global guestAccess
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY]
|
||||
],
|
||||
'action' => 'testAction']);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
$this->becomeUser('User1');
|
||||
$accessCheck->user = Yii::$app->user->getIdentity();
|
||||
$this->assertFalse($accessCheck->isGuest());
|
||||
$this->assertTrue($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testAdminOnly()
|
||||
{
|
||||
// Non space member not allowed
|
||||
$space4 = Space::findOne(4);
|
||||
$this->becomeUser('User3');
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space4,
|
||||
'rules' => [[ControllerAccess::RULE_ADMIN_ONLY]],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Member not allowed
|
||||
$this->becomeUser('User2');
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space4,
|
||||
'rules' => [[ControllerAccess::RULE_ADMIN_ONLY]],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Space Admin allowed
|
||||
$this->becomeUser('User1');
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space4,
|
||||
'rules' => [[ControllerAccess::RULE_ADMIN_ONLY]],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// System/Space Admin allowed
|
||||
$this->becomeUser('Admin');
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space4,
|
||||
'rules' => [[ControllerAccess::RULE_ADMIN_ONLY]],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// System Admin allowed
|
||||
$space2 = Space::findOne(2);
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space4,
|
||||
'rules' => [[ControllerAccess::RULE_ADMIN_ONLY]],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertTrue($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testInactiveUser()
|
||||
{
|
||||
$space = Space::findOne(1);
|
||||
$this->becomeUser('DisabledUser');
|
||||
$accessCheck = new ContentContainerControllerAccess(['contentContainer' => $space,'rules' => [], 'action' => 'testAction']);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
$this->becomeUser('UnapprovedUser');
|
||||
$accessCheck = new ContentContainerControllerAccess(['contentContainer' => $space, 'rules' => [], 'action' => 'testAction']);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testPermissionRule()
|
||||
{
|
||||
$space = Space::findOne(3);
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [
|
||||
['permission' => [ContentTestPermission1::class]]
|
||||
],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
|
||||
# $this->assertFalse($accessCheck->run());
|
||||
|
||||
$this->setGroupPermission(2, ContentTestPermission1::class);
|
||||
|
||||
$this->becomeUser('User1');
|
||||
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [
|
||||
['permission' => [ContentTestPermission2::class]]
|
||||
],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
# $this->assertFalse($accessCheck->run());
|
||||
|
||||
$accessCheck->rules = [
|
||||
['permission' => [ContentTestPermission1::class, ContentTestPermission2::class]]
|
||||
];
|
||||
# $this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck->rules = [
|
||||
['permission' => [ContentTestPermission2::class], 'actions' => 'otherPermission'],
|
||||
['permission' => [ContentTestPermission1::class, ContentTestPermission2::class]]
|
||||
];
|
||||
# $this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck->rules = [
|
||||
['permission' => [ContentTestPermission2::class], 'actions' => 'otherPermission'],
|
||||
['permission' => ContentTestPermission1::class]
|
||||
];
|
||||
#$this->assertTrue($accessCheck->run());
|
||||
|
||||
$accessCheck->rules = [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY],
|
||||
['permission' => [ContentTestPermission2::class], 'actions' => 'otherPermission'],
|
||||
['permission' => [ContentTestPermission1::class, ContentTestPermission2::class]]
|
||||
];
|
||||
#$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Set contentcotnainer permission
|
||||
$this->setContentContainerPermission($space, Space::USERGROUP_MEMBER, ContentTestPermission2::class);
|
||||
|
||||
$accessCheck = new ContentContainerControllerAccess([
|
||||
'contentContainer' => $space,
|
||||
'rules' => [
|
||||
['permission' => [ContentTestPermission2::class]]
|
||||
],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertTrue($accessCheck->run());
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 27.07.2017
|
||||
* Time: 00:06
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\unit;
|
||||
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
|
||||
class ContentTestPermission1 extends BasePermission
|
||||
{
|
||||
public $moduleId = 'content';
|
||||
|
||||
public $id = 'content-test-permission2';
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 27.07.2017
|
||||
* Time: 00:06
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\tests\codeception\unit;
|
||||
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
|
||||
class ContentTestPermission2 extends BasePermission
|
||||
{
|
||||
public $moduleId = 'content';
|
||||
|
||||
public $id = 'content-test-permission';
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace dashboard\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace friendship\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace like\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace notification\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace post\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
namespace humhub\modules\space\modules\manage\components;
|
||||
|
||||
use humhub\modules\admin\permissions\ManageSpaces;
|
||||
use Yii;
|
||||
use yii\web\HttpException;
|
||||
|
||||
@ -23,48 +24,13 @@ class Controller extends \humhub\modules\content\components\ContentContainerCont
|
||||
*/
|
||||
public $hideSidebar = true;
|
||||
|
||||
/**
|
||||
* Can be overwritten by subclasses to allow non space admins
|
||||
* @var type
|
||||
*/
|
||||
protected $adminOnly = true;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'acl' => [
|
||||
'class' => \humhub\components\behaviors\AccessControl::className(),
|
||||
'adminOnly' => $this->adminOnly,
|
||||
'rules' => $this->getAccessRules()
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
protected function getAccessRules() {
|
||||
return [];
|
||||
return [
|
||||
['login'],
|
||||
['permission' => [
|
||||
ManageSpaces::class
|
||||
]]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Request only allowed for space admins
|
||||
*/
|
||||
public function adminOnly()
|
||||
{
|
||||
if (!$this->getSpace()->isAdmin())
|
||||
throw new HttpException(403, 'Access denied - Space Administrator only!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Request only allowed for workspace owner
|
||||
*/
|
||||
public function ownerOnly()
|
||||
{
|
||||
$workspace = $this->getSpace();
|
||||
|
||||
if (!$workspace->isSpaceOwner() && !Yii::$app->user->isAdmin())
|
||||
throw new HttpException(403, 'Access denied - Space Owner only!');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,9 @@
|
||||
namespace humhub\modules\space\modules\manage\controllers;
|
||||
|
||||
use Yii;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\space\modules\manage\models\AdvancedSettingsSpace;
|
||||
use humhub\modules\space\widgets\Chooser;
|
||||
use humhub\modules\space\modules\manage\components\Controller;
|
||||
use humhub\modules\space\modules\manage\models\DeleteForm;
|
||||
|
||||
@ -20,6 +23,18 @@ use humhub\modules\space\modules\manage\models\DeleteForm;
|
||||
class DefaultController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getAccessRules()
|
||||
{
|
||||
$result = parent::getAccessRules();
|
||||
$result[] = [
|
||||
'userGroup' => [Space::USERGROUP_OWNER], 'actions' => ['archive', 'unarchive', 'delete']
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* General space settings
|
||||
*/
|
||||
@ -37,7 +52,7 @@ class DefaultController extends Controller
|
||||
|
||||
public function actionAdvanced()
|
||||
{
|
||||
$space = \humhub\modules\space\modules\manage\models\AdvancedSettingsSpace::findOne(['id' => $this->contentContainer->id]);
|
||||
$space = AdvancedSettingsSpace::findOne(['id' => $this->contentContainer->id]);
|
||||
$space->scenario = 'edit';
|
||||
$space->indexUrl = Yii::$app->getModule('space')->settings->space()->get('indexUrl');
|
||||
$space->indexGuestUrl = Yii::$app->getModule('space')->settings->space()->get('indexGuestUrl');
|
||||
@ -61,7 +76,6 @@ class DefaultController extends Controller
|
||||
*/
|
||||
public function actionArchive()
|
||||
{
|
||||
$this->ownerOnly();
|
||||
$space = $this->getSpace();
|
||||
$space->archive();
|
||||
|
||||
@ -69,7 +83,7 @@ class DefaultController extends Controller
|
||||
Yii::$app->response->format = 'json';
|
||||
return [
|
||||
'success' => true,
|
||||
'space' => \humhub\modules\space\widgets\Chooser::getSpaceResult($space, true, ['isMember' => true])
|
||||
'space' => Chooser::getSpaceResult($space, true, ['isMember' => true])
|
||||
];
|
||||
}
|
||||
|
||||
@ -81,7 +95,6 @@ class DefaultController extends Controller
|
||||
*/
|
||||
public function actionUnarchive()
|
||||
{
|
||||
$this->ownerOnly();
|
||||
$space = $this->getSpace();
|
||||
$space->unarchive();
|
||||
|
||||
@ -89,7 +102,7 @@ class DefaultController extends Controller
|
||||
Yii::$app->response->format = 'json';
|
||||
return [
|
||||
'success' => true,
|
||||
'space' => \humhub\modules\space\widgets\Chooser::getSpaceResult($space, true, ['isMember' => true])
|
||||
'space' => Chooser::getSpaceResult($space, true, ['isMember' => true])
|
||||
];
|
||||
}
|
||||
|
||||
@ -101,14 +114,13 @@ class DefaultController extends Controller
|
||||
*/
|
||||
public function actionDelete()
|
||||
{
|
||||
$this->ownerOnly();
|
||||
$model = new DeleteForm();
|
||||
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
|
||||
$this->getSpace()->delete();
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
return $this->render('delete', array('model' => $model, 'space' => $this->getSpace()));
|
||||
return $this->render('delete', ['model' => $model, 'space' => $this->getSpace()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
namespace humhub\modules\space\modules\manage\controllers;
|
||||
|
||||
use humhub\modules\space\models\Space;
|
||||
use Yii;
|
||||
use yii\web\HttpException;
|
||||
use humhub\modules\space\modules\manage\components\Controller;
|
||||
@ -23,6 +24,17 @@ use humhub\modules\space\modules\manage\models\ChangeOwnerForm;
|
||||
*/
|
||||
class MemberController extends Controller
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getAccessRules()
|
||||
{
|
||||
$result = parent::getAccessRules();
|
||||
$result[] = [
|
||||
'userGroup' => [Space::USERGROUP_OWNER], 'actions' => ['change-owner']
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Members Administration Action
|
||||
@ -157,7 +169,6 @@ class MemberController extends Controller
|
||||
*/
|
||||
public function actionChangeOwner()
|
||||
{
|
||||
$this->ownerOnly();
|
||||
$space = $this->getSpace();
|
||||
|
||||
$model = new ChangeOwnerForm([
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace space\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 1cb90cb7de157697c2044b397df5dd61
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace stream\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3062,6 +3062,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -41,10 +41,10 @@ class PermissionManager extends \yii\base\Component
|
||||
/**
|
||||
* Verifies a given $permission or $permission array for a permission subject.
|
||||
*
|
||||
* If $params['all'] is set to true and a $permission array is given all given permissions
|
||||
* have to be verified successfully otherwise (default) only one permission test has to pass.
|
||||
* If $params['strict'] is set to true and a $permission array is given all given permissions
|
||||
* have to be granted otherwise (default) only one permission test has to pass.
|
||||
*
|
||||
* @param array|BasePermission|mixed $permission
|
||||
* @param string|string[]|BasePermission $permission
|
||||
* @param array $params
|
||||
* @param boolean $allowCaching
|
||||
* @return boolean
|
||||
@ -53,7 +53,8 @@ class PermissionManager extends \yii\base\Component
|
||||
{
|
||||
|
||||
if (is_array($permission)) {
|
||||
$verifyAll = isset($params['all']) ? $params['all'] : false;
|
||||
// compatibility for old 'all' param
|
||||
$verifyAll = $this->isVerifyAll($params);
|
||||
foreach ($permission as $current) {
|
||||
$can = $this->can($current, $params, $allowCaching);
|
||||
if ($can && !$verifyAll) {
|
||||
@ -78,6 +79,20 @@ class PermissionManager extends \yii\base\Component
|
||||
}
|
||||
}
|
||||
|
||||
private function isVerifyAll($params = [])
|
||||
{
|
||||
if(isset($params['strict'])) {
|
||||
return $params['strict'];
|
||||
}
|
||||
|
||||
//deprecated
|
||||
if(isset($params['all'])) {
|
||||
return $params['all'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a single permission for a given permission subject.
|
||||
*
|
||||
@ -118,11 +133,12 @@ class PermissionManager extends \yii\base\Component
|
||||
* Sets the state for a given groupId.
|
||||
*
|
||||
* @param string $groupId
|
||||
* @param BasePermission $permission
|
||||
* @param string|BasePermission $permission either permission class or instance
|
||||
* @param string $state
|
||||
*/
|
||||
public function setGroupState($groupId, BasePermission $permission, $state)
|
||||
public function setGroupState($groupId, $permission, $state)
|
||||
{
|
||||
$permission = (is_string($permission)) ? Yii::createObject($permission) : $permission;
|
||||
$record = $this->getGroupStateRecord($groupId, $permission);
|
||||
|
||||
// No need to store default state
|
||||
|
@ -63,22 +63,23 @@ class User extends \yii\web\User
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for getPermisisonManager()->can().
|
||||
*
|
||||
* Note: This method is used to verify global GroupPermissions and not ContentContainerPermissions.
|
||||
*
|
||||
* @param mixed $permission
|
||||
* Verifies global GroupPermissions of this User component.
|
||||
*
|
||||
* The following example checks if this User is granted the GroupPermission
|
||||
*
|
||||
* ```php
|
||||
* if(Yii::$app->user->can(MyGroupPermission::class) {
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param string|string[]|BasePermission $permission
|
||||
* @see PermissionManager::can()
|
||||
* @return boolean
|
||||
* @since 1.2
|
||||
*/
|
||||
public function can($permission, $params = [], $allowCaching = true)
|
||||
{
|
||||
// Compatibility with Yii2 base permission system.
|
||||
if (is_string($permission)) {
|
||||
return parent::can($permission, $params, $allowCaching);
|
||||
}
|
||||
|
||||
return $this->getPermissionManager()->can($permission, $params, $allowCaching);
|
||||
}
|
||||
|
||||
|
@ -63,13 +63,13 @@ class AccountController extends BaseAccountController
|
||||
|
||||
// Get Form Definition
|
||||
$definition = $user->profile->getFormDefinition();
|
||||
$definition['buttons'] = array(
|
||||
'save' => array(
|
||||
$definition['buttons'] = [
|
||||
'save' => [
|
||||
'type' => 'submit',
|
||||
'label' => Yii::t('UserModule.controllers_AccountController', 'Save profile'),
|
||||
'class' => 'btn btn-primary'
|
||||
),
|
||||
);
|
||||
],
|
||||
];
|
||||
|
||||
$form = new \humhub\compat\HForm($definition, $user->profile);
|
||||
$form->showErrorSummary = true;
|
||||
@ -82,7 +82,7 @@ class AccountController extends BaseAccountController
|
||||
return $this->redirect(['edit']);
|
||||
}
|
||||
|
||||
return $this->render('edit', array('hForm' => $form));
|
||||
return $this->render('edit', ['hForm' => $form]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\user\models;
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
|
||||
|
||||
/**
|
||||
@ -22,6 +22,21 @@ class GroupPermission extends \yii\db\ActiveRecord
|
||||
{
|
||||
return 'group_permission';
|
||||
}
|
||||
|
||||
public static function instance(BasePermission $basePermission, $groupId = null, $state = null) {
|
||||
$instance = new static([
|
||||
'permission_id' => $basePermission->getId(),
|
||||
'module_id' => $basePermission->getModuleId(),
|
||||
'class' => $basePermission->className()
|
||||
]);
|
||||
|
||||
if(!empty($groupId)) {
|
||||
$instance->group_id = ($groupId instanceof Group) ? $groupId->id : $groupId;
|
||||
}
|
||||
|
||||
$instance->state = $state;
|
||||
return $instance;
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
|
@ -424,15 +424,6 @@ class User extends ContentContainerActiveRecord implements \yii\web\IdentityInte
|
||||
$userInvite->delete();
|
||||
}
|
||||
|
||||
// Auto Assign User to the Group Space
|
||||
/* $group = Group::findOne(['id' => $this->group_id]);
|
||||
if ($group != null && $group->space_id != "") {
|
||||
$space = \humhub\modules\space\models\Space::findOne(['id' => $group->space_id]);
|
||||
if ($space !== null) {
|
||||
$space->addMember($this->id);
|
||||
}
|
||||
} */
|
||||
|
||||
// Auto Add User to the default spaces
|
||||
foreach (\humhub\modules\space\models\Space::findAll(['auto_add_new_members' => 1]) as $space) {
|
||||
$space->addMember($this->id);
|
||||
@ -486,6 +477,9 @@ class User extends ContentContainerActiveRecord implements \yii\web\IdentityInte
|
||||
*/
|
||||
public function is(User $user)
|
||||
{
|
||||
if(!$user) {
|
||||
return false;
|
||||
}
|
||||
return $user->id === $this->id;
|
||||
}
|
||||
|
||||
@ -662,6 +656,4 @@ class User extends ContentContainerActiveRecord implements \yii\web\IdentityInte
|
||||
// TODO: Implement same logic as for Spaces
|
||||
return Content::VISIBILITY_PUBLIC;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -26,22 +26,22 @@ class CountrySelect extends Select
|
||||
*
|
||||
* @return array Form Definition
|
||||
*/
|
||||
public function getFormDefinition($definition = array())
|
||||
public function getFormDefinition($definition = [])
|
||||
{
|
||||
return parent::getFormDefinition(array(
|
||||
get_class($this) => array(
|
||||
return parent::getFormDefinition([
|
||||
get_class($this) => [
|
||||
'type' => 'form',
|
||||
'title' => Yii::t('UserModule.models_ProfileFieldTypeSelect', 'Supported ISO3166 country codes'),
|
||||
'elements' => array(
|
||||
'options' => array(
|
||||
'elements' => [
|
||||
'options' => [
|
||||
'type' => 'textarea',
|
||||
'label' => Yii::t('UserModule.models_ProfileFieldTypeSelect', 'Possible values'),
|
||||
'class' => 'form-control',
|
||||
'hint' => Yii::t('UserModule.models_ProfileFieldTypeSelect', 'Comma separated country codes, e.g. DE,EN,AU')
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +103,7 @@ class CountrySelect extends Select
|
||||
public function getFieldFormDefinition()
|
||||
{
|
||||
$definition = parent::getFieldFormDefinition();
|
||||
$definition[$this->profileField->internal_name]['htmlOptions'] = ['data-ui-select2' => true];
|
||||
$definition[$this->profileField->internal_name]['htmlOptions'] = ['data-ui-select2' => true, 'style' => 'width:100%'];
|
||||
return $definition;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 05d523175a26a8580a6b1e51bc071c3c
|
||||
<?php //[STAMP] 142934168f3943147d5338fad03349ce
|
||||
namespace user\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
|
@ -14,12 +14,10 @@ modules:
|
||||
- WebDriver
|
||||
- tests\codeception\_support\WebHelper
|
||||
- tests\codeception\_support\DynamicFixtureHelper
|
||||
- Yii2
|
||||
config:
|
||||
WebDriver:
|
||||
url: http://localhost:8080/
|
||||
browser: firefox
|
||||
window_size: 1024x768
|
||||
restart: true
|
||||
lang: en
|
||||
Yii
|
||||
lang: en
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
namespace humhub\modules\user\tests\codeception\fixtures;
|
||||
|
||||
use yii\test\ActiveFixture;
|
||||
|
||||
class UserFullFixture extends ActiveFixture
|
||||
{
|
||||
|
||||
public $tableName = 'user_mentioning';
|
||||
public $depends = [
|
||||
UserFixture::class,
|
||||
'humhub\modules\user\tests\codeception\fixtures\UserProfileFixture',
|
||||
'humhub\modules\content\tests\codeception\fixtures\ContentContainerFixture',
|
||||
'humhub\modules\user\tests\codeception\fixtures\UserPasswordFixture',
|
||||
'humhub\modules\user\tests\codeception\fixtures\UserFollowFixture',
|
||||
'humhub\modules\user\tests\codeception\fixtures\UserModuleFixture',
|
||||
'humhub\modules\user\tests\codeception\fixtures\GroupFixture'
|
||||
];
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 01.08.2017
|
||||
* Time: 20:22
|
||||
*/
|
||||
|
||||
namespace humhub\modules\user\tests\codeception\functional;
|
||||
|
||||
|
||||
use tests\codeception\_pages\LoginPage;
|
||||
use Yii;
|
||||
use user\FunctionalTester;
|
||||
|
||||
class RegistrationCest
|
||||
{
|
||||
public function testRegister(FunctionalTester $I)
|
||||
{
|
||||
$auth = Yii::$app->getModule('user')->settings->set('auth.anonymousRegistration', 1);
|
||||
LoginPage::openBy($I);
|
||||
$I->see('Sign up');
|
||||
$I->fillField('#register-email', 'wronEmail');
|
||||
$I->click('.btn-primary', '#invite-form');
|
||||
$I->see('Email is not a valid email address.');
|
||||
|
||||
$I->fillField('#register-email', 'mytestmail@test.de');
|
||||
$I->click('.btn-primary', '#invite-form');
|
||||
$I->see('Registration successful!');
|
||||
|
||||
$I->assertMailSent(1);
|
||||
$I->assertEqualsLastEmailSubject('Welcome to HumHub Test');
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
namespace user\functional;
|
||||
|
||||
use humhub\modules\user\models\User;
|
||||
use user\FunctionalTester;
|
||||
|
||||
class UserAccessCest
|
||||
{
|
||||
|
||||
public function testDisabledUserAccess(FunctionalTester $I)
|
||||
{
|
||||
$I->wantTo('ensure that disabled users have no access');
|
||||
|
||||
$I->amUser2();
|
||||
$I->amGoingTo('to deactivate the current user');
|
||||
|
||||
$user = User::findOne(3);
|
||||
$user->status = User::STATUS_DISABLED;
|
||||
$user->save();
|
||||
|
||||
$I->amOnPage(['/dashboard/dashboard']);
|
||||
$I->see('Please sign in');
|
||||
}
|
||||
|
||||
public function testNeedApprovalUserAccess(FunctionalTester $I)
|
||||
{
|
||||
$I->wantTo('ensure that see admin information permission works');
|
||||
|
||||
$I->amUser2();
|
||||
$I->amGoingTo('to deactivate the current user');
|
||||
|
||||
$user = User::findOne(3);
|
||||
$user->status = User::STATUS_NEED_APPROVAL;
|
||||
$user->save();
|
||||
|
||||
$I->amOnPage(['/dashboard/dashboard']);
|
||||
$I->see('Please sign in');
|
||||
}
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
<?php
|
||||
use yii\bootstrap\ActiveForm;
|
||||
?>
|
||||
|
||||
<?php $this->beginContent('@user/views/account/_userProfileLayout.php') ?>
|
||||
<div class="help-block">
|
||||
<?php echo Yii::t('UserModule.views_account_edit', 'Here you can edit your general profile data, which is visible in the about page of your profile.'); ?>
|
||||
<?= Yii::t('UserModule.views_account_edit', 'Here you can edit your general profile data, which is visible in the about page of your profile.'); ?>
|
||||
</div>
|
||||
<?php $form = \yii\bootstrap\ActiveForm::begin(['enableClientValidation' => false, 'options' => ['data-ui-widget' => 'ui.form.TabbedForm', 'data-ui-init' => '']]); ?>
|
||||
<?php echo $hForm->render($form); ?>
|
||||
<?php \yii\bootstrap\ActiveForm::end(); ?>
|
||||
<?php $form = ActiveForm::begin(['enableClientValidation' => false, 'options' => ['data-ui-widget' => 'ui.form.TabbedForm', 'data-ui-init' => '', 'style' => 'display:none']]); ?>
|
||||
<?= $hForm->render($form); ?>
|
||||
<?php ActiveForm::end(); ?>
|
||||
<?php $this->endContent(); ?>
|
||||
|
||||
|
81
protected/humhub/tests/codeception/_support/BasePage.php
Normal file
81
protected/humhub/tests/codeception/_support/BasePage.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace tests\codeception\_support;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Component;
|
||||
use yii\base\InvalidConfigException;
|
||||
|
||||
/**
|
||||
* BasePage is the base class for page classes that represent Web pages to be tested.
|
||||
*
|
||||
* @property string $url The URL to this page. This property is read-only.
|
||||
*
|
||||
* @author Mark Jebri <mark.github@yandex.ru>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class BasePage extends Component
|
||||
{
|
||||
/**
|
||||
* @var string|array the route (controller ID and action ID, e.g. `site/about`) to this page.
|
||||
* Use array to represent a route with GET parameters. The first element of the array represents
|
||||
* the route and the rest of the name-value pairs are treated as GET parameters, e.g. `array('site/page', 'name' => 'about')`.
|
||||
*/
|
||||
public $route;
|
||||
|
||||
/**
|
||||
* @var \Codeception\Actor the testing guy object
|
||||
*/
|
||||
protected $actor;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \Codeception\Actor $I the testing guy object
|
||||
*/
|
||||
public function __construct($I)
|
||||
{
|
||||
$this->actor = $I;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to this page.
|
||||
* The URL will be returned by calling the URL manager of the application
|
||||
* with [[route]] and the provided parameters.
|
||||
* @param array $params the GET parameters for creating the URL
|
||||
* @return string the URL to this page
|
||||
* @throws InvalidConfigException if [[route]] is not set or invalid
|
||||
*/
|
||||
public function getUrl($params = [])
|
||||
{
|
||||
if (is_string($this->route)) {
|
||||
$params[0] = $this->route;
|
||||
|
||||
return Yii::$app->getUrlManager()->createUrl($params);
|
||||
} elseif (is_array($this->route) && isset($this->route[0])) {
|
||||
return Yii::$app->getUrlManager()->createUrl(array_merge($this->route, $params));
|
||||
} else {
|
||||
throw new InvalidConfigException('The "route" property must be set.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a page instance and sets the test guy to use [[url]].
|
||||
* @param \Codeception\Actor $I the test guy instance
|
||||
* @param array $params the GET parameters to be used to generate [[url]]
|
||||
* @return static the page instance
|
||||
*/
|
||||
public static function openBy($I, $params = [])
|
||||
{
|
||||
$page = new static($I);
|
||||
$I->amOnPage($page->getUrl($params));
|
||||
|
||||
return $page;
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ class HumHubDbTestCase extends Test
|
||||
Yii::setAlias('@webroot', $webRoot);
|
||||
$this->initModules();
|
||||
$this->reloadSettings();
|
||||
$this->deleteMails();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
@ -66,6 +67,17 @@ class HumHubDbTestCase extends Test
|
||||
}
|
||||
}
|
||||
|
||||
protected function deleteMails()
|
||||
{
|
||||
$path = Yii::getAlias('@runtime/mail');
|
||||
$files = glob($path . '/*'); // get all file names
|
||||
foreach ($files as $file) { // iterate files
|
||||
if (is_file($file)) {
|
||||
unlink($file); // delete file
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes modules defined in @tests/codeception/config/test.config.php
|
||||
* Note the config key in test.config.php is modules and not humhubModules!
|
||||
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
namespace tests\codeception\_support;
|
||||
|
||||
use Codeception\Events;
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 31.07.2017
|
||||
* Time: 23:22
|
||||
*/
|
||||
class HumHubExtension extends \Codeception\Extension
|
||||
{
|
||||
public static $events = [
|
||||
Events::MODULE_INIT => 'moduleInit',
|
||||
#Events::STEP_BEFORE => 'beforeStep',
|
||||
#Events::TEST_FAIL => 'testFailed',
|
||||
#Events::RESULT_PRINT_AFTER => 'print',
|
||||
];
|
||||
|
||||
public function moduleInit($test) {
|
||||
$GLOBALS['env'] = $this->options['env'];
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] ffd625c70933a7c0926fa73ac6513fde
|
||||
<?php //[STAMP] b8162d517b4257b92313df71eac4c547
|
||||
namespace _generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
@ -3061,6 +3061,28 @@ trait FunctionalTesterActions
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertMailSent()
|
||||
*/
|
||||
public function assertMailSent($count = null, $msg = null) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertMailSent', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
*
|
||||
* @see \tests\codeception\_support\HumHubHelper::assertEqualsLastEmailSubject()
|
||||
*/
|
||||
public function assertEqualsLastEmailSubject($subject) {
|
||||
return $this->getScenario()->runStep(new \Codeception\Step\Action('assertEqualsLastEmailSubject', func_get_args()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [!] Method is generated. Documentation taken from corresponding module.
|
||||
*
|
||||
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 27.07.2017
|
||||
* Time: 00:06
|
||||
*/
|
||||
|
||||
namespace humhub\tests\codeception\unit\components\access;
|
||||
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
|
||||
class AccessTestPermission1 extends BasePermission
|
||||
{
|
||||
public $moduleId = 'content';
|
||||
|
||||
public $id = 'content-test-permission2';
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 27.07.2017
|
||||
* Time: 00:06
|
||||
*/
|
||||
|
||||
namespace humhub\tests\codeception\unit\components\access;
|
||||
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
|
||||
class AccessTestPermission2 extends BasePermission
|
||||
{
|
||||
public $moduleId = 'test';
|
||||
|
||||
public $id = 'content-test-permission';
|
||||
|
||||
}
|
@ -0,0 +1,452 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 27.07.2017
|
||||
* Time: 13:27
|
||||
*/
|
||||
|
||||
namespace humhub\tests\codeception\unit\components\access;
|
||||
|
||||
|
||||
use humhub\commands\TestController;
|
||||
use humhub\components\access\AccessValidator;
|
||||
use humhub\components\access\ControllerAccess;
|
||||
use humhub\components\access\StrictAccess;
|
||||
use tests\codeception\_support\HumHubDbTestCase;
|
||||
use Yii;
|
||||
|
||||
class ControllerAccessTest extends HumHubDbTestCase
|
||||
{
|
||||
public $fixtureConfig = ['default'];
|
||||
|
||||
public function testLoggedInOnlyValidator()
|
||||
{
|
||||
// Guest not allowed for global loggedInOnly rule
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals('Login required for this section.', $controllerAccess->reason);
|
||||
|
||||
// Guest not allowed for not action related loggedInOnly rule
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY => ['testAction2']]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// Guest not allowed for action related loggedInOnly rule
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY => ['testAction', 'testAction2']]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals('Login required for this section.', $controllerAccess->reason);
|
||||
|
||||
// User allowed for global loggedInOnly rule
|
||||
$this->becomeUser('User1');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
}
|
||||
|
||||
public function testAdminOnlyValidator()
|
||||
{
|
||||
// Guest
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals('You need admin permissions to access this section.', $controllerAccess->reason);
|
||||
|
||||
// User
|
||||
$this->becomeUser('User1');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals('You need admin permissions to access this section.', $controllerAccess->reason);
|
||||
|
||||
// Admin
|
||||
$this->becomeUser('Admin');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
}
|
||||
|
||||
public function testStrictModeValidator()
|
||||
{
|
||||
// Guest not allowed for global strict rule
|
||||
$this->allowGuestAccess(false);
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_STRICT]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals('Guest mode not active, please login first.', $controllerAccess->reason);
|
||||
|
||||
// Guest allowed for global strict rule if guest mode active
|
||||
$this->allowGuestAccess(true);
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_STRICT]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// User allowed for global strict rule if guest mode not active
|
||||
$this->allowGuestAccess(false);
|
||||
$this->becomeUser('User1');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_STRICT]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
}
|
||||
|
||||
public function testInactiveUserValidator()
|
||||
{
|
||||
// Guests should not be affected
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_DISABLED_USER],
|
||||
[ControllerAccess::RULE_UNAPPROVED_USER]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// Active user should not be affected
|
||||
$this->becomeUser('User1');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_DISABLED_USER],
|
||||
[ControllerAccess::RULE_UNAPPROVED_USER]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// Disabled user should not be allowed
|
||||
$this->becomeUser('DisabledUser');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_DISABLED_USER],
|
||||
[ControllerAccess::RULE_UNAPPROVED_USER]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals(401, $controllerAccess->code );
|
||||
$this->assertEquals('Your user account is inactive, please login with an active account or contact a network administrator.', $controllerAccess->reason);
|
||||
|
||||
// UnnapprovedUser
|
||||
$this->becomeUser('UnapprovedUser');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
[ControllerAccess::RULE_DISABLED_USER],
|
||||
[ControllerAccess::RULE_UNAPPROVED_USER]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals(401, $controllerAccess->code );
|
||||
$this->assertEquals('Your user account has not been approved yet, please try again later or contact a network administrator.', $controllerAccess->reason);
|
||||
}
|
||||
|
||||
public function testGuestUserValidator()
|
||||
{
|
||||
$this->allowGuestAccess();
|
||||
|
||||
// If no guest restriction is given the validation should pass
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => []]);
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// Set two guestaccess rules
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
['guestAccess' => ['otherAction']],
|
||||
['guestAccess' => ['testAction']],
|
||||
]]);
|
||||
|
||||
#$this->assertTrue($controllerAccess->run());
|
||||
|
||||
|
||||
// If global guest restriction is given allow for all actions
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
['guestAccess']
|
||||
]]);
|
||||
#$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// Non action related guestAccess rule should fail
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
['guestAccess' => ['testAction2']]
|
||||
]]);
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
|
||||
// Action related guestAccess rule should succeed
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
['guestAccess' => ['testAction']]
|
||||
]]);
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// LoggedIn users should not be affected
|
||||
$this->becomeUser('User1');
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => [
|
||||
['guestAccess' => ['testAction2']]
|
||||
]]);
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
}
|
||||
|
||||
public function testPermissionRuleValidator()
|
||||
{
|
||||
// Guest has no permission
|
||||
$accessCheck = new ControllerAccess([
|
||||
'rules' => [
|
||||
['permissions' => [AccessTestPermission1::class]]
|
||||
],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Add Permission1 to User Group but validate against Permission2
|
||||
$this->setGroupPermission(2, AccessTestPermission1::class);
|
||||
$this->becomeUser('User1');
|
||||
$accessCheck = new ControllerAccess([
|
||||
'rules' => [
|
||||
['permissions' => [AccessTestPermission2::class]]
|
||||
],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Permission2 included
|
||||
$accessCheck->rules = [
|
||||
['permissions' => [AccessTestPermission1::class, AccessTestPermission2::class]]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// In strict mode both permission have to be granted
|
||||
$accessCheck->rules = [
|
||||
['permissions' => [AccessTestPermission1::class, AccessTestPermission2::class], 'strict' => true]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Check two permission rules one non action related and one global valid one. The non action related should be ignored
|
||||
$accessCheck->rules = [
|
||||
['permissions' => [AccessTestPermission2::class], 'actions' => 'otherPermission'],
|
||||
['permissions' => [AccessTestPermission1::class, AccessTestPermission2::class]]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
|
||||
// Check non strict behaviour of permissoin rule with one not allowed global rule which is overwritten by action related
|
||||
// This check passes, since only one of them has to pass.
|
||||
$accessCheck->rules = [
|
||||
['permissions' => [AccessTestPermission2::class]],
|
||||
['permissions' => [AccessTestPermission1::class], 'actions' => 'testAction']
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
|
||||
// Check string permission definition
|
||||
$accessCheck->rules = [
|
||||
['permissions' => AccessTestPermission1::class]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// Check permission rule in combination with adminOnly
|
||||
$accessCheck->rules = [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY],
|
||||
['permissions' => [AccessTestPermission2::class], 'actions' => 'otherPermission'],
|
||||
['permissions' => [AccessTestPermission1::class, AccessTestPermission2::class]]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testGuestRunValidation()
|
||||
{
|
||||
$this->allowGuestAccess();
|
||||
|
||||
// AdminOnly overwrites guestAccess
|
||||
$accessCheck = new ControllerAccess([
|
||||
'rules' => [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY],
|
||||
['guestAccess' => ['testAction']]
|
||||
],
|
||||
'action' => 'testAction'
|
||||
]);
|
||||
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// AdminOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
['guestAccess' => ['otherTestAction', 'testAction']],
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['testAction']]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// AdminOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
['guestAccess' => ['testAction']],
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['otherTestAction']]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// LoggedInOnly setting should overwrite the guestAccess
|
||||
$accessCheck->rules = [
|
||||
['guestAccess'],
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Non action related adminOnly and loggedInOnly
|
||||
$accessCheck->rules = [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['otherTestAction']],
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY => 'otherTestAction']
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// LoggedInOnly overwrites guest access
|
||||
$accessCheck->rules = [
|
||||
[ControllerAccess::RULE_ADMIN_ONLY => ['otherTestAction']],
|
||||
[ControllerAccess::RULE_LOGGED_IN_ONLY => 'testAction'],
|
||||
['guestAccess' => 'testAction']
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Global permission rule
|
||||
$accessCheck->rules = [
|
||||
['permissions' => [AccessTestPermission1::class]]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
// Non action related permission rule
|
||||
$accessCheck->rules = [
|
||||
['permissions' => AccessTestPermission1::class, 'actions' => ['otherTestAction']]
|
||||
];
|
||||
$this->assertTrue($accessCheck->run());
|
||||
|
||||
// Matching action related permission setting
|
||||
$accessCheck->rules = [
|
||||
['permissions' => [AccessTestPermission1::class], 'actions' => ['otherTestAction', 'testAction']]
|
||||
];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
|
||||
$this->allowGuestAccess(false);
|
||||
|
||||
$accessCheck->rules = [['strict']];
|
||||
$this->assertFalse($accessCheck->run());
|
||||
}
|
||||
|
||||
public function testFixedRuleValidation()
|
||||
{
|
||||
// DsiabledUser and Unapproved are fixed rules and should always be validated
|
||||
$this->becomeUser('DisabledUser');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => []]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals(401, $controllerAccess->code );
|
||||
$this->assertEquals('Your user account is inactive, please login with an active account or contact a network administrator.', $controllerAccess->reason);
|
||||
|
||||
// UnnapprovedUser
|
||||
$this->becomeUser('UnapprovedUser');
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'rules' => []]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals(401, $controllerAccess->code );
|
||||
$this->assertEquals('Your user account has not been approved yet, please try again later or contact a network administrator.', $controllerAccess->reason);
|
||||
}
|
||||
|
||||
public function testStrictAccess()
|
||||
{
|
||||
// Guest not allowed for global strict rule
|
||||
$this->allowGuestAccess(false);
|
||||
|
||||
$controllerAccess = new StrictAccess(['action' => 'testAction', 'rules' => []]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals('Guest mode not active, please login first.', $controllerAccess->reason);
|
||||
|
||||
// Guest allowed for global strict rule if guest mode active
|
||||
$this->allowGuestAccess(true);
|
||||
|
||||
$controllerAccess = new StrictAccess(['action' => 'testAction', 'rules' => []]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
|
||||
// User allowed for global strict rule if guest mode not active
|
||||
$this->allowGuestAccess(false);
|
||||
$this->becomeUser('User1');
|
||||
|
||||
$controllerAccess = new StrictAccess(['action' => 'testAction', 'rules' => []]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
}
|
||||
|
||||
public function testCustomOwnerRule()
|
||||
{
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'owner' => $this, 'rules' => [
|
||||
['validateTestRule', 'return' => false]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals(404, $controllerAccess->code);
|
||||
$this->assertEquals('Not you again!', $controllerAccess->reason);
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'owner' => $this, 'rules' => [
|
||||
['validateTestRule', 'return' => true]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
$this->assertEquals(null, $controllerAccess->code);
|
||||
$this->assertEquals(null, $controllerAccess->reason);
|
||||
}
|
||||
|
||||
public function validateTestRule($rule, $access)
|
||||
{
|
||||
$this->assertEquals($access->owner, $this);
|
||||
if(!$rule['return']) {
|
||||
$access->code = 404;
|
||||
$access->reason = 'Not you again!';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function testCustomClassRule()
|
||||
{
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'owner' => $this, 'rules' => [
|
||||
[TestActionValidator::class, 'return' => false]
|
||||
]]);
|
||||
|
||||
$this->assertFalse($controllerAccess->run());
|
||||
$this->assertEquals(404, $controllerAccess->code);
|
||||
$this->assertEquals('Not you again!', $controllerAccess->reason);
|
||||
|
||||
$controllerAccess = new ControllerAccess(['action' => 'testAction', 'owner' => $this, 'rules' => [
|
||||
[TestActionValidator::class, 'return' => true]
|
||||
]]);
|
||||
|
||||
$this->assertTrue($controllerAccess->run());
|
||||
$this->assertEquals(null, $controllerAccess->code);
|
||||
$this->assertEquals(null, $controllerAccess->reason);
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 28.07.2017
|
||||
* Time: 17:47
|
||||
*/
|
||||
|
||||
namespace humhub\tests\codeception\unit\components\access;
|
||||
|
||||
|
||||
use humhub\components\access\ActionAccessValidator;
|
||||
|
||||
class TestActionValidator extends ActionAccessValidator
|
||||
{
|
||||
protected function validate($rule)
|
||||
{
|
||||
if(!$rule['return']) {
|
||||
$this->access->code = 404;
|
||||
$this->access->reason = 'Not you again!';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ abstract class BootstrapComponent extends Widget
|
||||
public $htmlOptions = [];
|
||||
public $text;
|
||||
public $_icon;
|
||||
public $_iconRight;
|
||||
|
||||
public $_visible = true;
|
||||
|
||||
@ -119,6 +120,12 @@ abstract class BootstrapComponent extends Widget
|
||||
return static::info($text)->color($color);
|
||||
}
|
||||
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
* @return $this
|
||||
@ -238,12 +245,13 @@ abstract class BootstrapComponent extends Widget
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function icon($content, $raw = false)
|
||||
public function icon($content, $right = false, $raw = false)
|
||||
{
|
||||
if(!$raw) {
|
||||
$this->icon(Html::tag('i', '', ['class' => 'fa '.$content]), true);
|
||||
$this->icon(Html::tag('i', '', ['class' => 'fa '.$content]), $right, true);
|
||||
} else {
|
||||
$this->_icon = $content;
|
||||
$this->_iconRight = $right;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -299,7 +307,7 @@ abstract class BootstrapComponent extends Widget
|
||||
protected function getText()
|
||||
{
|
||||
if($this->_icon) {
|
||||
return $this->_icon.' '.$this->text;
|
||||
return ($this->_iconRight) ? $this->text.' '.$this->_icon : $this->_icon.' '.$this->text;
|
||||
}
|
||||
|
||||
return $this->text;
|
||||
@ -327,6 +335,7 @@ abstract class BootstrapComponent extends Widget
|
||||
'text' => $this->text,
|
||||
'htmlOptions' => $this->htmlOptions,
|
||||
'_icon' => $this->_icon,
|
||||
'_iconRight' => $this->_iconRight,
|
||||
'render' => $this->_visible
|
||||
];
|
||||
}
|
||||
|
57
protected/humhub/widgets/FadeIn.php
Normal file
57
protected/humhub/widgets/FadeIn.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: buddha
|
||||
* Date: 25.07.2017
|
||||
* Time: 14:31
|
||||
*/
|
||||
|
||||
namespace humhub\widgets;
|
||||
|
||||
|
||||
/**
|
||||
* Simple FadeIn JsWidget
|
||||
* @since 1.2.2
|
||||
*/
|
||||
class FadeIn extends JsWidget
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $fadeIn = true;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $jsWidget = 'ui.widget.Widget';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $init = true;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
ob_start();
|
||||
ob_implicit_flush(false);
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->content = ob_get_clean();
|
||||
return parent::run();
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
namespace humhub\widgets;
|
||||
|
||||
use humhub\components\Widget;
|
||||
use humhub\libs\Html;
|
||||
|
||||
/**
|
||||
* Description of JsWidget
|
||||
@ -57,6 +58,15 @@ class JsWidget extends Widget
|
||||
*/
|
||||
public $container = 'div';
|
||||
|
||||
/**
|
||||
* If set to true or 'fast', 'slow' or a integer duration in milliseconds the jsWidget will fade in the root element after initialization.
|
||||
* This can be handy for widgets which need some time to initialize.
|
||||
*
|
||||
* @var bool|string|integer
|
||||
* @since 1.2.2
|
||||
*/
|
||||
public $fadeIn = false;
|
||||
|
||||
/**
|
||||
* @var string html content.
|
||||
*/
|
||||
@ -92,11 +102,7 @@ class JsWidget extends Widget
|
||||
$result = \yii\helpers\ArrayHelper::merge($attributes, $this->options);
|
||||
|
||||
if (!$this->visible) {
|
||||
if (isset($result['style'])) {
|
||||
$result['style'] .= ';display:none;';
|
||||
} else {
|
||||
$result['style'] = 'display:none;';
|
||||
}
|
||||
Html::addCssStyle($result, 'display:none');
|
||||
}
|
||||
|
||||
return $result;
|
||||
@ -117,6 +123,12 @@ class JsWidget extends Widget
|
||||
$this->options['data']['ui-widget'] = $this->jsWidget;
|
||||
}
|
||||
|
||||
if($this->fadeIn) {
|
||||
$fadeIn = $this->fadeIn === true ? 'fast' : $this->fadeIn;
|
||||
$this->options['data']['widget-fade-in'] = $fadeIn;
|
||||
$this->visible = false;
|
||||
}
|
||||
|
||||
if (!empty($this->init)) {
|
||||
$this->options['data']['ui-init'] = $this->init;
|
||||
}
|
||||
|
@ -89,6 +89,11 @@ class MarkdownField extends InputWidget
|
||||
*/
|
||||
public $placeholder;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $fadeIn = 'fast';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -127,7 +132,8 @@ class MarkdownField extends InputWidget
|
||||
'rows' => $this->rows,
|
||||
'disabled' => $this->disabled,
|
||||
'readonly' => $this->readonly,
|
||||
'placeholder' => $this->placeholder
|
||||
'placeholder' => $this->placeholder,
|
||||
'class' => 'form-control'
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user