Merge branch 'v1.3-dev' of github.com:humhub/humhub into v1.3-dev

This commit is contained in:
Lucas Bartholemy 2017-10-25 15:31:35 +02:00
commit 11d8ccd6c8
69 changed files with 827 additions and 438 deletions

View File

@ -61,7 +61,7 @@ script:
- curl http://127.0.0.1:8080/index-test.php - curl http://127.0.0.1:8080/index-test.php
- | - |
cd protected/humhub/tests/ cd protected/humhub/tests/
codecept run -d codecept run
after_failure: after_failure:
- cd ../modules/user/tests/codeception/_output/ - cd ../modules/user/tests/codeception/_output/
- ls - ls

View File

@ -9,6 +9,8 @@
namespace humhub\commands; namespace humhub\commands;
use Yii; use Yii;
use yii\web\Application;
use yii\console\Exception;
/** /**
* Manages application migrations. * Manages application migrations.
@ -134,7 +136,7 @@ class MigrateController extends \yii\console\controllers\MigrateController
} }
} }
throw new \yii\console\Exception("Could not find path for: " . $migration); throw new Exception("Could not find path for: " . $migration);
} }
/** /**
@ -191,6 +193,7 @@ class MigrateController extends \yii\console\controllers\MigrateController
$controller->migrationPath = $migrationPath; $controller->migrationPath = $migrationPath;
$controller->color = false; $controller->color = false;
$controller->runAction('up'); $controller->runAction('up');
return ob_get_clean(); return ob_get_clean();
} }
@ -199,7 +202,7 @@ class MigrateController extends \yii\console\controllers\MigrateController
*/ */
public function stdout($string) public function stdout($string)
{ {
if (Yii::$app instanceof \yii\web\Application) { if (Yii::$app instanceof Application) {
print $string; print $string;
} else { } else {
return parent::stdout($string); return parent::stdout($string);
@ -211,7 +214,7 @@ class MigrateController extends \yii\console\controllers\MigrateController
*/ */
public function stderr($string) public function stderr($string)
{ {
if (Yii::$app instanceof \yii\web\Application) { if (Yii::$app instanceof Application) {
print $string; print $string;
} else { } else {
return parent::stderr($string); return parent::stderr($string);

View File

@ -41,8 +41,6 @@ use yii\base\Object;
* A Validator has an unique name which is used to detect related rules and can filter out non related rules by * 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. * 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. * AccessValidators have access to a ControllerAccess instance, which holds the ruleset and validation state.
* *
* This abstract validator class furthermore provides some helper functions as: * This abstract validator class furthermore provides some helper functions as:

View File

@ -23,43 +23,89 @@ use yii\base\Object;
use yii\web\Controller; use yii\web\Controller;
/** /**
* ControllerAccess contains the actual logic to verify if a user can access a given $action. * ControllerAccess contains the actual logic to verify whether or not a user can access a controller action by means of
* a given set of access rules.
* *
* By default the AccessCheck will set the current logged in user permission object, if $user is null, we assume a guest * By default the AccessCheck will use the current logged in user as permission subject.
* user.
* *
* The guest user access can be verified by calling the `reguiresLogin()` check. * The actual permission rule verification is handled by the [[run()]] function.
* *
* Inactive users are can be catched by calling `isInActiveUser()`. * Subclasses can extend the set of available validators by calling [[registerValidator()]] and providing a validator setting array as:
* *
* The actual permission rule verification is handled by the `verify()` check, subclasses may overwrite and extend this * ```php
* function with additional checks.
*
* Subclasses can extend available validators by calling `registerValidator` and providing a validator setting array as:
*
* ```
* public function init() * public function init()
* { * {
* parent::init(); * parent::init();
* $this->registerValidator([ * $this->registerValidator([
* self::RULE_MY_CUSTOM_RULE => 'validateCustomRule', * self::RULE_MY_RULE => 'validateMyRule',
* 'reason' => Yii::t('error', 'Guest mode not active, please login first.'), * 'reason' => Yii::t('error', 'My validation rule could not be verified.'),
* 'code' => 401]); * 'code' => 401
* ]);
* } * }
* ``` * ```
* *
* The previous example registered an new validator repsonsible for validating $rules with name self::RULE_MY_CUSTOM_RULE and validation * The previous example registered a new validator responsible for validating rules with the name `validateMyRule` and validation
* handler function 'validateCustomRule' which defines an handler method within the subclass. * handler function `validateMyRule` which defines an handler method within the subclass.
* *
* The validator can be set the following additional settings: * Custom Validators can also be added by means of a Validator class as in the following example:
* *
* - **reason**: Reason set if the validaiton fails * ```php
* - **code**: Http Code e.g. 404, 403, 401 * $this->registerValidator(MyValidator::class);
* - **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)
* *
* where `MyValidator` is a subclass of [[\humhub\components\access\AccessValidator]]
*
* A single rule is provided as a array. If not specified otherwise, a rule supports the following base format:
*
* ```php
* ['ruleName', 'actions' => ['action1', 'action2']]
* ```
* or
*
* ```php
* ['ruleName' => ['action1', action2]]
* ```
*
* > Note: the second format is not supported by all rules e.g. permission rule
*
* If no action array is provided, the rule is considered to be controller global and will be verified for all actions.
*
* If a rule for a given name could not be found, the ControllerAccess tries to determine a custom rule validator set by the controller itself:
*
* ```php
* ['validateMyCustomRule', 'someParameter' => $value]
* ```
*
* will search for controller validator function `validateMyCustomRule`:
*
* ```php
* public function validateTestRule($rule, $access)
* {
* if($rule['someParameter'] == 'valid') {
* $access->code = 401;
* $access->reason = 'Not authorized!';
* return false;
* }
*
* return true;
* }
* ```
*
* By defining the [[fixedRules]] array property a ControllerAccess can define rules which are always applied, this property (or [[getFixedRules()]] function
* may be overwritten by subclasses.
*
* The following rules are available by default:
*
* - **admin**: The user has to be system admin to access a action
* - **permission** Group Permission check
* - **login**: The user has to be logged in to access a action
* - **strict**: Will check for guest users against the guest users allowed setting
* - **post**: Will only accept post requests for the given actions
* - **json**: Will handle json result requests by setting `Yii::$app->response->format = 'json'`
* - **disabledUser**: Checks if the given user is a disabled user **(fixed)**
* - **unapprovedUser**: Checks if the given user is a unapproved user **(fixed)**
*
* @see AccessValidator
* @since 1.2.2 * @since 1.2.2
*/ */
class ControllerAccess extends Object class ControllerAccess extends Object
@ -74,14 +120,44 @@ class ControllerAccess extends Object
*/ */
const ACTION_SETTING_TYPE_BOTH = 1; const ACTION_SETTING_TYPE_BOTH = 1;
/**
* Only admins have access to the given set of actions e.g.: ['admin' => ['action1']]
*/
const RULE_ADMIN_ONLY = 'admin'; const RULE_ADMIN_ONLY = 'admin';
/**
* Validate against a given set of permissions e.g.: ['permission' => [MyPermission::class], 'actions' => ['action1']]
*/
const RULE_PERMISSION = 'permission'; const RULE_PERMISSION = 'permission';
/**
* Only logged in user have access e.g.: ['login' => ['action1', 'action2']]
*/
const RULE_LOGGED_IN_ONLY = 'login'; const RULE_LOGGED_IN_ONLY = 'login';
const RULE_GUEST_CUSTOM = 'custom';
/**
* Check guest mode e.g.: ['strict'] (mainly used as global)
*/
const RULE_STRICT = 'strict'; const RULE_STRICT = 'strict';
/**
* Check guest if user is disabled
*/
const RULE_DISABLED_USER = 'disabledUser'; const RULE_DISABLED_USER = 'disabledUser';
/**
* Check guest if user is unnapproved
*/
const RULE_UNAPPROVED_USER = 'unapprovedUser'; const RULE_UNAPPROVED_USER = 'unapprovedUser';
/**
* Check guest if request method is post
*/
const RULE_POST = 'post'; const RULE_POST = 'post';
/**
* Make sure response type is json
*/
const RULE_JSON = 'json'; const RULE_JSON = 'json';
/** /**
@ -152,11 +228,20 @@ class ControllerAccess extends Object
$this->registerValidator([self::RULE_JSON => 'validateJsonResponse']); $this->registerValidator([self::RULE_JSON => 'validateJsonResponse']);
} }
/**
* @return array set of rules
*/
public function getRules() public function getRules()
{ {
return $this->rules; return $this->rules;
} }
/**
* Sets the current set of rules.
* > Note: This will merge the given set of rules with the fixed rules.
*
* @param array $rules sets th
*/
public function setRules($rules = []) public function setRules($rules = [])
{ {
$this->rules = array_merge($this->getFixedRules(), $rules); $this->rules = array_merge($this->getFixedRules(), $rules);
@ -176,9 +261,7 @@ class ControllerAccess extends Object
protected function registerValidator($options) protected function registerValidator($options)
{ {
if(is_string($options)) { if(is_string($options)) {
$options = [ $options = ['class' => $options];
'class' => $options,
];
} }
$options['access'] = $this; $options['access'] = $this;
@ -264,7 +347,7 @@ class ControllerAccess extends Object
} }
/** /**
* Extracts the ruleName from the given $array. * Extracts the ruleName from a given rule option array.
* *
* @param $arr * @param $arr
* @return mixed|null * @return mixed|null

View File

@ -14,38 +14,81 @@ use humhub\components\access\ControllerAccess;
use yii\web\HttpException; use yii\web\HttpException;
/** /**
* AccessControl provides basic controller access protection * Handles the AccessControl for a Controller.
* *
* Here are some examples access control settings: * Controller level AccessRules can be provided by either setting the [[rules]] array, or by implementing a `getAccessRules()` function
* within the controller itself (prefered).
* *
* Allow guest access for action 'info' * **Examples:**
* *
* ``` * Disable guest access for all controller actions:
* [ *
* 'acl' => [ * ```php
* 'class' => \humhub\components\behaviors\AccessControl::className(), * public function getAccessRules()
* 'guestAllowedActions' => ['info'] * {
* ] * return [
* ] * ['login']
* ];
* }
* ``` * ```
* *
* Allow access by pemission rule: * Disable guest access for specific controller actions:
* *
* ``` * ```php
* [ * public function getAccessRules()
* 'acl' => [ * {
* 'class' => \humhub\components\behaviors\AccessControl::className(), * return [
* 'rules' => [ * ['login' => ['action1', 'action2']]
* [ * ];
* 'groups' => [ * }
* 'humhub\modules\xy\permissions\MyAccessPermssion'
* ]
* ]
* ]
* ]
* ]
* ``` * ```
* *
* All users have to be logged in + additional permission check for 'action1' and 'action2':
*
* ```php
* public function getAccessRules()
* {
* return [
* ['login'],
* ['permission' => MyPermission::class, 'actions' => ['action1', 'action2']]
* ];
* }
* ```
*
* Custom inline validator for action 'action1':
*
* ```php
* public function getAccessRules()
* {
* return [
* ['validateMyCustomRule', 'someParameter' => 'someValue', 'actions' => ['action1']]
* ];
* }
*
* public function validateMyCustomRule($rule, $access)
* {
* if($rule['someParameter'] !== 'someValue') {
* $access->code = 401;
* $access->reason = 'Not authorized!';
* return false;
* }
*
* return true;
* }
*
* ```
*
* The list of available rules is given by the [[\humhub\components\access\ControllerAccess]] class set by a controller. By
* default the base [[\humhub\components\access\ControllerAccess]] class will be used.
*
* The default ControllerAccess class can be overwritten by implementing the `getAccess()` function within a controller, which should return an instance
* of ControllerAccess.
*
* > Note: You can also use the [[\humhub\components\Controller::access]] property to define a ControllerAccess class string.
*
*
*
* @see ControllerAccess
* @author luke * @author luke
*/ */
class AccessControl extends \yii\base\ActionFilter class AccessControl extends \yii\base\ActionFilter

View File

@ -2,7 +2,7 @@
/** /**
* This file is generated by the "yii asset" command. * This file is generated by the "yii asset" command.
* DO NOT MODIFY THIS FILE DIRECTLY. * DO NOT MODIFY THIS FILE DIRECTLY.
* @version 2017-10-21 00:16:59 * @version 2017-10-23 13:26:02
*/ */
return [ return [
'all' => [ 'all' => [

View File

@ -48,7 +48,7 @@ class ErrorController extends Controller
/** /**
* Show special login required view for guests * Show special login required view for guests
*/ */
if (Yii::$app->user->isGuest && $exception instanceof HttpException && $exception->statusCode == "401" && Yii::$app->getModule('user')->settings->get('auth.allowGuestAccess')) { if (Yii::$app->user->isGuest && $exception instanceof HttpException && $exception->statusCode == '401' && Yii::$app->getModule('user')->settings->get('auth.allowGuestAccess')) {
return $this->render('@humhub/views/error/401_guests', ['message' => $message]); return $this->render('@humhub/views/error/401_guests', ['message' => $message]);
} }

View File

@ -10,6 +10,8 @@ namespace humhub\controllers;
use Yii; use Yii;
use humhub\components\Controller; use humhub\components\Controller;
use humhub\components\behaviors\AccessControl;
use humhub\widgets\MarkdownView;
/** /**
* MarkdownController provides preview for MarkdownEditorWidget * MarkdownController provides preview for MarkdownEditorWidget
@ -27,7 +29,7 @@ class MarkdownController extends Controller
{ {
return [ return [
'acl' => [ 'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(), 'class' => AccessControl::className(),
] ]
]; ];
} }
@ -36,7 +38,7 @@ class MarkdownController extends Controller
{ {
$this->forcePostRequest(); $this->forcePostRequest();
return \humhub\widgets\MarkdownView::widget(['markdown' => Yii::$app->request->post('markdown')]); return MarkdownView::widget(['markdown' => Yii::$app->request->post('markdown')]);
} }
} }

View File

@ -1,13 +1,13 @@
HumHub Change Log HumHub Change Log
================= =================
1.2.3 (Not released yet) 1.2.3 (October 23, 2017)
-------------------------------- -------------------------
Important note for LDAP users: There is a new setting "ID Attribute" which should be set to clearly identify users. Important note for LDAP users: There is a new setting "ID Attribute" which should be set to clearly identify users.
Important note for Git/Composer installations: http://www.yiiframework.com/news/148/important-note-about-bower-and-the-asset-plugin/
- Fix: Readonly markdown field issue. - Fix: Readonly markdown field issue.
- Enh: Added flag to control automatically created social activities at content creation.
- Enh: Fixed registration approval/denial mails and made their default value configurable. - Enh: Fixed registration approval/denial mails and made their default value configurable.
- Enh: Updated primary auth client interface for more flexibility - Enh: Updated primary auth client interface for more flexibility
- Enh: Added LDAP ID attribute to improve user mapping - Enh: Added LDAP ID attribute to improve user mapping
@ -49,7 +49,11 @@ Important note for LDAP users: There is a new setting "ID Attribute" which shoul
- Fix #2613: Wrong username encoding with pretty url (githubjeka) - Fix #2613: Wrong username encoding with pretty url (githubjeka)
- Fix #2791, #2749: Force private join policy on private spaces + non changeable post visibility - Fix #2791, #2749: Force private join policy on private spaces + non changeable post visibility
- Fix wrong Comment date issue in notification mails - Fix wrong Comment date issue in notification mails
- Added `data-file-*` attributes to download links, for intercepting file downloads - Enh: Added `data-file-*` attributes to download links, for beeing able to intercept file downloads
- Enh: Added `apple-mobile-web-app-*` and `mobile-web-app-capable` meta tags to `head.php`
- Fix #2783: E-Mail notification link broken when guest mode is enabled (Buliwyfa)
- Enh: Added `ContentActiveRecord::silentContentCreation` for disabling ContentCreated Activity/Notification on ContentActiveRecord level
- Enh: Now the `NewContent` live event is always fired with `sourceClass` and `sourceId` information and a `silent` flag for silent content creations
1.2.2 (August 2, 2017) 1.2.2 (August 2, 2017)
-------------------------------- --------------------------------
@ -149,6 +153,8 @@ Important note for LDAP users: There is a new setting "ID Attribute" which shoul
- Fix: Show more suppression entries with sort order update + equal update_at not working. - Fix: Show more suppression entries with sort order update + equal update_at not working.
- Fix #2627: Incorrect language used in group admin user approval e-mail - Fix #2627: Incorrect language used in group admin user approval e-mail
- Fix #2631: Module configuration link shown for disabled modules - Fix #2631: Module configuration link shown for disabled modules
- Fix #2785 #2172: Added iconv PHP extension to the requirement check (leuprechtroman)
1.2.0 (April 16, 2017) 1.2.0 (April 16, 2017)
-------------------------------- --------------------------------

View File

@ -9,6 +9,8 @@
namespace humhub\libs; namespace humhub\libs;
use Yii; use Yii;
use yii\base\Object;
use yii\base\Exception;
use humhub\modules\space\models\Space; use humhub\modules\space\models\Space;
/** /**
@ -16,7 +18,7 @@ use humhub\modules\space\models\Space;
* @author luke * @author luke
*/ */
class BasePermission extends \yii\base\Object class BasePermission extends Object
{ {
/** /**
@ -34,17 +36,17 @@ class BasePermission extends \yii\base\Object
/** /**
* @var string title of the permission * @var string title of the permission
*/ */
protected $title = ""; protected $title ='';
/** /**
* @var string description of the permission * @var string description of the permission
*/ */
protected $description = ""; protected $description = '';
/** /**
* @var string module id which belongs to the permission * @var string module id which belongs to the permission
*/ */
protected $moduleId = ""; protected $moduleId = '';
/** /**
* A list of groupIds which allowed per default. * A list of groupIds which allowed per default.
@ -203,7 +205,7 @@ class BasePermission extends \yii\base\Object
return Yii::t('base', 'Default'); return Yii::t('base', 'Default');
} }
throw new \yii\base\Exception('Invalid permission state'); throw new Exception('Invalid permission state');
} }
} }

View File

@ -10,6 +10,8 @@ namespace humhub\libs;
use Yii; use Yii;
use yii\base\Component; use yii\base\Component;
use yii\base\Exception;
use yii\helpers\Json;
/** /**
* Description of SettingManager * Description of SettingManager
@ -41,7 +43,7 @@ abstract class BaseSettingsManager extends Component
public function init() public function init()
{ {
if ($this->moduleId === null) { if ($this->moduleId === null) {
throw new \Exception('Could not determine module id'); throw new Exception('Could not determine module id');
} }
$this->loadValues(); $this->loadValues();
@ -74,7 +76,7 @@ abstract class BaseSettingsManager extends Component
$record->value = (string) $value; $record->value = (string) $value;
if (!$record->save()) { if (!$record->save()) {
throw new \yii\base\Exception("Could not store setting! (" . print_r($record->getErrors(), 1) . ")"); throw new Exception("Could not store setting! (" . print_r($record->getErrors(), 1) . ")");
} }
// Store to runtime // Store to runtime
@ -92,7 +94,7 @@ abstract class BaseSettingsManager extends Component
*/ */
public function setSerialized($name, $value) public function setSerialized($name, $value)
{ {
$this->set($name, \yii\helpers\Json::encode($value)); $this->set($name, Json::encode($value));
} }
/** /**
@ -105,7 +107,7 @@ abstract class BaseSettingsManager extends Component
{ {
$value = $this->get($name, $default); $value = $this->get($name, $default);
if(is_string($value)) { if(is_string($value)) {
$value = \yii\helpers\Json::decode($value); $value = Json::decode($value);
} }
return $value; return $value;
} }

View File

@ -9,6 +9,7 @@
namespace humhub\libs; namespace humhub\libs;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\base\Exception;
/** /**
* This class contains a lot of html helpers for the views * This class contains a lot of html helpers for the views
@ -30,7 +31,7 @@ class Helpers
if (strlen($text) > $length) { if (strlen($text) > $length) {
$text = preg_replace("/^(.{1,$length})(\s.*|$)/s", '\\1...', $text); $text = preg_replace("/^(.{1,$length})(\s.*|$)/s", '\\1...', $text);
} }
$text = str_replace("<br />", "", $text); $text = str_replace('<br />', '', $text);
return($text); return($text);
} }
@ -44,7 +45,7 @@ class Helpers
$text = self::substru($text, 0, $textlength - ($textlength - $length)); $text = self::substru($text, 0, $textlength - ($textlength - $length));
$text .= '...'; $text .= '...';
} }
$text = str_replace("<br />", "", $text); $text = str_replace('<br />', '', $text);
return($text); return($text);
} }
@ -64,6 +65,7 @@ class Helpers
return false; return false;
sort($a); sort($a);
sort($b); sort($b);
return $a == $b; return $a == $b;
} }
@ -178,9 +180,9 @@ class Helpers
* @param string $type * @param string $type
* @return boolean * @return boolean
*/ */
public static function CheckClassType($className, $type = "") public static function CheckClassType($className, $type = '')
{ {
$className = preg_replace('/[^a-z0-9_\-\\\]/i', "", $className); $className = preg_replace('/[^a-z0-9_\-\\\]/i', '', $className);
if (is_array($type)) { if (is_array($type)) {
foreach ($type as $t) { foreach ($type as $t) {
@ -194,7 +196,7 @@ class Helpers
} }
} }
throw new \yii\base\Exception("Invalid class type! (" . $className . ")"); throw new Exception("Invalid class type! (" . $className . ")");
} }
/** /**
@ -229,6 +231,7 @@ class Helpers
$check = 0; $check = 0;
for ($i = 0; $i < $length; $i += 1) for ($i = 0; $i < $length; $i += 1)
$check |= (ord($a[$i]) ^ ord($b[$i])); $check |= (ord($a[$i]) ^ ord($b[$i]));
return $check === 0; return $check === 0;
} }

View File

@ -170,6 +170,21 @@ class SelfTest
); );
} }
// Checks iconv Extension
$title = 'PHP - iconv Extension';
if (function_exists('iconv_strlen')) {
$checks[] = array(
'title' => Yii::t('base', $title),
'state' => 'OK'
);
} else {
$checks[] = array(
'title' => Yii::t('base', $title),
'state' => 'ERROR',
'hint' => 'Install PHP iconv Extension'
);
}
// Checks cURL Extension // Checks cURL Extension
$title = 'PHP - cURL Extension'; $title = 'PHP - cURL Extension';

View File

@ -9,6 +9,8 @@
namespace humhub\models; namespace humhub\models;
use Yii; use Yii;
use yii\db\ActiveRecord;
use yii\base\Exception;
/** /**
* This is the model class for table "setting". * This is the model class for table "setting".
@ -18,7 +20,7 @@ use Yii;
* @property string $value * @property string $value
* @property string $module_id * @property string $module_id
*/ */
class Setting extends \yii\db\ActiveRecord class Setting extends ActiveRecord
{ {
/** /**
@ -176,7 +178,7 @@ class Setting extends \yii\db\ActiveRecord
$module = Yii::$app->getModule($moduleId); $module = Yii::$app->getModule($moduleId);
} }
if ($module === null) { if ($module === null) {
throw new \yii\base\Exception("Could not find module: " . $moduleId); throw new Exception("Could not find module: " . $moduleId);
} }
return $module; return $module;

View File

@ -9,17 +9,19 @@
namespace humhub\modules\activity; namespace humhub\modules\activity;
use Yii; use Yii;
use yii\base\Object;
use humhub\modules\activity\components\MailSummary; use humhub\modules\activity\components\MailSummary;
use humhub\modules\activity\jobs\SendMailSummary; use humhub\modules\activity\jobs\SendMailSummary;
use humhub\modules\activity\models\Activity; use humhub\modules\activity\models\Activity;
use yii\base\Event; use yii\base\Event;
use yii\db\ActiveRecord;
/** /**
* Events provides callbacks to handle events. * Events provides callbacks to handle events.
* *
* @author luke * @author luke
*/ */
class Events extends \yii\base\Object class Events extends Object
{ {
/** /**
@ -46,7 +48,7 @@ class Events extends \yii\base\Object
*/ */
public static function onActiveRecordDelete(Event $event) public static function onActiveRecordDelete(Event $event)
{ {
if (!($event->sender instanceof \yii\db\ActiveRecord)) { if (!($event->sender instanceof ActiveRecord)) {
throw new \LogicException('The handler can be applied only to the \yii\db\ActiveRecord.'); throw new \LogicException('The handler can be applied only to the \yii\db\ActiveRecord.');
} }
@ -74,28 +76,28 @@ class Events extends \yii\base\Object
public static function onIntegrityCheck($event) public static function onIntegrityCheck($event)
{ {
$integrityController = $event->sender; $integrityController = $event->sender;
$integrityController->showTestHeadline("Activity Module (" . Activity::find()->count() . " entries)"); $integrityController->showTestHeadline('Activity Module (' . Activity::find()->count() . ' entries)');
// Loop over all comments // Loop over all comments
foreach (Activity::find()->all() as $a) { foreach (Activity::find()->all() as $a) {
// Check for object_model / object_id // Check for object_model / object_id
if ($a->object_model != "" && $a->object_id != "" && $a->getSource() === null) { if ($a->object_model != '' && $a->object_id != '' && $a->getSource() === null) {
if ($integrityController->showFix("Deleting activity id " . $a->id . " without existing target! (" . $a->object_model . ")")) { if ($integrityController->showFix('Deleting activity id ' . $a->id . ' without existing target! (' . $a->object_model . ')')) {
$a->delete(); $a->delete();
} }
} }
// Check for moduleId is set // Check for moduleId is set
if ($a->module == "") { if ($a->module == '') {
if ($integrityController->showFix("Deleting activity id " . $a->id . " without module_id!")) { if ($integrityController->showFix('Deleting activity id ' . $a->id . ' without module_id!')) {
$a->delete(); $a->delete();
} }
} }
// Check Activity class exists // Check Activity class exists
if (!class_exists($a->class)) { if (!class_exists($a->class)) {
if ($integrityController->showFix("Deleting activity id " . $a->id . " class not exists! (" . $a->class . ")")) { if ($integrityController->showFix('Deleting activity id ' . $a->id . ' class not exists! (' . $a->class . ')')) {
$a->delete(); $a->delete();
} }
} }

View File

@ -9,6 +9,7 @@
namespace humhub\modules\activity\components; namespace humhub\modules\activity\components;
use Yii; use Yii;
use humhub\components\rendering\LayoutRenderer;
use humhub\components\rendering\Viewable; use humhub\components\rendering\Viewable;
/** /**
@ -26,7 +27,7 @@ use humhub\components\rendering\Viewable;
* @author buddha * @author buddha
* @since 1.2 * @since 1.2
*/ */
class ActivityWebRenderer extends \humhub\components\rendering\LayoutRenderer class ActivityWebRenderer extends LayoutRenderer
{ {
/** /**

View File

@ -8,6 +8,10 @@
namespace humhub\modules\activity\components; namespace humhub\modules\activity\components;
use yii\base\InvalidConfigException;
use yii\base\Exception;
use yii\db\ActiveRecord;
use humhub\components\SocialActivity;
use humhub\modules\activity\models\Activity; use humhub\modules\activity\models\Activity;
use humhub\modules\content\components\ContentActiveRecord; use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\content\components\ContentAddonActiveRecord; use humhub\modules\content\components\ContentAddonActiveRecord;
@ -18,7 +22,7 @@ use humhub\modules\content\models\Content;
* *
* @author luke * @author luke
*/ */
abstract class BaseActivity extends \humhub\components\SocialActivity abstract class BaseActivity extends SocialActivity
{ {
/** /**
@ -42,8 +46,8 @@ abstract class BaseActivity extends \humhub\components\SocialActivity
*/ */
public function init() public function init()
{ {
if ($this->viewName == "") { if ($this->viewName == '') {
throw new \yii\base\InvalidConfigException("Missing viewName!"); throw new InvalidConfigException('Missing viewName!');
} }
parent::init(); parent::init();
@ -76,12 +80,12 @@ abstract class BaseActivity extends \humhub\components\SocialActivity
*/ */
public function create() public function create()
{ {
if ($this->moduleId == "") { if ($this->moduleId == '') {
throw new \yii\base\InvalidConfigException("No moduleId given!"); throw new InvalidConfigException('No moduleId given!');
} }
if (!$this->source instanceof \yii\db\ActiveRecord) { if (!$this->source instanceof ActiveRecord) {
throw new \yii\base\InvalidConfigException("Invalid source object given!"); throw new InvalidConfigException('Invalid source object given!');
} }
$this->saveModelInstance(); $this->saveModelInstance();
@ -140,11 +144,11 @@ abstract class BaseActivity extends \humhub\components\SocialActivity
$this->record->content->created_by = $this->getOriginatorId(); $this->record->content->created_by = $this->getOriginatorId();
if ($this->record->content->created_by == null) { if ($this->record->content->created_by == null) {
throw new \yii\base\InvalidConfigException("Could not determine originator for activity!"); throw new InvalidConfigException('Could not determine originator for activity!');
} }
if (!$this->record->save()) { if (!$this->record->save()) {
throw new \yii\base\Exception("Could not save activity!" . $this->record->getErrors()); throw new Exception('Could not save activity!' . $this->record->getErrors());
} }
} }

View File

@ -11,9 +11,12 @@ namespace humhub\modules\activity\components;
use Yii; use Yii;
use yii\base\Exception; use yii\base\Exception;
use yii\base\Component; use yii\base\Component;
use yii\helpers\Url;
use yii\db\Expression;
use humhub\modules\dashboard\components\actions\DashboardStream; use humhub\modules\dashboard\components\actions\DashboardStream;
use humhub\modules\content\models\ContentContainer; use humhub\modules\content\models\ContentContainer;
use humhub\modules\activity\models\MailSummaryForm; use humhub\modules\activity\models\MailSummaryForm;
use humhub\modules\activity\models\Activity;
/** /**
* MailSummary is send to the user with a list of new activities * MailSummary is send to the user with a list of new activities
@ -83,7 +86,7 @@ class MailSummary extends Component
try { try {
Yii::$app->view->params['showUnsubscribe'] = true; Yii::$app->view->params['showUnsubscribe'] = true;
Yii::$app->view->params['unsubscribeUrl'] = \yii\helpers\Url::to(['/activity/user'], true); Yii::$app->view->params['unsubscribeUrl'] = Url::to(['/activity/user'], true);
$mail = Yii::$app->mailer->compose([ $mail = Yii::$app->mailer->compose([
'html' => $this->layout, 'html' => $this->layout,
'text' => $this->layoutPlaintext 'text' => $this->layoutPlaintext
@ -113,14 +116,14 @@ class MailSummary extends Component
protected function getSubject() protected function getSubject()
{ {
if ($this->interval === self::INTERVAL_DAILY) { if ($this->interval === self::INTERVAL_DAILY) {
return Yii::t('ActivityModule.base', "Your daily summary"); return Yii::t('ActivityModule.base', 'Your daily summary');
} elseif ($this->interval === self::INTERVAL_HOURY) { } elseif ($this->interval === self::INTERVAL_HOURY) {
return Yii::t('ActivityModule.base', "Latest news"); return Yii::t('ActivityModule.base', 'Latest news');
} elseif ($this->interval === self::INTERVAL_WEEKLY) { } elseif ($this->interval === self::INTERVAL_WEEKLY) {
return Yii::t('ActivityModule.base', "Your weekly summary"); return Yii::t('ActivityModule.base', 'Your weekly summary');
} }
return ""; return '';
} }
/** /**
@ -155,7 +158,7 @@ class MailSummary extends Component
foreach ($stream->activeQuery->all() as $content) { foreach ($stream->activeQuery->all() as $content) {
try { try {
$activity = $content->getPolymorphicRelation(); $activity = $content->getPolymorphicRelation();
if ($activity instanceof \humhub\modules\activity\models\Activity) { if ($activity instanceof Activity) {
/** /**
* @var $activity \humhub\modules\activity\models\Activity * @var $activity \humhub\modules\activity\models\Activity
*/ */
@ -187,7 +190,7 @@ class MailSummary extends Component
{ {
$lastSent = (int) Yii::$app->getModule('activity')->settings->user($this->user)->get('mailSummaryLast'); $lastSent = (int) Yii::$app->getModule('activity')->settings->user($this->user)->get('mailSummaryLast');
if (empty($lastSent)) { if (empty($lastSent)) {
$lastSent = new \yii\db\Expression('NOW() - INTERVAL 24 HOUR'); $lastSent = new Expression('NOW() - INTERVAL 24 HOUR');
} else { } else {
$lastSent = date('Y-m-d G:i:s', $lastSent); $lastSent = date('Y-m-d G:i:s', $lastSent);
} }

View File

@ -10,10 +10,11 @@ use humhub\commands\CronController;
use humhub\modules\activity\Events; use humhub\modules\activity\Events;
use humhub\components\ActiveRecord; use humhub\components\ActiveRecord;
use humhub\commands\IntegrityController; use humhub\commands\IntegrityController;
use humhub\modules\activity\Module;
return [ return [
'id' => 'activity', 'id' => 'activity',
'class' => humhub\modules\activity\Module::className(), 'class' => Module::className(),
'isCoreModule' => true, 'isCoreModule' => true,
'events' => [ 'events' => [
['class' => ActiveRecord::className(), 'event' => ActiveRecord::EVENT_BEFORE_DELETE, 'callback' => [Events::className(), 'onActiveRecordDelete']], ['class' => ActiveRecord::className(), 'event' => ActiveRecord::EVENT_BEFORE_DELETE, 'callback' => [Events::className(), 'onActiveRecordDelete']],
@ -21,4 +22,4 @@ return [
['class' => CronController::className(), 'event' => CronController::EVENT_ON_HOURLY_RUN, 'callback' => [Events::className(), 'onCronRun']], ['class' => CronController::className(), 'event' => CronController::EVENT_ON_HOURLY_RUN, 'callback' => [Events::className(), 'onCronRun']],
['class' => CronController::className(), 'event' => CronController::EVENT_ON_DAILY_RUN, 'callback' => [Events::className(), 'onCronRun']], ['class' => CronController::className(), 'event' => CronController::EVENT_ON_DAILY_RUN, 'callback' => [Events::className(), 'onCronRun']],
], ],
]; ];

View File

@ -10,6 +10,7 @@ namespace humhub\modules\activity\controllers;
use Yii; use Yii;
use humhub\modules\admin\components\Controller; use humhub\modules\admin\components\Controller;
use humhub\modules\admin\permissions\ManageSettings;
use humhub\modules\activity\models\MailSummaryForm; use humhub\modules\activity\models\MailSummaryForm;
/** /**
@ -26,7 +27,7 @@ class AdminController extends Controller
public function getAccessRules() public function getAccessRules()
{ {
return [ return [
['permissions' => \humhub\modules\admin\permissions\ManageSettings::className()] ['permissions' => ManageSettings::className()]
]; ];
} }

View File

@ -11,6 +11,7 @@ namespace humhub\modules\activity\controllers;
use Yii; use Yii;
use humhub\components\Controller; use humhub\components\Controller;
use humhub\modules\activity\models\Activity; use humhub\modules\activity\models\Activity;
use humhub\components\behaviors\AccessControl;
/** /**
* LinkController provides link informations about an Activity via JSON. * LinkController provides link informations about an Activity via JSON.
@ -27,7 +28,7 @@ class LinkController extends Controller
{ {
return [ return [
'acl' => [ 'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(), 'class' => AccessControl::className(),
'guestAllowedActions' => ['info'] 'guestAllowedActions' => ['info']
] ]
]; ];

View File

@ -35,7 +35,7 @@ class SendMailSummary extends ActiveJob
if ($this->interval === MailSummary::INTERVAL_DAILY || $this->interval === MailSummary::INTERVAL_HOURY || $this->interval === MailSummary::INTERVAL_WEEKLY) { if ($this->interval === MailSummary::INTERVAL_DAILY || $this->interval === MailSummary::INTERVAL_HOURY || $this->interval === MailSummary::INTERVAL_WEEKLY) {
MailSummaryProcessor::process($this->interval); MailSummaryProcessor::process($this->interval);
} else { } else {
Yii::error('Invalid summary interval given'. $this->interval, 'activity.job'); Yii::error('Invalid summary interval given' . $this->interval, 'activity.job');
return; return;
} }
} }

View File

@ -12,6 +12,8 @@ use Yii;
use yii\base\Exception; use yii\base\Exception;
use humhub\modules\content\components\ContentActiveRecord; use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\activity\components\ActivityWebRenderer; use humhub\modules\activity\components\ActivityWebRenderer;
use humhub\components\behaviors\PolymorphicRelation;
use yii\db\ActiveRecord;
/** /**
* This is the model class for table "activity". * This is the model class for table "activity".
@ -27,7 +29,7 @@ class Activity extends ContentActiveRecord
/** /**
* @inheritdoc * @inheritdoc
*/ */
public $wallEntryClass = "humhub\modules\activity\widgets\Activity"; public $wallEntryClass = 'humhub\modules\activity\widgets\Activity';
/** /**
* @inheritdoc * @inheritdoc
@ -39,6 +41,11 @@ class Activity extends ContentActiveRecord
*/ */
protected $streamChannel = 'activity'; protected $streamChannel = 'activity';
/**
* @inheritdoc
*/
public $silentContentCreation = true;
/** /**
* @inheritdoc * @inheritdoc
*/ */
@ -46,9 +53,9 @@ class Activity extends ContentActiveRecord
{ {
return [ return [
[ [
'class' => \humhub\components\behaviors\PolymorphicRelation::className(), 'class' => PolymorphicRelation::className(),
'mustBeInstanceOf' => [ 'mustBeInstanceOf' => [
\yii\db\ActiveRecord::className(), ActiveRecord::className(),
] ]
] ]
]; ];
@ -90,7 +97,7 @@ class Activity extends ContentActiveRecord
$result->record = $this; // If we include the record in createObject, it somehow loses activerecord data (id etc...) $result->record = $this; // If we include the record in createObject, it somehow loses activerecord data (id etc...)
return $result; return $result;
} else { } else {
throw new Exception("Could not find BaseActivity " . $this->class . " for Activity Record."); throw new Exception('Could not find BaseActivity ' . $this->class . ' for Activity Record.');
} }
} }

View File

@ -133,7 +133,6 @@ class MailSummaryForm extends Model
$contents = []; $contents = [];
foreach (Module::getConfigurableActivities() as $activity) { foreach (Module::getConfigurableActivities() as $activity) {
#$contents[$activity->className()] = Html::tag('strong', $activity->getTitle()) . "<br />" . $activity->getDescription()."<br />";
$contents[$activity->className()] = $activity->getTitle() . ' - ' . $activity->getDescription(); $contents[$activity->className()] = $activity->getTitle() . ' - ' . $activity->getDescription();
} }
@ -191,7 +190,7 @@ class MailSummaryForm extends Model
} }
$settingsManager->set('mailSummaryInterval', $this->interval); $settingsManager->set('mailSummaryInterval', $this->interval);
$settingsManager->set('mailSummaryLimitSpaces', implode(",", $this->limitSpaces)); $settingsManager->set('mailSummaryLimitSpaces', implode(',', $this->limitSpaces));
$settingsManager->set('mailSummaryLimitSpacesMode', $this->limitSpacesMode); $settingsManager->set('mailSummaryLimitSpacesMode', $this->limitSpacesMode);
// We got a list of enabled activities, but we store only disabled activity class names // We got a list of enabled activities, but we store only disabled activity class names
@ -209,7 +208,7 @@ class MailSummaryForm extends Model
public function resetUserSettings() public function resetUserSettings()
{ {
if ($this->user === null) { if ($this->user === null) {
throw new Exception("Could not reset settings when no user is set!"); throw new Exception('Could not reset settings when no user is set!');
} }
$settingsManager = Yii::$app->getModule('activity')->settings->user($this->user); $settingsManager = Yii::$app->getModule('activity')->settings->user($this->user);

View File

@ -5,9 +5,15 @@
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
use humhub\modules\content\components\ContentContainerController;
use humhub\modules\space\models\Space;
use humhub\modules\space\widgets\Image;
use humhub\widgets\TimeAgo;
?> ?>
<?php if ($clickable): ?> <?php if ($clickable) : ?>
<a href="<?= \yii\helpers\Url::to(['/activity/link', 'id' => $record->id])?>"> <a href="<?= \yii\helpers\Url::to(['/activity/link', 'id' => $record->id])?>">
<?php endif; ?> <?php endif; ?>
<li class="activity-entry" data-stream-entry data-action-component="activity.ActivityStreamEntry" data-content-key="<?= $record->content->id ?>"> <li class="activity-entry" data-stream-entry data-action-component="activity.ActivityStreamEntry" data-content-key="<?= $record->content->id ?>">
@ -20,10 +26,10 @@
<?php endif; ?> <?php endif; ?>
<!-- Show space image, if you are outside from a space --> <!-- Show space image, if you are outside from a space -->
<?php if (!Yii::$app->controller instanceof \humhub\modules\content\components\ContentContainerController): ?> <?php if (!Yii::$app->controller instanceof ContentContainerController) : ?>
<?php if ($record->content->container instanceof humhub\modules\space\models\Space): ?> <?php if ($record->content->container instanceof Space) : ?>
<?= <?=
\humhub\modules\space\widgets\Image::widget([ Image::widget([
'space' => $record->content->container, 'space' => $record->content->container,
'width' => 20, 'width' => 20,
'htmlOptions' => [ 'htmlOptions' => [
@ -38,12 +44,12 @@
<div class="media-body text-break"> <div class="media-body text-break">
<!-- Show content --> <!-- Show content -->
<?= $content; ?><br/> <?= $content; ?><br>
<!-- show time --> <!-- show time -->
<?= \humhub\widgets\TimeAgo::widget(['timestamp' => $record->content->created_at]); ?> <?= TimeAgo::widget(['timestamp' => $record->content->created_at]); ?>
</div> </div>
</div> </div>
</li> </li>
<?php if ($clickable): ?></a> <?php if ($clickable) : ?></a>
<?php endif; ?> <?php endif; ?>

View File

@ -8,8 +8,8 @@
namespace humhub\modules\activity\widgets; namespace humhub\modules\activity\widgets;
use humhub\modules\content\widgets\WallEntry;
use Yii; use Yii;
use humhub\modules\content\widgets\WallEntry;
use humhub\modules\content\components\ContentActiveRecord; use humhub\modules\content\components\ContentActiveRecord;
use humhub\modules\content\components\ContentAddonActiveRecord; use humhub\modules\content\components\ContentAddonActiveRecord;
@ -56,7 +56,7 @@ class Activity extends WallEntry
// When element is assigned to a workspace, assign variable // When element is assigned to a workspace, assign variable
$space = null; $space = null;
if ($this->activity->content->space_id != "") { if ($this->activity->content->space_id != '') {
$space = $this->activity->content->space; $space = $this->activity->content->space;
} }
@ -64,13 +64,13 @@ class Activity extends WallEntry
$user = $this->activity->content->user; $user = $this->activity->content->user;
if ($user == null) { if ($user == null) {
Yii::warning("Skipping activity without valid user", "warning"); Yii::warning('Skipping activity without valid user', 'warning');
return; return;
} }
// Dertermine View // Dertermine View
if ($this->activity->module == "") { if ($this->activity->module == '') {
$view = '@humhub/modules/activity/views/activities/' . $this->activity->type; $view = '@humhub/modules/activity/views/activities/' . $this->activity->type;
} else { } else {
$module = Yii::$app->getModule($this->activity->module, true); $module = Yii::$app->getModule($this->activity->module, true);
@ -83,13 +83,13 @@ class Activity extends WallEntry
// Activity Layout can access it // Activity Layout can access it
$this->wallEntryId = $wallEntryId; $this->wallEntryId = $wallEntryId;
return $this->render($view, array( return $this->render($view, [
'activity' => $this->activity, 'activity' => $this->activity,
'wallEntryId' => $wallEntryId, 'wallEntryId' => $wallEntryId,
'user' => $user, 'user' => $user,
'target' => $source, 'target' => $source,
'space' => $space, 'space' => $space,
)); ]);
} }
} }

View File

@ -8,7 +8,10 @@
namespace humhub\modules\activity\widgets; namespace humhub\modules\activity\widgets;
use yii\base\Widget;
use yii\web\HttpException; use yii\web\HttpException;
use yii\helpers\Url;
use humhub\modules\stream\actions\Stream;
/** /**
* ActivityStreamWidget shows an stream/wall of activities inside a sidebar. * ActivityStreamWidget shows an stream/wall of activities inside a sidebar.
@ -17,7 +20,7 @@ use yii\web\HttpException;
* @package humhub.modules_core.activity * @package humhub.modules_core.activity
* @since 0.5 * @since 0.5
*/ */
class Stream extends \yii\base\Widget class Stream extends Widget
{ {
/** /**
* Optional content container if this stream belongs to one * Optional content container if this stream belongs to one
@ -50,7 +53,7 @@ class Stream extends \yii\base\Widget
public function run() public function run()
{ {
$streamUrl = $this->getStreamUrl(); $streamUrl = $this->getStreamUrl();
$infoUrl = \yii\helpers\Url::to(['/activity/link/info', 'id' => '-id-']); $infoUrl = Url::to(['/activity/link/info', 'id' => '-id-']);
return $this->render('activityStream', [ return $this->render('activityStream', [
'streamUrl' => $streamUrl, 'streamUrl' => $streamUrl,
@ -61,14 +64,14 @@ class Stream extends \yii\base\Widget
protected function getStreamUrl() protected function getStreamUrl()
{ {
$params = [ $params = [
'mode' => \humhub\modules\stream\actions\Stream::MODE_ACTIVITY, 'mode' => Stream::MODE_ACTIVITY,
]; ];
if ($this->contentContainer) { if ($this->contentContainer) {
return $this->contentContainer->createUrl($this->streamAction, $params); return $this->contentContainer->createUrl($this->streamAction, $params);
} }
return \yii\helpers\Url::to(array_merge([$this->streamAction], $params)); return Url::to(array_merge([$this->streamAction], $params));
} }
} }

View File

@ -2,13 +2,15 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\admin\controllers; namespace humhub\modules\admin\controllers;
use Yii; use Yii;
use yii\web\HttpException;
use yii\db\Query;
use humhub\modules\admin\components\Controller; use humhub\modules\admin\components\Controller;
use humhub\modules\user\models\Group; use humhub\modules\user\models\Group;
use humhub\modules\user\models\GroupUser; use humhub\modules\user\models\GroupUser;
@ -16,6 +18,9 @@ use humhub\modules\user\models\forms\EditGroupForm;
use humhub\modules\user\models\UserPicker; use humhub\modules\user\models\UserPicker;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\admin\models\forms\AddGroupMemberForm; use humhub\modules\admin\models\forms\AddGroupMemberForm;
use humhub\modules\admin\permissions\ManageGroups;
use humhub\modules\admin\models\GroupSearch;
use humhub\modules\admin\models\UserSearch;
/** /**
* Group Administration Controller * Group Administration Controller
@ -44,7 +49,7 @@ class GroupController extends Controller
public function getAccessRules() public function getAccessRules()
{ {
return [ return [
['permissions' => \humhub\modules\admin\permissions\ManageGroups::className()] ['permissions' => ManageGroups::className()]
]; ];
} }
@ -53,7 +58,7 @@ class GroupController extends Controller
*/ */
public function actionIndex() public function actionIndex()
{ {
$searchModel = new \humhub\modules\admin\models\GroupSearch(); $searchModel = new GroupSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams); $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [ return $this->render('index', [
@ -104,7 +109,7 @@ class GroupController extends Controller
Yii::$app->response->format = 'json'; Yii::$app->response->format = 'json';
$permission = Yii::$app->user->permissionManager->getById(Yii::$app->request->post('permissionId'), Yii::$app->request->post('moduleId')); $permission = Yii::$app->user->permissionManager->getById(Yii::$app->request->post('permissionId'), Yii::$app->request->post('moduleId'));
if ($permission === null) { if ($permission === null) {
throw new \yii\web\HttpException(500, 'Could not find permission!'); throw new HttpException(500, 'Could not find permission!');
} }
Yii::$app->user->permissionManager->setGroupState($group->id, $permission, Yii::$app->request->post('state')); Yii::$app->user->permissionManager->setGroupState($group->id, $permission, Yii::$app->request->post('state'));
return []; return [];
@ -116,7 +121,7 @@ class GroupController extends Controller
public function actionManageGroupUsers() public function actionManageGroupUsers()
{ {
$group = Group::findOne(['id' => Yii::$app->request->get('id')]); $group = Group::findOne(['id' => Yii::$app->request->get('id')]);
$searchModel = new \humhub\modules\admin\models\UserSearch(); $searchModel = new UserSearch();
$searchModel->query = $group->getUsers(); $searchModel->query = $group->getUsers();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams); $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('members', [ return $this->render('members', [
@ -156,7 +161,7 @@ class GroupController extends Controller
$group = Group::findOne(['id' => Yii::$app->request->get('id')]); $group = Group::findOne(['id' => Yii::$app->request->get('id')]);
if ($group == null) { if ($group == null) {
throw new \yii\web\HttpException(404, Yii::t('AdminModule.controllers_GroupController', 'Group not found!')); throw new HttpException(404, Yii::t('AdminModule.controllers_GroupController', 'Group not found!'));
} }
//Double check to get sure we don't remove the admin group //Double check to get sure we don't remove the admin group
@ -175,18 +180,17 @@ class GroupController extends Controller
$value = Yii::$app->request->post('value'); $value = Yii::$app->request->post('value');
if ($group == null) { if ($group == null) {
throw new \yii\web\HttpException(404, Yii::t('AdminModule.controllers_GroupController', 'Group not found!')); throw new HttpException(404, Yii::t('AdminModule.controllers_GroupController', 'Group not found!'));
} else if ($value == null) { } else if ($value == null) {
throw new \yii\web\HttpException(400, Yii::t('AdminModule.controllers_GroupController', 'No value found!')); throw new HttpException(400, Yii::t('AdminModule.controllers_GroupController', 'No value found!'));
} }
$groupUser = $group->getGroupUser(User::findOne(Yii::$app->request->post('userId'))); $groupUser = $group->getGroupUser(User::findOne(Yii::$app->request->post('userId')));
if ($groupUser == null) { if ($groupUser == null) {
throw new \yii\web\HttpException(404, Yii::t('AdminModule.controllers_GroupController', 'Group user not found!')); throw new HttpException(404, Yii::t('AdminModule.controllers_GroupController', 'Group user not found!'));
} }
$groupUser->is_group_manager = ($value) ? true : false; $groupUser->is_group_manager = ($value) ? true : false;
$groupUser->save(); $groupUser->save();
@ -214,7 +218,7 @@ class GroupController extends Controller
$keyword = Yii::$app->request->get('keyword'); $keyword = Yii::$app->request->get('keyword');
$group = Group::findOne(Yii::$app->request->get('id')); $group = Group::findOne(Yii::$app->request->get('id'));
$subQuery = (new \yii\db\Query())->select('*')->from(GroupUser::tableName(). ' g')->where([ $subQuery = (new Query())->select('*')->from(GroupUser::tableName(). ' g')->where([
'and', 'g.user_id=user.id', ['g.group_id' => $group->id]]); 'and', 'g.user_id=user.id', ['g.group_id' => $group->id]]);
$query = User::find()->where(['not exists', $subQuery]); $query = User::find()->where(['not exists', $subQuery]);

View File

@ -19,6 +19,7 @@ use humhub\modules\admin\models\forms\UserEditForm;
use humhub\modules\admin\permissions\ManageUsers; use humhub\modules\admin\permissions\ManageUsers;
use humhub\modules\admin\permissions\ManageGroups; use humhub\modules\admin\permissions\ManageGroups;
use humhub\modules\admin\permissions\ManageSettings; use humhub\modules\admin\permissions\ManageSettings;
use humhub\modules\space\models\Membership;
/** /**
* User management * User management
@ -90,7 +91,7 @@ class UserController extends Controller
$user->initGroupSelection(); $user->initGroupSelection();
if ($user == null) { if ($user == null) {
throw new \yii\web\HttpException(404, Yii::t('AdminModule.controllers_UserController', 'User not found!')); throw new HttpException(404, Yii::t('AdminModule.controllers_UserController', 'User not found!'));
} }
$user->scenario = 'editAdmin'; $user->scenario = 'editAdmin';
@ -123,7 +124,7 @@ class UserController extends Controller
'data-placeholder' => Yii::t('AdminModule.controllers_UserController', 'Select Groups'), 'data-placeholder' => Yii::t('AdminModule.controllers_UserController', 'Select Groups'),
'data-placeholder-more' => Yii::t('AdminModule.controllers_UserController', 'Add Groups...') 'data-placeholder-more' => Yii::t('AdminModule.controllers_UserController', 'Add Groups...')
], ],
'isVisible' => Yii::$app->user->can(new \humhub\modules\admin\permissions\ManageGroups()) 'isVisible' => Yii::$app->user->can(new ManageGroups())
], ],
'status' => [ 'status' => [
'type' => 'dropdownlist', 'type' => 'dropdownlist',
@ -224,7 +225,7 @@ class UserController extends Controller
if ($doit == 2) { if ($doit == 2) {
$this->forcePostRequest(); $this->forcePostRequest();
foreach (\humhub\modules\space\models\Membership::GetUserSpaces($user->id) as $space) { foreach (Membership::GetUserSpaces($user->id) as $space) {
if ($space->isSpaceOwner($user->id)) { if ($space->isSpaceOwner($user->id)) {
$space->addMember(Yii::$app->user->id); $space->addMember(Yii::$app->user->id);
$space->setSpaceOwner(Yii::$app->user->id); $space->setSpaceOwner(Yii::$app->user->id);

View File

@ -8,14 +8,17 @@
namespace humhub\modules\admin\models\forms; namespace humhub\modules\admin\models\forms;
use yii\base\Model;
use yii\web\HttpException;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\user\models\Group;
/** /**
* Description of UserGroupForm * Description of UserGroupForm
* *
* @author buddha * @author buddha
*/ */
class AddGroupMemberForm extends \yii\base\Model class AddGroupMemberForm extends Model
{ {
/** /**
@ -69,7 +72,7 @@ class AddGroupMemberForm extends \yii\base\Model
$group = $this->getGroup(); $group = $this->getGroup();
if($group == null) { if($group == null) {
throw new \yii\web\HttpException(404, Yii::t('AdminModule.models_form_AddGroupMemberForm', 'Group not found!')); throw new HttpException(404, Yii::t('AdminModule.models_form_AddGroupMemberForm', 'Group not found!'));
} }
foreach ($this->userGuids as $userGuid) { foreach ($this->userGuids as $userGuid) {
@ -84,6 +87,6 @@ class AddGroupMemberForm extends \yii\base\Model
public function getGroup() public function getGroup()
{ {
return \humhub\modules\user\models\Group::findOne($this->groupId); return Group::findOne($this->groupId);
} }
} }

View File

@ -8,21 +8,25 @@
namespace humhub\modules\admin\widgets; namespace humhub\modules\admin\widgets;
use humhub\modules\admin\models\UserApprovalSearch;
use humhub\modules\user\models\Invite;
use Yii; use Yii;
use yii\helpers\Url; use yii\helpers\Url;
use humhub\modules\admin\models\UserApprovalSearch;
use humhub\modules\admin\permissions\ManageUsers;
use humhub\modules\admin\permissions\ManageGroups;
use humhub\modules\admin\permissions\ManageSettings;
use humhub\modules\user\models\Invite;
use humhub\widgets\BaseMenu;
/** /**
* User Administration Menu * User Administration Menu
* *
* @author Basti * @author Basti
*/ */
class UserMenu extends \humhub\widgets\BaseMenu class UserMenu extends BaseMenu
{ {
public $template = "@humhub/widgets/views/tabMenu"; public $template = '@humhub/widgets/views/tabMenu';
public $type = "adminUserSubNavigation"; public $type = 'adminUserSubNavigation';
public function init() public function init()
{ {
@ -32,8 +36,8 @@ class UserMenu extends \humhub\widgets\BaseMenu
'sortOrder' => 100, 'sortOrder' => 100,
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && (Yii::$app->controller->id == 'user' || Yii::$app->controller->id == 'pending-registrations')), 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && (Yii::$app->controller->id == 'user' || Yii::$app->controller->id == 'pending-registrations')),
'isVisible' => Yii::$app->user->can([ 'isVisible' => Yii::$app->user->can([
new \humhub\modules\admin\permissions\ManageUsers(), new ManageUsers(),
new \humhub\modules\admin\permissions\ManageGroups(), new ManageGroups(),
]) ])
]); ]);
@ -43,7 +47,7 @@ class UserMenu extends \humhub\widgets\BaseMenu
'sortOrder' => 200, 'sortOrder' => 200,
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'authentication'), 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'authentication'),
'isVisible' => Yii::$app->user->can([ 'isVisible' => Yii::$app->user->can([
new \humhub\modules\admin\permissions\ManageSettings() new ManageSettings()
]) ])
]); ]);
@ -55,8 +59,8 @@ class UserMenu extends \humhub\widgets\BaseMenu
'sortOrder' => 300, 'sortOrder' => 300,
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'approval'), 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'approval'),
'isVisible' => Yii::$app->user->can([ 'isVisible' => Yii::$app->user->can([
new \humhub\modules\admin\permissions\ManageUsers(), new ManageUsers(),
new \humhub\modules\admin\permissions\ManageGroups() new ManageGroups()
]) ])
]); ]);
} }
@ -67,7 +71,7 @@ class UserMenu extends \humhub\widgets\BaseMenu
'sortOrder' => 400, 'sortOrder' => 400,
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'user-profile'), 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'user-profile'),
'isVisible' => Yii::$app->user->can([ 'isVisible' => Yii::$app->user->can([
new \humhub\modules\admin\permissions\ManageUsers() new ManageUsers()
]) ])
]); ]);
@ -77,7 +81,7 @@ class UserMenu extends \humhub\widgets\BaseMenu
'sortOrder' => 500, 'sortOrder' => 500,
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'group'), 'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'group'),
'isVisible' => Yii::$app->user->can( 'isVisible' => Yii::$app->user->can(
new \humhub\modules\admin\permissions\ManageGroups() new ManageGroups()
) )
]); ]);

View File

@ -2,16 +2,20 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\comment\controllers; namespace humhub\modules\comment\controllers;
use Yii; use Yii;
use humhub\modules\comment\models\Comment; use yii\data\Pagination;
use \humhub\modules\comment\widgets\ShowMore;
use yii\web\HttpException; use yii\web\HttpException;
use humhub\modules\content\components\ContentAddonController;
use humhub\components\behaviors\AccessControl;
use humhub\modules\comment\models\Comment;
use humhub\modules\comment\widgets\Comment as CommentWidget;
use humhub\modules\comment\widgets\ShowMore;
/** /**
* CommentController provides all comment related actions. * CommentController provides all comment related actions.
@ -19,7 +23,7 @@ use yii\web\HttpException;
* @package humhub.modules_core.comment.controllers * @package humhub.modules_core.comment.controllers
* @since 0.5 * @since 0.5
*/ */
class CommentController extends \humhub\modules\content\components\ContentAddonController class CommentController extends ContentAddonController
{ {
/** /**
@ -29,7 +33,7 @@ class CommentController extends \humhub\modules\content\components\ContentAddonC
{ {
return [ return [
'acl' => [ 'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(), 'class' => AccessControl::className(),
'guestAllowedActions' => ['show'] 'guestAllowedActions' => ['show']
] ]
]; ];
@ -49,7 +53,7 @@ class CommentController extends \humhub\modules\content\components\ContentAddonC
'object_id' => $content->getPrimaryKey(), 'object_id' => $content->getPrimaryKey(),
]); ]);
$pagination = new \yii\data\Pagination([ $pagination = new Pagination([
'totalCount' => Comment::GetCommentCount($content->className(), $content->getPrimaryKey()), 'totalCount' => Comment::GetCommentCount($content->className(), $content->getPrimaryKey()),
'pageSize' => $this->module->commentsBlockLoadSize 'pageSize' => $this->module->commentsBlockLoadSize
]); ]);
@ -59,7 +63,7 @@ class CommentController extends \humhub\modules\content\components\ContentAddonC
$output = ShowMore::widget(['pagination' => $pagination, 'object' => $content]); $output = ShowMore::widget(['pagination' => $pagination, 'object' => $content]);
foreach ($comments as $comment) { foreach ($comments as $comment) {
$output .= \humhub\modules\comment\widgets\Comment::widget(['comment' => $comment]); $output .= CommentWidget::widget(['comment' => $comment]);
} }
if (Yii::$app->request->get('mode') == 'popup') { if (Yii::$app->request->get('mode') == 'popup') {
@ -87,7 +91,6 @@ class CommentController extends \humhub\modules\content\components\ContentAddonC
$message = Yii::$app->request->post('message'); $message = Yii::$app->request->post('message');
$files = Yii::$app->request->post('fileList'); $files = Yii::$app->request->post('fileList');
if (empty(trim($message)) && empty($files)) { if (empty(trim($message)) && empty($files)) {
// do not create empty comments // do not create empty comments
return ''; return '';
@ -101,7 +104,7 @@ class CommentController extends \humhub\modules\content\components\ContentAddonC
// Reload comment to get populated created_at field // Reload comment to get populated created_at field
$comment->refresh(); $comment->refresh();
return $this->renderAjaxContent(\humhub\modules\comment\widgets\Comment::widget(['comment' => $comment])); return $this->renderAjaxContent(CommentWidget::widget(['comment' => $comment]));
} }
public function actionEdit() public function actionEdit()
@ -117,17 +120,17 @@ class CommentController extends \humhub\modules\content\components\ContentAddonC
// Reload comment to get populated updated_at field // Reload comment to get populated updated_at field
$this->contentAddon = Comment::findOne(['id' => $this->contentAddon->id]); $this->contentAddon = Comment::findOne(['id' => $this->contentAddon->id]);
return $this->renderAjaxContent(\humhub\modules\comment\widgets\Comment::widget([ return $this->renderAjaxContent(CommentWidget::widget([
'comment' => $this->contentAddon, 'comment' => $this->contentAddon,
'justEdited' => true 'justEdited' => true
])); ]));
} }
return $this->renderAjax('edit', array( return $this->renderAjax('edit', [
'comment' => $this->contentAddon, 'comment' => $this->contentAddon,
'contentModel' => $this->contentAddon->object_model, 'contentModel' => $this->contentAddon->object_model,
'contentId' => $this->contentAddon->object_id 'contentId' => $this->contentAddon->object_id
)); ]);
} }
public function actionLoad() public function actionLoad()
@ -138,7 +141,7 @@ class CommentController extends \humhub\modules\content\components\ContentAddonC
throw new HttpException(403, Yii::t('CommentModule.controllers_CommentController', 'Access denied!')); throw new HttpException(403, Yii::t('CommentModule.controllers_CommentController', 'Access denied!'));
} }
return $this->renderAjaxContent(\humhub\modules\comment\widgets\Comment::widget(['comment' => $this->contentAddon])); return $this->renderAjaxContent(CommentWidget::widget(['comment' => $this->contentAddon]));
} }
/** /**

View File

@ -18,4 +18,5 @@ return array (
', ',
'{displayName} just commented your {contentTitle} in space {space}' => '{displayName} kommentierte gerade deinen {contentTitle} im Space {space} '{displayName} just commented your {contentTitle} in space {space}' => '{displayName} kommentierte gerade deinen {contentTitle} im Space {space}
', ',
'[Deleted]' => '[Gelöscht]'
); );

View File

@ -156,6 +156,10 @@ class NewComment extends \humhub\modules\notification\components\BaseNotificatio
{ {
$contentInfo = $this->getContentInfo($this->getCommentedRecord()); $contentInfo = $this->getContentInfo($this->getCommentedRecord());
if (!$contentInfo) {
$contentInfo = Yii::t('CommentModule.notification', "[Deleted]");
}
if ($this->groupCount > 1) { if ($this->groupCount > 1) {
return Yii::t('CommentModule.notification', "{displayNames} commented {contentTitle}.", [ return Yii::t('CommentModule.notification', "{displayNames} commented {contentTitle}.", [
'displayNames' => $this->getGroupUserDisplayNames(), 'displayNames' => $this->getGroupUserDisplayNames(),
@ -175,7 +179,12 @@ class NewComment extends \humhub\modules\notification\components\BaseNotificatio
*/ */
public function getCommentedRecord() public function getCommentedRecord()
{ {
return $this->source->getCommentedRecord(); $source = $this->source;
if (is_null($source)) {
//This prevents the error, but we need to clean the database
return null;
} else {
return $source->getCommentedRecord();
}
} }
} }

View File

@ -8,16 +8,15 @@
namespace humhub\modules\content\components; namespace humhub\modules\content\components;
use Yii;
use yii\base\Exception;
use humhub\modules\content\widgets\WallEntry; use humhub\modules\content\widgets\WallEntry;
use humhub\widgets\Label; use humhub\widgets\Label;
use Yii;
use humhub\libs\BasePermission; use humhub\libs\BasePermission;
use humhub\modules\content\permissions\ManageContent; use humhub\modules\content\permissions\ManageContent;
use yii\base\Exception;
use humhub\components\ActiveRecord; use humhub\components\ActiveRecord;
use humhub\modules\content\models\Content; use humhub\modules\content\models\Content;
use humhub\modules\content\interfaces\ContentOwner; use humhub\modules\content\interfaces\ContentOwner;
use yii\base\Widget;
/** /**
* ContentActiveRecord is the base ActiveRecord [[\yii\db\ActiveRecord]] for Content. * ContentActiveRecord is the base ActiveRecord [[\yii\db\ActiveRecord]] for Content.
@ -84,6 +83,15 @@ class ContentActiveRecord extends ActiveRecord implements ContentOwner
*/ */
protected $managePermission = ManageContent::class; protected $managePermission = ManageContent::class;
/**
* If set to true this flag will prevent default ContentCreated Notifications and Activities.
* This can be used e.g. for sub content entries, whose creation is not worth mentioning.
*
* @var bool
* @since 1.2.3
*/
public $silentContentCreation = false;
/** /**
* ContentActiveRecord constructor accepts either an configuration array as first argument or an ContentContainerActiveRecord * ContentActiveRecord constructor accepts either an configuration array as first argument or an ContentContainerActiveRecord
* and visibility settings. * and visibility settings.
@ -99,6 +107,7 @@ class ContentActiveRecord extends ActiveRecord implements ContentOwner
* or * or
* *
* `$model = new MyContent($space1, ['myField' => 'value']);` * `$model = new MyContent($space1, ['myField' => 'value']);`
*
* @param array|ContentContainerActiveRecord $contentContainer either the configuration or contentcontainer * @param array|ContentContainerActiveRecord $contentContainer either the configuration or contentcontainer
* @param int $visibility * @param int $visibility
* @param array $config * @param array $config

View File

@ -9,7 +9,10 @@
namespace humhub\modules\content\components; namespace humhub\modules\content\components;
use Yii; use Yii;
use humhub\components\Controller;
use yii\web\HttpException; use yii\web\HttpException;
use yii\base\Exception;
use humhub\libs\Helpers;
/** /**
@ -23,7 +26,7 @@ use yii\web\HttpException;
* @author luke * @author luke
* @version 0.11 * @version 0.11
*/ */
class ContentAddonController extends \humhub\components\Controller class ContentAddonController extends Controller
{ {
/** /**
@ -83,7 +86,7 @@ class ContentAddonController extends \humhub\components\Controller
throw new HttpException(500, 'Model & ID parameter required!'); throw new HttpException(500, 'Model & ID parameter required!');
} }
\humhub\libs\Helpers::CheckClassType($modelClass, array(ContentAddonActiveRecord::className(), ContentActiveRecord::className())); Helpers::CheckClassType($modelClass, [ContentAddonActiveRecord::className(), ContentActiveRecord::className()]);
$target = $modelClass::findOne(['id' => $pk]); $target = $modelClass::findOne(['id' => $pk]);
if ($target === null) { if ($target === null) {
@ -116,8 +119,8 @@ class ContentAddonController extends \humhub\components\Controller
*/ */
public function loadContentAddon($className, $pk) public function loadContentAddon($className, $pk)
{ {
if (!\humhub\libs\Helpers::CheckClassType($className, ContentAddonActiveRecord::className())) { if (!Helpers::CheckClassType($className, ContentAddonActiveRecord::className())) {
throw new \yii\base\Exception("Given className is not a content addon model!"); throw new Exception("Given className is not a content addon model!");
} }
$target = $className::findOne(['id' => $pk]); $target = $className::findOne(['id' => $pk]);

View File

@ -10,6 +10,7 @@ namespace humhub\modules\content\components\behaviors;
use Yii; use Yii;
use yii\base\Behavior; use yii\base\Behavior;
use yii\base\Exception;
/** /**
* Settings is a helper for deprecated methods getSetting/setSetting of Space/User Model * Settings is a helper for deprecated methods getSetting/setSetting of Space/User Model
@ -30,7 +31,7 @@ class SettingsBehavior extends Behavior
* @param String $default value when no setting exists * @param String $default value when no setting exists
* @return String * @return String
*/ */
public function getSetting($name, $moduleId = "core", $default = "") public function getSetting($name, $moduleId = 'core', $default = '')
{ {
$value = $this->getModule($moduleId)->settings->contentContainer($this->owner)->get($name); $value = $this->getModule($moduleId)->settings->contentContainer($this->owner)->get($name);
if ($value === null) { if ($value === null) {
@ -68,7 +69,7 @@ class SettingsBehavior extends Behavior
} }
if ($app === null) { if ($app === null) {
throw new \Exception('Could not find module for setting manager: ' . $moduleId); throw new Exception('Could not find module for setting manager: ' . $moduleId);
} }
return $app; return $app;

View File

@ -38,4 +38,19 @@ class NewContent extends LiveEvent
*/ */
public $originator; public $originator;
/**
* @var string class of the ContentActiveRecord
*/
public $sourceClass;
/**
* @var int id of the ContentActiveRecord
*/
public $sourceId;
/**
* @var boolean if true it's meant to be a silent content creation
*/
public $silent;
} }

View File

@ -76,6 +76,7 @@ class Content extends ContentDeprecated
/** /**
* @var bool flag to disable the creation of default social activities like activity and notifications in afterSave() at content creation. * @var bool flag to disable the creation of default social activities like activity and notifications in afterSave() at content creation.
* @deprecated since v1.2.3 use ContentActiveRecord::silentContentCreation instead.
*/ */
public $muteDefaultSocialActivities = false; public $muteDefaultSocialActivities = false;
@ -173,41 +174,61 @@ class Content extends ContentDeprecated
*/ */
public function afterSave($insert, $changedAttributes) public function afterSave($insert, $changedAttributes)
{ {
/* @var $contentSource ContentActiveRecord */
$contentSource = $this->getPolymorphicRelation(); $contentSource = $this->getPolymorphicRelation();
foreach ($this->notifyUsersOfNewContent as $user) { foreach ($this->notifyUsersOfNewContent as $user) {
$contentSource->follow($user->id); $contentSource->follow($user->id);
} }
if ($insert && !$contentSource instanceof \humhub\modules\activity\models\Activity) { // TODO: handle ContentCreated notifications and live events for global content
if ($insert && !$this->isMuted()) {
$this->notifyContentCreated();
}
if (!$this->muteDefaultSocialActivities && $this->container !== null) { if($this->container) {
$notifyUsers = array_merge($this->notifyUsersOfNewContent, Yii::$app->notification->getFollowers($this)); Yii::$app->live->send(new \humhub\modules\content\live\NewContent([
'sguid' => ($this->container instanceof Space) ? $this->container->guid : null,
\humhub\modules\content\notifications\ContentCreated::instance() 'uguid' => ($this->container instanceof User) ? $this->container->guid : null,
->from($this->user) 'originator' => $this->user->guid,
->about($contentSource) 'contentContainerId' => $this->container->contentContainerRecord->id,
->sendBulk($notifyUsers); 'visibility' => $this->visibility,
'sourceClass' => $contentSource->className(),
\humhub\modules\content\activities\ContentCreated::instance() 'sourceId' => $contentSource->getPrimaryKey(),
->from($this->user) 'silent' => $this->isMuted(),
->about($contentSource)->save(); 'contentId' => $this->id
]));
Yii::$app->live->send(new \humhub\modules\content\live\NewContent([
'sguid' => ($this->container instanceof Space) ? $this->container->guid : null,
'uguid' => ($this->container instanceof User) ? $this->container->guid : null,
'originator' => $this->user->guid,
'contentContainerId' => $this->container->contentContainerRecord->id,
'visibility' => $this->visibility,
'contentId' => $this->id
]));
}
} }
return parent::afterSave($insert, $changedAttributes); return parent::afterSave($insert, $changedAttributes);
} }
/**
* @return bool checks if the given content allows content creation notifications and activities
*/
private function isMuted()
{
return $this->getPolymorphicRelation()->silentContentCreation || $this->muteDefaultSocialActivities || !$this->container;
}
/**
* Notifies all followers and manually set $notifyUsersOfNewContent of the creation of this content and creates an activity.
*/
private function notifyContentCreated()
{
$contentSource = $this->getPolymorphicRelation();
$notifyUsers = array_merge($this->notifyUsersOfNewContent, Yii::$app->notification->getFollowers($this));
\humhub\modules\content\notifications\ContentCreated::instance()
->from($this->user)
->about($contentSource)
->sendBulk($notifyUsers);
\humhub\modules\content\activities\ContentCreated::instance()
->from($this->user)
->about($contentSource)->save();
}
/** /**
* @inheritdoc * @inheritdoc
*/ */
@ -268,7 +289,7 @@ class Content extends ContentDeprecated
public function pin() public function pin()
{ {
$this->pinned = 1; $this->pinned = 1;
//This prevents the call of beforesave, and the setting of update_at //This prevents the call of beforeSave, and the setting of update_at
$this->updateAttributes(['pinned']); $this->updateAttributes(['pinned']);
} }

View File

@ -31,6 +31,34 @@ class ContentCreatedTest extends HumHubDbTestCase
$this->assertMailSent(1, 'ContentCreated Notification Mail sent'); $this->assertMailSent(1, 'ContentCreated Notification Mail sent');
} }
public function testSilentContentCreation()
{
$this->becomeUser('User2');
$post = new Post(['message' => 'MyTestContent']);
$post->silentContentCreation = true;
$post->content->setContainer(Space::findOne(['id' => 2]));
$post->content->visibility = Content::VISIBILITY_PUBLIC;
$post->save();
// Note Admin is following Space2 so we expect one notification mail.
$this->assertMailSent(0, 'ContentCreated Notification Mail not sent');
}
public function testMuteContentNotifications()
{
$this->becomeUser('User2');
$post = new Post(['message' => 'MyTestContent']);
$post->content->setContainer(Space::findOne(['id' => 2]));
$post->content->visibility = Content::VISIBILITY_PUBLIC;
$post->content->muteDefaultSocialActivities = true;
$post->save();
// Note Admin is following Space2 so we expect one notification mail.
$this->assertMailSent(0, 'ContentCreated Notification Mail not sent');
}
/** /**
* Disable mail notifications for a follower. * Disable mail notifications for a follower.
*/ */

View File

@ -2,13 +2,14 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\file\components; namespace humhub\modules\file\components;
use Yii; use Yii;
use yii\base\Component;
use humhub\modules\file\models\File; use humhub\modules\file\models\File;
use humhub\modules\file\libs\ImageConverter; use humhub\modules\file\libs\ImageConverter;
use humhub\modules\file\libs\FileHelper; use humhub\modules\file\libs\FileHelper;
@ -19,7 +20,7 @@ use humhub\modules\file\libs\FileHelper;
* @since 1.2 * @since 1.2
* @author Luke * @author Luke
*/ */
class StorageManager extends \yii\base\Component implements StorageManagerInterface class StorageManager extends Component implements StorageManagerInterface
{ {
/** /**
@ -65,6 +66,7 @@ class StorageManager extends \yii\base\Component implements StorageManagerInterf
$variants[] = $file; $variants[] = $file;
} }
} }
return $variants; return $variants;
} }

View File

@ -9,6 +9,7 @@
namespace humhub\modules\friendship\controllers; namespace humhub\modules\friendship\controllers;
use Yii; use Yii;
use yii\web\HttpException;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\friendship\models\Friendship; use humhub\modules\friendship\models\Friendship;
use humhub\components\Controller; use humhub\components\Controller;
@ -30,12 +31,13 @@ class ListController extends Controller
{ {
$user = User::findOne(['id' => Yii::$app->request->get('userId')]); $user = User::findOne(['id' => Yii::$app->request->get('userId')]);
if ($user === null) { if ($user === null) {
throw new \yii\web\HttpException(404, 'Could not find user!'); throw new HttpException(404, 'Could not find user!');
} }
$query = Friendship::getFriendsQuery($user); $query = Friendship::getFriendsQuery($user);
$title = '<strong>' . Yii::t('FriendshipModule.base', "Friends") . '</strong>'; $title = '<strong>' . Yii::t('FriendshipModule.base', 'Friends') . '</strong>';
return $this->renderAjaxContent(UserListBox::widget(['query' => $query, 'title' => $title])); return $this->renderAjaxContent(UserListBox::widget(['query' => $query, 'title' => $title]));
} }

View File

@ -9,6 +9,7 @@
namespace humhub\modules\friendship\controllers; namespace humhub\modules\friendship\controllers;
use Yii; use Yii;
use yii\web\HttpException;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\components\Controller; use humhub\components\Controller;
use humhub\modules\friendship\models\Friendship; use humhub\modules\friendship\models\Friendship;
@ -31,7 +32,7 @@ class RequestController extends Controller
$friend = User::findOne(['id' => Yii::$app->request->get('userId')]); $friend = User::findOne(['id' => Yii::$app->request->get('userId')]);
if ($friend === null) { if ($friend === null) {
throw new \yii\web\HttpException(404, 'User not found!'); throw new HttpException(404, 'User not found!');
} }
Friendship::add(Yii::$app->user->getIdentity(), $friend); Friendship::add(Yii::$app->user->getIdentity(), $friend);
@ -49,7 +50,7 @@ class RequestController extends Controller
$friend = User::findOne(['id' => Yii::$app->request->get('userId')]); $friend = User::findOne(['id' => Yii::$app->request->get('userId')]);
if ($friend === null) { if ($friend === null) {
throw new \yii\web\HttpException(404, 'User not found!'); throw new HttpException(404, 'User not found!');
} }
Friendship::cancel(Yii::$app->user->getIdentity(), $friend); Friendship::cancel(Yii::$app->user->getIdentity(), $friend);

View File

@ -2,7 +2,7 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
@ -11,6 +11,9 @@ namespace humhub\modules\installer;
use Yii; use Yii;
use yii\helpers\Url; use yii\helpers\Url;
use yii\base\Exception; use yii\base\Exception;
use yii\web\HttpException;
use yii\console\Application;
use humhub\libs\DynamicConfig;
/** /**
* InstallerModule provides an web installation interface for the applcation * InstallerModule provides an web installation interface for the applcation
@ -44,7 +47,7 @@ class Module extends \humhub\components\Module
{ {
parent::init(); parent::init();
if (Yii::$app instanceof \yii\console\Application) { if (Yii::$app instanceof Application) {
return; return;
} }
@ -61,10 +64,11 @@ class Module extends \humhub\components\Module
// Block installer, when it's marked as installed // Block installer, when it's marked as installed
if (Yii::$app->params['installed']) { if (Yii::$app->params['installed']) {
throw new \yii\web\HttpException(500, 'HumHub is already installed!'); throw new HttpException(500, 'HumHub is already installed!');
} }
Yii::$app->controller->enableCsrfValidation = false; Yii::$app->controller->enableCsrfValidation = false;
return parent::beforeAction($action); return parent::beforeAction($action);
} }
@ -83,11 +87,12 @@ class Module extends \humhub\components\Module
return Yii::$app->db->getIsActive(); return Yii::$app->db->getIsActive();
} catch (Exception $e) { } catch (Exception $e) {
} catch (\yii\base\Exception $e) { } catch (Exception $e) {
} catch (\PDOException $e) { } catch (\PDOException $e) {
} }
return false; return false;
} }
@ -99,6 +104,7 @@ class Module extends \humhub\components\Module
if (Yii::$app->settings->get('secret') != "") { if (Yii::$app->settings->get('secret') != "") {
return true; return true;
} }
return false; return false;
} }
@ -107,9 +113,9 @@ class Module extends \humhub\components\Module
*/ */
public function setInstalled() public function setInstalled()
{ {
$config = \humhub\libs\DynamicConfig::load(); $config = DynamicConfig::load();
$config['params']['installed'] = true; $config['params']['installed'] = true;
\humhub\libs\DynamicConfig::save($config); DynamicConfig::save($config);
} }
/** /**
@ -117,9 +123,9 @@ class Module extends \humhub\components\Module
*/ */
public function setDatabaseInstalled() public function setDatabaseInstalled()
{ {
$config = \humhub\libs\DynamicConfig::load(); $config = DynamicConfig::load();
$config['params']['databaseInstalled'] = true; $config['params']['databaseInstalled'] = true;
\humhub\libs\DynamicConfig::save($config); DynamicConfig::save($config);
} }
protected function initConfigSteps() protected function initConfigSteps()

View File

@ -2,7 +2,7 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
@ -11,11 +11,12 @@ namespace humhub\modules\installer\commands;
use Yii; use Yii;
use yii\console\Controller; use yii\console\Controller;
use yii\helpers\Console; use yii\helpers\Console;
use yii\base\Exception;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\user\models\Password; use humhub\modules\user\models\Password;
use humhub\modules\user\models\Group; use humhub\modules\user\models\Group;
use humhub\modules\installer\libs\InitialData;
use humhub\libs\UUID;
/** /**
* Console Install * Console Install
@ -29,26 +30,26 @@ class InstallController extends Controller
{ {
$this->stdout("Install:\n\n", Console::FG_YELLOW); $this->stdout("Install:\n\n", Console::FG_YELLOW);
\humhub\modules\installer\libs\InitialData::bootstrap(); InitialData::bootstrap();
Yii::$app->settings->set('name', "HumHub Test"); Yii::$app->settings->set('name', 'HumHub Test');
Yii::$app->settings->set('mailer.systemEmailName', "humhub@example.com"); Yii::$app->settings->set('mailer.systemEmailName', 'humhub@example.com');
Yii::$app->settings->set('mailer.systemEmailName', "humhub@example.com"); Yii::$app->settings->set('mailer.systemEmailName', 'humhub@example.com');
Yii::$app->settings->set('secret', \humhub\libs\UUID::v4()); Yii::$app->settings->set('secret', UUID::v4());
$user = new User(); $user = new User();
//$user->group_id = 1; //$user->group_id = 1;
$user->username = "Admin"; $user->username = 'Admin';
$user->email = 'humhub@example.com'; $user->email = 'humhub@example.com';
$user->status = User::STATUS_ENABLED; $user->status = User::STATUS_ENABLED;
$user->language = ''; $user->language = '';
if (!$user->save()) { if (!$user->save()) {
throw new \yii\base\Exception("Could not save user"); throw new Exception("Could not save user");
} }
$user->profile->title = "System Administration"; $user->profile->title = 'System Administration';
$user->profile->firstname = "John"; $user->profile->firstname = 'John';
$user->profile->lastname = "Doe"; $user->profile->lastname = 'Doe';
$user->profile->save(); $user->profile->save();
$password = new Password(); $password = new Password();
@ -59,7 +60,6 @@ class InstallController extends Controller
// Assign to system admin group // Assign to system admin group
Group::getAdminGroup()->addUser($user); Group::getAdminGroup()->addUser($user);
return self::EXIT_CODE_NORMAL; return self::EXIT_CODE_NORMAL;
} }

View File

@ -2,7 +2,7 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
@ -11,7 +11,12 @@ namespace humhub\modules\notification\components;
use humhub\components\SocialActivity; use humhub\components\SocialActivity;
use Yii; use Yii;
use yii\helpers\Url; use yii\helpers\Url;
use yii\helpers\ArrayHelper;
use yii\bootstrap\Html; use yii\bootstrap\Html;
use yii\db\Expression;
use yii\db\ActiveQuery;
use yii\base\InvalidConfigException;
use humhub\components\SocialActivity;
use humhub\modules\notification\models\Notification; use humhub\modules\notification\models\Notification;
use humhub\modules\notification\jobs\SendNotification; use humhub\modules\notification\jobs\SendNotification;
use humhub\modules\notification\jobs\SendBulkNotification; use humhub\modules\notification\jobs\SendBulkNotification;
@ -114,7 +119,7 @@ abstract class BaseNotification extends SocialActivity
*/ */
public function getViewParams($params = []) public function getViewParams($params = [])
{ {
if ($this->hasContent() && $this->getContent()->updated_at instanceof \yii\db\Expression) { if ($this->hasContent() && $this->getContent()->updated_at instanceof Expression) {
$this->getContent()->refresh(); $this->getContent()->refresh();
$date = $this->getContent()->updated_at; $date = $this->getContent()->updated_at;
} else if ($this->hasContent()) { } else if ($this->hasContent()) {
@ -129,7 +134,7 @@ abstract class BaseNotification extends SocialActivity
'isNew' => !$this->record->seen, 'isNew' => !$this->record->seen,
]; ];
return \yii\helpers\ArrayHelper::merge(parent::getViewParams($result), $params); return ArrayHelper::merge(parent::getViewParams($result), $params);
} }
/** /**
@ -143,10 +148,10 @@ abstract class BaseNotification extends SocialActivity
public function sendBulk($users) public function sendBulk($users)
{ {
if (empty($this->moduleId)) { if (empty($this->moduleId)) {
throw new \yii\base\InvalidConfigException('No moduleId given for "' . $this->className() . '"'); throw new InvalidConfigException('No moduleId given for "' . $this->className() . '"');
} }
if ($users instanceof \yii\db\ActiveQuery) { if ($users instanceof ActiveQuery) {
$users = $users->all(); $users = $users->all();
} }
@ -166,7 +171,7 @@ abstract class BaseNotification extends SocialActivity
public function send(User $user) public function send(User $user)
{ {
if (empty($this->moduleId)) { if (empty($this->moduleId)) {
throw new \yii\base\InvalidConfigException('No moduleId given for "' . $this->className() . '"'); throw new InvalidConfigException('No moduleId given for "' . $this->className() . '"');
} }
if ($this->isOriginator($user)) { if ($this->isOriginator($user)) {
@ -188,7 +193,7 @@ abstract class BaseNotification extends SocialActivity
*/ */
public function getMailSubject() public function getMailSubject()
{ {
return "New notification"; return 'New notification';
} }
/** /**
@ -243,6 +248,7 @@ abstract class BaseNotification extends SocialActivity
} }
parent::about($source); parent::about($source);
$this->record->space_id = $this->getSpaceId(); $this->record->space_id = $this->getSpaceId();
return $this; return $this;
} }
@ -256,6 +262,7 @@ abstract class BaseNotification extends SocialActivity
} }
$this->originator = $originator; $this->originator = $originator;
$this->record->originator_user_id = $originator->id; $this->record->originator_user_id = $originator->id;
return $this; return $this;
} }
@ -360,6 +367,7 @@ abstract class BaseNotification extends SocialActivity
} }
list($user1, $user2) = $this->getGroupLastUsers(2); list($user1, $user2) = $this->getGroupLastUsers(2);
return Yii::t('NotificationModule.base', '{displayName} and {displayName2}', [ return Yii::t('NotificationModule.base', '{displayName} and {displayName2}', [
'displayName' => Html::tag('strong', Html::encode($user1->displayName)), 'displayName' => Html::tag('strong', Html::encode($user1->displayName)),
'displayName2' => Html::tag('strong', Html::encode($user2->displayName)), 'displayName2' => Html::tag('strong', Html::encode($user2->displayName)),
@ -402,6 +410,7 @@ abstract class BaseNotification extends SocialActivity
{ {
$result = parent::asArray($user); $result = parent::asArray($user);
$result['mailSubject'] = $this->getMailSubject($user); $result['mailSubject'] = $this->getMailSubject($user);
return $result; return $result;
} }

View File

@ -2,15 +2,18 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\notification\controllers; namespace humhub\modules\notification\controllers;
use Yii; use Yii;
use yii\web\HttpException;
use humhub\components\Controller; use humhub\components\Controller;
use humhub\components\behaviors\AccessControl;
use humhub\modules\notification\models\Notification; use humhub\modules\notification\models\Notification;
use humhub\components\access\ControllerAccess;
/** /**
* EntryController * EntryController
@ -23,12 +26,10 @@ class EntryController extends Controller
/** /**
* @inheritdoc * @inheritdoc
*/ */
public function behaviors() public function getAccessRules()
{ {
return [ return [
'acl' => [ [ControllerAccess::RULE_LOGGED_IN_ONLY]
'class' => \humhub\components\behaviors\AccessControl::className(),
]
]; ];
} }
@ -40,7 +41,7 @@ class EntryController extends Controller
$notificationModel = Notification::findOne(['id' => Yii::$app->request->get('id'), 'user_id' => Yii::$app->user->id]); $notificationModel = Notification::findOne(['id' => Yii::$app->request->get('id'), 'user_id' => Yii::$app->user->id]);
if ($notificationModel === null) { if ($notificationModel === null) {
throw new \yii\web\HttpException(404, Yii::t('NotificationModule.error','The requested content is not valid or was removed!')); throw new HttpException(404, Yii::t('NotificationModule.error','The requested content is not valid or was removed!'));
} }
$notification = $notificationModel->getClass(); $notification = $notificationModel->getClass();
@ -48,7 +49,7 @@ class EntryController extends Controller
if ($notification->markAsSeenOnClick) { if ($notification->markAsSeenOnClick) {
$notification->markAsSeen(); $notification->markAsSeen();
} }
// Redirect to notification URL // Redirect to notification URL
return $this->redirect($notification->getUrl()); return $this->redirect($notification->getUrl());
} }

View File

@ -1,17 +1,26 @@
<?php <?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\notification\models\forms; namespace humhub\modules\notification\models\forms;
use humhub\modules\notification\components\NotificationCategory; use humhub\modules\notification\components\NotificationCategory;
use Yii; use Yii;
use yii\base\Model;
use yii\web\HttpException;
use humhub\modules\notification\targets\BaseTarget; use humhub\modules\notification\targets\BaseTarget;
use humhub\modules\admin\permissions\ManageSettings;
/** /**
* Description of NotificationSettings * Description of NotificationSettings
* *
* @author buddha * @author buddha
*/ */
class NotificationSettings extends \yii\base\Model class NotificationSettings extends Model
{ {
/** /**
@ -60,6 +69,7 @@ class NotificationSettings extends \yii\base\Model
$this->desktopNotifications = Yii::$app->notification->getDesktopNoficationSettings($this->user); $this->desktopNotifications = Yii::$app->notification->getDesktopNoficationSettings($this->user);
$module = Yii::$app->getModule('notification'); $module = Yii::$app->getModule('notification');
return ($this->user) ? $module->settings->user($this->user) : $module->settings; return ($this->user) ? $module->settings->user($this->user) : $module->settings;
} }
@ -99,6 +109,7 @@ class NotificationSettings extends \yii\base\Model
if ($this->user) { if ($this->user) {
return $this->getSettings()->get('notification.like_email') !== null; return $this->getSettings()->get('notification.like_email') !== null;
} }
return false; return false;
} }
@ -143,7 +154,7 @@ class NotificationSettings extends \yii\base\Model
public function save() public function save()
{ {
if (!$this->checkPermission()) { if (!$this->checkPermission()) {
throw new \yii\web\HttpException(403); throw new HttpException(403);
} }
if (!$this->validate()) { if (!$this->validate()) {
@ -208,12 +219,13 @@ class NotificationSettings extends \yii\base\Model
public function getSettings() public function getSettings()
{ {
$module = Yii::$app->getModule('notification'); $module = Yii::$app->getModule('notification');
return ($this->user) ? $module->settings->user($this->user) : $module->settings; return ($this->user) ? $module->settings->user($this->user) : $module->settings;
} }
public function checkPermission() public function checkPermission()
{ {
if (Yii::$app->user->can(new \humhub\modules\admin\permissions\ManageSettings())) { if (Yii::$app->user->can(new ManageSettings())) {
return true; return true;
} else if (!$this->user) { } else if (!$this->user) {
return false; // Only ManageSettings user can set global notification settings return false; // Only ManageSettings user can set global notification settings
@ -235,6 +247,7 @@ class NotificationSettings extends \yii\base\Model
} }
} }
Yii::$app->notification->setSpaces([], $this->user); Yii::$app->notification->setSpaces([], $this->user);
return true; return true;
} }

View File

@ -9,8 +9,10 @@
namespace humhub\modules\notification\targets; namespace humhub\modules\notification\targets;
use Yii; use Yii;
use yii\base\Exception;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\notification\components\BaseNotification; use humhub\modules\notification\components\BaseNotification;
use humhub\modules\notification\live\NewNotification;
/** /**
* Web Target * Web Target
@ -37,13 +39,13 @@ class WebTarget extends BaseTarget
public function handle(BaseNotification $notification, User $user) public function handle(BaseNotification $notification, User $user)
{ {
if (!$notification->record) { if (!$notification->record) {
throw new \yii\base\Exception('Notification record not found for BaseNotification "' . $notification->className() . '"'); throw new Exception('Notification record not found for BaseNotification "' . $notification->className() . '"');
} }
$notification->record->send_web_notifications = true; $notification->record->send_web_notifications = true;
$notification->record->save(); $notification->record->save();
Yii::$app->live->send(new \humhub\modules\notification\live\NewNotification([ Yii::$app->live->send(new NewNotification([
'notificationId' => $notification->record->id, 'notificationId' => $notification->record->id,
'contentContainerId' => $user->contentcontainer_id, 'contentContainerId' => $user->contentcontainer_id,
'ts' => time(), 'ts' => time(),

View File

@ -2,7 +2,7 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
@ -10,14 +10,22 @@ namespace humhub\modules\space\behaviors;
use Yii; use Yii;
use yii\base\Behavior; use yii\base\Behavior;
use yii\base\Exception;
use yii\validators\EmailValidator;;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\space\models\Space; use humhub\modules\space\models\Space;
use humhub\modules\space\models\Membership; use humhub\modules\space\models\Membership;
use humhub\modules\user\models\Invite; use humhub\modules\user\models\Invite;
use humhub\modules\space\notifications\Invite as InviteNotification;
use humhub\modules\admin\permissions\ManageSpaces; use humhub\modules\admin\permissions\ManageSpaces;
use humhub\modules\space\notifications\ApprovalRequestAccepted; use humhub\modules\space\notifications\ApprovalRequestAccepted;
use humhub\modules\space\notifications\ApprovalRequestDeclined;
use humhub\modules\space\notifications\ApprovalRequest;
use humhub\modules\space\notifications\InviteAccepted; use humhub\modules\space\notifications\InviteAccepted;
use humhub\modules\space\notifications\InviteDeclined;
use humhub\modules\space\MemberEvent; use humhub\modules\space\MemberEvent;
use humhub\modules\space\activities\MemberAdded;
use humhub\modules\space\activities\MemberRemoved;
/** /**
* SpaceModelMemberBehavior bundles all membership related methods of the Space model. * SpaceModelMemberBehavior bundles all membership related methods of the Space model.
@ -35,13 +43,13 @@ class SpaceModelMembership extends Behavior
* @param integer $userId * @param integer $userId
* @return boolean * @return boolean
*/ */
public function isMember($userId = "") public function isMember($userId = '')
{ {
// Take current userid if none is given // Take current userid if none is given
if ($userId == "" && !Yii::$app->user->isGuest) { if ($userId == '' && !Yii::$app->user->isGuest) {
$userId = Yii::$app->user->id; $userId = Yii::$app->user->id;
} elseif ($userId == "" && Yii::$app->user->isGuest) { } elseif ($userId == '' && Yii::$app->user->isGuest) {
return false; return false;
} }
@ -61,11 +69,11 @@ class SpaceModelMembership extends Behavior
* @param number $userId, if empty hte currently logged in user is taken. * @param number $userId, if empty hte currently logged in user is taken.
* @return bool * @return bool
*/ */
public function canLeave($userId = "") public function canLeave($userId = '')
{ {
// Take current userid if none is given // Take current userid if none is given
if ($userId == "") { if ($userId == '') {
$userId = Yii::$app->user->id; $userId = Yii::$app->user->id;
} }
@ -129,6 +137,7 @@ class SpaceModelMembership extends Behavior
$this->owner->update(false, ['created_by']); $this->owner->update(false, ['created_by']);
$this->_spaceOwner = null; $this->_spaceOwner = null;
return true; return true;
} }
@ -144,6 +153,7 @@ class SpaceModelMembership extends Behavior
} }
$this->_spaceOwner = User::findOne(['id' => $this->owner->created_by]); $this->_spaceOwner = User::findOne(['id' => $this->owner->created_by]);
return $this->_spaceOwner; return $this->_spaceOwner;
} }
@ -185,6 +195,7 @@ class SpaceModelMembership extends Behavior
$membership->save(); $membership->save();
return true; return true;
} }
return false; return false;
} }
@ -214,7 +225,7 @@ class SpaceModelMembership extends Behavior
{ {
// Invalid E-Mail // Invalid E-Mail
$validator = new \yii\validators\EmailValidator; $validator = new EmailValidator;
if (!$validator->validate($email)) if (!$validator->validate($email))
return false; return false;
@ -255,7 +266,7 @@ class SpaceModelMembership extends Behavior
* @param integer $userId * @param integer $userId
* @param string $message * @param string $message
*/ */
public function requestMembership($userId, $message = "") public function requestMembership($userId, $message = '')
{ {
$user = ($userId instanceof User) ? $userId : User::findOne(['id' => $userId]); $user = ($userId instanceof User) ? $userId : User::findOne(['id' => $userId]);
@ -271,7 +282,7 @@ class SpaceModelMembership extends Behavior
$membership->save(); $membership->save();
\humhub\modules\space\notifications\ApprovalRequest::instance() ApprovalRequest::instance()
->from($user)->about($this->owner)->withMessage($message)->sendBulk($this->getAdmins()); ->from($user)->about($this->owner)->withMessage($message)->sendBulk($this->getAdmins());
} }
@ -313,7 +324,7 @@ class SpaceModelMembership extends Behavior
return; return;
case Membership::STATUS_INVITED: case Membership::STATUS_INVITED:
// If user is already invited, remove old invite notification and retrigger // If user is already invited, remove old invite notification and retrigger
$oldNotification = new \humhub\modules\space\notifications\Invite(['source' => $this->owner]); $oldNotification = new InviteNotification(['source' => $this->owner]);
$oldNotification->delete(User::findOne(['id' => $userId])); $oldNotification->delete(User::findOne(['id' => $userId]));
break; break;
} }
@ -332,7 +343,7 @@ class SpaceModelMembership extends Behavior
if ($membership->save()) { if ($membership->save()) {
$this->sendInviteNotification($userId, $originatorId); $this->sendInviteNotification($userId, $originatorId);
} else { } else {
throw new \yii\base\Exception("Could not save membership!" . print_r($membership->getErrors(), 1)); throw new Exception('Could not save membership!' . print_r($membership->getErrors(), 1));
} }
} }
@ -344,7 +355,7 @@ class SpaceModelMembership extends Behavior
*/ */
protected function sendInviteNotification($userId, $originatorId) protected function sendInviteNotification($userId, $originatorId)
{ {
$notification = new \humhub\modules\space\notifications\Invite([ $notification = new InviteNotification([
'source' => $this->owner, 'source' => $this->owner,
'originator' => User::findOne(['id' => $originatorId]) 'originator' => User::findOne(['id' => $originatorId])
]); ]);
@ -413,16 +424,16 @@ class SpaceModelMembership extends Behavior
// Create Activity // Create Activity
\humhub\modules\space\activities\MemberAdded::instance()->from($user)->about($this->owner)->save(); MemberAdded::instance()->from($user)->about($this->owner)->save();
// Members can't also follow the space // Members can't also follow the space
$this->owner->unfollow($userId); $this->owner->unfollow($userId);
// Delete invite notification for this user // Delete invite notification for this user
\humhub\modules\space\notifications\Invite::instance()->about($this->owner)->delete($user); InviteNotification::instance()->about($this->owner)->delete($user);
// Delete pending approval request notifications for this user // Delete pending approval request notifications for this user
\humhub\modules\space\notifications\ApprovalRequest::instance()->from($user)->about($this->owner)->delete(); ApprovalRequest::instance()->from($user)->about($this->owner)->delete();
} }
/** /**
@ -450,7 +461,7 @@ class SpaceModelMembership extends Behavior
// If was member, create a activity for that // If was member, create a activity for that
if ($membership->status == Membership::STATUS_MEMBER) { if ($membership->status == Membership::STATUS_MEMBER) {
$activity = new \humhub\modules\space\activities\MemberRemoved(); $activity = new MemberRemoved();
$activity->source = $this->owner; $activity->source = $this->owner;
$activity->originator = $user; $activity->originator = $user;
$activity->create(); $activity->create();
@ -460,10 +471,10 @@ class SpaceModelMembership extends Behavior
])); ]));
} elseif ($membership->status == Membership::STATUS_INVITED && $membership->originator !== null) { } elseif ($membership->status == Membership::STATUS_INVITED && $membership->originator !== null) {
// Was invited, but declined the request - inform originator // Was invited, but declined the request - inform originator
\humhub\modules\space\notifications\InviteDeclined::instance() InviteDeclined::instance()
->from($user)->about($this->owner)->send($membership->originator); ->from($user)->about($this->owner)->send($membership->originator);
} elseif ($membership->status == Membership::STATUS_APPLICANT) { } elseif ($membership->status == Membership::STATUS_APPLICANT) {
\humhub\modules\space\notifications\ApprovalRequestDeclined::instance() ApprovalRequestDeclined::instance()
->from(Yii::$app->user->getIdentity())->about($this->owner)->send($user); ->from(Yii::$app->user->getIdentity())->about($this->owner)->send($user);
} }
@ -471,9 +482,9 @@ class SpaceModelMembership extends Behavior
$membership->delete(); $membership->delete();
} }
\humhub\modules\space\notifications\ApprovalRequest::instance()->from($user)->about($this->owner)->delete(); ApprovalRequest::instance()->from($user)->about($this->owner)->delete();
\humhub\modules\space\notifications\Invite::instance()->from($this->owner)->delete($user); InviteNotification::instance()->from($this->owner)->delete($user);
} }
} }

View File

@ -2,17 +2,23 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\space\controllers; namespace humhub\modules\space\controllers;
use Yii; use Yii;
use yii\web\HttpException;
use yii\db\Expression;
use humhub\modules\content\components\ContentContainerController;
use humhub\components\behaviors\AccessControl;
use humhub\modules\space\models\Space; use humhub\modules\space\models\Space;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\user\widgets\UserListBox; use humhub\modules\user\widgets\UserListBox;
use humhub\modules\stream\actions\ContentContainerStream; use humhub\modules\stream\actions\ContentContainerStream;
use humhub\modules\space\widgets\Menu;
use humhub\modules\post\permissions\CreatePost;
/** /**
* SpaceController is the main controller for spaces. * SpaceController is the main controller for spaces.
@ -24,7 +30,7 @@ use humhub\modules\stream\actions\ContentContainerStream;
* @package humhub.modules_core.space.controllers * @package humhub.modules_core.space.controllers
* @since 0.5 * @since 0.5
*/ */
class SpaceController extends \humhub\modules\content\components\ContentContainerController class SpaceController extends ContentContainerController
{ {
/** /**
@ -34,7 +40,7 @@ class SpaceController extends \humhub\modules\content\components\ContentContaine
{ {
return [ return [
'acl' => [ 'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(), 'class' => AccessControl::className(),
'guestAllowedActions' => ['index', 'stream'], 'guestAllowedActions' => ['index', 'stream'],
] ]
]; ];
@ -65,13 +71,13 @@ class SpaceController extends \humhub\modules\content\components\ContentContaine
} }
if (!$space->isMember()) { if (!$space->isMember()) {
$defaultPageUrl = \humhub\modules\space\widgets\Menu::getGuestsDefaultPageUrl($space); $defaultPageUrl = Menu::getGuestsDefaultPageUrl($space);
if ($defaultPageUrl != null) { if ($defaultPageUrl != null) {
return $this->redirect($defaultPageUrl); return $this->redirect($defaultPageUrl);
} }
} }
$defaultPageUrl = \humhub\modules\space\widgets\Menu::getDefaultPageUrl($space); $defaultPageUrl = Menu::getDefaultPageUrl($space);
if ($defaultPageUrl != null) { if ($defaultPageUrl != null) {
return $this->redirect($defaultPageUrl); return $this->redirect($defaultPageUrl);
} }
@ -87,7 +93,7 @@ class SpaceController extends \humhub\modules\content\components\ContentContaine
public function actionHome() public function actionHome()
{ {
$space = $this->contentContainer; $space = $this->contentContainer;
$canCreatePosts = $space->permissionManager->can(new \humhub\modules\post\permissions\CreatePost()); $canCreatePosts = $space->permissionManager->can(new CreatePost());
$isMember = $space->isMember(); $isMember = $space->isMember();
return $this->render('home', [ return $this->render('home', [
@ -103,7 +109,7 @@ class SpaceController extends \humhub\modules\content\components\ContentContaine
public function actionFollow() public function actionFollow()
{ {
if(Yii::$app->getModule('space')->disableFollow) { if(Yii::$app->getModule('space')->disableFollow) {
throw new \yii\web\HttpException(403, Yii::t('ContentModule.controllers_ContentController', 'This action is disabled!')); throw new HttpException(403, Yii::t('ContentModule.controllers_ContentController', 'This action is disabled!'));
} }
$this->forcePostRequest(); $this->forcePostRequest();
@ -148,15 +154,14 @@ class SpaceController extends \humhub\modules\content\components\ContentContaine
public function actionFollowerList() public function actionFollowerList()
{ {
$query = User::find(); $query = User::find();
$query->leftJoin('user_follow', 'user.id=user_follow.user_id and object_model=:userClass and user_follow.object_id=:spaceId', [':userClass' => Space::className(), ':spaceId' => $this->getSpace()->id]); $query->leftJoin('user_follow', 'user.id=user_follow.user_id AND object_model=:userClass AND user_follow.object_id=:spaceId', [':userClass' => Space::className(), ':spaceId' => $this->getSpace()->id]);
$query->orderBy(['user_follow.id' => SORT_DESC]); $query->orderBy(['user_follow.id' => SORT_DESC]);
$query->andWhere(['IS NOT', 'user_follow.id', new \yii\db\Expression('NULL')]); $query->andWhere(['IS NOT', 'user_follow.id', new Expression('NULL')]);
$query->visible(); $query->visible();
$title = Yii::t('SpaceModule.base', '<strong>Space</strong> followers'); $title = Yii::t('SpaceModule.base', '<strong>Space</strong> followers');
return $this->renderAjaxContent(UserListBox::widget(['query' => $query, 'title' => $title])); return $this->renderAjaxContent(UserListBox::widget(['query' => $query, 'title' => $title]));
} }
} }
?>

View File

@ -8,9 +8,9 @@
namespace humhub\modules\space\modules\manage\controllers; namespace humhub\modules\space\modules\manage\controllers;
use humhub\modules\space\models\Space;
use Yii; use Yii;
use yii\web\HttpException; use yii\web\HttpException;
use humhub\modules\space\models\Space;
use humhub\modules\space\modules\manage\components\Controller; use humhub\modules\space\modules\manage\components\Controller;
use humhub\modules\space\modules\manage\models\MembershipSearch; use humhub\modules\space\modules\manage\models\MembershipSearch;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
@ -52,7 +52,7 @@ class MemberController extends Controller
Yii::$app->response->format = 'json'; Yii::$app->response->format = 'json';
$membership = Membership::findOne(['space_id' => $space->id, 'user_id' => Yii::$app->request->post('user_id')]); $membership = Membership::findOne(['space_id' => $space->id, 'user_id' => Yii::$app->request->post('user_id')]);
if ($membership === null) { if ($membership === null) {
throw new \yii\web\HttpException(404, 'Could not find membership!'); throw new HttpException(404, 'Could not find membership!');
} }
if ($membership->load(Yii::$app->request->post()) && $membership->validate() && $membership->save()) { if ($membership->load(Yii::$app->request->post()) && $membership->validate() && $membership->save()) {
@ -189,5 +189,3 @@ class MemberController extends Controller
} }
} }
?>

View File

@ -2,7 +2,7 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
@ -31,6 +31,7 @@ class SecurityController extends Controller
$this->view->saved(); $this->view->saved();
return $this->redirect($space->createUrl('index')); return $this->redirect($space->createUrl('index'));
} }
return $this->render('index', ['model' => $space]); return $this->render('index', ['model' => $space]);
} }
@ -52,19 +53,17 @@ class SecurityController extends Controller
Yii::$app->response->format = 'json'; Yii::$app->response->format = 'json';
$permission = $space->permissionManager->getById(Yii::$app->request->post('permissionId'), Yii::$app->request->post('moduleId')); $permission = $space->permissionManager->getById(Yii::$app->request->post('permissionId'), Yii::$app->request->post('moduleId'));
if ($permission === null) { if ($permission === null) {
throw new \yii\web\HttpException(500, 'Could not find permission!'); throw new HttpException(500, 'Could not find permission!');
} }
$space->permissionManager->setGroupState($groupId, $permission, Yii::$app->request->post('state')); $space->permissionManager->setGroupState($groupId, $permission, Yii::$app->request->post('state'));
return []; return [];
} }
return $this->render('permissions', array( return $this->render('permissions', [
'space' => $space, 'space' => $space,
'groups' => $groups, 'groups' => $groups,
'groupId' => $groupId 'groupId' => $groupId
)); ]);
} }
} }
?>

View File

@ -100,9 +100,11 @@ humhub.module('space.chooser', function (module, require, $) {
var increments = {}; var increments = {};
liveEvents.forEach(function (event) { liveEvents.forEach(function (event) {
if (event.data.uguid || event.data.originator === user.guid()) { if (event.data.uguid || event.data.originator === user.guid() || event.data.silent) {
return; return;
} else if (increments[event.data.sguid]) { }
if (increments[event.data.sguid]) {
increments[event.data.sguid]++; increments[event.data.sguid]++;
} else { } else {
increments[event.data.sguid] = 1; increments[event.data.sguid] = 1;

View File

@ -1,9 +1,15 @@
<?php <?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\space\widgets; namespace humhub\modules\space\widgets;
use Yii; use Yii;
use yii\base\Exception;
use humhub\modules\content\components\ContentContainerController; use humhub\modules\content\components\ContentContainerController;
use humhub\modules\space\models\Space; use humhub\modules\space\models\Space;
@ -27,7 +33,7 @@ class Menu extends \humhub\widgets\BaseMenu
} }
if ($this->space === null) { if ($this->space === null) {
throw new \yii\base\Exception("Could not instance space menu without space!"); throw new Exception("Could not instance space menu without space!");
} }
$this->id = 'navigation-menu-space-' . $this->space->getUniqueId(); $this->id = 'navigation-menu-space-' . $this->space->getUniqueId();
@ -44,7 +50,7 @@ class Menu extends \humhub\widgets\BaseMenu
'url' => $this->space->createUrl('/space/space/home'), 'url' => $this->space->createUrl('/space/space/home'),
'icon' => '<i class="fa fa-bars"></i>', 'icon' => '<i class="fa fa-bars"></i>',
'sortOrder' => 100, 'sortOrder' => 100,
'isActive' => (Yii::$app->controller->id == "space" && (Yii::$app->controller->action->id == "index" || Yii::$app->controller->action->id == 'home') && Yii::$app->controller->module->id == "space"), 'isActive' => (Yii::$app->controller->id == 'space' && (Yii::$app->controller->action->id == 'index' || Yii::$app->controller->action->id == 'home') && Yii::$app->controller->module->id == 'space'),
)); ));
parent::init(); parent::init();
@ -66,6 +72,7 @@ class Menu extends \humhub\widgets\BaseMenu
foreach ($moduleItems as $moduleItem) { foreach ($moduleItems as $moduleItem) {
$result[$moduleItem['url']] = $moduleItem['label']; $result[$moduleItem['url']] = $moduleItem['label'];
} }
return $result; return $result;
} }
@ -88,6 +95,7 @@ class Menu extends \humhub\widgets\BaseMenu
$settings->contentContainer($space)->delete('indexUrl'); $settings->contentContainer($space)->delete('indexUrl');
} }
} }
return null; return null;
} }
@ -110,9 +118,8 @@ class Menu extends \humhub\widgets\BaseMenu
$settings->contentContainer($space)->delete('indexGuestUrl'); $settings->contentContainer($space)->delete('indexGuestUrl');
} }
} }
return null; return null;
} }
} }
?>

View File

@ -1,9 +1,16 @@
<?php <?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\stream\models; namespace humhub\modules\stream\models;
use humhub\modules\content\models\Content; use humhub\modules\content\models\Content;
use Yii; use Yii;
use yii\base\Exception;
/** /**
* StreamSuppressQuery detects same content types in a row and trims the output. * StreamSuppressQuery detects same content types in a row and trims the output.
@ -205,7 +212,7 @@ class StreamSuppressQuery extends StreamQuery
public function getSuppressions() public function getSuppressions()
{ {
if (!$this->isQueryExecuted) { if (!$this->isQueryExecuted) {
throw new \yii\base\Exception("Execute query first via all() method before reading suppressed items."); throw new Exception('Execute query first via all() method before reading suppressed items.');
} }
$results = []; $results = [];

View File

@ -99,7 +99,7 @@ humhub.module('stream', function (module, require, $) {
var that = this; var that = this;
var stream = this.stream(); var stream = this.stream();
promise.then(function ($confirm) { promise.then(function ($confirm) {
if ($confirm) { if ($confirm) {
that.remove(); // Make sure to remove the wallentry node. that.remove(); // Make sure to remove the wallentry node.
@ -262,7 +262,6 @@ humhub.module('stream', function (module, require, $) {
that.remove().then(function () { that.remove().then(function () {
stream.loadEntry(that.getKey(), {'prepend': true}); stream.loadEntry(that.getKey(), {'prepend': true});
}); });
module.log.success('success.pin');
} else if (data.info) { } else if (data.info) {
module.log.info(data.info, true); module.log.info(data.info, true);
} else { } else {
@ -298,9 +297,8 @@ humhub.module('stream', function (module, require, $) {
StreamEntry.prototype.unpin = function (evt) { StreamEntry.prototype.unpin = function (evt) {
var that = this; var that = this;
this.loader(); this.loader();
client.post(evt.url).then(function (data) { client.post(evt.url).then(function () {
that.stream().init(); that.stream().init();
module.log.success('success.unpin');
}).catch(function (e) { }).catch(function (e) {
module.log.error(e, true); module.log.error(e, true);
that.loader(false); that.loader(false);
@ -897,7 +895,7 @@ humhub.module('stream', function (module, require, $) {
/** /**
* Simple stream component can be used for static streams without load logic (only reload single content). * Simple stream component can be used for static streams without load logic (only reload single content).
* *
* @param {type} container * @param {type} container
* @param {type} cfg * @param {type} cfg
* @returns {humhub.streamL#5.SimpleStream} * @returns {humhub.streamL#5.SimpleStream}
@ -924,7 +922,7 @@ humhub.module('stream', function (module, require, $) {
return client.get(contentModule.config.reloadUrl, {data: {id: contentId}}).then(function (response) { return client.get(contentModule.config.reloadUrl, {data: {id: contentId}}).then(function (response) {
if (response.output) { if (response.output) {
entry.replace(response.output); entry.replace(response.output);
} }
return response; return response;
}).catch(function (err) { }).catch(function (err) {
module.log.error(err, true); module.log.error(err, true);
@ -995,11 +993,11 @@ humhub.module('stream', function (module, require, $) {
/* /*
This can be used to trace the currently visible entries This can be used to trace the currently visible entries
var lastKey; var lastKey;
// Defines our base y position for changing the current entry // Defines our base y position for changing the current entry
var yLimit = scrollTop + (windowHeight / 2); var yLimit = scrollTop + (windowHeight / 2);
// Get id of current scroll item // Get id of current scroll item
//TODO: chache the entry nodes ! //TODO: chache the entry nodes !
var matchingNodes = stream.$entryCache.map(function () { var matchingNodes = stream.$entryCache.map(function () {
@ -1008,11 +1006,11 @@ humhub.module('stream', function (module, require, $) {
return $this; return $this;
} }
}); });
// Get the id of the current element // Get the id of the current element
var $current = matchingNodes[matchingNodes.length - 1]; var $current = matchingNodes[matchingNodes.length - 1];
var currentKey = $current && $current.length ? $current.data('content-key') : ""; var currentKey = $current && $current.length ? $current.data('content-key') : "";
if (lastKey !== currentKey) { if (lastKey !== currentKey) {
lastKey = currentKey; lastKey = currentKey;
// Set/remove active class // Set/remove active class
@ -1082,4 +1080,4 @@ humhub.module('stream', function (module, require, $) {
getStream: getStream, getStream: getStream,
getEntry: getEntry getEntry: getEntry
}); });
}); });

View File

@ -2396,7 +2396,7 @@ trait AcceptanceTesterActions
* *
* Wait for $timeout seconds. * Wait for $timeout seconds.
* *
* @param int $timeout secs * @param int|float $timeout secs
* @throws \Codeception\Exception\TestRuntimeException * @throws \Codeception\Exception\TestRuntimeException
* @see \Codeception\Module\WebDriver::wait() * @see \Codeception\Module\WebDriver::wait()
*/ */

View File

@ -107,23 +107,21 @@ class StreamCest
$newEntrySelector2 = '[data-content-key="14"]'; $newEntrySelector2 = '[data-content-key="14"]';
$I->waitForElementVisible($newEntrySelector2); $I->waitForElementVisible($newEntrySelector2);
$I->expectTo('my new post beeing the latest entry'); $I->expectTo('my new post beeing the latest entry');
$I->see('This is my second stream test post', '.s2_streamContent div:nth-child(1)'); $I->waitForText('This is my second stream test post',null, '.s2_streamContent div:nth-child(1)');
$I->amGoingTo('pin my first entry'); $I->amGoingTo('pin my first entry');
$I->click('.preferences .dropdown-toggle', $newEntrySelector); $I->click('.preferences .dropdown-toggle', $newEntrySelector);
$I->waitForText('Pin', 10); $I->waitForText('Pin', 10);
$I->click('Pin', $newEntrySelector); $I->click('Pin', $newEntrySelector);
$I->seeSuccess('The content has been pinned.');
$I->see('This is my first stream test post!', '.s2_streamContent div:nth-child(1)'); $I->waitForText('This is my first stream test post!',null, '.s2_streamContent div:nth-child(1)');
$I->see('Pinned', $newEntrySelector); $I->see('Pinned', $newEntrySelector);
$I->amGoingTo('unpin my first entry'); $I->amGoingTo('unpin my first entry');
$I->click('.preferences .dropdown-toggle', $newEntrySelector); $I->click('.preferences .dropdown-toggle', $newEntrySelector);
$I->waitForText('Unpin', 10); $I->waitForText('Unpin', 10);
$I->click('Unpin', $newEntrySelector); $I->click('Unpin', $newEntrySelector);
$I->seeSuccess('The content has been unpinned.'); $I->waitForText('This is my second stream test post!',null, '.s2_streamContent div:nth-child(1)');
$I->see('This is my second stream test post!', '.s2_streamContent div:nth-child(1)');
$I->dontSee('Pinned', $newEntrySelector); $I->dontSee('Pinned', $newEntrySelector);
} }
@ -145,7 +143,7 @@ class StreamCest
$I->click('.preferences .dropdown-toggle', $newEntrySelector); $I->click('.preferences .dropdown-toggle', $newEntrySelector);
$I->waitForText('Edit', 10); $I->waitForText('Edit', 10);
$I->click('Edit', $newEntrySelector); $I->click('Edit', $newEntrySelector);
$I->waitForElementVisible($newEntrySelector . ' .content_edit', 20); $I->waitForElementVisible($newEntrySelector . ' .content_edit', 20);
$I->amGoingTo('cancel my edit'); $I->amGoingTo('cancel my edit');
$I->click('.preferences .dropdown-toggle', $newEntrySelector); $I->click('.preferences .dropdown-toggle', $newEntrySelector);
@ -154,43 +152,43 @@ class StreamCest
$I->waitForElementNotVisible($newEntrySelector . ' .content_edit', 20); $I->waitForElementNotVisible($newEntrySelector . ' .content_edit', 20);
$I->waitForElementVisible($newEntrySelector . ' .content', 20); $I->waitForElementVisible($newEntrySelector . ' .content', 20);
$I->see('This is my first stream test post!', $newEntrySelector); $I->see('This is my first stream test post!', $newEntrySelector);
$I->amGoingTo('edit my new post'); $I->amGoingTo('edit my new post');
$I->click('.preferences .dropdown-toggle', $newEntrySelector); $I->click('.preferences .dropdown-toggle', $newEntrySelector);
$I->waitForText('Edit', 10); $I->waitForText('Edit', 10);
$I->click('Edit', $newEntrySelector); $I->click('Edit', $newEntrySelector);
$I->waitForElementVisible($newEntrySelector . ' .content_edit', 20); $I->waitForElementVisible($newEntrySelector . ' .content_edit', 20);
$I->fillField($newEntrySelector . ' [contenteditable]', 'This is my edited post!'); $I->fillField($newEntrySelector . ' [contenteditable]', 'This is my edited post!');
$I->click('Save', $newEntrySelector); $I->click('Save', $newEntrySelector);
$I->seeSuccess('Saved'); $I->seeSuccess('Saved');
$I->seeElement($newEntrySelector); $I->seeElement($newEntrySelector);
$I->see('This is my edited post!', $newEntrySelector); $I->see('This is my edited post!', $newEntrySelector);
} }
public function testEmptyStream(AcceptanceTester $I) public function testEmptyStream(AcceptanceTester $I)
{ {
$I->amUser(); $I->amUser();
$I->amOnSpace3(); $I->amOnSpace3();
$I->wantToTest('the empty stream message and filter'); $I->wantToTest('the empty stream message and filter');
$I->waitForText('This space is still empty!'); $I->waitForText('This space is still empty!');
$I->dontSeeElement('#filter'); $I->dontSeeElement('#filter');
$I->amGoingTo('create a new post and delete it afterwards'); $I->amGoingTo('create a new post and delete it afterwards');
$I->createPost('This is my first stream test post!'); $I->createPost('This is my first stream test post!');
$I->wait(1); $I->wait(1);
$I->amGoingTo('Delete my new post again.'); $I->amGoingTo('Delete my new post again.');
$I->dontSee('This space is still empty!'); $I->dontSee('This space is still empty!');
$I->seeElement('#filter'); $I->seeElement('#filter');
$I->click('.preferences .dropdown-toggle', '[data-stream-entry]:nth-of-type(1)'); $I->click('.preferences .dropdown-toggle', '[data-stream-entry]:nth-of-type(1)');
$I->wait(1); $I->wait(1);
$I->click('Delete'); $I->click('Delete');
$I->waitForElementVisible('#globalModalConfirm', 5); $I->waitForElementVisible('#globalModalConfirm', 5);
$I->see('Confirm post deletion'); $I->see('Confirm post deletion');
$I->click('Delete', '#globalModalConfirm'); $I->click('Delete', '#globalModalConfirm');
@ -199,7 +197,7 @@ class StreamCest
$I->see('This space is still empty!'); $I->see('This space is still empty!');
$I->dontSeeElement('#filter'); $I->dontSeeElement('#filter');
} }
public function testFilterInvolved(AcceptanceTester $I) public function testFilterInvolved(AcceptanceTester $I)
{ {
$I->amUser(); $I->amUser();
@ -209,25 +207,26 @@ class StreamCest
$I->waitForElementVisible('#filter_entry_userinvolved'); $I->waitForElementVisible('#filter_entry_userinvolved');
$I->click('#filter_entry_userinvolved'); $I->click('#filter_entry_userinvolved');
$I->waitForText('No matches with your selected filters!'); $I->waitForText('No matches with your selected filters!');
$I->createPost('Involved Post.'); $I->createPost('Involved Post.');
$I->wait(1);
$I->dontSee('No matches with your selected filters!'); $I->dontSee('No matches with your selected filters!');
$I->amGoingTo('Reset filter'); $I->amGoingTo('Reset filter');
$I->click('.stream-filter', '#filter'); $I->click('.stream-filter', '#filter');
$I->waitForElementVisible('#filter_entry_userinvolved'); $I->waitForElementVisible('#filter_entry_userinvolved');
$I->click('#filter_entry_userinvolved'); $I->click('#filter_entry_userinvolved');
$I->waitForElementVisible('[data-content-key="10"]'); $I->waitForElementVisible('[data-content-key="10"]');
$I->click('Comment', '[data-content-key="10"]'); $I->click('Comment', '[data-content-key="10"]');
$I->waitForElementVisible('#newCommentForm_humhubmodulespostmodelsPost_10'); $I->waitForElementVisible('#newCommentForm_humhubmodulespostmodelsPost_10');
$I->fillField('#newCommentForm_humhubmodulespostmodelsPost_10', 'My Comment'); $I->fillField('#newCommentForm_humhubmodulespostmodelsPost_10', 'My Comment');
$I->click('Send', '#comment_create_form_humhubmodulespostmodelsPost_10'); $I->click('Send', '#comment_create_form_humhubmodulespostmodelsPost_10');
$I->waitForText('My Comment', 30, '#comment_humhubmodulespostmodelsPost_10 .comment'); $I->waitForText('My Comment', 30, '#comment_humhubmodulespostmodelsPost_10 .comment');
$I->click('Like', '[data-content-key="11"]'); $I->click('Like', '[data-content-key="11"]');
$I->click('.stream-filter', '#filter'); $I->click('.stream-filter', '#filter');
$I->waitForElementVisible('#filter_entry_userinvolved'); $I->waitForElementVisible('#filter_entry_userinvolved');
$I->click('#filter_entry_userinvolved'); $I->click('#filter_entry_userinvolved');
@ -267,15 +266,15 @@ class StreamCest
$I->click('Comment', $post4Selector); $I->click('Comment', $post4Selector);
$I->fillField($post4Selector . ' [contenteditable]', 'My Comment!'); $I->fillField($post4Selector . ' [contenteditable]', 'My Comment!');
$I->click('Send', $post4Selector . ' .comment-buttons'); $I->click('Send', $post4Selector . ' .comment-buttons');
$I->scrollTop(); $I->scrollTop();
$I->click('.stream-sorting', '#filter'); $I->click('.stream-sorting', '#filter');
$I->waitForElementVisible('#sorting_u'); $I->waitForElementVisible('#sorting_u');
$I->click('#sorting_u'); $I->click('#sorting_u');
$I->wait(2); $I->wait(2);
$I->waitForElementVisible($post4Selector); $I->waitForElementVisible($post4Selector);
$I->see('POST4', '.s2_streamContent > [data-stream-entry]:nth-of-type(1)'); $I->see('POST4', '.s2_streamContent > [data-stream-entry]:nth-of-type(1)');
$I->see('POST5', '.s2_streamContent > [data-stream-entry]:nth-of-type(2)'); $I->see('POST5', '.s2_streamContent > [data-stream-entry]:nth-of-type(2)');
$I->see('POST3', '.s2_streamContent > [data-stream-entry]:nth-of-type(3)'); $I->see('POST3', '.s2_streamContent > [data-stream-entry]:nth-of-type(3)');

View File

@ -2,17 +2,21 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\user\controllers; namespace humhub\modules\user\controllers;
use humhub\modules\admin\permissions\ManageGroups;
use humhub\modules\admin\permissions\ManageUsers;
use Yii; use Yii;
use yii\web\Controller; use yii\web\Controller;
use yii\web\HttpException;
use humhub\components\behaviors\AccessControl;
use humhub\modules\admin\permissions\ManageGroups;
use humhub\modules\admin\permissions\ManageUsers;
use humhub\modules\user\models\Invite; use humhub\modules\user\models\Invite;
use humhub\modules\user\models\forms\Invite as InviteForm;
use humhub\widgets\ModalClose;
/** /**
* InviteController for new user invites * InviteController for new user invites
@ -29,7 +33,7 @@ class InviteController extends Controller
{ {
return [ return [
'acl' => [ 'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(), 'class' => AccessControl::className(),
] ]
]; ];
} }
@ -43,22 +47,22 @@ class InviteController extends Controller
public function actionIndex() public function actionIndex()
{ {
if (!$this->canInvite()) { if (!$this->canInvite()) {
throw new \yii\web\HttpException(403, 'Invite denied!'); throw new HttpException(403, 'Invite denied!');
} }
$model = new \humhub\modules\user\models\forms\Invite; $model = new InviteForm;
if ($model->load(Yii::$app->request->post()) && $model->validate()) { if ($model->load(Yii::$app->request->post()) && $model->validate()) {
foreach ($model->getEmails() as $email) { foreach ($model->getEmails() as $email) {
$this->createInvite($email); $this->createInvite($email);
} }
return \humhub\widgets\ModalClose::widget([ return ModalClose::widget([
'success' => Yii::t('UserModule.user', 'User has been invited.') 'success' => Yii::t('UserModule.user', 'User has been invited.')
]); ]);
} }
return $this->renderAjax('index', array('model' => $model)); return $this->renderAjax('index', ['model' => $model]);
} }
/** /**
@ -94,5 +98,3 @@ class InviteController extends Controller
} }
} }
?>

View File

@ -2,17 +2,24 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\user\controllers; namespace humhub\modules\user\controllers;
use Yii; use Yii;
use yii\web\HttpException;
use yii\db\Expression;
use humhub\modules\content\components\ContentContainerController; use humhub\modules\content\components\ContentContainerController;
use humhub\modules\stream\actions\ContentContainerStream; use humhub\modules\stream\actions\ContentContainerStream;
use humhub\modules\user\models\User; use humhub\modules\user\models\User;
use humhub\modules\user\widgets\UserListBox; use humhub\modules\user\widgets\UserListBox;
use humhub\modules\space\widgets\ListBox;
use humhub\components\behaviors\AccessControl;
use humhub\modules\user\permissions\ViewAboutPage;
use humhub\modules\space\models\Membership;
use humhub\modules\space\models\Space;
/** /**
* ProfileController is responsible for all user profiles. * ProfileController is responsible for all user profiles.
@ -32,7 +39,7 @@ class ProfileController extends ContentContainerController
{ {
return [ return [
'acl' => [ 'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(), 'class' => AccessControl::className(),
'guestAllowedActions' => ['index', 'stream', 'about'] 'guestAllowedActions' => ['index', 'stream', 'about']
] ]
]; ];
@ -43,13 +50,13 @@ class ProfileController extends ContentContainerController
*/ */
public function actions() public function actions()
{ {
return array( return [
'stream' => array( 'stream' => [
'class' => ContentContainerStream::className(), 'class' => ContentContainerStream::className(),
'mode' => ContentContainerStream::MODE_NORMAL, 'mode' => ContentContainerStream::MODE_NORMAL,
'contentContainer' => $this->contentContainer 'contentContainer' => $this->contentContainer
), ],
); ];
} }
/** /**
@ -74,8 +81,8 @@ class ProfileController extends ContentContainerController
public function actionAbout() public function actionAbout()
{ {
if (!$this->contentContainer->permissionManager->can(new \humhub\modules\user\permissions\ViewAboutPage())) { if (!$this->contentContainer->permissionManager->can(new ViewAboutPage())) {
throw new \yii\web\HttpException(403, 'Forbidden'); throw new HttpException(403, 'Forbidden');
} }
return $this->render('about', ['user' => $this->contentContainer]); return $this->render('about', ['user' => $this->contentContainer]);
@ -84,7 +91,7 @@ class ProfileController extends ContentContainerController
public function actionFollow() public function actionFollow()
{ {
if(Yii::$app->getModule('user')->disableFollow) { if(Yii::$app->getModule('user')->disableFollow) {
throw new \yii\web\HttpException(403, Yii::t('ContentModule.controllers_ContentController', 'This action is disabled!')); throw new HttpException(403, Yii::t('ContentModule.controllers_ContentController', 'This action is disabled!'));
} }
$this->forcePostRequest(); $this->forcePostRequest();
@ -114,21 +121,22 @@ class ProfileController extends ContentContainerController
public function actionFollowerList() public function actionFollowerList()
{ {
$query = User::find(); $query = User::find();
$query->leftJoin('user_follow', 'user.id=user_follow.user_id and object_model=:userClass and user_follow.object_id=:userId', [':userClass' => User::className(), ':userId' => $this->getUser()->id]); $query->leftJoin('user_follow', 'user.id=user_follow.user_id AND object_model=:userClass AND user_follow.object_id=:userId', [':userClass' => User::className(), ':userId' => $this->getUser()->id]);
$query->orderBy(['user_follow.id' => SORT_DESC]); $query->orderBy(['user_follow.id' => SORT_DESC]);
$query->andWhere(['IS NOT', 'user_follow.id', new \yii\db\Expression('NULL')]); $query->andWhere(['IS NOT', 'user_follow.id', new Expression('NULL')]);
$query->active(); $query->active();
$title = Yii::t('UserModule.widgets_views_userFollower', '<strong>User</strong> followers'); $title = Yii::t('UserModule.widgets_views_userFollower', '<strong>User</strong> followers');
return $this->renderAjaxContent(UserListBox::widget(['query' => $query, 'title' => $title])); return $this->renderAjaxContent(UserListBox::widget(['query' => $query, 'title' => $title]));
} }
public function actionFollowedUsersList() public function actionFollowedUsersList()
{ {
$query = User::find(); $query = User::find();
$query->leftJoin('user_follow', 'user.id=user_follow.object_id and object_model=:userClass and user_follow.user_id=:userId', [':userClass' => User::className(), ':userId' => $this->getUser()->id]); $query->leftJoin('user_follow', 'user.id=user_follow.object_id AND object_model=:userClass AND user_follow.user_id=:userId', [':userClass' => User::className(), ':userId' => $this->getUser()->id]);
$query->orderBy(['user_follow.id' => SORT_DESC]); $query->orderBy(['user_follow.id' => SORT_DESC]);
$query->andWhere(['IS NOT', 'user_follow.id', new \yii\db\Expression('NULL')]); $query->andWhere(['IS NOT', 'user_follow.id', new Expression('NULL')]);
$query->active(); $query->active();
$title = Yii::t('UserModule.widgets_views_userFollower', '<strong>Following</strong> user'); $title = Yii::t('UserModule.widgets_views_userFollower', '<strong>Following</strong> user');
@ -137,16 +145,14 @@ class ProfileController extends ContentContainerController
public function actionSpaceMembershipList() public function actionSpaceMembershipList()
{ {
$query = \humhub\modules\space\models\Membership::getUserSpaceQuery($this->getUser()); $query = Membership::getUserSpaceQuery($this->getUser());
if (!$this->getUser()->isCurrentUser()) { if (!$this->getUser()->isCurrentUser()) {
$query->andWhere(['!=', 'space.visibility', \humhub\modules\space\models\Space::VISIBILITY_NONE]); $query->andWhere(['!=', 'space.visibility', Space::VISIBILITY_NONE]);
} }
$title = Yii::t('UserModule.widgets_views_userSpaces', '<strong>Member</strong> in these spaces'); $title = Yii::t('UserModule.widgets_views_userSpaces', '<strong>Member</strong> in these spaces');
return $this->renderAjaxContent(\humhub\modules\space\widgets\ListBox::widget(['query' => $query, 'title' => $title])); return $this->renderAjaxContent(ListBox::widget(['query' => $query, 'title' => $title]));
} }
} }
?>

View File

@ -1,12 +1,15 @@
<?php <?php
use yii\db\Schema; use yii\db\Schema;
use yii\db\Query;
use yii\db\Expression;
use humhub\components\Migration;
class m160229_162959_multiusergroups extends \humhub\components\Migration class m160229_162959_multiusergroups extends Migration
{ {
public function up() public function up()
{ {
$this->createTable('group_user', array( $this->createTable('group_user', [
'id' => 'pk', 'id' => 'pk',
'user_id' => 'int(11) NOT NULL', 'user_id' => 'int(11) NOT NULL',
'group_id' => 'int(11) NOT NULL', 'group_id' => 'int(11) NOT NULL',
@ -15,53 +18,53 @@ class m160229_162959_multiusergroups extends \humhub\components\Migration
'created_by' => 'int(11) DEFAULT NULL', 'created_by' => 'int(11) DEFAULT NULL',
'updated_at' => 'datetime DEFAULT NULL', 'updated_at' => 'datetime DEFAULT NULL',
'updated_by' => 'int(11) DEFAULT NULL', 'updated_by' => 'int(11) DEFAULT NULL',
), ''); ], '');
//Add indexes and foreign keys // Add indexes and foreign keys
$this->createIndex('idx-group_user', 'group_user', ['user_id', 'group_id'], true); $this->createIndex('idx-group_user', 'group_user', ['user_id', 'group_id'], true);
$this->addForeignKey('fk-user-group', 'group_user', 'user_id', 'user', 'id', 'CASCADE'); $this->addForeignKey('fk-user-group', 'group_user', 'user_id', 'user', 'id', 'CASCADE');
$this->addForeignKey('fk-group-group', 'group_user', 'group_id', '`group`', 'id', 'CASCADE'); $this->addForeignKey('fk-group-group', 'group_user', 'group_id', '`group`', 'id', 'CASCADE');
//Merge old group user and group admins // Merge old group user and group admins
$this->execute('INSERT INTO group_user (user_id, group_id) SELECT DISTINCT user.id, user.group_id FROM user LEFT JOIN `group` ON user.group_id=group.id WHERE group.id IS NOT NULL'); $this->execute('INSERT INTO group_user (user_id, group_id) SELECT DISTINCT user.id, user.group_id FROM user LEFT JOIN `group` ON user.group_id=group.id WHERE group.id IS NOT NULL');
$this->execute('UPDATE group_user u SET is_group_admin = :value WHERE EXISTS (Select 1 FROM group_admin a WHERE u.user_id = a.user_id);', [':value' => 1]); $this->execute('UPDATE group_user u SET is_group_admin = :value WHERE EXISTS (Select 1 FROM group_admin a WHERE u.user_id = a.user_id);', [':value' => 1]);
//Add group columns // Add group columns
$this->addColumn('group', 'is_admin_group', Schema::TYPE_BOOLEAN. ' NOT NULL DEFAULT 0'); $this->addColumn('group', 'is_admin_group', Schema::TYPE_BOOLEAN. ' NOT NULL DEFAULT 0');
$this->addColumn('group', 'show_at_registration', Schema::TYPE_BOOLEAN. ' NOT NULL DEFAULT 1'); $this->addColumn('group', 'show_at_registration', Schema::TYPE_BOOLEAN. ' NOT NULL DEFAULT 1');
$this->addColumn('group', 'show_at_directory', Schema::TYPE_BOOLEAN. ' NOT NULL DEFAULT 1'); $this->addColumn('group', 'show_at_directory', Schema::TYPE_BOOLEAN. ' NOT NULL DEFAULT 1');
//Create initial administration group // Create initial administration group
$this->insertSilent('group', [ $this->insertSilent('group', [
'name' => 'Administrator', 'name' => 'Administrator',
'description' => 'Administrator Group', 'description' => 'Administrator Group',
'is_admin_group' => '1', 'is_admin_group' => '1',
'show_at_registration' => '0', 'show_at_registration' => '0',
'show_at_directory' => '0', 'show_at_directory' => '0',
'created_at' => new \yii\db\Expression('NOW()') 'created_at' => new Expression('NOW()')
]); ]);
//Determine administration group id // Determine administration group id
$adminGroupId = (new \yii\db\Query()) $adminGroupId = (new Query())
->select('id') ->select('id')
->from('group') ->from('group')
->where(['is_admin_group' => '1']) ->where(['is_admin_group' => '1'])
->scalar(); ->scalar();
//Load current super_admin user // Load current super_admin user
$rows = (new \yii\db\Query()) $rows = (new Query())
->select("id") ->select("id")
->from('user') ->from('user')
->where(['super_admin' => '1']) ->where(['super_admin' => '1'])
->all(); ->all();
//Insert group_user for administartion groups for all current super_admins // Insert group_user for administration groups for all current super_admins
foreach($rows as $adminUserRow) { foreach ($rows as $adminUserRow) {
$this->insertSilent('group_user', ['user_id' => $adminUserRow['id'], 'group_id' => $adminGroupId, 'is_group_admin' => '1']); $this->insertSilent('group_user', ['user_id' => $adminUserRow['id'], 'group_id' => $adminGroupId, 'is_group_admin' => '1']);
} }
//$this->insertSilent('group_permission', ['permission_id' => 'user_admin', 'group_id' => $adminGroupId, 'module_id' => 'user', 'class' => 'humhub\modules\user\permissions']); //$this->insertSilent('group_permission', ['permission_id' => 'user_admin', 'group_id' => $adminGroupId, 'module_id' => 'user', 'class' => 'humhub\modules\user\permissions']);
$this->dropTable('group_admin'); $this->dropTable('group_admin');
$this->dropColumn('user', 'super_admin'); $this->dropColumn('user', 'super_admin');
$this->dropColumn('user', 'group_id'); $this->dropColumn('user', 'group_id');

View File

@ -2,13 +2,17 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\user\models; namespace humhub\modules\user\models;
use Yii; use Yii;
use yii\db\ActiveRecord;
use yii\base\Exception;
use yii\db\Expression;
use humhub\libs\UUID;
use humhub\modules\user\components\CheckPasswordValidator; use humhub\modules\user\components\CheckPasswordValidator;
/** /**
@ -21,7 +25,7 @@ use humhub\modules\user\components\CheckPasswordValidator;
* @property string $salt * @property string $salt
* @property string $created_at * @property string $created_at
*/ */
class Password extends \yii\db\ActiveRecord class Password extends ActiveRecord
{ {
/** /**
@ -30,13 +34,13 @@ class Password extends \yii\db\ActiveRecord
public $currentPassword; public $currentPassword;
public $newPassword; public $newPassword;
public $newPasswordConfirm; public $newPasswordConfirm;
public $defaultAlgorithm = ""; public $defaultAlgorithm = '';
public function init() public function init()
{ {
parent::init(); parent::init();
$this->defaultAlgorithm = "sha1md5"; $this->defaultAlgorithm = 'sha1md5';
if (function_exists('hash_algos')) { if (function_exists('hash_algos')) {
$algos = hash_algos(); $algos = hash_algos();
@ -50,7 +54,8 @@ class Password extends \yii\db\ActiveRecord
public function beforeSave($insert) public function beforeSave($insert)
{ {
$this->created_at = new \yii\db\Expression("NOW()"); $this->created_at = new Expression('NOW()');
return parent::beforeSave($insert); return parent::beforeSave($insert);
} }
@ -92,7 +97,7 @@ class Password extends \yii\db\ActiveRecord
public function unequalsCurrentPassword($attribute, $params) public function unequalsCurrentPassword($attribute, $params)
{ {
if($this->newPassword === $this->currentPassword) { if($this->newPassword === $this->currentPassword) {
$this->addError($attribute, Yii::t('UserModule.base', 'Your new password must not equal your current password!')); $this->addError($attribute, Yii::t('UserModule.base', 'Your new password must not be equal your current password!'));
} }
} }
@ -106,6 +111,7 @@ class Password extends \yii\db\ActiveRecord
} }
$scenarios['registration'] = ['newPassword', 'newPasswordConfirm']; $scenarios['registration'] = ['newPassword', 'newPasswordConfirm'];
return $scenarios; return $scenarios;
} }
@ -162,7 +168,7 @@ class Password extends \yii\db\ActiveRecord
} elseif ($this->algorithm == 'sha512') { } elseif ($this->algorithm == 'sha512') {
return hash('sha512', $password); return hash('sha512', $password);
} else { } else {
throw new \yii\base\Exception("Invalid Hashing Algorithm!"); throw new Exception('Invalid Hashing Algorithm!');
} }
} }
@ -173,7 +179,7 @@ class Password extends \yii\db\ActiveRecord
*/ */
public function setPassword($newPassword) public function setPassword($newPassword)
{ {
$this->salt = \humhub\libs\UUID::v4(); $this->salt = UUID::v4();
$this->algorithm = $this->defaultAlgorithm; $this->algorithm = $this->defaultAlgorithm;
$this->password = $this->hashPassword($newPassword); $this->password = $this->hashPassword($newPassword);
} }

View File

@ -2,13 +2,18 @@
/** /**
* @link https://www.humhub.org/ * @link https://www.humhub.org/
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG * @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences * @license https://www.humhub.com/licences
*/ */
namespace humhub\modules\user\models\fieldtype; namespace humhub\modules\user\models\fieldtype;
use Yii; use Yii;
use yii\base\Model;
use yii\base\Exception;
use yii\helpers\Json;
use yii\helpers\Html;
use humhub\libs\Helpers;
use humhub\modules\user\models\Profile; use humhub\modules\user\models\Profile;
/** /**
@ -17,7 +22,7 @@ use humhub\modules\user\models\Profile;
* @package humhub.modules_core.user.models * @package humhub.modules_core.user.models
* @since 0.5 * @since 0.5
*/ */
class BaseType extends \yii\base\Model class BaseType extends Model
{ {
/** /**
@ -28,7 +33,7 @@ class BaseType extends \yii\base\Model
* *
* @var Array * @var Array
*/ */
public $fieldTypes = array(); public $fieldTypes = [];
/** /**
* Corresponding ProfileField Model * Corresponding ProfileField Model
@ -73,7 +78,7 @@ class BaseType extends \yii\base\Model
*/ */
public function getFieldTypes() public function getFieldTypes()
{ {
$fieldTypes = array_merge(array( $fieldTypes = array_merge([
Number::className() => Yii::t('UserModule.models_ProfileFieldType', 'Number'), Number::className() => Yii::t('UserModule.models_ProfileFieldType', 'Number'),
Text::className() => Yii::t('UserModule.models_ProfileFieldType', 'Text'), Text::className() => Yii::t('UserModule.models_ProfileFieldType', 'Text'),
TextArea::className() => Yii::t('UserModule.models_ProfileFieldType', 'Text Area'), TextArea::className() => Yii::t('UserModule.models_ProfileFieldType', 'Text Area'),
@ -85,7 +90,8 @@ class BaseType extends \yii\base\Model
MarkdownEditor::className() => Yii::t('UserModule.models_ProfileFieldType', 'Markdown'), MarkdownEditor::className() => Yii::t('UserModule.models_ProfileFieldType', 'Markdown'),
Checkbox::className() => Yii::t('UserModule.models_ProfileFieldType', 'Checkbox'), Checkbox::className() => Yii::t('UserModule.models_ProfileFieldType', 'Checkbox'),
CheckboxList::className() => Yii::t('UserModule.models_ProfileFieldType', 'Checkbox List'), CheckboxList::className() => Yii::t('UserModule.models_ProfileFieldType', 'Checkbox List'),
), $this->fieldTypes); ], $this->fieldTypes);
return $fieldTypes; return $fieldTypes;
} }
@ -97,14 +103,13 @@ class BaseType extends \yii\base\Model
public function getTypeInstances($profileField = null) public function getTypeInstances($profileField = null)
{ {
$types = array(); $types = [];
foreach ($this->getFieldTypes() as $className => $title) { foreach ($this->getFieldTypes() as $className => $title) {
if (\humhub\libs\Helpers::CheckClassType($className, self::className())) { if (Helpers::CheckClassType($className, self::className())) {
$instance = new $className; $instance = new $className;
if ($profileField != null) { if ($profileField != null) {
$instance->profileField = $profileField; $instance->profileField = $profileField;
// Seems current type, so try load data // Seems current type, so try load data
if ($profileField->field_type_class == $className) { if ($profileField->field_type_class == $className) {
$instance->loadFieldConfig(); $instance->loadFieldConfig();
@ -113,6 +118,7 @@ class BaseType extends \yii\base\Model
$types[] = $instance; $types[] = $instance;
} }
} }
return $types; return $types;
} }
@ -122,11 +128,11 @@ class BaseType extends \yii\base\Model
public function getFieldFormDefinition() public function getFieldFormDefinition()
{ {
$definition = array($this->profileField->internal_name => [ $definition = [$this->profileField->internal_name => [
'type' => 'text', 'type' => 'text',
'class' => 'form-control', 'class' => 'form-control',
'readonly' => (!$this->profileField->editable) 'readonly' => (!$this->profileField->editable)
]); ]];
return $definition; return $definition;
} }
@ -139,10 +145,11 @@ class BaseType extends \yii\base\Model
* @param type $definition * @param type $definition
* @return Array of Form Definition * @return Array of Form Definition
*/ */
public function getFormDefinition($definition = array()) public function getFormDefinition($definition = [])
{ {
$definition[get_class($this)]['class'] = "fieldTypeSettings " . str_replace("\\", "_", get_class($this)); $definition[get_class($this)]['class'] = "fieldTypeSettings " . str_replace("\\", "_", get_class($this));
return $definition; return $definition;
} }
@ -179,7 +186,7 @@ class BaseType extends \yii\base\Model
public function save() public function save()
{ {
$data = array(); $data = [];
foreach ($this->attributes as $attributeName => $value) { foreach ($this->attributes as $attributeName => $value) {
// Dont save profile field attribute // Dont save profile field attribute
@ -188,13 +195,13 @@ class BaseType extends \yii\base\Model
$data[$attributeName] = $this->$attributeName; $data[$attributeName] = $this->$attributeName;
} }
$this->profileField->field_type_config = \yii\helpers\Json::encode($data); $this->profileField->field_type_config = Json::encode($data);
if (!$this->profileField->save()) { if (!$this->profileField->save()) {
throw new \yii\base\Exception("Could not save profile field!"); throw new Exception("Could not save profile field!");
} }
// Clear Database Schema // Clear Database Schema
Yii::$app->getDb()->getSchema()->getTableSchema(\humhub\modules\user\models\Profile::tableName(), true); Yii::$app->getDb()->getSchema()->getTableSchema(Profile::tableName(), true);
return true; return true;
} }
@ -210,7 +217,7 @@ class BaseType extends \yii\base\Model
return; return;
} }
$config = \yii\helpers\Json::decode($this->profileField->field_type_config); $config = Json::decode($this->profileField->field_type_config);
if (is_array($config)) { if (is_array($config)) {
foreach ($config as $key => $value) { foreach ($config as $key => $value) {
if (property_exists($this, $key)) if (property_exists($this, $key))
@ -225,8 +232,8 @@ class BaseType extends \yii\base\Model
public function delete() public function delete()
{ {
$columnName = $this->profileField->internal_name; $columnName = $this->profileField->internal_name;
if (\humhub\modules\user\models\Profile::columnExists($columnName)) { if (Profile::columnExists($columnName)) {
$query = Yii::$app->db->getQueryBuilder()->dropColumn(\humhub\modules\user\models\Profile::tableName(), $this->profileField->internal_name); $query = Yii::$app->db->getQueryBuilder()->dropColumn(Profile::tableName(), $this->profileField->internal_name);
Yii::$app->db->createCommand($query)->execute(); Yii::$app->db->createCommand($query)->execute();
} else { } else {
Yii::error('Could not delete profile column - not exists!'); Yii::error('Could not delete profile column - not exists!');
@ -250,12 +257,11 @@ class BaseType extends \yii\base\Model
* @param type $rules * @param type $rules
* @return Array rules * @return Array rules
*/ */
public function getFieldRules($rules = array()) public function getFieldRules($rules = [])
{ {
if ($this->profileField->required) if ($this->profileField->required)
$rules[] = array($this->profileField->internal_name, 'required'); $rules[] = [$this->profileField->internal_name, 'required'];
return $rules; return $rules;
} }
@ -274,14 +280,15 @@ class BaseType extends \yii\base\Model
if ($raw) { if ($raw) {
return $user->profile->$internalName; return $user->profile->$internalName;
} else { } else {
return \yii\helpers\Html::encode($user->profile->$internalName); return Html::encode($user->profile->$internalName);
} }
} }
public function getLabels() public function getLabels()
{ {
$labels = array(); $labels = [];
$labels[$this->profileField->internal_name] = Yii::t($this->profileField->getTranslationCategory(), $this->profileField->title); $labels[$this->profileField->internal_name] = Yii::t($this->profileField->getTranslationCategory(), $this->profileField->title);
return $labels; return $labels;
} }
@ -298,7 +305,7 @@ class BaseType extends \yii\base\Model
*/ */
public function beforeProfileSave($value) public function beforeProfileSave($value)
{ {
if ($value == "") { if ($value == '') {
return null; return null;
} }
@ -312,7 +319,6 @@ class BaseType extends \yii\base\Model
*/ */
public function loadDefaults(Profile $profile) public function loadDefaults(Profile $profile)
{ {
} }
} }

View File

@ -23,7 +23,7 @@ use humhub\components\access\StrictAccess;
use tests\codeception\_support\HumHubDbTestCase; use tests\codeception\_support\HumHubDbTestCase;
use Yii; use Yii;
class ControllerAccessTest extends HumHubDbTestCase class TestControllerAccess extends HumHubDbTestCase
{ {
public $fixtureConfig = ['default']; public $fixtureConfig = ['default'];

View File

@ -178,8 +178,6 @@ class CoreJsConfig extends Widget
'text' => [ 'text' => [
'success.archive' => Yii::t('ContentModule.widgets_views_stream', 'The content has been archived.'), 'success.archive' => Yii::t('ContentModule.widgets_views_stream', 'The content has been archived.'),
'success.unarchive' => Yii::t('ContentModule.widgets_views_stream', 'The content has been unarchived.'), 'success.unarchive' => Yii::t('ContentModule.widgets_views_stream', 'The content has been unarchived.'),
'success.pin' => Yii::t('ContentModule.widgets_views_stream', 'The content has been pinned.'),
'success.unpin' => Yii::t('ContentModule.widgets_views_stream', 'The content has been unpinned.'),
'success.delete' => Yii::t('ContentModule.widgets_views_stream', 'The content has been deleted.'), 'success.delete' => Yii::t('ContentModule.widgets_views_stream', 'The content has been deleted.'),
'info.editCancel' => Yii::t('ContentModule.widgets_views_stream', 'Your last edit state has been saved!'), 'info.editCancel' => Yii::t('ContentModule.widgets_views_stream', 'Your last edit state has been saved!'),
] ]

View File

@ -100,9 +100,11 @@ humhub.module('space.chooser', function (module, require, $) {
var increments = {}; var increments = {};
liveEvents.forEach(function (event) { liveEvents.forEach(function (event) {
if (event.data.uguid || event.data.originator === user.guid()) { if (event.data.uguid || event.data.originator === user.guid() || event.data.silent) {
return; return;
} else if (increments[event.data.sguid]) { }
if (increments[event.data.sguid]) {
increments[event.data.sguid]++; increments[event.data.sguid]++;
} else { } else {
increments[event.data.sguid] = 1; increments[event.data.sguid] = 1;

View File

@ -1,5 +1,4 @@
{ {
"name": "App",
"icons": [ "icons": [
{ {
"src": "\/android-icon-36x36.png", "src": "\/android-icon-36x36.png",

View File

@ -1,6 +1,11 @@
<link href="<?= $this->theme->getBaseUrl(); ?>/css/theme.css" rel="stylesheet"> <link href="<?= $this->theme->getBaseUrl(); ?>/css/theme.css" rel="stylesheet">
<link href="<?= $this->theme->getBaseUrl(); ?>/font/open_sans/open-sans.css" rel="stylesheet"> <link href="<?= $this->theme->getBaseUrl(); ?>/font/open_sans/open-sans.css" rel="stylesheet">
<!-- start: Web App Data-->
<link rel="manifest" href="<?= $this->theme->getBaseUrl(); ?>/ico/manifest.json">
<meta name="application-name" content="<?= \yii\helpers\Html::encode(Yii::$app->name) ?>">
<!-- end: Web App Data-->
<!-- start: Favicon and Touch Icons --> <!-- start: Favicon and Touch Icons -->
<link rel="apple-touch-icon" sizes="57x57" href="<?= $this->theme->getBaseUrl(); ?>/ico/apple-icon-57x57.png"> <link rel="apple-touch-icon" sizes="57x57" href="<?= $this->theme->getBaseUrl(); ?>/ico/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="<?= $this->theme->getBaseUrl(); ?>/ico/apple-icon-60x60.png"> <link rel="apple-touch-icon" sizes="60x60" href="<?= $this->theme->getBaseUrl(); ?>/ico/apple-icon-60x60.png">
@ -15,8 +20,19 @@
<link rel="icon" type="image/png" sizes="32x32" href="<?= $this->theme->getBaseUrl(); ?>/ico/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="<?= $this->theme->getBaseUrl(); ?>/ico/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="<?= $this->theme->getBaseUrl(); ?>/ico/favicon-96x96.png"> <link rel="icon" type="image/png" sizes="96x96" href="<?= $this->theme->getBaseUrl(); ?>/ico/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="<?= $this->theme->getBaseUrl(); ?>/ico/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="<?= $this->theme->getBaseUrl(); ?>/ico/favicon-16x16.png">
<link rel="manifest" href="<?= $this->theme->getBaseUrl(); ?>/ico/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff"> <meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="<?= $this->theme->getBaseUrl(); ?>/ico/ms-icon-144x144.png"> <meta name="msapplication-TileImage" content="<?= $this->theme->getBaseUrl(); ?>/ico/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<!-- end: Favicon and Touch Icons --> <!-- end: Favicon and Touch Icons -->
<!-- start: Apple Fullscreen and Webapp Title -->
<meta name="apple-mobile-web-app-title" content="<?= \yii\helpers\Html::encode(Yii::$app->name) ?>" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<!-- end: Apple Fullscreen and Webapp Title -->
<!-- start: Android Fullscreen -->
<meta name="mobile-web-app-capable" content="yes">
<!-- end: Android Fullscreen -->