diff --git a/CHANGELOG.md b/CHANGELOG.md index af443d009c..c096adace8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ HumHub Changelog - Fix #5997: Possible NULL param value in Birthday field (PHP 8.1) - Enh #6001: Added new `ContentActiveFixture` and migrated `PostFixture` to it - Fix #6007: Fix number of space members +- Fix #6012: View own invisible profile 1.13.0 (December 21, 2022) -------------------------- diff --git a/protected/humhub/modules/content/components/AbstractActiveQueryContentContainer.php b/protected/humhub/modules/content/components/AbstractActiveQueryContentContainer.php new file mode 100644 index 0000000000..2e4cde72f1 --- /dev/null +++ b/protected/humhub/modules/content/components/AbstractActiveQueryContentContainer.php @@ -0,0 +1,69 @@ + $guid]); - if ($contentContainer !== null) { - /* @var Space|User $contentContainerClass */ - $contentContainerClass = $contentContainer->class; - - $query = $contentContainerClass::find()->where(['guid' => $guid]); - if (!Yii::$app->user->can(new ManageSpaces())) { - $query->visible(); - } - return $query->one(); - } + if (empty($guid)) { + return null; } - return null; + $contentContainer = ContentContainer::findOne(['guid' => $guid]); + if ($contentContainer === null) { + return null; + } + + /* @var Space|User $contentContainerClass */ + $contentContainerClass = $contentContainer->class; + + return $contentContainerClass::find()->where(['guid' => $guid])->visible()->one(); } } diff --git a/protected/humhub/modules/content/models/ContentContainer.php b/protected/humhub/modules/content/models/ContentContainer.php index 433af0bcd3..b22087770f 100644 --- a/protected/humhub/modules/content/models/ContentContainer.php +++ b/protected/humhub/modules/content/models/ContentContainer.php @@ -8,11 +8,8 @@ namespace humhub\modules\content\models; - use humhub\components\behaviors\PolymorphicRelation; use humhub\modules\content\components\ContentContainerActiveRecord; -use humhub\modules\space\models\Space; -use humhub\modules\user\models\User; use yii\db\ActiveRecord; /** diff --git a/protected/humhub/modules/space/components/ActiveQuerySpace.php b/protected/humhub/modules/space/components/ActiveQuerySpace.php index e9cda8ab67..9e3133daa6 100644 --- a/protected/humhub/modules/space/components/ActiveQuerySpace.php +++ b/protected/humhub/modules/space/components/ActiveQuerySpace.php @@ -10,9 +10,10 @@ namespace humhub\modules\space\components; use humhub\events\ActiveQueryEvent; +use humhub\modules\admin\permissions\ManageSpaces; +use humhub\modules\content\components\AbstractActiveQueryContentContainer; use humhub\modules\space\models\Membership; use humhub\modules\space\models\Space; -use humhub\modules\user\components\ActiveQueryUser; use humhub\modules\user\models\User; use humhub\modules\user\Module; use Yii; @@ -24,10 +25,8 @@ use yii\db\ActiveQuery; * * @since 1.4 */ -class ActiveQuerySpace extends ActiveQuery +class ActiveQuerySpace extends AbstractActiveQueryContentContainer { - const MAX_SEARCH_NEEDLES = 5; - /** * @event Event an event that is triggered when only visible spaces are requested via [[visible()]]. */ @@ -36,10 +35,10 @@ class ActiveQuerySpace extends ActiveQuery /** * Only returns spaces which are visible for this user * - * @param User|null $user - * @return ActiveQuerySpace the query + * @inheritdoc + * @return self */ - public function visible(User $user = null) + public function visible(?User $user = null): ActiveQuery { $this->trigger(self::EVENT_CHECK_VISIBILITY, new ActiveQueryEvent(['query' => $this])); @@ -52,6 +51,10 @@ class ActiveQuerySpace extends ActiveQuery } if ($user !== null) { + if ($user->can(ManageSpaces::class)) { + return $this; + } + $this->andWhere(['OR', ['IN', 'space.visibility', [Space::VISIBILITY_ALL, Space::VISIBILITY_REGISTERED_ONLY]], ['AND', @@ -67,13 +70,18 @@ class ActiveQuerySpace extends ActiveQuery } /** - * Performs a space full text search - * - * @param string|array $keywords - * @param array $columns - * @return ActiveQuerySpace the query + * @inerhitdoc */ - public function search($keywords, $columns = ['space.name', 'space.description', 'contentcontainer.tags_cached']) + protected function getSearchableFields(): array + { + return ['space.name', 'space.description', 'contentcontainer.tags_cached']; + } + + /** + * @inheritdoc + * @return self + */ + public function search($keywords, ?array $fields = null): ActiveQuery { if (empty($keywords)) { return $this; @@ -81,26 +89,36 @@ class ActiveQuerySpace extends ActiveQuery $this->joinWith('contentContainerRecord'); - if (!is_array($keywords)) { - $keywords = explode(' ', $keywords); - } - - foreach (array_slice($keywords, 0, static::MAX_SEARCH_NEEDLES) as $keyword) { - $conditions = []; - foreach ($columns as $field) { - $conditions[] = ['LIKE', $field, $keyword]; - } - $this->andWhere(array_merge(['OR'], $conditions)); + foreach ($this->setUpKeywords($keywords) as $keyword) { + $this->searchKeyword($keyword, $fields); } return $this; } + /** + * @inheritdoc + * @return self + */ + public function searchKeyword(string $keyword, ?array $fields = null): ActiveQuery + { + if (empty($fields)) { + $fields = $this->getSearchableFields(); + } + + $conditions = []; + foreach ($fields as $field) { + $conditions[] = ['LIKE', $field, $keyword]; + } + + return $this->andWhere(array_merge(['OR'], $conditions)); + } + /** * Exclude blocked spaces for the given $user or for the current User * - * @param User $user - * @return ActiveQueryUser the query + * @param User|null $user + * @return self */ public function filterBlockedSpaces(?User $user = null): ActiveQuerySpace { diff --git a/protected/humhub/modules/user/components/ActiveQueryUser.php b/protected/humhub/modules/user/components/ActiveQueryUser.php index 57b8c8d2ed..c388a07c0c 100644 --- a/protected/humhub/modules/user/components/ActiveQueryUser.php +++ b/protected/humhub/modules/user/components/ActiveQueryUser.php @@ -10,10 +10,12 @@ namespace humhub\modules\user\components; use humhub\events\ActiveQueryEvent; use humhub\modules\admin\permissions\ManageUsers; +use humhub\modules\content\components\AbstractActiveQueryContentContainer; use humhub\modules\user\models\fieldtype\BaseTypeVirtual; use humhub\modules\user\models\Group; use humhub\modules\user\models\GroupUser; use humhub\modules\user\models\ProfileField; +use humhub\modules\user\models\User; use humhub\modules\user\models\User as UserModel; use humhub\modules\user\Module; use Yii; @@ -24,17 +26,8 @@ use yii\db\ActiveQuery; * * @author luke */ -class ActiveQueryUser extends ActiveQuery +class ActiveQueryUser extends AbstractActiveQueryContentContainer { - /** - * Query keywords will be broken down into array needles with this length - * Meaning, if you search for "word1 word2 word3" and MAX_SEARCH_NEEDLES being 2 - * word3 will be left out, and search will only look for word1, word2. - * - * @var string - */ - const MAX_SEARCH_NEEDLES = 5; - /** * @event Event an event that is triggered when only visible users are requested via [[visible()]]. */ @@ -73,20 +66,36 @@ class ActiveQueryUser extends ActiveQuery * Returns only users that should appear in user lists or in the search results. * Also only active (enabled) users are returned. * - * @return ActiveQueryUser the query * @since 1.2.3 + * @inheritdoc + * @return self */ - public function visible() + public function visible(?User $user = null): ActiveQuery { $this->trigger(self::EVENT_CHECK_VISIBILITY, new ActiveQueryEvent(['query' => $this])); + if ($user === null && !Yii::$app->user->isGuest) { + try { + $user = Yii::$app->user->getIdentity(); + } catch (\Throwable $e) { + Yii::error($e, 'user'); + } + } + $allowedVisibilities = [UserModel::VISIBILITY_ALL]; - if (!Yii::$app->user->isGuest) { + if ($user !== null) { + if ((new PermissionManager(['subject' => $user]))->can(ManageUsers::class)) { + return $this; + } + $allowedVisibilities[] = UserModel::VISIBILITY_REGISTERED_ONLY; } return $this->active() - ->andWhere(['IN', 'user.visibility', $allowedVisibilities]); + ->andWhere(['OR', + ['user.id' => $user->id], // User can view own profile + ['IN', 'user.visibility', $allowedVisibilities] + ]); } @@ -104,14 +113,10 @@ class ActiveQueryUser extends ActiveQuery } /** - * Performs a user full text search - * - * @param string|array $keywords - * @param array|null $fields if empty all searchable profile fields will be used - * - * @return ActiveQueryUser the query + * @inheritdoc + * @return self */ - public function search($keywords, $fields = null) + public function search($keywords, ?array $fields = null): ActiveQuery { if (empty($keywords)) { return $this; @@ -120,21 +125,20 @@ class ActiveQueryUser extends ActiveQuery $this->joinWith('profile')->joinWith('contentContainerRecord'); foreach ($this->setUpKeywords($keywords) as $keyword) { - $this->andWhere(array_merge(['OR'], $this->createKeywordCondition($keyword, $fields))); + $this->searchKeyword($keyword, $fields); } return $this; } /** - * @param $keyword - * @param null $fields - * @return array + * @inheritdoc + * @return self */ - protected function createKeywordCondition($keyword, $fields = null) + public function searchKeyword(string $keyword, ?array $fields = null): ActiveQuery { if (empty($fields)) { - $fields = $this->getSearchableUserFields(); + $fields = $this->getSearchableFields(); } $conditions = []; @@ -148,20 +152,7 @@ class ActiveQueryUser extends ActiveQuery $conditions[] = array_merge(['OR'], $subConditions); } - return $conditions; - } - - /** - * @param $keywords - * @return array - */ - protected function setUpKeywords($keywords) - { - if (!is_array($keywords)) { - $keywords = explode(' ', $keywords); - } - - return array_slice($keywords, 0, static::MAX_SEARCH_NEEDLES); + return $this->andWhere(array_merge(['OR'], $conditions)); } /** @@ -216,11 +207,9 @@ class ActiveQueryUser extends ActiveQuery } /** - * Returns a list of fields to be included in a user search. - * - * @return array + * @inheritdoc */ - private function getSearchableUserFields() + protected function getSearchableFields(): array { $fields = ['user.username', 'contentcontainer.tags_cached']; diff --git a/protected/humhub/modules/user/tests/codeception/acceptance/InvisibleUserCest.php b/protected/humhub/modules/user/tests/codeception/acceptance/InvisibleUserCest.php index 0f269a34d7..9457254028 100644 --- a/protected/humhub/modules/user/tests/codeception/acceptance/InvisibleUserCest.php +++ b/protected/humhub/modules/user/tests/codeception/acceptance/InvisibleUserCest.php @@ -30,7 +30,26 @@ class InvisibleUserCest $I->click('Save'); $I->seeSuccess(); - $I->amGoingTo('be sure Sara Tester is visible'); + $I->amGoingTo('be sure Sara Tester is visible in administration'); + // Administration users list + $I->amOnRoute(['/admin/user']); + $I->waitForText($userName); + + $I->amGoingTo('be sure Sara Tester is visible for owner'); + $I->amUser2(true); + // People + $I->amOnRoute(['/people']); + $I->waitForText('People'); + $I->see($userName); + // Space members + $I->amOnSpace1(); + $I->waitForText('Space members'); + $I->click('Members', '.statistics'); + $I->waitForText('Members', null, '#globalModal'); + $I->see($userName, '#globalModal'); + + $I->amGoingTo('be sure Sara Tester is invisible for other users without permissions'); + $I->amUser1(true); // People $I->amOnRoute(['/people']); $I->waitForText('People'); @@ -41,9 +60,6 @@ class InvisibleUserCest $I->click('Members', '.statistics'); $I->waitForText('Members', null, '#globalModal'); $I->dontSee($userName, '#globalModal'); - // Administration users list - $I->amOnRoute(['/admin/user']); - $I->waitForText($userName); } }