mirror of
https://github.com/humhub/humhub.git
synced 2025-01-16 21:58:17 +01:00
Merge branch 'master' into develop
This commit is contained in:
commit
1f791cde44
@ -32,6 +32,11 @@ HumHub Changelog
|
||||
- Fix #7146: Fix search request by container guid
|
||||
- Fix #7141: Fix meta searching twice for the same keyword
|
||||
- Fix #7150: Remove js statement `with` to avoid error on build assets by grunt uglify
|
||||
- Fix #7156: Fix duplicated following spaces in the chooser widget
|
||||
- Enh #7157: Highlight content after open a page from search results
|
||||
- Fix #7153: Fix content visibility of disabled users
|
||||
- Fix #324: Focus on active and selected nav page after reload on mobile
|
||||
- Fix #7170: Fix rendering of new line on email messages
|
||||
|
||||
1.16.1 (July 1, 2024)
|
||||
---------------------
|
||||
|
@ -32,12 +32,35 @@ class ContentHighlightAsset extends AssetBundle
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if (Yii::$app instanceof Application && Yii::$app->isInstalled()) {
|
||||
$highlight = Yii::$app->session->get('contentHighlight');
|
||||
if ($highlight !== null && $highlight !== '') {
|
||||
Yii::$app->session->remove('contentHighlight');
|
||||
Yii::$app->view->registerJsConfig('content.highlight', ['keyword' => $highlight]);
|
||||
}
|
||||
$keyword = $this->getKeyword();
|
||||
if ($keyword !== null) {
|
||||
Yii::$app->view->registerJsConfig('content.highlight', ['keyword' => $keyword]);
|
||||
}
|
||||
}
|
||||
|
||||
private function getKeyword(): ?string
|
||||
{
|
||||
if (!(Yii::$app instanceof Application && Yii::$app->isInstalled())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$keyword = Yii::$app->session->get('contentHighlight');
|
||||
if ($keyword !== null && $keyword !== '') {
|
||||
Yii::$app->session->remove('contentHighlight');
|
||||
return $keyword;
|
||||
}
|
||||
|
||||
$keyword = Yii::$app->request->get('highlight');
|
||||
if ($keyword !== null && $keyword !== '') {
|
||||
return $keyword;
|
||||
}
|
||||
|
||||
if (isset(Yii::$app->request->referrer) &&
|
||||
preg_match('/search.*?(&|\?)keyword=(.*?)(&|$)/i', Yii::$app->request->referrer, $m) &&
|
||||
$m[2] !== '') {
|
||||
return urldecode($m[2]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -74,9 +74,10 @@ class ActiveQueryContent extends ActiveQuery
|
||||
$this->joinWith(['content', 'content.contentContainer', 'content.createdBy']);
|
||||
$this->leftJoin('space', 'contentcontainer.pk=space.id AND contentcontainer.class=:spaceClass', [':spaceClass' => Space::class]);
|
||||
$this->leftJoin('user cuser', 'contentcontainer.pk=cuser.id AND contentcontainer.class=:userClass', [':userClass' => User::class]);
|
||||
$conditionSpace = '';
|
||||
$conditionUser = '';
|
||||
$globalCondition = '';
|
||||
|
||||
if (!Yii::$app->getModule('stream')->showDeactivatedUserContent) {
|
||||
$this->andWhere(['user.status' => User::STATUS_ENABLED]);
|
||||
}
|
||||
|
||||
if ($user !== null) {
|
||||
$this->leftJoin('space_membership', 'contentcontainer.pk=space_membership.space_id AND contentcontainer.class=:spaceClass AND space_membership.user_id=:userId', [':userId' => $user->id, ':spaceClass' => Space::class]);
|
||||
@ -111,18 +112,17 @@ class ActiveQueryContent extends ActiveQuery
|
||||
|
||||
// Created content of is always visible
|
||||
$conditionUser .= 'OR content.created_by=' . $user->id;
|
||||
$globalCondition .= 'content.contentcontainer_id IS NULL';
|
||||
$globalCondition = 'content.contentcontainer_id IS NULL';
|
||||
} elseif (AuthHelper::isGuestAccessEnabled()) {
|
||||
$conditionSpace = 'space.id IS NOT NULL and space.visibility=' . Space::VISIBILITY_ALL . ' AND content.visibility=1';
|
||||
$conditionUser = 'cuser.id IS NOT NULL and cuser.visibility=' . User::VISIBILITY_ALL . ' AND content.visibility=1';
|
||||
$globalCondition .= 'content.contentcontainer_id IS NULL AND content.visibility=1';
|
||||
$globalCondition = 'content.contentcontainer_id IS NULL AND content.visibility=1';
|
||||
} else {
|
||||
return $this->emulateExecution();
|
||||
}
|
||||
|
||||
$this->andWhere("{$conditionSpace} OR {$conditionUser} OR {$globalCondition}");
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
65
protected/humhub/modules/content/jobs/ReindexUserContent.php
Normal file
65
protected/humhub/modules/content/jobs/ReindexUserContent.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\jobs;
|
||||
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\content\services\ContentSearchService;
|
||||
use humhub\modules\content\services\SearchJobService;
|
||||
use humhub\modules\queue\interfaces\ExclusiveJobInterface;
|
||||
use humhub\modules\queue\LongRunningActiveJob;
|
||||
use humhub\modules\user\models\User;
|
||||
|
||||
class ReindexUserContent extends LongRunningActiveJob implements ExclusiveJobInterface
|
||||
{
|
||||
public $userId;
|
||||
|
||||
/**
|
||||
* @inhertidoc
|
||||
*/
|
||||
public function getExclusiveJobId()
|
||||
{
|
||||
return 'content-search.reindex-user.' . $this->userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inhertidoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
return $this->getService()->run(function () {
|
||||
$user = User::findOne(['id' => $this->userId]);
|
||||
if (!$user) {
|
||||
return;
|
||||
}
|
||||
|
||||
$contents = Content::find()
|
||||
->where(['created_by' => $user->id]);
|
||||
|
||||
foreach ($contents->each() as $content) {
|
||||
if ($user->status === User::STATUS_ENABLED) {
|
||||
(new ContentSearchService($content))->update(false);
|
||||
} else {
|
||||
(new ContentSearchService($content))->delete(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function canRetry($attempt, $error)
|
||||
{
|
||||
return $this->getService()->canRetry($attempt);
|
||||
}
|
||||
|
||||
public function getService(): SearchJobService
|
||||
{
|
||||
return new SearchJobService();
|
||||
}
|
||||
}
|
@ -3,9 +3,13 @@ humhub.module('content.highlight', function (module, require, $) {
|
||||
const event = require('event');
|
||||
const highlightWords = require('ui.additions').highlightWords;
|
||||
|
||||
const layout = $('.layout-content-container');
|
||||
const layout = $('.layout-content-container').length
|
||||
? $('.layout-content-container')
|
||||
: $('#layout-content');
|
||||
|
||||
const init = function () {
|
||||
$(document).ready(() => highlight());
|
||||
|
||||
event.on('humhub:modules:content:highlight:afterInit', () => highlight());
|
||||
layout.find('[data-ui-widget="ui.richtext.prosemirror.RichText"]')
|
||||
.on('afterRender', (obj) => highlight(obj.target));
|
||||
|
@ -10,6 +10,7 @@ use humhub\modules\content\Module;
|
||||
use humhub\modules\content\search\driver\AbstractDriver;
|
||||
use humhub\modules\file\converter\TextConverter;
|
||||
use humhub\modules\file\models\File;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
|
||||
class ContentSearchService
|
||||
@ -21,7 +22,7 @@ class ContentSearchService
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function update($asActiveJob = true): void
|
||||
public function update(bool $asActiveJob = true): void
|
||||
{
|
||||
if (!$this->isIndexable()) {
|
||||
return;
|
||||
@ -38,12 +39,8 @@ class ContentSearchService
|
||||
}
|
||||
}
|
||||
|
||||
public function delete($asActiveJob = true): void
|
||||
public function delete(bool $asActiveJob = true): void
|
||||
{
|
||||
if (!$this->isIndexable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($asActiveJob) {
|
||||
Yii::$app->queue->push(new SearchDeleteDocument(['contentId' => $this->content->id]));
|
||||
} else {
|
||||
@ -80,7 +77,16 @@ class ContentSearchService
|
||||
|
||||
public function isIndexable(): bool
|
||||
{
|
||||
return $this->content->stream_channel === Content::STREAM_CHANNEL_DEFAULT;
|
||||
if ($this->content->stream_channel !== Content::STREAM_CHANNEL_DEFAULT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Yii::$app->getModule('stream')->showDeactivatedUserContent) {
|
||||
$author = $this->content->createdBy;
|
||||
return $author && $author->status === User::STATUS_ENABLED;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getSearchDriver(): AbstractDriver
|
||||
|
@ -121,6 +121,6 @@ class RichTextToEmailHtmlConverter extends RichTextToHtmlConverter
|
||||
*/
|
||||
protected function renderParagraph($block)
|
||||
{
|
||||
return '<p>' . nl2br($this->renderAbsy($block['content'])) . "</p>\n";
|
||||
return '<p>' . $this->renderAbsy($block['content']) . "</p>\n";
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ use humhub\modules\user\events\UserEvent;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\space\models\Membership;
|
||||
use humhub\modules\space\helpers\MembershipHelper;
|
||||
use humhub\modules\user\models\Follow;
|
||||
use Yii;
|
||||
use yii\base\BaseObject;
|
||||
use humhub\components\Event;
|
||||
@ -85,6 +86,18 @@ class Events extends BaseObject
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$integrityController->showTestHeadline('Space Module - Follow (' . Follow::find()->where(['object_model' => Space::class])->count() . ' entries)');
|
||||
$follows = Follow::find()
|
||||
->innerJoin('space_membership', 'space_membership.user_id = user_follow.user_id AND space_membership.space_id = user_follow.object_id')
|
||||
->where(['user_follow.object_model' => Space::class])
|
||||
->andWhere(['space_membership.status' => Membership::STATUS_MEMBER]);
|
||||
foreach ($follows->each() as $follow) {
|
||||
/* @var Follow $follow */
|
||||
if ($integrityController->showFix('Deleting a following of user #' . $follow->user_id . ' to space #' . $follow->object_id . ' because of membership!')) {
|
||||
$follow->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@ namespace stream\acceptance;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use humhub\modules\user\models\User;
|
||||
use stream\AcceptanceTester;
|
||||
use Yii;
|
||||
|
||||
@ -377,6 +378,28 @@ class StreamCest
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @skip Skip it while Yii::$app->getModule('stream')->showDeactivatedUserContent === true
|
||||
*/
|
||||
public function testDisabledUserPost(AcceptanceTester $I)
|
||||
{
|
||||
$I->wantTo('ensure that content of disabled users is not visible');
|
||||
|
||||
$I->amAdmin();
|
||||
|
||||
$I->amOnSpace2();
|
||||
$I->waitForText('Admin Space 2 Post Public');
|
||||
$I->see('User 2 Space 2 Post Public');
|
||||
|
||||
$user2 = User::findOne(['id' => 2]);
|
||||
$user2->status = User::STATUS_DISABLED;
|
||||
$user2->save();
|
||||
|
||||
$I->amOnSpace2();
|
||||
$I->waitForText('Admin Space 2 Post Public');
|
||||
$I->dontSee('User 2 Space 2 Post Public');
|
||||
}
|
||||
|
||||
// Filtering
|
||||
// multi click logic
|
||||
// empty form
|
||||
|
@ -8,14 +8,14 @@
|
||||
|
||||
namespace humhub\modules\user\behaviors;
|
||||
|
||||
use humhub\components\Controller;
|
||||
use humhub\modules\content\components\ContentContainerController;
|
||||
use humhub\modules\user\helpers\AuthHelper;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
use yii\base\Behavior;
|
||||
use yii\base\InvalidValueException;
|
||||
use yii\web\HttpException;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\components\Controller;
|
||||
|
||||
/**
|
||||
* ProfileController Behavior
|
||||
@ -72,6 +72,10 @@ class ProfileController extends Behavior
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
if ($this->user->status == User::STATUS_DISABLED) {
|
||||
throw new HttpException(404, Yii::t('UserModule.profile', 'This profile is disabled!'));
|
||||
}
|
||||
|
||||
if ($this->user->status == User::STATUS_NEED_APPROVAL) {
|
||||
throw new HttpException(404, Yii::t('UserModule.profile', 'This user account is not approved yet!'));
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ use humhub\modules\admin\permissions\ManageSpaces;
|
||||
use humhub\modules\admin\permissions\ManageUsers;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\components\ContentContainerSettingsManager;
|
||||
use humhub\modules\content\jobs\ReindexUserContent;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\friendship\models\Friendship;
|
||||
use humhub\modules\space\helpers\MembershipHelper;
|
||||
@ -583,6 +584,12 @@ class User extends ContentContainerActiveRecord implements IdentityInterface
|
||||
$this->profile->user_id = $this->id;
|
||||
}
|
||||
|
||||
// Reindex user content when status is changed to/from Enabled
|
||||
if (!$insert && isset($changedAttributes['status']) &&
|
||||
($this->status === User::STATUS_ENABLED || $changedAttributes['status'] === User::STATUS_ENABLED)) {
|
||||
Yii::$app->queue->push(new ReindexUserContent(['userId' => $this->id]));
|
||||
}
|
||||
|
||||
// Don't move this line under setUpApproved() because ContentContainer record should be created firstly
|
||||
parent::afterSave($insert, $changedAttributes);
|
||||
|
||||
|
@ -51,6 +51,14 @@ class LoginCest
|
||||
$I->waitForText('Your account is disabled!');
|
||||
}
|
||||
|
||||
public function testDisabledUserProfilePage(AcceptanceTester $I)
|
||||
{
|
||||
$I->wantTo('ensure that disabled user profile page is not viewable');
|
||||
$I->amAdmin();
|
||||
$I->amOnPage('/u/disableduser');
|
||||
$I->waitForText('This profile is disabled!');
|
||||
}
|
||||
|
||||
public function testUnApprovedUser(AcceptanceTester $I)
|
||||
{
|
||||
$user = User::findOne(['id' => 4]);
|
||||
|
@ -14,16 +14,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
a.list-group-item:hover,
|
||||
a.list-group-item.active,
|
||||
a.list-group-item.active:hover,
|
||||
a.list-group-item.active:focus {
|
||||
z-index: 2;
|
||||
color: @text-color-highlight;
|
||||
background-color: @background-color-secondary;
|
||||
border-left: 3px solid @info !important;
|
||||
a.list-group-item {
|
||||
|
||||
.listGroupItemActiveOrFocus {
|
||||
z-index: 2;
|
||||
color: @text-color-highlight;
|
||||
background-color: @background-color-secondary;
|
||||
border-left: 3px solid @info !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.listGroupItemActiveOrFocus();
|
||||
}
|
||||
|
||||
// Hover effect only on desktop
|
||||
&:hover, &.active:hover, &.active:focus {
|
||||
background: inherit;
|
||||
color: inherit;
|
||||
border-left: none !important;
|
||||
}
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover, &.active:hover, &.active:focus {
|
||||
.listGroupItemActiveOrFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.list-group {
|
||||
margin-left: 4px;
|
||||
@ -41,9 +58,22 @@ a.list-group-item.active:focus {
|
||||
|
||||
}
|
||||
|
||||
a.list-group-item:hover, a.list-group-item.active, a.list-group-item.active:hover, a.list-group-item.active:focus {
|
||||
border: none !important;
|
||||
background: @primary !important;
|
||||
color: #fff !important;
|
||||
a.list-group-item {
|
||||
.mobileListGroupItemActiveOrFocus {
|
||||
border: none !important;
|
||||
background: @primary !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.mobileListGroupItemActiveOrFocus();
|
||||
}
|
||||
|
||||
// Hover effect only on desktop
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
&:hover, &.active:hover, &.active:focus {
|
||||
.mobileListGroupItemActiveOrFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user