diff --git a/CHANGELOG.md b/CHANGELOG.md index d194fb2632..9276467dff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ HumHub Changelog --------------------- - Fix #7102: Fix content search with word ending with hyphen - Fix #7104: Missing `--text-color-default` CSS variable +- Enh #7105: Add an external link icon to the "Install Updates" button to avoid thinking it updates the modules directly +- Fix #7116: Fix rebuilding the search index with Grunt (since 1.16.0) +- Fix #7120: Error after failed migration of content fulltext index +- Fix #7126: Fix member count on a space directory +- Enh #6794: Improve log wrong parsing of OEmbed URL +- Fix #6794: Add `User-Agent` to oEmbed CURL request (fix for Reddit) 1.16.1 (July 1, 2024) --------------------- diff --git a/Gruntfile.js b/Gruntfile.js index 00dd5ac8f7..ba302a5bdb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,11 +6,11 @@ module.exports = function (grunt) { var cssMinAssetcfg = {}; cssMinAssetcfg[grunt.option('to')] = [grunt.option('from')]; - var isWin = function() { + var isWin = function () { return (process.platform === "win32"); }; - var cmdSep = function() { + var cmdSep = function () { return isWin() ? '&' : ';'; }; @@ -19,7 +19,7 @@ module.exports = function (grunt) { clean: ["assets/*"], shell: { buildAssets: { - command: function() { + command: function () { let rm = isWin() ? 'del' : 'rm'; let sep = cmdSep(); let delAssets = isWin() ? '(For /D %i in (static\\assets\\*.*) do (rmdir %i /S /Q))' : `${rm} -rf static/assets/*/`; @@ -30,18 +30,18 @@ module.exports = function (grunt) { } }, buildSearch: { - command: function() { + command: function () { let sep = cmdSep(); - return `cd protected ${sep} php yii search/rebuild`; + return `cd protected ${sep} php yii content-search/rebuild`; } }, testServer: { command: "php -S localhost:8080 index-test.php" }, testRun: { - command: function() { + command: function () { let sep = cmdSep(); - let moduleName = grunt.option('module') || grunt.option('m') || null; + let moduleName = grunt.option('module') || grunt.option('m') || null; let doBuild = grunt.option('build') || false; let base = process.cwd(); @@ -49,7 +49,7 @@ module.exports = function (grunt) { let rootTestPath = `${base}/protected/humhub/tests`; let testPath = rootTestPath; - if(moduleName) { + if (moduleName) { testPath = `${base}/protected/humhub/modules/${moduleName}/tests`; } @@ -57,10 +57,10 @@ module.exports = function (grunt) { let path = grunt.option('path') || null; let executionPath = ''; - if(suite) { + if (suite) { executionPath = suite; - } else if(path) { - if(path.indexOf('codeception') !== 0) { + } else if (path) { + if (path.indexOf('codeception') !== 0) { path = 'codeception' + ((path.indexOf('/') !== 0) ? '/' : '') + path; } executionPath = path; @@ -69,10 +69,10 @@ module.exports = function (grunt) { let options = grunt.option('options') || ''; options += grunt.option('raw') ? ' --no-ansi' : ''; options += grunt.option('debug') ? ' -d' : ''; - options += grunt.option('env') ? ' --env '+ grunt.option('env') : ''; + options += grunt.option('env') ? ' --env ' + grunt.option('env') : ''; - let build = `cd ${rootTestPath} ${sep} php ${codeceptPath} build`; + let build = `cd ${rootTestPath} ${sep} php ${codeceptPath} build`; let run = `cd ${testPath} ${sep} php ${codeceptPath} run ${executionPath} ${options}`; @@ -80,21 +80,21 @@ module.exports = function (grunt) { } }, buildTheme: { - command: function(name) { + command: function (name) { let theme = name || grunt.option('name') || "HumHub"; let sep = cmdSep(); return `cd themes/${theme}/less ${sep} lessc -x build.less ../css/theme.css`; } }, migrateCreate: { - command: function(name) { + command: function (name) { let migrationName = name || grunt.option('name'); let sep = cmdSep(); return `cd protected ${sep} php yii migrate/create ${migrationName}`; } }, migrateUp: { - command: function(modules) { + command: function (modules) { let includeModuleMigrations = modules || grunt.option('modules') || "1"; let sep = cmdSep(); return `cd protected ${sep} php yii migrate/up --includeModuleMigrations=${includeModuleMigrations}`; diff --git a/protected/humhub/libs/UrlOembedHttpClient.php b/protected/humhub/libs/UrlOembedHttpClient.php index 5451f5958a..7cc69e4041 100644 --- a/protected/humhub/libs/UrlOembedHttpClient.php +++ b/protected/humhub/libs/UrlOembedHttpClient.php @@ -24,6 +24,7 @@ class UrlOembedHttpClient implements UrlOembedClient $curl = curl_init($url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_TIMEOUT, 15); + curl_setopt($curl, CURLOPT_USERAGENT, Yii::$app->name); // Not available when open_basedir is set. if (!function_exists('ini_get') || !ini_get('open_basedir')) { @@ -62,7 +63,8 @@ class UrlOembedHttpClient implements UrlOembedClient return Json::decode($json); } } catch (\Exception $ex) { - Yii::warning($ex); + Yii::warning("Error decoding JSON from OEmbed URL:\n" . $json . + "\n\n" . $ex->getTraceAsString()); } return null; diff --git a/protected/humhub/migrations/m220121_193617_oembed_setting_update.php b/protected/humhub/migrations/m220121_193617_oembed_setting_update.php index 5faa19bcd4..817cc1d7b9 100644 --- a/protected/humhub/migrations/m220121_193617_oembed_setting_update.php +++ b/protected/humhub/migrations/m220121_193617_oembed_setting_update.php @@ -51,6 +51,10 @@ class m220121_193617_oembed_setting_update extends Migration 'pattern' => '/slideshare\.net/', 'endpoint' => 'https://www.slideshare.net/api/oembed/2?url=%url%&format=json&maxwidth=450', ], + 'Reddit' => [ + 'pattern' => '/reddit\.com/', + 'endpoint' => 'https://www.reddit.com/oembed?format=json&url=%url%', + ], ]; foreach (UrlOembed::getProviders() as $providerUrl => $providerEndpoint) { diff --git a/protected/humhub/modules/admin/widgets/views/available-module-updates-info.php b/protected/humhub/modules/admin/widgets/views/available-module-updates-info.php index 9827818886..f582c55771 100644 --- a/protected/humhub/modules/admin/widgets/views/available-module-updates-info.php +++ b/protected/humhub/modules/admin/widgets/views/available-module-updates-info.php @@ -10,7 +10,7 @@ use humhub\modules\marketplace\widgets\MarketplaceLink; /* @var int $count */ ?>
- right()->sm() ?> + icon('external-link')->right()->sm() ?> $count]) ?>
diff --git a/protected/humhub/modules/comment/models/forms/CommentForm.php b/protected/humhub/modules/comment/models/forms/CommentForm.php index 5b68f1570f..06d9e7b6d8 100644 --- a/protected/humhub/modules/comment/models/forms/CommentForm.php +++ b/protected/humhub/modules/comment/models/forms/CommentForm.php @@ -57,10 +57,7 @@ class CommentForm extends yii\base\Model } /** - * @param null $attributeNames - * @param bool $clearErrors - * @return bool - * @throws ServerErrorHttpException + * @inheritdoc */ public function validate($attributeNames = null, $clearErrors = true) { @@ -70,6 +67,7 @@ class CommentForm extends yii\base\Model if (!$this->comment->validate() || !parent::validate($attributeNames, $clearErrors)) { $this->comment->addError('message', Yii::t('CommentModule.base', 'Comment could not be saved!')); + return false; } if (!empty($this->comment->message)) { @@ -82,6 +80,7 @@ class CommentForm extends yii\base\Model } $this->comment->addError('message', Yii::t('CommentModule.base', 'The comment must not be empty!')); + return false; } /** diff --git a/protected/humhub/modules/content/migrations/m240715_150726_fulltext_index.php b/protected/humhub/modules/content/migrations/m240715_150726_fulltext_index.php new file mode 100644 index 0000000000..c297290bb4 --- /dev/null +++ b/protected/humhub/modules/content/migrations/m240715_150726_fulltext_index.php @@ -0,0 +1,42 @@ +indexExists('ftx', 'content_fulltext')) { + return; + } + + try { + $this->execute('ALTER TABLE content_fulltext ADD FULLTEXT INDEX ftx (contents, comments, files)'); + + Yii::$app->queue->push(new SearchRebuildIndex()); + + FileHelper::removeDirectory(Yii::getAlias('@runtime/searchdb')); + } catch (\Exception $ex) { + Yii::error('Could not execute content fulltext search migration: ' . $ex->getMessage()); + } + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + echo "m240715_150726_fulltext_index cannot be reverted.\n"; + + return false; + } +} diff --git a/protected/humhub/modules/space/services/MemberListService.php b/protected/humhub/modules/space/services/MemberListService.php index 23992ee735..7e21349539 100644 --- a/protected/humhub/modules/space/services/MemberListService.php +++ b/protected/humhub/modules/space/services/MemberListService.php @@ -11,6 +11,7 @@ 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 Yii; /** * @since 1.14 @@ -34,6 +35,18 @@ class MemberListService return Membership::getSpaceMembersQuery($this->space, true, $withNotifications); } + public function getReadableQuery(?User $user = null): ActiveQueryUser + { + $query = Membership::getSpaceMembersQuery($this->space); + + if (Yii::$app->user->isGuest) { + return $query->active() + ->andWhere(['!=', 'user.visibility', User::VISIBILITY_HIDDEN]); + } + + return $query->visible($user); + } + public function getQuery(?User $user = null): ActiveQueryUser { return Membership::getSpaceMembersQuery($this->space)->visible($user); @@ -44,8 +57,8 @@ class MemberListService return $this->getQuery($user)->filterBlockedUsers($user); } - public function getCount(): int + public function getCount(?User $user = null): int { - return $this->getQuery()->count(); + return $this->getQuery($user)->count(); } } diff --git a/protected/humhub/modules/space/widgets/SpaceDirectoryIcons.php b/protected/humhub/modules/space/widgets/SpaceDirectoryIcons.php index 822f4c24bf..1a9087fb1b 100644 --- a/protected/humhub/modules/space/widgets/SpaceDirectoryIcons.php +++ b/protected/humhub/modules/space/widgets/SpaceDirectoryIcons.php @@ -34,7 +34,11 @@ class SpaceDirectoryIcons extends Widget } $membership = $this->space->getMembership(); - $membersCount = $this->space->getMemberListService()->getCount(); + + $membersCountQuery = $this->space->getMemberListService()->getReadableQuery(); + $membersCount = Yii::$app->runtimeCache->getOrSet(__METHOD__ . Yii::$app->user->id . '-' . $this->space->id, function () use ($membersCountQuery) { + return $membersCountQuery->count(); + }); return $this->render('spaceDirectoryIcons', [ 'space' => $this->space, diff --git a/protected/humhub/tests/codeception/fixtures/data/setting.php b/protected/humhub/tests/codeception/fixtures/data/setting.php index 2802840a49..ec97273046 100644 --- a/protected/humhub/tests/codeception/fixtures/data/setting.php +++ b/protected/humhub/tests/codeception/fixtures/data/setting.php @@ -70,6 +70,10 @@ return [ 'pattern' => '/slideshare\.net/', 'endpoint' => 'https://www.slideshare.net/api/oembed/2?url=%url%&format=json&maxwidth=450', ], + 'Reddit' => [ + 'pattern' => '/reddit\.com/', + 'endpoint' => 'https://www.reddit.com/oembed?format=json&url=%url%', + ], ]), 'module_id' => 'base'], ['name' => 'defaultLanguage', 'value' => 'en-US', 'module_id' => 'base'], ['name' => 'maintenanceMode', 'value' => '0', 'module_id' => 'base'],