mirror of
https://github.com/humhub/humhub.git
synced 2025-03-14 20:19:47 +01:00
Allow to manage blocked users (#5309)
* Allow to manage blocked users * Restrict access on container controllers for blocked users * TODO point for blocked user from anonymous * Cache blocked user Ids in container settings * Exclude blocked used from streams and activites * Hide blocked comments * Change comment view from blocked user * Change wording * Allow to enabled user blocking in administration panel * Disable notifications from blocked users * Exclude blocked users from mentioning list * Test users blocking * Enable users blocking by default * Refactor container settings method * Fix tests of blocking users Co-authored-by: Lucas Bartholemy <luke-@users.noreply.github.com>
This commit is contained in:
parent
73dd4f8f1b
commit
81ca33a6e9
@ -8,10 +8,9 @@
|
||||
|
||||
namespace humhub\modules\admin\models\forms;
|
||||
|
||||
use humhub\modules\user\models\Group;
|
||||
use humhub\libs\DynamicConfig;
|
||||
use humhub\modules\user\Module;
|
||||
use Yii;
|
||||
use humhub\libs\DynamicConfig;
|
||||
|
||||
/**
|
||||
* AuthenticationSettingsForm
|
||||
@ -24,6 +23,7 @@ class AuthenticationSettingsForm extends \yii\base\Model
|
||||
public $internalRequireApprovalAfterRegistration;
|
||||
public $internalUsersCanInvite;
|
||||
public $showRegistrationUserGroup;
|
||||
public $blockUsers;
|
||||
public $defaultUserIdleTimeoutSec;
|
||||
public $allowGuestAccess;
|
||||
public $showCaptureInRegisterForm;
|
||||
@ -46,6 +46,7 @@ class AuthenticationSettingsForm extends \yii\base\Model
|
||||
$this->internalRequireApprovalAfterRegistration = $settingsManager->get('auth.needApproval');
|
||||
$this->internalAllowAnonymousRegistration = $settingsManager->get('auth.anonymousRegistration');
|
||||
$this->showRegistrationUserGroup = $settingsManager->get('auth.showRegistrationUserGroup');
|
||||
$this->blockUsers = $module->allowBlockUsers();
|
||||
$this->defaultUserIdleTimeoutSec = $settingsManager->get('auth.defaultUserIdleTimeoutSec');
|
||||
$this->allowGuestAccess = $settingsManager->get('auth.allowGuestAccess');
|
||||
$this->showCaptureInRegisterForm = $settingsManager->get('auth.showCaptureInRegisterForm');
|
||||
@ -60,7 +61,7 @@ class AuthenticationSettingsForm extends \yii\base\Model
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['internalUsersCanInvite', 'internalAllowAnonymousRegistration', 'internalRequireApprovalAfterRegistration', 'allowGuestAccess', 'showCaptureInRegisterForm', 'showRegistrationUserGroup'], 'boolean'],
|
||||
[['internalUsersCanInvite', 'internalAllowAnonymousRegistration', 'internalRequireApprovalAfterRegistration', 'allowGuestAccess', 'showCaptureInRegisterForm', 'showRegistrationUserGroup', 'blockUsers'], 'boolean'],
|
||||
['defaultUserProfileVisibility', 'in', 'range' => [1, 2]],
|
||||
['defaultUserIdleTimeoutSec', 'integer', 'min' => 20],
|
||||
[['registrationApprovalMailContent', 'registrationDenialMailContent'], 'string']
|
||||
@ -77,6 +78,7 @@ class AuthenticationSettingsForm extends \yii\base\Model
|
||||
'internalAllowAnonymousRegistration' => Yii::t('AdminModule.user', 'New users can register'),
|
||||
'internalUsersCanInvite' => Yii::t('AdminModule.user', 'Members can invite external users by email'),
|
||||
'showRegistrationUserGroup' => Yii::t('AdminModule.user', 'Show group selection at registration'),
|
||||
'blockUsers' => Yii::t('AdminModule.user', 'Allow users to block each other'),
|
||||
'defaultUserIdleTimeoutSec' => Yii::t('AdminModule.user', 'Default user idle timeout, auto-logout (in seconds, optional)'),
|
||||
'allowGuestAccess' => Yii::t('AdminModule.user', 'Allow visitors limited access to content without an account (Adds visibility: "Guest")'),
|
||||
'showCaptureInRegisterForm' => Yii::t('AdminModule.user', 'Include captcha in registration form'),
|
||||
@ -101,6 +103,7 @@ class AuthenticationSettingsForm extends \yii\base\Model
|
||||
$settingsManager->set('auth.needApproval', $this->internalRequireApprovalAfterRegistration);
|
||||
$settingsManager->set('auth.anonymousRegistration', $this->internalAllowAnonymousRegistration);
|
||||
$settingsManager->set('auth.showRegistrationUserGroup', $this->showRegistrationUserGroup);
|
||||
$settingsManager->set('auth.blockUsers', $this->blockUsers);
|
||||
$settingsManager->set('auth.defaultUserIdleTimeoutSec', $this->defaultUserIdleTimeoutSec);
|
||||
$settingsManager->set('auth.allowGuestAccess', $this->allowGuestAccess);
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
<?php
|
||||
|
||||
use humhub\modules\admin\models\forms\AuthenticationSettingsForm;
|
||||
use humhub\modules\content\widgets\richtext\RichTextField;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use humhub\modules\user\Module;
|
||||
use yii\helpers\Html;
|
||||
|
||||
/** @var \humhub\modules\user\Module $userModule */
|
||||
/* @var AuthenticationSettingsForm $model */
|
||||
|
||||
/* @var Module $userModule */
|
||||
$userModule = Yii::$app->getModule('user');
|
||||
|
||||
?>
|
||||
@ -27,6 +31,8 @@ $userModule = Yii::$app->getModule('user');
|
||||
|
||||
<?= $form->field($model, 'showRegistrationUserGroup')->checkbox(); ?>
|
||||
|
||||
<?= $form->field($model, 'blockUsers')->checkbox(); ?>
|
||||
|
||||
<?= $form->field($model, 'defaultUserIdleTimeoutSec')->textInput(['readonly' => $userModule->settings->isFixed('auth.defaultUserIdleTimeoutSec')]); ?>
|
||||
<p class="help-block"><?= Yii::t('AdminModule.user', 'Min value is 20 seconds. If not set, session will timeout after 1400 seconds (24 minutes) regardless of activity (default session timeout)'); ?></p>
|
||||
|
||||
|
@ -182,7 +182,10 @@ class CommentController extends Controller
|
||||
throw new ForbiddenHttpException();
|
||||
}
|
||||
|
||||
return $this->renderAjaxContent(CommentWidget::widget(['comment' => $comment]));
|
||||
return $this->renderAjaxContent(CommentWidget::widget([
|
||||
'comment' => $comment,
|
||||
'showBlocked' => Yii::$app->request->get('showBlocked'),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,6 +204,18 @@ humhub.module('comment', function (module, require, $) {
|
||||
this.$.find('.preferences:first').hide();
|
||||
};
|
||||
|
||||
Comment.prototype.showBlocked = function (evt) {
|
||||
var that = this;
|
||||
that.loader();
|
||||
client.html(evt).then(function (response) {
|
||||
that.replace(response.html);
|
||||
}).catch(function (err) {
|
||||
module.log.error(err, true);
|
||||
}).finally(function () {
|
||||
that.loader(false);
|
||||
});
|
||||
};
|
||||
|
||||
var showAll = function (evt) {
|
||||
client.post(evt, {dataType: 'html'}).then(function (response) {
|
||||
var $container = evt.$trigger.parent();
|
||||
|
@ -9,6 +9,8 @@
|
||||
namespace humhub\modules\comment\widgets;
|
||||
|
||||
use humhub\components\Widget;
|
||||
use Yii;
|
||||
use yii\helpers\Url;
|
||||
|
||||
/**
|
||||
* This widget is used to show a single comment.
|
||||
@ -27,6 +29,11 @@ class Comment extends Widget
|
||||
*/
|
||||
public $justEdited = false;
|
||||
|
||||
/**
|
||||
* @var bool True to force show even blocked comment
|
||||
*/
|
||||
public $showBlocked = false;
|
||||
|
||||
/**
|
||||
* @var string Default style class of div wrapper around Comment block
|
||||
*/
|
||||
@ -42,6 +49,38 @@ class Comment extends Widget
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
return $this->isBlockedAuthor()
|
||||
? $this->renderBlockedComment()
|
||||
: $this->renderComment();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function renderBlockedComment(): string
|
||||
{
|
||||
$loadBlockedCommentUrl = Url::to(['/comment/comment/load',
|
||||
'objectModel' => $this->comment->object_model,
|
||||
'objectId' => $this->comment->object_id,
|
||||
'id' => $this->comment->id,
|
||||
'showBlocked' => true,
|
||||
]);
|
||||
|
||||
return $this->render('commentBlockedUser', [
|
||||
'comment' => $this->comment,
|
||||
'loadBlockedCommentUrl' => $loadBlockedCommentUrl,
|
||||
]);
|
||||
}
|
||||
|
||||
private function renderComment(): string
|
||||
{
|
||||
$deleteUrl = Url::to(['/comment/comment/delete',
|
||||
'objectModel' => $this->comment->object_model, 'objectId' => $this->comment->object_id, 'id' => $this->comment->id]);
|
||||
$editUrl = Url::to(['/comment/comment/edit',
|
||||
'objectModel' => $this->comment->object_model, 'objectId' => $this->comment->object_id, 'id' => $this->comment->id]);
|
||||
$loadUrl = Url::to(['/comment/comment/load',
|
||||
'objectModel' => $this->comment->object_model, 'objectId' => $this->comment->object_id, 'id' => $this->comment->id]);
|
||||
|
||||
return $this->render('comment', [
|
||||
'comment' => $this->comment,
|
||||
'user' => $this->comment->user,
|
||||
@ -50,4 +89,22 @@ class Comment extends Widget
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if author of the Comment is blocked for the current User
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isBlockedAuthor(): bool
|
||||
{
|
||||
if ($this->showBlocked) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Yii::$app->user->isGuest) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Yii::$app->user->getIdentity()->isBlockedForUser($this->comment->createdBy);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,30 @@
|
||||
<?php
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\comment\Module;
|
||||
use humhub\modules\comment\widgets\CommentControls;
|
||||
use humhub\modules\content\widgets\UpdatedIcon;
|
||||
use humhub\modules\comment\widgets\CommentEntryLinks;
|
||||
use humhub\modules\ui\view\components\View;
|
||||
use humhub\widgets\TimeAgo;
|
||||
use humhub\modules\content\widgets\richtext\RichText;
|
||||
use humhub\modules\user\widgets\Image as UserImage;
|
||||
use humhub\modules\file\widgets\ShowFiles;
|
||||
use humhub\modules\comment\widgets\Comments;
|
||||
|
||||
/* @var $this View */
|
||||
/* @var $comment \humhub\modules\comment\models\Comment */
|
||||
/* @var $user \humhub\modules\user\models\User */
|
||||
/* @var $deleteUrl string */
|
||||
/* @var $editUrl string */
|
||||
/* @var $loadUrl string */
|
||||
/* @var $createdAt string */
|
||||
/* @var $updatedAt string */
|
||||
/* @var $class string */
|
||||
|
||||
/** @var Module $module */
|
||||
$module = Yii::$app->getModule('comment');
|
||||
|
||||
?>
|
||||
|
||||
<div class="<?= $class; ?>" id="comment_<?= $comment->id; ?>"
|
||||
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\modules\comment\models\Comment;
|
||||
use humhub\modules\ui\view\components\View;
|
||||
use humhub\modules\user\widgets\Image as UserImage;
|
||||
use humhub\widgets\Button;
|
||||
|
||||
/* @var $this View */
|
||||
/* @var $comment Comment */
|
||||
/* @var $loadBlockedCommentUrl string */
|
||||
?>
|
||||
|
||||
<div class="media comment-blocked-user" id="comment_<?= $comment->id; ?>"
|
||||
data-action-component="comment.Comment">
|
||||
|
||||
<hr class="comment-separator">
|
||||
|
||||
<?= UserImage::widget(['user' => $comment->user, 'width' => 25, 'htmlOptions' => ['class' => 'pull-left', 'data-contentcontainer-id' => $comment->user->contentcontainer_id]]); ?>
|
||||
<?= Yii::t('CommentModule.base', 'Comment of blocked user.') ?>
|
||||
<?= Button::asLink(Yii::t('CommentModule.base', 'Show'))->action('showBlocked', $loadBlockedCommentUrl)->xs()->cssClass('text-primary') ?>
|
||||
</div>
|
@ -31,6 +31,7 @@ use yii\base\Exception;
|
||||
* - updated_at
|
||||
*
|
||||
* @property-read Content $content
|
||||
* @property-read User $user
|
||||
* @author Lucas Bartholemy <lucas@bartholemy.com>
|
||||
* @package humhub.components
|
||||
* @since 0.5
|
||||
|
@ -14,10 +14,12 @@ use humhub\libs\ProfileBannerImage;
|
||||
use humhub\libs\ProfileImage;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\content\models\ContentContainer;
|
||||
use humhub\modules\content\models\ContentContainerTag;
|
||||
use humhub\modules\content\models\ContentContainerBlockedUsers;
|
||||
use humhub\modules\content\models\ContentContainerTagRelation;
|
||||
use humhub\modules\content\Module;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\user\Module as UserModule;
|
||||
use Yii;
|
||||
use yii\helpers\Url;
|
||||
|
||||
@ -71,6 +73,11 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
*/
|
||||
public $tagsField;
|
||||
|
||||
/**
|
||||
* @var array Related Blcoked Users IDs which should be updated after save
|
||||
*/
|
||||
public $blockedUsersField;
|
||||
|
||||
/**
|
||||
* Returns the display name of content container
|
||||
*
|
||||
@ -181,6 +188,11 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
return $container->contentcontainer_id === $this->contentcontainer_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContentContainerSettingsManager
|
||||
*/
|
||||
abstract public function getSettings(): ContentContainerSettingsManager;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -207,6 +219,10 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
ContentContainerTagRelation::updateByContainer($this, $this->tagsField);
|
||||
}
|
||||
|
||||
if ($this->isAttributeSafe('blockedUsersField') && $this->blockedUsersField !== null) {
|
||||
ContentContainerBlockedUsers::updateByContainer($this, $this->blockedUsersField);
|
||||
}
|
||||
|
||||
parent::afterSave($insert, $changedAttributes);
|
||||
}
|
||||
|
||||
@ -372,4 +388,66 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
return ContentContainerTagRelation::getNamesByContainer($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with GUIDs of the blocked users
|
||||
*
|
||||
* @return string[] a list of user GUIDs
|
||||
*/
|
||||
public function getBlockedUserGuids(): array
|
||||
{
|
||||
return $this->allowBlockUsers() ? ContentContainerBlockedUsers::getGuidsByContainer($this) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with IDs of the blocked user
|
||||
*
|
||||
* @return int[] a list of user IDs
|
||||
*/
|
||||
public function getBlockedUserIds(): array
|
||||
{
|
||||
if (!$this->allowBlockUsers()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$blockedUsers = $this->getSettings()->get(ContentContainerBlockedUsers::BLOCKED_USERS_SETTING);
|
||||
return empty($blockedUsers) ? [] : explode(',', $blockedUsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current container is blocked for the User
|
||||
*
|
||||
* @param User|null $user
|
||||
* @return bool
|
||||
*/
|
||||
public function isBlockedForUser(?User $user = null): bool
|
||||
{
|
||||
if (!$this->allowBlockUsers()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($user === null) {
|
||||
if (Yii::$app->user->isGuest) {
|
||||
$visibilityAll = ($this instanceof Space) ? Space::VISIBILITY_ALL : User::VISIBILITY_ALL;
|
||||
return $this->isVisibleFor($visibilityAll);
|
||||
}
|
||||
|
||||
$user = Yii::$app->user->getIdentity();
|
||||
}
|
||||
|
||||
return in_array($user->id, $this->getBlockedUserIds());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the blocking users is allowed by users module
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allowBlockUsers(): bool
|
||||
{
|
||||
/* @var UserModule $userModule */
|
||||
$userModule = Yii::$app->getModule('user');
|
||||
|
||||
return $userModule->allowBlockUsers();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -85,6 +85,10 @@ class ContentContainerController extends Controller
|
||||
if ($this->contentContainer !== null && $this->contentContainer->controllerBehavior) {
|
||||
$this->attachBehavior('containerControllerBehavior', ['class' => $this->contentContainer->controllerBehavior]);
|
||||
}
|
||||
|
||||
if ($this->contentContainer !== null && $this->contentContainer->isBlockedForUser()) {
|
||||
throw new HttpException(400, 'You are blocked for this page!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use humhub\components\Migration;
|
||||
|
||||
/**
|
||||
* Class m210924_114847_container_blocked_users
|
||||
*/
|
||||
class m210924_114847_container_blocked_users extends Migration
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function safeUp()
|
||||
{
|
||||
$this->safeCreateTable('contentcontainer_blocked_users', [
|
||||
'contentcontainer_id' => $this->integer()->notNull(),
|
||||
'user_id' => $this->integer()->notNull(),
|
||||
]);
|
||||
$this->safeAddPrimaryKey('pk-contentcontainer-blocked-users-rel', 'contentcontainer_blocked_users', ['contentcontainer_id', 'user_id']);
|
||||
$this->safeAddForeignKey('fk-contentcontainer-blocked-users-rel-contentcontainer-id', 'contentcontainer_blocked_users', 'contentcontainer_id', 'contentcontainer', 'id', 'CASCADE');
|
||||
$this->safeAddForeignKey('fk-contentcontainer-blocked-users-rel-user-id', 'contentcontainer_blocked_users', 'user_id', 'user', 'id', 'CASCADE');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function safeDown()
|
||||
{
|
||||
$this->dropTable('contentcontainer_blocked_users');
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\models;
|
||||
|
||||
use humhub\components\ActiveRecord;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\user\Module;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Class ContentContainerBlockedUsers
|
||||
*
|
||||
* @property integer $contentcontainer_id
|
||||
* @property integer $user_id
|
||||
*
|
||||
* @since 1.10
|
||||
*/
|
||||
class ContentContainerBlockedUsers extends ActiveRecord
|
||||
{
|
||||
const BLOCKED_USERS_SETTING = 'blockedUsers';
|
||||
|
||||
public static function tableName()
|
||||
{
|
||||
return 'contentcontainer_blocked_users';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['contentcontainer_id', 'user_id'], 'required'],
|
||||
[['contentcontainer_id', 'user_id'], 'integer'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocked user guids of the Content Container
|
||||
*
|
||||
* @param ContentContainerActiveRecord $contentContainer
|
||||
* @return int[]
|
||||
*/
|
||||
public static function getGuidsByContainer(ContentContainerActiveRecord $contentContainer): array
|
||||
{
|
||||
return self::find()
|
||||
->select('user.guid')
|
||||
->innerJoin(User::tableName(), 'user.id = user_id')
|
||||
->where([self::tableName() . '.contentcontainer_id' => $contentContainer->contentcontainer_id])
|
||||
->column();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update blocked users of the Content Container
|
||||
*
|
||||
* @param ContentContainerActiveRecord $contentContainer
|
||||
* @param string[]|null $newBlockedUserGuids
|
||||
*/
|
||||
public static function updateByContainer(ContentContainerActiveRecord $contentContainer, $newBlockedUserGuids = null)
|
||||
{
|
||||
/* @var Module $moduleUser */
|
||||
$moduleUser = Yii::$app->getModule('user');
|
||||
if (!$moduleUser->allowBlockUsers()) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::deleteByContainer($contentContainer);
|
||||
|
||||
if (empty($newBlockedUserGuids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$newBlockedUsers = User::find()->where(['IN', 'guid', $newBlockedUserGuids])->all();
|
||||
|
||||
$newBlockedUserIds = [];
|
||||
foreach ($newBlockedUsers as $newBlockedUser) {
|
||||
/* @var User $newBlockedUser */
|
||||
if ($newBlockedUser->is($contentContainer)) {
|
||||
continue;
|
||||
}
|
||||
$newBlockedUserRelation = new ContentContainerBlockedUsers();
|
||||
$newBlockedUserRelation->contentcontainer_id = $contentContainer->contentcontainer_id;
|
||||
$newBlockedUserRelation->user_id = $newBlockedUser->id;
|
||||
if ($newBlockedUserRelation->save()) {
|
||||
$newBlockedUserIds[] = $newBlockedUser->id;
|
||||
}
|
||||
}
|
||||
|
||||
$contentContainer->settings->set(self::BLOCKED_USERS_SETTING, empty($newBlockedUserIds) ? null : implode(',', $newBlockedUserIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete blocked user relations of the Content Container
|
||||
*
|
||||
* @param ContentContainerActiveRecord $contentContainer
|
||||
*/
|
||||
public static function deleteByContainer(ContentContainerActiveRecord $contentContainer)
|
||||
{
|
||||
$blockedUserRelations = self::findAll(['contentcontainer_id' => $contentContainer->contentcontainer_id]);
|
||||
|
||||
foreach ($blockedUserRelations as $blockedUserRelation) {
|
||||
$blockedUserRelation->delete();
|
||||
}
|
||||
|
||||
$contentContainer->settings->delete(self::BLOCKED_USERS_SETTING);
|
||||
}
|
||||
}
|
@ -198,6 +198,10 @@ abstract class BaseNotification extends SocialActivity
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isBlockedFromUser($user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Yii::$app->queue->push(new SendNotification(['notification' => $this, 'recipientId' => $user->id]));
|
||||
}
|
||||
|
||||
@ -223,6 +227,18 @@ abstract class BaseNotification extends SocialActivity
|
||||
return $this->originator && $this->originator->id === $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the originator blocked the given $user in order to avoid receive any notifications from the $user.
|
||||
*
|
||||
* @param User $user
|
||||
* @return boolean
|
||||
* @since 1.10
|
||||
*/
|
||||
public function isBlockedFromUser(User $user): bool
|
||||
{
|
||||
return $this->originator && $user->isBlockedForUser($this->originator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Notification instance of the current BaseNotification type for the
|
||||
* given $user.
|
||||
|
@ -72,6 +72,10 @@ class NotificationManager
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($notification->isBlockedFromUser($user)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($user->id, $processed)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ class MentioningController extends Controller
|
||||
$users = User::find()
|
||||
->visible()
|
||||
->search($keyword)
|
||||
->filterBlockedUsers()
|
||||
->limit($this->module->mentioningSearchBoxResultLimit)
|
||||
->orderBy(['user.last_login' => SORT_DESC])
|
||||
->all();
|
||||
@ -92,6 +93,7 @@ class MentioningController extends Controller
|
||||
// Find space members
|
||||
$users = Membership::getSpaceMembersQuery($space)
|
||||
->search($keyword)
|
||||
->filterBlockedUsers()
|
||||
->limit($this->module->mentioningSearchBoxResultLimit)
|
||||
->orderBy(['space_membership.last_visit' => SORT_DESC])
|
||||
->all();
|
||||
@ -131,6 +133,7 @@ class MentioningController extends Controller
|
||||
// Find users followed to the Content
|
||||
$users = Follow::getFollowersQuery($object, true)
|
||||
->search($keyword)
|
||||
->filterBlockedUsers()
|
||||
->limit($this->module->mentioningSearchBoxResultLimit)
|
||||
->orderBy(['user.last_login' => SORT_DESC])
|
||||
->all();
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\modules\space\models;
|
||||
|
||||
use humhub\libs\ProfileImage;
|
||||
use humhub\modules\content\components\ContentContainerSettingsManager;
|
||||
use humhub\modules\search\interfaces\Searchable;
|
||||
use humhub\modules\search\events\SearchAddEvent;
|
||||
use humhub\modules\search\jobs\DeleteDocument;
|
||||
@ -16,27 +17,23 @@ use humhub\modules\search\jobs\UpdateDocument;
|
||||
use humhub\modules\space\behaviors\SpaceModelMembership;
|
||||
use humhub\modules\space\behaviors\SpaceController;
|
||||
use humhub\modules\space\components\ActiveQuerySpace;
|
||||
use humhub\modules\space\Module;
|
||||
use humhub\modules\user\behaviors\Followable;
|
||||
use humhub\components\behaviors\GUID;
|
||||
use humhub\modules\content\components\behaviors\SettingsBehavior;
|
||||
use humhub\modules\content\components\behaviors\CompatModuleManager;
|
||||
use humhub\modules\space\permissions\CreatePrivateSpace;
|
||||
use humhub\modules\space\permissions\CreatePublicSpace;
|
||||
use humhub\modules\space\permissions\InviteUsers;
|
||||
use humhub\modules\content\permissions\CreatePublicContent;
|
||||
use humhub\modules\space\components\UrlValidator;
|
||||
use humhub\modules\space\activities\Created;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\user\components\ActiveQueryUser;
|
||||
use humhub\modules\user\helpers\AuthHelper;
|
||||
use humhub\modules\user\models\GroupSpace;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\user\models\Follow;
|
||||
use humhub\modules\user\models\Invite;
|
||||
use humhub\modules\user\models\Group;
|
||||
use humhub\modules\space\widgets\Wall;
|
||||
use humhub\modules\space\widgets\Members;
|
||||
use humhub\modules\user\models\User as UserModel;
|
||||
use Yii;
|
||||
|
||||
@ -641,6 +638,16 @@ class Space extends ContentContainerActiveRecord implements Searchable
|
||||
return Content::VISIBILITY_PRIVATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getSettings(): ContentContainerSettingsManager
|
||||
{
|
||||
/* @var $module Module */
|
||||
$module = Yii::$app->getModule('space');
|
||||
return $module->settings->contentContainer($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns space privileged groups and their members` User model in array
|
||||
*
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace humhub\modules\stream\models;
|
||||
|
||||
use humhub\modules\stream\models\filters\BlockedUsersStreamFilter;
|
||||
use humhub\modules\stream\models\filters\StreamQueryFilter;
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
@ -133,6 +134,7 @@ class StreamQuery extends Model
|
||||
TopicStreamFilter::class,
|
||||
ContentTypeStreamFilter::class,
|
||||
OriginatorStreamFilter::class,
|
||||
BlockedUsersStreamFilter::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2021 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\stream\models\filters;
|
||||
|
||||
use humhub\modules\user\models\User;
|
||||
|
||||
class BlockedUsersStreamFilter extends StreamQueryFilter
|
||||
{
|
||||
/**
|
||||
* @var array IDs of the blocked users for the current User
|
||||
*/
|
||||
private $blockedUsers;
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
|
||||
if (!empty($this->streamQuery->user) && $this->streamQuery->user instanceof User) {
|
||||
$this->blockedUsers = $this->streamQuery->user->getBlockedUserIds();
|
||||
}
|
||||
}
|
||||
|
||||
public function apply()
|
||||
{
|
||||
if (empty($this->blockedUsers)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->query->andWhere(['NOT IN', 'user.id', $this->blockedUsers]);
|
||||
}
|
||||
}
|
@ -236,4 +236,14 @@ class Module extends \humhub\components\Module
|
||||
$group->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the blocking users is allowed
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function allowBlockUsers(): bool
|
||||
{
|
||||
return (bool) $this->settings->get('auth.blockUsers', true);
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,16 @@
|
||||
|
||||
namespace humhub\modules\user\components;
|
||||
|
||||
use humhub\events\ActiveQueryEvent;
|
||||
use humhub\modules\admin\permissions\ManageUsers;
|
||||
use humhub\modules\user\models\fieldtype\BaseTypeVirtual;
|
||||
use humhub\modules\user\models\GroupUser;
|
||||
use humhub\modules\user\models\Group;
|
||||
use humhub\modules\user\models\ProfileField;
|
||||
use yii\db\ActiveQuery;
|
||||
use humhub\modules\user\models\User as UserModel;
|
||||
use humhub\events\ActiveQueryEvent;
|
||||
use humhub\modules\user\Module;
|
||||
use Yii;
|
||||
use yii\db\ActiveQuery;
|
||||
|
||||
/**
|
||||
* ActiveQueryUser is used to query User records.
|
||||
@ -169,4 +171,32 @@ class ActiveQueryUser extends ActiveQuery
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude blocked users for the given $user or for the current User
|
||||
*
|
||||
* @param UserModel $user
|
||||
* @return ActiveQueryUser the query
|
||||
*/
|
||||
public function filterBlockedUsers(?UserModel $user = null): ActiveQueryUser
|
||||
{
|
||||
if ($user === null && !Yii::$app->user->isGuest) {
|
||||
$user = Yii::$app->user->getIdentity();
|
||||
}
|
||||
|
||||
if (!($user instanceof UserModel)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/* @var Module $userModule */
|
||||
$userModule = Yii::$app->getModule('user');
|
||||
if (!$userModule->allowBlockUsers()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->leftJoin('contentcontainer_blocked_users', 'contentcontainer_blocked_users.contentcontainer_id=user.contentcontainer_id AND contentcontainer_blocked_users.user_id=:blockedUserId', [':blockedUserId' => $user->id]);
|
||||
$this->andWhere('contentcontainer_blocked_users.user_id IS NULL');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ use humhub\modules\user\models\User;
|
||||
use humhub\modules\user\authclient\BaseFormAuth;
|
||||
use humhub\modules\space\helpers\MembershipHelper;
|
||||
use humhub\modules\user\models\forms\AccountDelete;
|
||||
use humhub\modules\space\models\Membership;
|
||||
|
||||
/**
|
||||
* AccountController provides all standard actions for the current logged in
|
||||
@ -123,6 +122,7 @@ class AccountController extends BaseAccountController
|
||||
$model->tags = $user->getTags();
|
||||
$model->show_introduction_tour = Yii::$app->getModule('tour')->settings->contentContainer($user)->get("hideTourPanel");
|
||||
$model->visibility = $user->visibility;
|
||||
$model->blockedUsers = $user->getBlockedUserGuids();
|
||||
|
||||
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
|
||||
Yii::$app->getModule('tour')->settings->contentContainer($user)->set('hideTourPanel', $model->show_introduction_tour);
|
||||
@ -132,6 +132,9 @@ class AccountController extends BaseAccountController
|
||||
$user->tagsField = $model->tags;
|
||||
$user->time_zone = $model->timeZone;
|
||||
$user->visibility = $model->visibility;
|
||||
if (Yii::$app->getModule('user')->allowBlockUsers()) {
|
||||
$user->blockedUsersField = $model->blockedUsers;
|
||||
}
|
||||
$user->save();
|
||||
|
||||
$this->view->saved();
|
||||
|
@ -157,7 +157,7 @@ class User extends ContentContainerActiveRecord implements IdentityInterface, Se
|
||||
return $model->getAttribute($attribute) !== $model->getOldAttribute($attribute);
|
||||
}],
|
||||
[['status', 'created_by', 'updated_by', 'visibility'], 'integer'],
|
||||
[['tagsField'], 'safe'],
|
||||
[['tagsField', 'blockedUsersField'], 'safe'],
|
||||
[['guid'], 'string', 'max' => 45],
|
||||
[['time_zone'], 'validateTimeZone'],
|
||||
[['auth_mode'], 'string', 'max' => 10],
|
||||
@ -252,7 +252,7 @@ class User extends ContentContainerActiveRecord implements IdentityInterface, Se
|
||||
$scenarios = parent::scenarios();
|
||||
$scenarios[static::SCENARIO_LOGIN] = ['username', 'password'];
|
||||
$scenarios[static::SCENARIO_EDIT_ADMIN] = ['username', 'email', 'status', 'language', 'tagsField'];
|
||||
$scenarios[static::SCENARIO_EDIT_ACCOUNT_SETTINGS] = ['language', 'visibility', 'time_zone', 'tagsField'];
|
||||
$scenarios[static::SCENARIO_EDIT_ACCOUNT_SETTINGS] = ['language', 'visibility', 'time_zone', 'tagsField', 'blockedUsersField'];
|
||||
$scenarios[static::SCENARIO_REGISTRATION_EMAIL] = ['username', 'email', 'time_zone'];
|
||||
$scenarios[static::SCENARIO_REGISTRATION] = ['username', 'time_zone'];
|
||||
|
||||
@ -873,13 +873,12 @@ class User extends ContentContainerActiveRecord implements IdentityInterface, Se
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string Module id
|
||||
* @return ContentContainerSettingsManager
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getSettings($moduleId = 'user')
|
||||
public function getSettings(): ContentContainerSettingsManager
|
||||
{
|
||||
/* @var $module Module */
|
||||
$module = Yii::$app->getModule($moduleId);
|
||||
$module = Yii::$app->getModule('user');
|
||||
return $module->settings->contentContainer($this);
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ class AccountSettings extends \yii\base\Model
|
||||
public $show_introduction_tour;
|
||||
public $visibility;
|
||||
public $timeZone;
|
||||
public $blockedUsers;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@ -30,7 +31,7 @@ class AccountSettings extends \yii\base\Model
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
['tags', 'safe'],
|
||||
[['tags', 'blockedUsers'], 'safe'],
|
||||
[['show_introduction_tour'], 'boolean'],
|
||||
[['timeZone'], 'in', 'range' => \DateTimeZone::listIdentifiers()],
|
||||
['language', 'in', 'range' => array_keys(Yii::$app->i18n->getAllowedLanguages())],
|
||||
@ -49,6 +50,7 @@ class AccountSettings extends \yii\base\Model
|
||||
'show_introduction_tour' => Yii::t('UserModule.account', 'Hide introduction tour panel on dashboard'),
|
||||
'timeZone' => Yii::t('UserModule.account', 'TimeZone'),
|
||||
'visibility' => Yii::t('UserModule.account', 'Profile visibility'),
|
||||
'blockedUsers' => Yii::t('UserModule.account', 'Blocked users'),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
namespace user\acceptance;
|
||||
|
||||
use user\AcceptanceTester;
|
||||
|
||||
class BlockUsersCest
|
||||
{
|
||||
public function testBlockUsers(AcceptanceTester $I)
|
||||
{
|
||||
$I->wantTo('test users blocking');
|
||||
|
||||
$I->amGoingTo('check the users blocking is enabled in system by default');
|
||||
$I->amUser2();
|
||||
$this->isUsersBlockingEnabled($I);
|
||||
|
||||
$I->amGoingTo('block some users for the current user "Sara Tester"');
|
||||
$I->selectUserFromPicker('#accountsettings-blockedusers', 'Peter Tester');
|
||||
$I->selectUserFromPicker('#accountsettings-blockedusers', 'Sara Tester');
|
||||
$I->selectUserFromPicker('#accountsettings-blockedusers', 'Andreas Tester');
|
||||
$I->click('Save');
|
||||
$I->seeSuccess('Saved');
|
||||
$I->see('Peter Tester', '.field-accountsettings-blockedusers');
|
||||
$I->dontSee('Sara Tester', '.field-accountsettings-blockedusers');
|
||||
$I->see('Andreas Tester', '.field-accountsettings-blockedusers');
|
||||
|
||||
$I->amGoingTo('check the current user "Peter Tester" is blocked for the user "Sara Tester"');
|
||||
$I->amUser1(true);
|
||||
$I->amOnUser2Profile();
|
||||
$I->see('You are blocked for this page!');
|
||||
|
||||
$I->amGoingTo('enable the users blocking');
|
||||
$I->amAdmin(true);
|
||||
$this->disableUsersBlocking($I);
|
||||
|
||||
$I->amUser1(true);
|
||||
$this->isUsersBlockingDisabled($I);
|
||||
$I->amGoingTo('be sure the user "Sara Tester" is viewable for the user "Peter Tester"');
|
||||
$I->amOnUser2Profile();
|
||||
$I->see('Sara Tester');
|
||||
}
|
||||
|
||||
private function disableUsersBlocking(AcceptanceTester $I)
|
||||
{
|
||||
$I->amOnPage('/admin/authentication');
|
||||
$I->click('[for="authenticationsettingsform-blockusers"]');
|
||||
$I->wait(1);
|
||||
$I->click('Save');
|
||||
}
|
||||
|
||||
private function isUsersBlockingDisabled(AcceptanceTester $I)
|
||||
{
|
||||
$I->amOnPage('/user/account/edit-settings');
|
||||
$I->dontSee('Blocked users');
|
||||
}
|
||||
|
||||
private function isUsersBlockingEnabled(AcceptanceTester $I)
|
||||
{
|
||||
$I->amOnPage('/user/account/edit-settings');
|
||||
$I->see('Blocked users');
|
||||
}
|
||||
|
||||
}
|
@ -4,6 +4,11 @@ use humhub\libs\TimezoneHelper;
|
||||
use humhub\modules\content\widgets\ContainerTagPicker;
|
||||
use humhub\modules\user\helpers\AuthHelper;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use humhub\modules\user\models\forms\AccountSettings;
|
||||
use humhub\modules\user\widgets\UserPickerField;
|
||||
|
||||
/* @var AccountSettings $model */
|
||||
/* @var array $languages */
|
||||
?>
|
||||
|
||||
<?php $this->beginContent('@user/views/account/_userSettingsLayout.php') ?>
|
||||
@ -34,6 +39,10 @@ use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
<?= $form->field($model, 'show_introduction_tour')->checkbox(); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (Yii::$app->getModule('user')->allowBlockUsers()) : ?>
|
||||
<?= $form->field($model, 'blockedUsers')->widget(UserPickerField::class, ['minInput' => 2]); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<button class="btn btn-primary" type="submit" data-ui-loader><?= Yii::t('UserModule.account', 'Save') ?></button>
|
||||
|
||||
<?php ActiveForm::end(); ?>
|
||||
|
@ -53,6 +53,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.comment-blocked-user {
|
||||
img[data-contentcontainer-id] {
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
|
||||
/*-- Since v1.2 overflow: visible */
|
||||
|
||||
.media-body {
|
||||
|
Loading…
x
Reference in New Issue
Block a user