mirror of
https://github.com/humhub/humhub.git
synced 2025-04-20 07:02:13 +02:00
Compare commits
48 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
24052f9fff | ||
|
e927b4256f | ||
|
daf7ac12d2 | ||
|
a483f791a7 | ||
|
cc4b81a30c | ||
|
9a21276770 | ||
|
6b04a6a83e | ||
|
e4360f144c | ||
|
7e1a9aad94 | ||
|
edabe6036c | ||
|
9124eff27f | ||
|
0c56f2c7fa | ||
|
09b59a8bbc | ||
|
98b0dce221 | ||
|
3b6ec3d127 | ||
|
6a612c93f5 | ||
|
6f98ac37b1 | ||
|
164105b9a6 | ||
|
a8968c6fef | ||
|
c8be19776f | ||
|
163d948e6b | ||
|
a8ca3746ae | ||
|
365705433b | ||
|
bfdc4a913a | ||
|
03d21e4bd0 | ||
|
fe53f44547 | ||
|
8f9d04389a | ||
|
c904807b0a | ||
|
e5bb6a246a | ||
|
99969d2175 | ||
|
2885844519 | ||
|
ad0b0c8b86 | ||
|
ae3502fe82 | ||
|
38025387c7 | ||
|
e6d72bd182 | ||
|
645651cd60 | ||
|
e30c00b523 | ||
|
02400a8eae | ||
|
76a70079a2 | ||
|
c2737c384c | ||
|
056e0d4654 | ||
|
e31c77d603 | ||
|
c238611a65 | ||
|
eecf111971 | ||
|
eca400bbae | ||
|
6163852d8a | ||
|
376deed743 | ||
|
80b24f90c6 |
10
.github/workflows/php-test.yml
vendored
10
.github/workflows/php-test.yml
vendored
@ -1,6 +1,7 @@
|
||||
name: PHP Codeception Tests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
@ -56,7 +57,7 @@ jobs:
|
||||
steps:
|
||||
- name: Start Selenium
|
||||
run: |
|
||||
docker run --detach --net=host --shm-size="2g" selenium/standalone-chrome
|
||||
docker run --detach --net=host --shm-size="2g" selenium/standalone-chrome:108.0-20250123
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
@ -119,7 +120,7 @@ jobs:
|
||||
run: php protected/humhub/tests/codeception/bin/yii installer/auto
|
||||
|
||||
- name: Rebuild search index
|
||||
run: php protected/humhub/tests/codeception/bin/yii search/rebuild
|
||||
run: php protected/humhub/tests/codeception/bin/yii content-search/rebuild
|
||||
|
||||
- name: Run test server
|
||||
run: php --server 127.0.0.1:8080 index-test.php &>/tmp/phpserver.log &
|
||||
@ -138,4 +139,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: codeception-output
|
||||
path: protected/humhub/tests/codeception/_output/*
|
||||
path: |
|
||||
protected/humhub/tests/codeception/_output/*
|
||||
protected/humhub/modules/*/tests/codeception/_output/*
|
||||
protected/runtime/logs/*
|
||||
|
38
CHANGELOG.md
38
CHANGELOG.md
@ -1,6 +1,43 @@
|
||||
HumHub Changelog
|
||||
================
|
||||
|
||||
1.17.3 (Unreleased)
|
||||
----------------------
|
||||
- Fix #7484: Use password type on the installation DB config form
|
||||
- Fix #7486: Catch errors in external file handlers
|
||||
- Fix #7487: Fix comments list when comment is active from another parent comment
|
||||
- Enh #7492: Fix access to options on space invite form
|
||||
|
||||
1.17.2 (April 7, 2025)
|
||||
----------------------
|
||||
- Fix #7457: Fix changing of space visibility
|
||||
- Fix #7464: Fix searching with not full latin words
|
||||
- Fix #7465: Formatted Arabic numbers displays 0 instead of the number
|
||||
- Fix #7471: Fix advanced searching by space filter
|
||||
- Fix #7472: Fix missing fields when creating a new user from admin
|
||||
- Fix #7477: Refactor Registration Form Options
|
||||
- Enh #7455: Add Share Intend feature for the Mobile app
|
||||
- Fix #7482: Fix the post submit button title after back from draft mode
|
||||
|
||||
1.17.1 (March 6, 2025)
|
||||
----------------------
|
||||
- Fix #7377: Configured Redis cache key prefix was overwritten by the default value
|
||||
- Fix #7375: Use default language for email invitation and show language chooser on registration form
|
||||
- Enh #7383: Improve SelfTest for Base URL
|
||||
- Enh #5426: Show language chooser for guest on the sidebar footer
|
||||
- Fix #7395: Fix profile stream for guests
|
||||
- Fix #7400: Fixed `Default user profile visibility` field visibility in the user settings
|
||||
- Fix #7404: Marketplace - Allow symlinked `@app/modules` directory
|
||||
- Fix: Always allow admins to edit/delete content in the other Profile stream
|
||||
- Fix #7414: Fix profile field encoding
|
||||
- Fix #7419: Reset modal window after close
|
||||
- Fix #7428: Fix picker autofocus
|
||||
- Enh #7424: New event on get registration groups
|
||||
- Enh #7437: Add beforeInitCallback `humhub.ui.picker`
|
||||
- Fix #7441: Hide "Remember me" option on mobile app
|
||||
- Enh #7408: Update code to manage users from external modules
|
||||
- Fix #7453: Fix registration form submit
|
||||
|
||||
1.17.0 (January 13, 2025)
|
||||
-------------------------
|
||||
|
||||
@ -10,6 +47,7 @@ Info: The minimum PHP version is now `PHP 8.1`!
|
||||
|
||||
- Fix #7365: `DeviceDetectorHelper::isMobile()` and `DeviceDetectorHelper::isTablet()` when no user agent
|
||||
- Fix #7376: `humhub\helpers\ArrayHelper::flatten()` not compatible Yii base ArrayHelper
|
||||
- Enh #7382: Allow initial collapsed comments bu setting `\humhub\modules\comment\Module::$commentsPreviewMax` to 0
|
||||
|
||||
1.17.0-beta.4 (December 24, 2024)
|
||||
---------------------------------
|
||||
|
@ -1,14 +1,24 @@
|
||||
Module Migration Guide
|
||||
======================
|
||||
|
||||
Version 1.17.2
|
||||
---------------
|
||||
|
||||
Version 1.17 (Unreleased)
|
||||
### Behaviour change
|
||||
|
||||
- Method signature changed - `humhub\modules\user\models\fieldtype\BaseType::getUserValue(User $user, bool $raw = true, bool $encode = true): ?string`
|
||||
|
||||
- Constructor changed - `humhub\modules\user\models\forms\Registration` and properties (`$enablePasswordForm`, `$enableMustChangePassword`, `$enableEmailField`) are now private
|
||||
|
||||
|
||||
Version 1.17
|
||||
-------------------------
|
||||
|
||||
### Behaviour change
|
||||
|
||||
- Forms in modal box no longer have focus automatically on the first field. [The `autofocus` attribute](https://developer.mozilla.org/docs/Web/HTML/Global_attributes/autofocus) is now required on the field. More info: [#7136](https://github.com/humhub/humhub/issues/7136)
|
||||
- The new "Manage All Content" Group Permission allows managing all content (view, edit, move, archive, pin, etc.) even if the user is not a super administrator. It is disabled by default. It can be enabled via the configuration file, using the `\humhub\modules\admin\Module::$enableManageAllContentPermission` option.
|
||||
- System admins are allowed, in all cases (even when `enableManageAllContentPermission` is disabled), to edit and delete content in other Profile streams.
|
||||
- Users allowed to "Manage Users" can no longer move all content: they need to be allowed to "Manage All Content".
|
||||
|
||||
### New
|
||||
|
@ -31,6 +31,7 @@
|
||||
"laminas/laminas-zendframework-bridge": "^1.4",
|
||||
"matthewbdaly/zendsearch": "^0.0.3",
|
||||
"mistic100/randomcolor": "^1.0",
|
||||
"mobiledetect/mobiledetectlib": "4.8.09",
|
||||
"npm-asset/animate.css": "^4.0",
|
||||
"npm-asset/bluebird": "^3.3.5",
|
||||
"npm-asset/blueimp-file-upload": "^9.24",
|
||||
@ -87,8 +88,7 @@
|
||||
"yiisoft/yii2-jui": "^2.0.0",
|
||||
"yiisoft/yii2-queue": "^2.3.0",
|
||||
"yiisoft/yii2-redis": "^2.0.0",
|
||||
"yiisoft/yii2-symfonymailer": "^2.0",
|
||||
"mobiledetect/mobiledetectlib": "4.8.09"
|
||||
"yiisoft/yii2-symfonymailer": "^2.0"
|
||||
},
|
||||
"replace": {
|
||||
},
|
||||
|
1052
composer.lock
generated
1052
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -56,11 +56,15 @@ class HForm extends \yii\base\Component
|
||||
*/
|
||||
public $markedAsSubmitted = false;
|
||||
|
||||
public function __construct($definition = [], $primaryModel = null)
|
||||
public function __construct($definition = [], $primaryModel = null, array $config = [])
|
||||
{
|
||||
$this->definition = $definition;
|
||||
$this->primaryModel = $primaryModel;
|
||||
|
||||
if (!empty($config)) {
|
||||
Yii::configure($this, $config);
|
||||
}
|
||||
|
||||
$this->init();
|
||||
$this->trigger(static::EVENT_AFTER_INIT);
|
||||
}
|
||||
@ -69,11 +73,12 @@ class HForm extends \yii\base\Component
|
||||
{
|
||||
if (Yii::$app->request->method == 'POST') {
|
||||
if ($buttonName == "" || isset($_POST[$buttonName])) {
|
||||
$allowedPostData = $this->getAllowedPostData();
|
||||
foreach ($this->models as $model) {
|
||||
$model->load(Yii::$app->request->post());
|
||||
$model->load($allowedPostData);
|
||||
}
|
||||
if ($this->primaryModel !== null) {
|
||||
$this->primaryModel->load(Yii::$app->request->post());
|
||||
$this->primaryModel->load($allowedPostData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -84,6 +89,32 @@ class HForm extends \yii\base\Component
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getAllowedPostData(): array
|
||||
{
|
||||
$post = Yii::$app->request->post();
|
||||
|
||||
foreach ($this->models as $modelName => $model) {
|
||||
$className = substr(strrchr(get_class($model), '\\'), 1);
|
||||
if (!isset($post[$className])) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($this->definition['elements'][$modelName])) {
|
||||
// Remove post data of the object if no definition
|
||||
unset($post[$className]);
|
||||
}
|
||||
if (isset($this->definition['elements'][$modelName]['elements'])) {
|
||||
foreach ($this->definition['elements'][$modelName]['elements'] as $elementName => $element) {
|
||||
if (!empty($element['readonly']) && isset($post[$className][$elementName])) {
|
||||
// Remove a readonly field from the POST data
|
||||
unset($post[$className][$elementName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function validate()
|
||||
{
|
||||
$hasErrors = false;
|
||||
|
@ -581,8 +581,9 @@ class ModuleManager extends Component
|
||||
$marketplaceModule = Yii::$app->getModule('marketplace');
|
||||
if ($marketplaceModule !== null) {
|
||||
// Normalize paths before comparing in order to fix issues like Windows path separators `\`
|
||||
// Realpath is required when the modules path is a symlinked
|
||||
$modulePath = FileHelper::normalizePath($module->getBasePath());
|
||||
$aliasPath = FileHelper::normalizePath(Yii::getAlias($marketplaceModule->modulesPath));
|
||||
$aliasPath = FileHelper::normalizePath(realpath(Yii::getAlias($marketplaceModule->modulesPath)));
|
||||
if (strpos($modulePath, $aliasPath) !== false) {
|
||||
return true;
|
||||
}
|
||||
|
@ -89,8 +89,13 @@ class Formatter extends \yii\i18n\Formatter
|
||||
*/
|
||||
public function asShortInteger($value, $options = [], $textOptions = [])
|
||||
{
|
||||
list($params, $position) = $this->formatNumber($value, null, 2, 1000, $options, $textOptions);
|
||||
$params['nFormatted'] = floor((float)$params['nFormatted']);
|
||||
list($params, $position) = $this->formatNumber($value, 0, 2, 1000, $options, $textOptions);
|
||||
|
||||
if ($position < 3 && mb_strlen($params['nFormatted']) === 4) {
|
||||
// Convert 1000K to 1M or 1000M to 1B
|
||||
$params['nFormatted'] = mb_substr($params['nFormatted'], 0, 1);
|
||||
$position++;
|
||||
}
|
||||
|
||||
switch ($position) {
|
||||
case 0:
|
||||
|
@ -42,7 +42,7 @@ $logTargetConfig = [
|
||||
|
||||
$config = [
|
||||
'name' => 'HumHub',
|
||||
'version' => '1.17.0',
|
||||
'version' => '1.17.3-master',
|
||||
'minRecommendedPhpVersion' => '8.1',
|
||||
'minSupportedPhpVersion' => '8.1',
|
||||
'basePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR,
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\libs;
|
||||
|
||||
use humhub\widgets\Button;
|
||||
use yii\base\Event;
|
||||
use yii\grid\Column;
|
||||
use yii\helpers\Url;
|
||||
use humhub\libs\Html;
|
||||
@ -20,6 +21,8 @@ use humhub\libs\Html;
|
||||
*/
|
||||
class ActionColumn extends Column
|
||||
{
|
||||
public const EVENT_AFTER_INIT_ACTIONS = 'afterInitActions';
|
||||
|
||||
/**
|
||||
* @var string the ID attribute of the model, to generate action URLs.
|
||||
*/
|
||||
@ -85,6 +88,8 @@ class ActionColumn extends Column
|
||||
return call_user_func($this->actions, $model, $key, $index, $this);
|
||||
}
|
||||
|
||||
Event::trigger($this, self::EVENT_AFTER_INIT_ACTIONS);
|
||||
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
|
@ -92,21 +92,22 @@ class DynamicConfig extends BaseObject
|
||||
|
||||
// Add Caching
|
||||
$cacheClass = Yii::$app->settings->get('cacheClass');
|
||||
$cacheKeyPrefix = empty($config['components']['cache']['keyPrefix']) ? Yii::$app->id : $config['components']['cache']['keyPrefix'];
|
||||
if (in_array($cacheClass, ['yii\caching\DummyCache', 'yii\caching\FileCache'])) {
|
||||
$config['components']['cache'] = [
|
||||
'class' => $cacheClass,
|
||||
'keyPrefix' => Yii::$app->id,
|
||||
'keyPrefix' => $cacheKeyPrefix,
|
||||
];
|
||||
} elseif ($cacheClass == 'yii\caching\ApcCache' && (function_exists('apcu_add') || function_exists('apc_add'))) {
|
||||
$config['components']['cache'] = [
|
||||
'class' => $cacheClass,
|
||||
'keyPrefix' => Yii::$app->id,
|
||||
'keyPrefix' => $cacheKeyPrefix,
|
||||
'useApcu' => (function_exists('apcu_add')),
|
||||
];
|
||||
} elseif ($cacheClass === \yii\redis\Cache::class) {
|
||||
$config['components']['cache'] = [
|
||||
'class' => \yii\redis\Cache::class,
|
||||
'keyPrefix' => Yii::$app->id,
|
||||
'keyPrefix' => $cacheKeyPrefix,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ use humhub\modules\marketplace\Module;
|
||||
use humhub\services\MigrationService;
|
||||
use Yii;
|
||||
use yii\helpers\UnsetArrayValue;
|
||||
use yii\helpers\Url;
|
||||
|
||||
/**
|
||||
* SelfTest is a helper class which checks all dependencies of the application.
|
||||
@ -430,16 +431,7 @@ class SelfTest
|
||||
}
|
||||
|
||||
$title = Yii::t('AdminModule.information', 'Settings') . ' - ' . Yii::t('AdminModule.information', 'Base URL');
|
||||
$scheme = Yii::$app->request->getIsSecureConnection() ? 'https' : 'http';
|
||||
$port = Yii::$app->request->getServerPort();
|
||||
$currentBaseUrl = $scheme . '://' . preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST'])
|
||||
. (
|
||||
($scheme === 'https' && $port == 443) ||
|
||||
($scheme === 'http' && $port == 80)
|
||||
? ''
|
||||
: ':' . $port
|
||||
)
|
||||
. ($_SERVER['BASE'] ?? '');
|
||||
$currentBaseUrl = Url::base(true);
|
||||
if ($currentBaseUrl === Yii::$app->settings->get('baseUrl')) {
|
||||
$checks[] = [
|
||||
'title' => $title,
|
||||
|
@ -132,7 +132,7 @@ class GroupController extends Controller
|
||||
$group = Group::findOne(['id' => Yii::$app->request->get('id')]);
|
||||
$this->checkGroupAccess($group);
|
||||
|
||||
$searchModel = new UserSearch();
|
||||
$searchModel = Yii::createObject(UserSearch::class);
|
||||
$searchModel->query = $group->getUsers();
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
return $this->render('members', [
|
||||
|
@ -83,7 +83,7 @@ class UserController extends Controller
|
||||
*/
|
||||
public function actionList()
|
||||
{
|
||||
$searchModel = new UserSearch();
|
||||
$searchModel = Yii::createObject(UserSearch::class);
|
||||
$searchModel->status = User::STATUS_ENABLED;
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
$showPendingRegistrations = Invite::find()->where(Invite::filterSource())->exists() &&
|
||||
@ -261,10 +261,8 @@ class UserController extends Controller
|
||||
|
||||
public function actionAdd()
|
||||
{
|
||||
$registration = new Registration();
|
||||
$registration->enableEmailField = true;
|
||||
$registration = new Registration(enableEmailField: true, enableMustChangePassword: true);
|
||||
$registration->enableUserApproval = false;
|
||||
$registration->enableMustChangePassword = true;
|
||||
|
||||
if ($registration->submitted('save') && $registration->validate() && $registration->register()) {
|
||||
return $this->redirect(['edit', 'id' => $registration->getUser()->id]);
|
||||
@ -390,7 +388,7 @@ class UserController extends Controller
|
||||
*/
|
||||
public function actionExport($format)
|
||||
{
|
||||
$searchModel = new UserSearch();
|
||||
$searchModel = Yii::createObject(UserSearch::class);
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
|
||||
$exporter = new SpreadsheetExport([
|
||||
|
@ -24,82 +24,35 @@ $this->registerJsConfig('admin.space', [
|
||||
$userModule = Yii::$app->getModule('user');
|
||||
|
||||
$this->beginContent('@admin/views/authentication/_authenticationLayout.php');
|
||||
?>
|
||||
|
||||
echo Html::beginTag('div', ['class' => 'panel-body']);
|
||||
<div class="panel-body">
|
||||
<?php $form = ActiveForm::begin(['id' => 'authentication-settings-form', 'acknowledge' => true]) ?>
|
||||
<?= $form->errorSummary($model) ?>
|
||||
|
||||
$form = ActiveForm::begin(['id' => 'authentication-settings-form', 'acknowledge' => true]);
|
||||
<?= $form->field($model, 'allowGuestAccess')->checkbox() ?>
|
||||
<?= $form->field($model, 'internalAllowAnonymousRegistration')->checkbox() ?>
|
||||
<?= $form->field($model, 'internalUsersCanInviteByEmail')->checkbox() ?>
|
||||
<?= $form->field($model, 'internalUsersCanInviteByLink')->checkbox() ?>
|
||||
<?= $form->field($model, 'internalRequireApprovalAfterRegistration')->checkbox() ?>
|
||||
<?= $form->field($model, 'showRegistrationUserGroup')->checkbox() ?>
|
||||
<?= $form->field($model, 'blockUsers')->checkbox() ?>
|
||||
<?= $form->field($model, 'hideOnlineStatus')->checkbox() ?>
|
||||
<?= $form->field($model, 'allowUserTopics')->checkbox(['data' => ['action-change' => 'admin.space.restrictTopicCreation']]) ?>
|
||||
<?= $form->field($model, 'defaultUserIdleTimeoutSec')->textInput(['readonly' => $userModule->settings->isFixed('auth.defaultUserIdleTimeoutSec')]) ?>
|
||||
<p class="help-block"><?= Yii::t('AdminModule.user', 'The default user idle timeout is used when user session is idle for a certain time. The user is automatically logged out after this time.') ?></p>
|
||||
<?= $form->field($model, 'defaultUserProfileVisibility')->dropDownList(User::getVisibilityOptions(false), ['readonly' => (!Yii::$app->getModule('user')->settings->get('auth.allowGuestAccess'))]) ?>
|
||||
<p class="help-block"><?= Yii::t('AdminModule.user', 'Only applicable when limited access for non-authenticated users is enabled. Only affects new users.') ?></p>
|
||||
|
||||
echo $form->errorSummary($model);
|
||||
<?php if (Yii::$app->getModule('user')->settings->get('auth.needApproval')) : ?>
|
||||
<?= $form->field($model, 'registrationSendMessageMailContent')->widget(RichTextField::class, ['exclude' => ['oembed', 'upload']]) ?>
|
||||
<?= $form->field($model, 'registrationApprovalMailContent')->widget(RichTextField::class, ['exclude' => ['oembed', 'upload']]) ?>
|
||||
<?= $form->field($model, 'registrationDenialMailContent')->widget(RichTextField::class, ['exclude' => ['oembed', 'upload']]) ?>
|
||||
<p class="help-block"><?= Yii::t('AdminModule.user', 'Do not change placeholders like {displayName} if you want them to be automatically filled by the system. To reset the email content fields with the system default, leave them empty.') ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
echo $form->field($model, 'allowGuestAccess')->checkbox();
|
||||
echo $form->field($model, 'internalAllowAnonymousRegistration')->checkbox();
|
||||
echo $form->field($model, 'internalUsersCanInviteByEmail')->checkbox();
|
||||
echo $form->field($model, 'internalUsersCanInviteByLink')->checkbox();
|
||||
echo $form->field($model, 'internalRequireApprovalAfterRegistration')->checkbox();
|
||||
echo $form->field($model, 'showRegistrationUserGroup')->checkbox();
|
||||
echo $form->field($model, 'blockUsers')->checkbox();
|
||||
echo $form->field($model, 'hideOnlineStatus')->checkbox();
|
||||
echo $form->field($model, 'allowUserTopics')->checkbox(['data' => ['action-change' => 'admin.space.restrictTopicCreation']]);
|
||||
echo $form->field($model, 'defaultUserIdleTimeoutSec')
|
||||
->textInput(['readonly' => $userModule->settings->isFixed('auth.defaultUserIdleTimeoutSec')]);
|
||||
|
||||
echo Html::tag(
|
||||
'p',
|
||||
Yii::t(
|
||||
'AdminModule.user',
|
||||
'The default user idle timeout is used when user session is idle for a certain time. The user is automatically logged out after this time.'
|
||||
),
|
||||
['class' => 'help-block']
|
||||
);
|
||||
|
||||
$form->field($model, 'defaultUserProfileVisibility')
|
||||
->dropDownList(
|
||||
User::getVisibilityOptions(false),
|
||||
['readonly' => (!Yii::$app->getModule('user')->settings->get('auth.allowGuestAccess'))]
|
||||
);
|
||||
|
||||
echo Html::tag(
|
||||
'p',
|
||||
Yii::t(
|
||||
'AdminModule.user',
|
||||
'Only applicable when limited access for non-authenticated users is enabled. Only affects new users.'
|
||||
),
|
||||
['class' => 'help-block']
|
||||
);
|
||||
|
||||
if (Yii::$app->getModule('user')->settings->get('auth.needApproval')) {
|
||||
echo $form->field($model, 'registrationSendMessageMailContent')->widget(
|
||||
RichTextField::class,
|
||||
['exclude' => ['oembed', 'upload']]
|
||||
);
|
||||
echo $form->field($model, 'registrationApprovalMailContent')->widget(
|
||||
RichTextField::class,
|
||||
['exclude' => ['oembed', 'upload']]
|
||||
);
|
||||
echo $form->field($model, 'registrationDenialMailContent')->widget(
|
||||
RichTextField::class,
|
||||
['exclude' => ['oembed', 'upload']]
|
||||
);
|
||||
|
||||
echo Html::tag(
|
||||
'p',
|
||||
Yii::t(
|
||||
'AdminModule.user',
|
||||
'Do not change placeholders like {displayName} if you want them to be automatically filled by the system. To reset the email content fields with the system default, leave them empty.',
|
||||
),
|
||||
['class' => 'help-block']
|
||||
);
|
||||
}
|
||||
|
||||
echo Html::tag('hr');
|
||||
|
||||
echo Html::submitButton(
|
||||
Yii::t('AdminModule.user', 'Save'),
|
||||
['class' => 'btn btn-primary', 'data-ui-loader' => ""]
|
||||
);
|
||||
|
||||
ActiveForm::end();
|
||||
|
||||
echo Html::endTag('div');
|
||||
|
||||
$this->endContent();
|
||||
<hr/>
|
||||
<?= Html::submitButton(Yii::t('AdminModule.user', 'Save'), ['class' => 'btn btn-primary', 'data-ui-loader' => '']) ?>
|
||||
<?php ActiveForm::end() ?>
|
||||
</div>
|
||||
<?php $this->endContent() ?>
|
||||
|
@ -10,7 +10,7 @@ use humhub\widgets\Button;
|
||||
?>
|
||||
<div class="panel-body">
|
||||
<div class="pull-right">
|
||||
<?= Button::back(['index'], Yii::t('AdminModule.base', 'Back to overview')) ?>
|
||||
<?= Button::back(['/admin/group/index'], Yii::t('AdminModule.base', 'Back to overview')) ?>
|
||||
</div>
|
||||
|
||||
<?php if (!$group->isNewRecord) : ?>
|
||||
|
@ -302,13 +302,13 @@ class Comment extends ContentAddonActiveRecord
|
||||
->limit($pageSize);
|
||||
|
||||
if ($type === ShowMore::TYPE_NEXT) {
|
||||
$query->orderBy(['created_at' => SORT_ASC]);
|
||||
$query->orderBy(['created_at' => SORT_ASC, 'id' => SORT_ASC]);
|
||||
if ($commentId) {
|
||||
$query->andWhere(['>', 'id', $commentId]);
|
||||
}
|
||||
$comments = $query->all();
|
||||
} else {
|
||||
$query->orderBy(['created_at' => SORT_DESC]);
|
||||
$query->orderBy(['created_at' => SORT_DESC, 'id' => SORT_DESC]);
|
||||
if ($commentId) {
|
||||
$query->andWhere(['<', 'id', $commentId]);
|
||||
}
|
||||
|
@ -308,6 +308,10 @@ humhub.module('comment', function (module, require, $) {
|
||||
if (!visible && !window.comments_collapsed) {
|
||||
target.find('.humhub-ui-richtext').trigger('focus');
|
||||
}
|
||||
|
||||
if (!visible && window.comments_collapsed && !target.find('.comment>.media').length) {
|
||||
target.find('[data-action-click="comment.showMore"]').trigger('click');
|
||||
}
|
||||
}
|
||||
|
||||
var toggleCommentHandler = function (evt) {
|
||||
|
@ -65,9 +65,7 @@ class Comments extends Widget
|
||||
{
|
||||
$objectModel = PolymorphicRelation::getObjectModel($this->object);
|
||||
$objectId = $this->object->getPrimaryKey();
|
||||
|
||||
$streamQuery = Yii::$app->request->getQueryParam('StreamQuery');
|
||||
$currentCommentId = empty($streamQuery['commentId']) ? null : $streamQuery['commentId'];
|
||||
$currentCommentId = $this->getCurrentCommentId();
|
||||
|
||||
// Count all Comments
|
||||
$commentCount = CommentModel::GetCommentCount($objectModel, $objectId);
|
||||
@ -101,4 +99,27 @@ class Comments extends Widget
|
||||
{
|
||||
return $this->isFullViewMode() ? $this->module->commentsBlockLoadSizeViewMode : $this->module->commentsBlockLoadSize;
|
||||
}
|
||||
|
||||
protected function getCurrentCommentId(): ?int
|
||||
{
|
||||
$streamQuery = Yii::$app->request->getQueryParam('StreamQuery');
|
||||
if (empty($streamQuery['commentId'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$currentCommentId = (int) $streamQuery['commentId'];
|
||||
|
||||
$currentComment = Yii::$app->runtimeCache->getOrSet('getCurrentComment' . $currentCommentId, function () use ($currentCommentId) {
|
||||
return CommentModel::findOne(['id' => $currentCommentId]);
|
||||
});
|
||||
|
||||
if (!$currentComment ||
|
||||
$currentComment->object_id !== $this->object?->id ||
|
||||
$currentComment->object_model !== get_class($this->object)) {
|
||||
// The current comment is from another parent object
|
||||
return null;
|
||||
}
|
||||
|
||||
return $currentCommentId;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
<?php
|
||||
|
||||
use humhub\commands\CronController;
|
||||
use humhub\modules\content\Events;
|
||||
use humhub\commands\IntegrityController;
|
||||
use humhub\modules\content\Events;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\content\Module;
|
||||
use humhub\modules\content\widgets\WallEntryAddons;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\user\models\User;
|
||||
|
||||
return [
|
||||
'id' => 'content',
|
||||
|
@ -24,6 +24,7 @@ use yii\base\Exception;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\IntegrityException;
|
||||
use yii\web\ForbiddenHttpException;
|
||||
use yii\web\HttpException;
|
||||
use yii\web\NotFoundHttpException;
|
||||
use yii\web\Response;
|
||||
|
||||
@ -421,4 +422,16 @@ class ContentController extends Controller
|
||||
'disableInputs' => $disableInputs,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after content creation
|
||||
*/
|
||||
public function actionRedirectToContentContainer($contentId)
|
||||
{
|
||||
$content = Content::findOne(['id' => $contentId]);
|
||||
if ($content === null) {
|
||||
throw new HttpException(404, 'Content not found!');
|
||||
}
|
||||
return $this->redirect($content->container->getUrl());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2025 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\controllers;
|
||||
|
||||
use humhub\components\behaviors\AccessControl;
|
||||
use humhub\components\Controller;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\models\ContentContainer;
|
||||
use humhub\modules\content\models\forms\ShareIntendTargetForm;
|
||||
use humhub\modules\space\helpers\CreateContentPermissionHelper;
|
||||
use humhub\modules\user\widgets\UserPicker;
|
||||
use Yii;
|
||||
use yii\web\HttpException;
|
||||
|
||||
/**
|
||||
* Allows sharing files from the mobile app
|
||||
*
|
||||
* @since 1.17.2
|
||||
*/
|
||||
abstract class ShareIntendController extends Controller
|
||||
{
|
||||
abstract public function actionCreate();
|
||||
|
||||
abstract protected function getCreatePermissionClass(): string;
|
||||
|
||||
private const SESSION_KEY_TARGET_GUID = 'shareIntendTargetGuid';
|
||||
|
||||
public ?ContentContainerActiveRecord $shareTarget = null;
|
||||
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'acl' => [
|
||||
'class' => AccessControl::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function beforeAction($action)
|
||||
{
|
||||
if (!parent::beforeAction($action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
\humhub\modules\file\controllers\ShareIntendController::checkShareFileGuids();
|
||||
|
||||
if (!in_array($action->id, ['index', 'container-search-json'])) {
|
||||
$this->initShareTarget();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function initShareTarget(): void
|
||||
{
|
||||
$shareTargetGuid = Yii::$app->session->get(self::SESSION_KEY_TARGET_GUID);
|
||||
$this->shareTarget = ContentContainer::findRecord($shareTargetGuid);
|
||||
if ($this->shareTarget === null) {
|
||||
throw new HttpException('500', 'No target to share found!');
|
||||
}
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
Yii::$app->session->remove(self::SESSION_KEY_TARGET_GUID);
|
||||
|
||||
$model = new ShareIntendTargetForm();
|
||||
|
||||
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
|
||||
Yii::$app->session->set(self::SESSION_KEY_TARGET_GUID, $model->targetContainerGuid);
|
||||
$this->initShareTarget();
|
||||
|
||||
return $this->actionCreate();
|
||||
}
|
||||
|
||||
return $this->renderAjax('@content/views/share-intend/index', [
|
||||
'model' => $model,
|
||||
'fileList' => \humhub\modules\file\controllers\ShareIntendController::getShareFileGuids(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function actionContainerSearchJson()
|
||||
{
|
||||
$containers = CreateContentPermissionHelper::findSpaces(
|
||||
$this->getCreatePermissionClass(),
|
||||
Yii::$app->request->get('keyword'),
|
||||
Yii::$app->user->identity,
|
||||
);
|
||||
|
||||
if (ShareIntendTargetForm::canPostInOwnProfile()) {
|
||||
$currentUser = UserPicker::createJSONUserInfo(Yii::$app->user->identity);
|
||||
$currentUser['text'] = Yii::t('base', 'My Profile');
|
||||
array_unshift($containers, $currentUser);
|
||||
}
|
||||
|
||||
return $this->asJson($containers);
|
||||
}
|
||||
}
|
@ -212,7 +212,7 @@ class Content extends ActiveRecord implements Movable, ContentOwner, Archiveable
|
||||
/**
|
||||
* @since 1.3
|
||||
*/
|
||||
public function getModel(): ContentActiveRecord
|
||||
public function getModel(): ?ContentActiveRecord
|
||||
{
|
||||
return $this->getPolymorphicRelation();
|
||||
}
|
||||
@ -915,11 +915,20 @@ class Content extends ActiveRecord implements Movable, ContentOwner, Archiveable
|
||||
$user = User::findOne(['id' => $user]);
|
||||
}
|
||||
|
||||
// Only owner can edit his content
|
||||
// Owner can edit his content
|
||||
if ($user !== null && $this->created_by === $user->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// System Admins can edit User content for moderation purposes
|
||||
if (
|
||||
$this->id // The content exists
|
||||
&& $this->container instanceof User
|
||||
&& $user->isSystemAdmin()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($user?->canManageAllContent()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\content\models\forms;
|
||||
|
||||
use humhub\modules\post\models\Post;
|
||||
use humhub\modules\user\Module;
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\helpers\Url;
|
||||
|
||||
class ShareIntendTargetForm extends Model
|
||||
{
|
||||
public $targetContainerGuid;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
[['targetContainerGuid'], 'required'],
|
||||
];
|
||||
}
|
||||
|
||||
public function attributeHints(): array
|
||||
{
|
||||
return [
|
||||
'targetContainerGuid' => static::canPostInOwnProfile() ?
|
||||
Yii::t('ContentModule.base', 'Select target Space/Profile.') :
|
||||
Yii::t('ContentModule.base', 'Select target Space.'),
|
||||
];
|
||||
}
|
||||
|
||||
public function getContainerSearchUrl(): string
|
||||
{
|
||||
return Url::to(['container-search-json']);
|
||||
}
|
||||
|
||||
public static function canPostInOwnProfile(): bool
|
||||
{
|
||||
/** @var Module $userModule */
|
||||
$userModule = Yii::$app->getModule('user');
|
||||
return
|
||||
!$userModule->profileDisableStream // The profile stream is enabled
|
||||
&& !Yii::$app->user->isGuest
|
||||
&& (new Post(Yii::$app->user->identity))->content->canEdit(); // Can post in own profile
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
humhub.module('content.form', function (module, require, $) {
|
||||
|
||||
var CREATE_FORM_ROOT_SELECTOR = '#contentFormBody';
|
||||
var CREATE_FORM_ROOT_SELECTOR_MODAL = CREATE_FORM_ROOT_SELECTOR + 'Modal';
|
||||
|
||||
var object = require('util').object;
|
||||
var client = require('client');
|
||||
@ -22,26 +23,32 @@ humhub.module('content.form', function (module, require, $) {
|
||||
object.inherits(CreateForm, Widget);
|
||||
|
||||
CreateForm.prototype.init = function () {
|
||||
this.$.hide();
|
||||
this.menu = this.$.parent().prev('#contentFormMenu');
|
||||
// Hide options by default
|
||||
$('.contentForm_options').hide();
|
||||
this.isModal = this.$.is(CREATE_FORM_ROOT_SELECTOR_MODAL)
|
||||
|
||||
if (!this.isModal) {
|
||||
this.$.hide();
|
||||
this.menu = this.$.parent().prev('#contentFormMenu'); // #contentFormMenuModal doesn't exist
|
||||
// Hide options by default
|
||||
this.$.find('.contentForm_options').hide();
|
||||
}
|
||||
|
||||
this.setDefaultVisibility();
|
||||
this.$.fadeIn('fast');
|
||||
this.showMenu();
|
||||
|
||||
if (!module.config['disabled']) {
|
||||
$('#contentFormBody').on('click.humhub:content:form dragover.humhub:content:form', function (evt) {
|
||||
this.$.on('click.humhub:content:form dragover.humhub:content:form', function (evt) {
|
||||
// Prevent fading in for topic remove button clicks
|
||||
if ($(evt.target).closest('.topic-remove-label').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.contentForm_options').fadeIn();
|
||||
});
|
||||
if (!this.isModal) {
|
||||
this.$.find('.contentForm_options').fadeIn();
|
||||
}
|
||||
}.bind(this));
|
||||
} else {
|
||||
$('#contentFormBody').find('.humhub-ui-richtext').trigger('disable');
|
||||
this.$.find('.humhub-ui-richtext').trigger('disable');
|
||||
}
|
||||
};
|
||||
|
||||
@ -65,11 +72,19 @@ humhub.module('content.form', function (module, require, $) {
|
||||
event.trigger('humhub:content:beforeSubmit', this);
|
||||
client.submit(evt).then(function (response) {
|
||||
that.$.find(".preferences, .fileinput-button").show();
|
||||
$('.contentForm_options .preferences, .fileinput-button').show();
|
||||
that.$.find('.contentForm_options .preferences, .fileinput-button').show();
|
||||
if (!response.errors) {
|
||||
event.trigger('humhub:content:newEntry', response.output, this);
|
||||
event.trigger('humhub:content:afterSubmit', response.output, this);
|
||||
that.resetForm();
|
||||
if ($('#share-intend-modal').length) {
|
||||
$("#globalModal").modal("hide");
|
||||
// If the dashboard stream is not displayed on the current page, redirect to the content container, to make sure the user sees the new content
|
||||
if (response.url && !$('.dashboard-wall-stream').length) {
|
||||
client.pjax.redirect(module.config.redirectToContentContainerUrl.replace('the-content-id', response.data.id));
|
||||
}
|
||||
} else {
|
||||
that.resetForm();
|
||||
}
|
||||
} else {
|
||||
that.handleError(response);
|
||||
}
|
||||
@ -82,12 +97,15 @@ humhub.module('content.form', function (module, require, $) {
|
||||
|
||||
/**
|
||||
* Todo: this is post form only, this needs to be added to post module perhaps by calling $form.trigger('humhub:form:clear');
|
||||
*
|
||||
* As the form for share intend is in a modal, we don't need to reset it
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
CreateForm.prototype.resetForm = function () {
|
||||
// Reset Form (Empty State)
|
||||
$('.contentForm_options').hide();
|
||||
var $contentForm = $('.contentForm');
|
||||
this.$.find('.contentForm_options').hide();
|
||||
var $contentForm = this.$.find('.contentForm');
|
||||
$contentForm.filter(':text').val('');
|
||||
$contentForm.filter('textarea').val('').trigger('autosize.resize');
|
||||
$contentForm.attr('checked', false);
|
||||
@ -98,30 +116,29 @@ humhub.module('content.form', function (module, require, $) {
|
||||
this.resetFileUpload();
|
||||
this.resetState();
|
||||
|
||||
$('#public').attr('checked', false);
|
||||
$('#contentFormBody').find('.humhub-ui-richtext').trigger('clear');
|
||||
this.$.find('.humhub-ui-richtext').trigger('clear');
|
||||
};
|
||||
|
||||
CreateForm.prototype.resetSettingInputs = function () {
|
||||
$('#notifyUserContainer').hide();
|
||||
Widget.instance('#notifyUserInput').reset();
|
||||
$('#postTopicContainer').hide();
|
||||
this.$.find('.notifyUserContainer').hide();
|
||||
Widget.instance('#notifyUserInput' + (this.isModal ? 'Modal' : '')).reset();
|
||||
$('#postTopicContainer' + (this.isModal ? 'Modal' : '')).hide();
|
||||
|
||||
var topicPicker = Widget.instance('#postTopicInput');
|
||||
var topicPicker = Widget.instance('#postTopicInput' + (this.isModal ? 'Modal' : ''));
|
||||
if (topicPicker) {
|
||||
topicPicker.reset();
|
||||
}
|
||||
};
|
||||
|
||||
CreateForm.prototype.resetFilePreview = function () {
|
||||
var preview = Widget.instance($('#contentFormFiles_preview'));
|
||||
var preview = Widget.instance($('#contentFormFiles_preview' + (this.isModal ? 'Modal' : '')));
|
||||
if (preview) {
|
||||
preview.reset();
|
||||
}
|
||||
};
|
||||
|
||||
CreateForm.prototype.resetFileUpload = function () {
|
||||
var upload = Widget.instance($('#contentForm_message-file-upload'));
|
||||
var upload = Widget.instance($('#contentFormFiles_progress' + (this.isModal ? 'Modal' : '')));
|
||||
if (upload) {
|
||||
upload.reset();
|
||||
}
|
||||
@ -146,7 +163,7 @@ humhub.module('content.form', function (module, require, $) {
|
||||
};
|
||||
|
||||
CreateForm.prototype.changeVisibility = function () {
|
||||
if (!$('#contentForm_visibility').prop('checked')) {
|
||||
if (!this.$.find('.contentForm_visibility').prop('checked')) {
|
||||
this.setPublicVisibility();
|
||||
} else {
|
||||
this.setPrivateVisibility();
|
||||
@ -162,26 +179,26 @@ humhub.module('content.form', function (module, require, $) {
|
||||
};
|
||||
|
||||
CreateForm.prototype.setPublicVisibility = function () {
|
||||
$('#contentForm_visibility').prop("checked", true);
|
||||
$('#contentForm_visibility_entry').html('<i class="fa fa-lock"></i>' + module.text(['makePrivate']));
|
||||
$('.label-public').removeClass('hidden');
|
||||
this.$.find('.contentForm_visibility').prop("checked", true);
|
||||
this.$.find('.contentForm_visibility_entry').html('<i class="fa fa-lock"></i>' + module.text(['makePrivate']));
|
||||
this.$.find('.label-public').removeClass('hidden');
|
||||
};
|
||||
|
||||
CreateForm.prototype.setPrivateVisibility = function () {
|
||||
$('#contentForm_visibility').prop("checked", false);
|
||||
$('#contentForm_visibility_entry').html('<i class="fa fa-unlock"></i>' + module.text(['makePublic']));
|
||||
$('.label-public').addClass('hidden');
|
||||
this.$.find('.contentForm_visibility').prop("checked", false);
|
||||
this.$.find('.contentForm_visibility_entry').html('<i class="fa fa-unlock"></i>' + module.text(['makePublic']));
|
||||
this.$.find('.label-public').addClass('hidden');
|
||||
};
|
||||
|
||||
CreateForm.prototype.notifyUser = function () {
|
||||
$('#notifyUserContainer').show();
|
||||
Widget.instance('#notifyUserInput').focus();
|
||||
this.$.find('.notifyUserContainer').show();
|
||||
Widget.instance('#notifyUserInput' + (this.isModal ? 'Modal' : '')).focus();
|
||||
};
|
||||
|
||||
CreateForm.prototype.setTopics = function () {
|
||||
$('#postTopicContainer').show();
|
||||
$('#postTopicContainer' + (this.isModal ? 'Modal' : '')).show();
|
||||
|
||||
var topicPicker = Widget.instance('#postTopicInput');
|
||||
var topicPicker = Widget.instance('#postTopicInput' + (this.isModal ? 'Modal' : ''));
|
||||
if (topicPicker) {
|
||||
topicPicker.focus();
|
||||
}
|
||||
@ -190,7 +207,7 @@ humhub.module('content.form', function (module, require, $) {
|
||||
CreateForm.prototype.changeState = function (state, title, buttonTitle) {
|
||||
const stateInput = this.$.find('input[name=state]');
|
||||
let stateLabel = this.$.find('.label-content-state');
|
||||
const button = this.$.find('#post_submit_button');
|
||||
const button = $('#post_submit_button' + (this.isModal ? '_modal' : ''));
|
||||
|
||||
if (!stateLabel.length) {
|
||||
stateLabel = $('<span>').addClass('label label-warning label-content-state');
|
||||
@ -217,27 +234,34 @@ humhub.module('content.form', function (module, require, $) {
|
||||
stateLabel.show().html(title);
|
||||
button.html(buttonTitle);
|
||||
this.$.find('.preferences [data-action-click=notifyUser]').parent().hide();
|
||||
this.$.find('#notifyUserContainer').hide();
|
||||
this.$.find('.notifyUserContainer').hide();
|
||||
}
|
||||
|
||||
CreateForm.prototype.resetState = function () {
|
||||
const stateInput = this.$.find('input[name=state]');
|
||||
const button = this.$.find('#post_submit_button');
|
||||
const button = $('#post_submit_button' + (this.isModal ? '_modal' : ''));
|
||||
const initial = stateInput.data('initial');
|
||||
if (initial !== undefined) {
|
||||
stateInput.val(initial.state);
|
||||
button.data('htmlOld', initial.buttonTitle).removeAttr('style');
|
||||
loader.reset(button);
|
||||
if (loader.is(button)) {
|
||||
button.data('htmlOld', initial.buttonTitle).removeAttr('style');
|
||||
loader.reset(button);
|
||||
} else {
|
||||
button.html(initial.buttonTitle);
|
||||
}
|
||||
}
|
||||
this.$.find('input[name^=scheduled]').remove();
|
||||
this.$.find('.label-content-state').hide();
|
||||
this.$.find('.preferences [data-action-click=notifyUser]').parent().show();
|
||||
const notifyUserContainer = this.$.find('#notifyUserContainer');
|
||||
const notifyUserContainer = this.$.find('.notifyUserContainer');
|
||||
if (notifyUserContainer.find('ul .select2-selection__clear').length) {
|
||||
notifyUserContainer.show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule is not available for share intend because it is already in a modal
|
||||
*/
|
||||
CreateForm.prototype.scheduleOptions = function (evt) {
|
||||
const that = this;
|
||||
const modalGlobal = modal.global.$;
|
||||
@ -275,6 +299,9 @@ humhub.module('content.form', function (module, require, $) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule is not available for share intend because it is already in a modal
|
||||
*/
|
||||
CreateForm.prototype.setScheduleOption = function (name, value) {
|
||||
let input = this.$.find('input[name=' + name + ']');
|
||||
|
||||
@ -290,10 +317,16 @@ humhub.module('content.form', function (module, require, $) {
|
||||
input.val(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule is not available for share intend because it is already in a modal
|
||||
*/
|
||||
CreateForm.prototype.resetScheduleOption = function (name) {
|
||||
this.setScheduleOption(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateFormMenu is not available for share intend
|
||||
*/
|
||||
const CreateFormMenu = Widget.extend();
|
||||
|
||||
CreateFormMenu.prototype.init = function () {
|
||||
@ -343,6 +376,13 @@ humhub.module('content.form', function (module, require, $) {
|
||||
}
|
||||
};
|
||||
|
||||
var initModal = function () {
|
||||
var $rootModal = $(CREATE_FORM_ROOT_SELECTOR_MODAL);
|
||||
if ($rootModal.length) {
|
||||
instance = Widget.instance($rootModal);
|
||||
}
|
||||
};
|
||||
|
||||
var unload = function () {
|
||||
instance = undefined;
|
||||
}
|
||||
@ -352,6 +392,7 @@ humhub.module('content.form', function (module, require, $) {
|
||||
CreateFormMenu: CreateFormMenu,
|
||||
instance: instance,
|
||||
init: init,
|
||||
initModal: initModal,
|
||||
initOnPjaxLoad: true,
|
||||
unload: unload
|
||||
});
|
||||
|
@ -165,7 +165,7 @@ class MysqlDriver extends AbstractDriver
|
||||
$term = preg_replace('/-+(\*?)$/', '$1', $term);
|
||||
|
||||
// Wrap a keyword in quotes to avoid error with the special chars in the sql MATCH-AGAINST expression
|
||||
return preg_match('#[^\p{L}\d\*’\'`\-\_]#', $term) ? '"' . $term . '"' : $term;
|
||||
return preg_match('#[^\p{L}\d\*’\'`\-\_]#u', $term) ? '"' . $term . '"' : $term;
|
||||
}
|
||||
|
||||
protected function addQueryFilterVisibility(ActiveQuery $query): ActiveQuery
|
||||
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2025 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\modules\content\models\forms\ShareIntendTargetForm;
|
||||
use humhub\modules\content\widgets\ContentContainerPickerField;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use humhub\modules\ui\view\components\View;
|
||||
use humhub\widgets\ModalButton;
|
||||
use humhub\widgets\ModalDialog;
|
||||
|
||||
/**
|
||||
* @var $this View
|
||||
* @var $model ShareIntendTargetForm
|
||||
* @var $fileList string[]
|
||||
*/
|
||||
?>
|
||||
|
||||
<?php ModalDialog::begin([
|
||||
'header' => Yii::t('ContentModule.base', 'Share'),
|
||||
]) ?>
|
||||
|
||||
<?php $form = ActiveForm::begin() ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<?= $form->field($model, 'targetContainerGuid')->widget(ContentContainerPickerField::class, [
|
||||
'maxSelection' => 1,
|
||||
'minInput' => 0,
|
||||
'focus' => true,
|
||||
'url' => $model->getContainerSearchUrl(),
|
||||
'options' => ['data-action-change' => 'ui.modal.submit'],
|
||||
])->label(false) ?>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<?= ModalButton::defaultType(Yii::t('base', 'Back'))
|
||||
->load(['/file/share-intend', 'fileList' => $fileList]) ?>
|
||||
</div>
|
||||
|
||||
<?php ActiveForm::end() ?>
|
||||
<?php ModalDialog::end() ?>
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\widgets;
|
||||
|
||||
use humhub\modules\content\models\ContentContainer;
|
||||
use humhub\modules\ui\form\widgets\BasePicker;
|
||||
|
||||
/**
|
||||
* Mutliselect input field for selecting Space guids or current user Profile
|
||||
*
|
||||
* This widget has no default route, so the `url` param is required.
|
||||
*
|
||||
* @since 1.17.2
|
||||
*/
|
||||
class ContentContainerPickerField extends BasePicker
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
* The 'guid' value is default for UserPickerField
|
||||
*/
|
||||
public $itemKey = 'guid';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $itemClass = ContentContainer::class;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getAttributes()
|
||||
{
|
||||
return array_merge(parent::getAttributes(), [
|
||||
'data-tags' => 'false',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getItemText($item)
|
||||
{
|
||||
return $this->itemClass === ContentContainer::class ?
|
||||
$item->getPolymorphicRelation()->displayName :
|
||||
$item->displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getItemImage($item)
|
||||
{
|
||||
return $this->itemClass === ContentContainer::class ?
|
||||
$item->getPolymorphicRelation()->getProfileImage()->getUrl() :
|
||||
$item->getProfileImage()->getUrl();
|
||||
}
|
||||
}
|
@ -105,7 +105,7 @@ class SearchFilters extends DirectoryFilters
|
||||
'sortOrder' => 500,
|
||||
]);*/
|
||||
|
||||
$this->addFilter('space', [
|
||||
$this->addFilter('contentContainer', [
|
||||
'title' => Yii::t('ContentModule.search', 'Space'),
|
||||
'type' => 'widget',
|
||||
'widget' => SpacePickerField::class,
|
||||
|
@ -38,6 +38,16 @@ abstract class WallCreateContentForm extends Widget
|
||||
*/
|
||||
public $contentContainer;
|
||||
|
||||
/**
|
||||
* Pre-uploaded File GUIDs to be attached to the new content
|
||||
*/
|
||||
public array $fileList = [];
|
||||
|
||||
/**
|
||||
* The widget is executed in a modal window
|
||||
*/
|
||||
public bool $isModal = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
@ -8,10 +8,10 @@
|
||||
|
||||
namespace humhub\modules\content\widgets;
|
||||
|
||||
use humhub\libs\Sort;
|
||||
use humhub\modules\content\widgets\stream\WallStreamEntryWidget;
|
||||
use humhub\components\Widget;
|
||||
use humhub\libs\Sort;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\widgets\stream\WallStreamEntryWidget;
|
||||
use yii\web\HttpException;
|
||||
|
||||
/**
|
||||
|
@ -24,7 +24,12 @@ use yii\web\HttpException;
|
||||
class WallCreateContentFormFooter extends Widget
|
||||
{
|
||||
/**
|
||||
* @var string form submit route/url (required)
|
||||
* @var WallCreateContentForm null (required)
|
||||
*/
|
||||
public ?WallCreateContentForm $wallCreateContentForm = null;
|
||||
|
||||
/**
|
||||
* @var string form submit route/url (automatically set if `wallCreateContentForm` is provided)
|
||||
*/
|
||||
public $submitUrl;
|
||||
|
||||
@ -51,6 +56,10 @@ class WallCreateContentFormFooter extends Widget
|
||||
throw new HttpException(500, 'No Content Container given!');
|
||||
}
|
||||
|
||||
if ($this->wallCreateContentForm !== null) {
|
||||
$this->submitUrl = $this->wallCreateContentForm->submitUrl;
|
||||
}
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
@ -61,6 +70,8 @@ class WallCreateContentFormFooter extends Widget
|
||||
{
|
||||
return $this->render('@humhub/modules/content/widgets/views/wallCreateContentFormFooter', [
|
||||
'contentContainer' => $this->contentContainer,
|
||||
'fileList' => $this->wallCreateContentForm?->fileList ?? [],
|
||||
'isModal' => $this->wallCreateContentForm?->isModal ?? false,
|
||||
'submitUrl' => $this->contentContainer->createUrl($this->submitUrl),
|
||||
'submitButtonText' => $this->submitButtonText,
|
||||
'canSwitchVisibility' => $this->contentContainer->visibility !== Space::VISIBILITY_NONE && $this->contentContainer->can(CreatePublicContent::class),
|
||||
|
@ -1,11 +1,12 @@
|
||||
<?php
|
||||
|
||||
use humhub\modules\content\assets\ContentFormAsset;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\widgets\WallCreateContentForm;
|
||||
use humhub\modules\content\widgets\WallCreateContentMenu;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use humhub\modules\content\assets\ContentFormAsset;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use yii\helpers\Url;
|
||||
|
||||
/* @var $wallCreateContentForm WallCreateContentForm */
|
||||
/* @var $defaultVisibility int */
|
||||
@ -19,14 +20,15 @@ $this->registerJsConfig('content.form', [
|
||||
'text' => [
|
||||
'makePrivate' => Yii::t('ContentModule.base', 'Change to "Private"'),
|
||||
'makePublic' => Yii::t('ContentModule.base', 'Change to "Public"'),
|
||||
'info.archived' => Yii::t('ContentModule.base', 'This space is archived.')
|
||||
]
|
||||
'info.archived' => Yii::t('ContentModule.base', 'This space is archived.'),
|
||||
],
|
||||
'redirectToContentContainerUrl' => Url::to(['/content/content/redirect-to-content-container', 'contentId' => 'the-content-id']),
|
||||
]);
|
||||
?>
|
||||
|
||||
<?php if (WallCreateContentMenu::canCreateEntry($contentContainer, 'form')) : ?>
|
||||
<div class="panel panel-default clearfix">
|
||||
<div class="panel-body" id="contentFormBody" style="display:none;"
|
||||
<div class="panel-body" id="contentFormBody<?= $wallCreateContentForm->isModal ? 'Modal' : '' ?>" class="content-form-body" style="display:none;"
|
||||
data-action-component="content.form.CreateForm">
|
||||
<?php $form = ActiveForm::begin(['acknowledge' => true]); ?>
|
||||
|
||||
|
@ -5,9 +5,9 @@
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\modules\content\assets\ContentFormAsset;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\widgets\WallCreateContentMenu;
|
||||
use humhub\modules\content\assets\ContentFormAsset;
|
||||
|
||||
/* @var $contentContainer ContentContainerActiveRecord */
|
||||
/* @var $formClass string */
|
||||
@ -19,4 +19,4 @@ ContentFormAsset::register($this);
|
||||
|
||||
<?php if ($formClass) : ?>
|
||||
<?= $formClass::widget(['contentContainer' => $contentContainer]) ?>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
@ -5,6 +5,7 @@
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\file\handler\BaseFileHandler;
|
||||
@ -17,20 +18,21 @@ use humhub\modules\ui\icon\widgets\Icon;
|
||||
use humhub\modules\user\widgets\UserPickerField;
|
||||
use humhub\widgets\Button;
|
||||
use humhub\widgets\Link;
|
||||
use yii\helpers\Html;
|
||||
|
||||
/* @var $submitUrl string */
|
||||
/* @var $submitButtonText string */
|
||||
/* @var $fileHandlers BaseFileHandler[] */
|
||||
/* @var $canSwitchVisibility bool */
|
||||
/* @var $contentContainer ContentContainerActiveRecord */
|
||||
/* @var $fileList array */
|
||||
/* @var $isModal bool */
|
||||
/* @var $pickerUrl string */
|
||||
/* @var $scheduleUrl string */
|
||||
?>
|
||||
|
||||
<div id="notifyUserContainer" class="form-group" style="margin-top:15px;display:none">
|
||||
<div class="notifyUserContainer form-group" style="margin-top:15px;display:none">
|
||||
<?= UserPickerField::widget([
|
||||
'id' => 'notifyUserInput',
|
||||
'id' => 'notifyUserInput' . ($isModal ? 'Modal' : ''),
|
||||
'url' => $pickerUrl,
|
||||
'formName' => 'notifyUserInput',
|
||||
'maxSelection' => 10,
|
||||
@ -39,34 +41,35 @@ use yii\helpers\Html;
|
||||
]) ?>
|
||||
</div>
|
||||
|
||||
<div id="postTopicContainer" class="form-group" style="margin-top:15px;display:none">
|
||||
<div id="postTopicContainer<?= $isModal ? 'Modal' : '' ?>" class="form-group" style="margin-top:15px;display:none">
|
||||
<?= TopicPicker::widget([
|
||||
'id' => 'postTopicInput',
|
||||
'id' => 'postTopicInput' . ($isModal ? 'Modal' : ''),
|
||||
'name' => 'postTopicInput',
|
||||
'contentContainer' => $contentContainer
|
||||
]); ?>
|
||||
'contentContainer' => $contentContainer,
|
||||
]) ?>
|
||||
</div>
|
||||
|
||||
<?= Html::hiddenInput('containerGuid', $contentContainer->guid); ?>
|
||||
<?= Html::hiddenInput('containerClass', get_class($contentContainer)); ?>
|
||||
<?= Html::hiddenInput('containerGuid', $contentContainer->guid) ?>
|
||||
<?= Html::hiddenInput('containerClass', get_class($contentContainer)) ?>
|
||||
|
||||
<div class="contentForm_options">
|
||||
<hr>
|
||||
<div class="btn_container">
|
||||
<?= Button::info($submitButtonText)->action('submit', $submitUrl)->id('post_submit_button')->submit() ?>
|
||||
<?= Button::info($submitButtonText)->action('submit', $submitUrl)->id('post_submit_button' . ($isModal ? '_modal' : ''))->submit() ?>
|
||||
|
||||
<?php $uploadButton = UploadButton::widget([
|
||||
'id' => 'contentFormFiles',
|
||||
'id' => 'contentFormFiles' . ($isModal ? 'Modal' : ''),
|
||||
'tooltip' => Yii::t('ContentModule.base', 'Attach Files'),
|
||||
'progress' => '#contentFormFiles_progress',
|
||||
'preview' => '#contentFormFiles_preview',
|
||||
'dropZone' => '#contentFormBody',
|
||||
'max' => Yii::$app->getModule('content')->maxAttachedFiles
|
||||
'progress' => '#contentFormFiles_progress' . ($isModal ? 'Modal' : ''),
|
||||
'preview' => '#contentFormFiles_preview' . ($isModal ? 'Modal' : ''),
|
||||
'dropZone' => '#contentFormBody' . ($isModal ? 'Modal' : ''),
|
||||
'max' => Yii::$app->getModule('content')->maxAttachedFiles,
|
||||
'fileList' => $fileList,
|
||||
]); ?>
|
||||
<?= FileHandlerButtonDropdown::widget(['primaryButton' => $uploadButton, 'handlers' => $fileHandlers, 'cssButtonClass' => 'btn-default']); ?>
|
||||
|
||||
<!-- public checkbox -->
|
||||
<?= Html::checkbox('visibility', '', ['id' => 'contentForm_visibility', 'class' => 'contentForm hidden', 'aria-hidden' => 'true']); ?>
|
||||
<?= Html::checkbox('visibility', '', ['class' => 'contentForm_visibility contentForm hidden', 'aria-hidden' => 'true']); ?>
|
||||
|
||||
<!-- state data -->
|
||||
<?= Html::hiddenInput('state', Content::STATE_PUBLISHED) ?>
|
||||
@ -95,7 +98,7 @@ use yii\helpers\Html;
|
||||
<?php if ($canSwitchVisibility): ?>
|
||||
<li>
|
||||
<?= Link::withAction(Yii::t('ContentModule.base', 'Change to "Public"'), 'changeVisibility')
|
||||
->id('contentForm_visibility_entry')->icon('unlock') ?>
|
||||
->cssClass('contentForm_visibility_entry')->icon('unlock') ?>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<li>
|
||||
@ -104,19 +107,28 @@ use yii\helpers\Html;
|
||||
->options([
|
||||
'data-state' => Content::STATE_DRAFT,
|
||||
'data-state-title' => Yii::t('ContentModule.base', 'Draft'),
|
||||
'data-button-title' => Yii::t('ContentModule.base', 'Save as draft')
|
||||
'data-button-title' => Yii::t('ContentModule.base', 'Save as draft'),
|
||||
]) ?>
|
||||
</li>
|
||||
<li>
|
||||
<?= Link::withAction(Yii::t('ContentModule.base', 'Schedule publication'), 'scheduleOptions', $scheduleUrl)
|
||||
->icon('clock-o') ?>
|
||||
</li>
|
||||
<?php if (!$isModal): ?>
|
||||
<li>
|
||||
<?= Link::withAction(Yii::t('ContentModule.base', 'Schedule publication'), 'scheduleOptions', $scheduleUrl)
|
||||
->icon('clock-o') ?>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= UploadProgress::widget(['id' => 'contentFormFiles_progress']) ?>
|
||||
<?= FilePreview::widget(['id' => 'contentFormFiles_preview', 'edit' => true, 'options' => ['style' => 'margin-top:10px;']]); ?>
|
||||
<?= UploadProgress::widget([
|
||||
'id' => 'contentFormFiles_progress' . ($isModal ? 'Modal' : ''),
|
||||
]) ?>
|
||||
<?= FilePreview::widget([
|
||||
'id' => 'contentFormFiles_preview' . ($isModal ? 'Modal' : ''),
|
||||
'edit' => true,
|
||||
'items' => $fileList,
|
||||
'options' => ['style' => 'margin-top:10px;'],
|
||||
]) ?>
|
||||
</div><!-- /contentForm_Options -->
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
namespace humhub\modules\dashboard\widgets;
|
||||
|
||||
use humhub\modules\post\widgets\Form;
|
||||
use Yii;
|
||||
use humhub\modules\stream\widgets\StreamViewer;
|
||||
use humhub\components\Widget;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\post\widgets\Form;
|
||||
use humhub\modules\stream\widgets\StreamViewer;
|
||||
use Yii;
|
||||
|
||||
class DashboardContent extends Widget
|
||||
{
|
||||
@ -33,6 +33,7 @@ class DashboardContent extends Widget
|
||||
}
|
||||
|
||||
echo StreamViewer::widget([
|
||||
'options' => ['class' => 'dashboard-wall-stream'],
|
||||
'streamAction' => '//dashboard/dashboard/stream',
|
||||
'showFilters' => (bool)Yii::$app->getModule('dashboard')->settings->get('showProfilePostForm'),
|
||||
'messageStreamEmpty' => $messageStreamEmpty,
|
||||
|
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2025 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\file\controllers;
|
||||
|
||||
use humhub\components\behaviors\AccessControl;
|
||||
use humhub\components\Controller;
|
||||
use humhub\modules\file\models\File;
|
||||
use Yii;
|
||||
use yii\web\HttpException;
|
||||
use yii\web\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Modules can be added as an additional target by
|
||||
* registering an event on `ShareIntendController::EVENT_INIT`
|
||||
* and adding the following method to the Events class:
|
||||
*
|
||||
* ```
|
||||
* public static function onShareIntendControllerInit($event)
|
||||
* {
|
||||
* $event->sender->shareTargets[] = [
|
||||
* 'title' => 'Your Module',
|
||||
* 'route' => '/your-module/share-intend/index',
|
||||
* ];
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The module must have the ShareIntendController and view,
|
||||
* similar to the Post module.
|
||||
* The controller must extend \humhub\modules\content\controllers\ShareIntendController
|
||||
*/
|
||||
final class ShareIntendController extends Controller
|
||||
{
|
||||
public $shareTargets = [];
|
||||
|
||||
public function behaviors()
|
||||
{
|
||||
return [
|
||||
'acl' => [
|
||||
'class' => AccessControl::class,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->shareTargets[] = [
|
||||
'title' => Yii::t('FileModule.base', 'Share as Post'),
|
||||
'route' => '/post/share-intend',
|
||||
];
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
$fileList = Yii::$app->request->get('fileList');
|
||||
if (!$fileList) {
|
||||
throw new NotFoundHttpException('No files to share found!');
|
||||
}
|
||||
|
||||
// Check if the files exists, and if user is the owner of the files
|
||||
if (File::find()->where(['guid' => $fileList])->andWhere(['created_by' => Yii::$app->user->id])->count() !== count($fileList)) {
|
||||
throw new NotFoundHttpException('Files not uploaded correctly!');
|
||||
}
|
||||
|
||||
if (count($this->shareTargets) === 0) {
|
||||
throw new NotFoundHttpException('No sharing targets found!');
|
||||
}
|
||||
|
||||
Yii::$app->session->set('shareIntendFiles', $fileList);
|
||||
|
||||
return $this->renderAjax('index', [
|
||||
'shareTargets' => $this->shareTargets,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function checkShareFileGuids(): void
|
||||
{
|
||||
$fileGuids = Yii::$app->session->get('shareIntendFiles');
|
||||
|
||||
if (empty($fileGuids)) {
|
||||
throw new HttpException('500', 'No files to share found!');
|
||||
}
|
||||
}
|
||||
|
||||
public static function getShareFileGuids(): ?array
|
||||
{
|
||||
return Yii::$app->session->get('shareIntendFiles');
|
||||
}
|
||||
}
|
@ -57,7 +57,11 @@ class FileHandlerCollection extends Component
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->trigger(self::EVENT_INIT);
|
||||
try {
|
||||
$this->trigger(self::EVENT_INIT);
|
||||
} catch (\Exception $ex) {
|
||||
Yii::error('Could not init file handler. Error: ' . $ex->getMessage(), 'file');
|
||||
}
|
||||
|
||||
// Register default handlers
|
||||
if ($this->type === self::TYPE_CREATE) {
|
||||
|
@ -17,8 +17,8 @@ return array (
|
||||
'Invalid Mime-Type' => 'Неправильный MIME-тип файла',
|
||||
'Last update by:' => 'Последнее обновление:',
|
||||
'Size:' => 'Размер:',
|
||||
'Sorry, you can only upload up to {n,plural,=1{# file} other{# files}} at once.' => 'К сожалению, вы можете загрузить только до {n, plural, =1{# файла} many{# файлов}} одновременно.',
|
||||
'Sorry, you can only upload up to {n,plural,=1{# file} other{# files}} at once.' => 'К сожалению, вы можете загрузить только до {n,plural,=1{# файла} other{# файлов}} одновременно.',
|
||||
'The uploaded image is not a squared.' => 'Загруженное изображение не квадратное.',
|
||||
'This upload field only allows a maximum of {n,plural,=1{# file} other{# files}}.' => 'Это поле загрузки допускает максимум {n,plural,=1{# файл} few{# файла} many{# файлов}}.',
|
||||
'This upload field only allows a maximum of {n,plural,=1{# file} other{# files}}.' => 'Это поле загрузки допускает максимум {n,plural,=1{# файл} other{# файлов}}.',
|
||||
'Upload files' => 'Загрузить файлы',
|
||||
);
|
||||
|
32
protected/humhub/modules/file/views/share-intend/index.php
Normal file
32
protected/humhub/modules/file/views/share-intend/index.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2025 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\modules\ui\view\components\View;
|
||||
use humhub\widgets\ModalButton;
|
||||
use humhub\widgets\ModalDialog;
|
||||
use yii\helpers\Url;
|
||||
|
||||
/**
|
||||
* @var $this View
|
||||
* @var $shareTargets array
|
||||
*/
|
||||
?>
|
||||
|
||||
<?php ModalDialog::begin(['header' => Yii::t('FileModule.base', 'Share')]) ?>
|
||||
<div class="modal-body">
|
||||
<?php foreach ($shareTargets as $target): ?>
|
||||
<a class="btn btn-primary btn-block" data-action-click="ui.modal.load"
|
||||
data-action-url="<?= Url::to([$target['route']]) ?>">
|
||||
<?= $target['title'] ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<?= ModalButton::cancel() ?>
|
||||
</div>
|
||||
<?php ModalDialog::end() ?>
|
@ -159,6 +159,11 @@ class UploadInput extends JsWidget
|
||||
*/
|
||||
public $attach = true;
|
||||
|
||||
/**
|
||||
* Pre-uploaded File GUIDs to be attached to the new content
|
||||
*/
|
||||
public array $fileList = [];
|
||||
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
@ -183,6 +188,9 @@ class UploadInput extends JsWidget
|
||||
$result .= Html::hiddenInput($this->submitName, $file->guid);
|
||||
}
|
||||
}
|
||||
foreach ((array)$this->fileList as $file) {
|
||||
$result .= Html::hiddenInput($this->submitName, $file);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ use humhub\modules\user\models\Password;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\caching\DummyCache;
|
||||
use yii\web\HttpException;
|
||||
|
||||
/**
|
||||
@ -75,10 +76,6 @@ class ConfigController extends Controller
|
||||
public function beforeAction($action)
|
||||
{
|
||||
if (parent::beforeAction($action)) {
|
||||
|
||||
// Flush Caches
|
||||
Yii::$app->cache->flush();
|
||||
|
||||
// Database Connection seems not to work
|
||||
if (!$this->module->checkDBConnection()) {
|
||||
$this->redirect(['/installer/setup']);
|
||||
@ -104,7 +101,6 @@ class ConfigController extends Controller
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
|
||||
if (Yii::$app->settings->get('name') == "") {
|
||||
Yii::$app->settings->set('name', "HumHub");
|
||||
}
|
||||
@ -204,11 +200,23 @@ class ConfigController extends Controller
|
||||
}
|
||||
|
||||
if ($form->load(Yii::$app->request->post()) && $form->validate()) {
|
||||
Yii::$app->getModule('user')->settings->set('auth.needApproval', $form->internalRequireApprovalAfterRegistration);
|
||||
Yii::$app->getModule('user')->settings->set('auth.anonymousRegistration', $form->internalAllowAnonymousRegistration);
|
||||
Yii::$app->getModule('user')->settings->set(
|
||||
'auth.needApproval',
|
||||
$form->internalRequireApprovalAfterRegistration,
|
||||
);
|
||||
Yii::$app->getModule('user')->settings->set(
|
||||
'auth.anonymousRegistration',
|
||||
$form->internalAllowAnonymousRegistration,
|
||||
);
|
||||
Yii::$app->getModule('user')->settings->set('auth.allowGuestAccess', $form->allowGuestAccess);
|
||||
Yii::$app->getModule('user')->settings->set('auth.internalUsersCanInviteByEmail', $form->canInviteExternalUsersByEmail);
|
||||
Yii::$app->getModule('user')->settings->set('auth.internalUsersCanInviteByLink', $form->canInviteExternalUsersByLink);
|
||||
Yii::$app->getModule('user')->settings->set(
|
||||
'auth.internalUsersCanInviteByEmail',
|
||||
$form->canInviteExternalUsersByEmail,
|
||||
);
|
||||
Yii::$app->getModule('user')->settings->set(
|
||||
'auth.internalUsersCanInviteByLink',
|
||||
$form->canInviteExternalUsersByLink,
|
||||
);
|
||||
Yii::$app->getModule('friendship')->settings->set('enable', $form->enableFriendshipModule);
|
||||
return $this->redirect(Yii::$app->getModule('installer')->getNextConfigStepUrl());
|
||||
}
|
||||
@ -230,7 +238,10 @@ class ConfigController extends Controller
|
||||
|
||||
$modules = $marketplaceModule->onlineModuleManager->getModules(false);
|
||||
foreach ($modules as $i => $module) {
|
||||
if (!isset($module['useCases']) || strpos($module['useCases'], Yii::$app->settings->get('useCase')) === false) {
|
||||
if (!isset($module['useCases']) || strpos(
|
||||
$module['useCases'],
|
||||
Yii::$app->settings->get('useCase'),
|
||||
) === false) {
|
||||
unset($modules[$i]);
|
||||
}
|
||||
}
|
||||
@ -279,7 +290,6 @@ class ConfigController extends Controller
|
||||
Yii::$app->getModule('installer')->settings->set('sampleData', $form->sampleData);
|
||||
|
||||
if (Yii::$app->getModule('installer')->settings->get('sampleData') == 1) {
|
||||
|
||||
// Add sample image to admin
|
||||
$admin = User::find()->where(['id' => 1])->one();
|
||||
$adminImage = new ProfileImage($admin->guid);
|
||||
@ -364,7 +374,10 @@ class ConfigController extends Controller
|
||||
|
||||
// Create a sample post
|
||||
$post = new Post();
|
||||
$post->message = Yii::t("InstallerModule.base", "We're looking for great slogans of famous brands. Maybe you can come up with some samples?");
|
||||
$post->message = Yii::t(
|
||||
"InstallerModule.base",
|
||||
"We're looking for great slogans of famous brands. Maybe you can come up with some samples?",
|
||||
);
|
||||
$post->content->container = $space;
|
||||
$post->content->visibility = Content::VISIBILITY_PRIVATE;
|
||||
$post->save();
|
||||
@ -382,7 +395,10 @@ class ConfigController extends Controller
|
||||
Yii::$app->user->switchIdentity($userModel2);
|
||||
|
||||
$comment2 = new Comment();
|
||||
$comment2->message = Yii::t("InstallerModule.base", "Calvin Klein – Between love and madness lies obsession.");
|
||||
$comment2->message = Yii::t(
|
||||
"InstallerModule.base",
|
||||
"Calvin Klein – Between love and madness lies obsession.",
|
||||
);
|
||||
$comment2->object_model = Post::class;
|
||||
$comment2->object_id = $post->getPrimaryKey();
|
||||
$comment2->save();
|
||||
@ -416,7 +432,6 @@ class ConfigController extends Controller
|
||||
*/
|
||||
public function actionAdmin()
|
||||
{
|
||||
|
||||
// Admin account already created
|
||||
if (User::find()->count() > 0) {
|
||||
return $this->redirect(Yii::$app->getModule('installer')->getNextConfigStepUrl());
|
||||
@ -486,7 +501,6 @@ class ConfigController extends Controller
|
||||
$form->models['Profile'] = $profileModel;
|
||||
|
||||
if ($form->submitted('save') && $form->validate()) {
|
||||
|
||||
$form->models['User']->status = User::STATUS_ENABLED;
|
||||
$form->models['User']->language = '';
|
||||
$form->models['User']->tagsField = ['Administration', 'Support', 'HumHub'];
|
||||
|
@ -21,7 +21,7 @@ use humhub\modules\user\models\ProfileField;
|
||||
use humhub\modules\user\models\ProfileFieldCategory;
|
||||
use Yii;
|
||||
use yii\base\Exception;
|
||||
use yii\helpers\BaseUrl;
|
||||
use yii\helpers\Url;
|
||||
|
||||
/**
|
||||
* InitialData
|
||||
@ -37,7 +37,7 @@ class InitialData
|
||||
return;
|
||||
}
|
||||
|
||||
Yii::$app->settings->set('baseUrl', BaseUrl::base(true));
|
||||
Yii::$app->settings->set('baseUrl', Url::base(true));
|
||||
Yii::$app->settings->set('paginationSize', 10);
|
||||
Yii::$app->settings->set('displayNameFormat', '{profile.firstname} {profile.lastname}');
|
||||
Yii::$app->settings->set('horImageScrollOnMobile', true);
|
||||
|
@ -24,7 +24,7 @@ use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
<hr/>
|
||||
<?= $form->field($model, 'username') ?>
|
||||
<hr/>
|
||||
<?= $form->field($model, 'password') ?>
|
||||
<?= $form->field($model, 'password')->passwordInput() ?>
|
||||
<hr/>
|
||||
<?= $form->field($model, 'database') ?>
|
||||
<?= $form->field($model, 'create')->checkbox() ?>
|
||||
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2025 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\post\controllers;
|
||||
|
||||
use humhub\modules\post\permissions\CreatePost;
|
||||
|
||||
final class ShareIntendController extends \humhub\modules\content\controllers\ShareIntendController
|
||||
{
|
||||
public function actionCreate()
|
||||
{
|
||||
return $this->renderAjax('create', [
|
||||
'shareTarget' => $this->shareTarget,
|
||||
'fileList' => \humhub\modules\file\controllers\ShareIntendController::getShareFileGuids(),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getCreatePermissionClass(): string
|
||||
{
|
||||
return CreatePost::class;
|
||||
}
|
||||
|
||||
}
|
57
protected/humhub/modules/post/views/share-intend/create.php
Normal file
57
protected/humhub/modules/post/views/share-intend/create.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2025 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\post\widgets\Form;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use humhub\modules\ui\view\components\View;
|
||||
use humhub\widgets\ModalButton;
|
||||
use humhub\widgets\ModalDialog;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
/**
|
||||
* @var $this View
|
||||
* @var $fileList array
|
||||
* @var $shareTarget ContentContainerActiveRecord
|
||||
*/
|
||||
?>
|
||||
|
||||
<?php ModalDialog::begin([
|
||||
'id' => 'share-intend-modal',
|
||||
'header' => Yii::t('FileModule.base', 'Share in {targetDisplayName}', [
|
||||
'targetDisplayName' => $shareTarget->guid === Yii::$app->user->identity->guid ?
|
||||
Yii::t('base', 'My Profile') :
|
||||
Html::encode(StringHelper::truncate($shareTarget->displayName, 10)),
|
||||
]),
|
||||
]) ?>
|
||||
<?php $form = ActiveForm::begin() ?>
|
||||
|
||||
<div class="modal-body">
|
||||
<div id="space-content-create-form" data-stream-create-content="stream.wall.WallStream">
|
||||
<?= Form::widget([
|
||||
'contentContainer' => $shareTarget,
|
||||
'fileList' => $fileList,
|
||||
'isModal' => true,
|
||||
]) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<?= ModalButton::defaultType(Yii::t('base', 'Back'))
|
||||
->load(['/post/share-intend']) ?>
|
||||
</div>
|
||||
|
||||
<?php ActiveForm::end() ?>
|
||||
<?php ModalDialog::end() ?>
|
||||
|
||||
<script <?= Html::nonce() ?>>
|
||||
$(function () {
|
||||
humhub.modules.content.form.initModal();
|
||||
$('#share-intend-modal').find('input[type=text], textarea, .ProseMirror').eq(0).trigger('click').focus();
|
||||
});
|
||||
</script>
|
@ -45,8 +45,8 @@ class Form extends WallCreateContentForm
|
||||
|
||||
return array_merge([
|
||||
'post' => $post,
|
||||
'wallCreateContentForm' => $this,
|
||||
'mentioningUrl' => $canCreatePostInSpace ? Url::to([$this->mentioningUrl, 'id' => $this->contentContainer->id]) : null,
|
||||
'submitUrl' => $this->submitUrl,
|
||||
], $additionalParams);
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,21 @@
|
||||
<?php
|
||||
|
||||
use humhub\modules\content\widgets\richtext\RichTextField;
|
||||
use humhub\modules\content\widgets\WallCreateContentForm;
|
||||
use humhub\modules\content\widgets\WallCreateContentFormFooter;
|
||||
use humhub\modules\post\models\Post;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
|
||||
/* @var WallCreateContentForm $wallCreateContentForm */
|
||||
/* @var string $mentioningUrl */
|
||||
/* @var ActiveForm $form */
|
||||
/* @var Post $post */
|
||||
/* @var string $submitUrl */
|
||||
?>
|
||||
|
||||
<?= $form->field($post, 'message')->widget(RichTextField::class, [
|
||||
'id' => 'contentForm_message',
|
||||
'id' => 'contentForm_message' . ($wallCreateContentForm->isModal ? 'Modal' : ''),
|
||||
'form' => $form,
|
||||
'layout' => RichTextField::LAYOUT_INLINE,
|
||||
'layout' => $wallCreateContentForm->isModal ? RichTextField::LAYOUT_BLOCK : RichTextField::LAYOUT_INLINE,
|
||||
'pluginOptions' => ['maxHeight' => '300px'],
|
||||
'placeholder' => Yii::t("PostModule.base", "What's on your mind?"),
|
||||
'name' => 'message',
|
||||
@ -25,5 +26,5 @@ use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
|
||||
<?= WallCreateContentFormFooter::widget([
|
||||
'contentContainer' => $post->content->container,
|
||||
'submitUrl' => $submitUrl,
|
||||
'wallCreateContentForm' => $wallCreateContentForm,
|
||||
]) ?>
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
namespace humhub\modules\space\controllers;
|
||||
|
||||
use humhub\components\Controller;
|
||||
use humhub\components\behaviors\AccessControl;
|
||||
use humhub\components\Controller;
|
||||
use humhub\modules\content\widgets\ContainerTagPicker;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\space\widgets\Chooser;
|
||||
@ -43,7 +43,7 @@ class BrowseController extends Controller
|
||||
/**
|
||||
* Returns a workspace list by json
|
||||
*
|
||||
* It can be filtered by by keyword.
|
||||
* It can be filtered by keyword.
|
||||
*/
|
||||
public function actionSearchJson()
|
||||
{
|
||||
|
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\space\helpers;
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
use humhub\modules\content\models\ContentContainerDefaultPermission;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\space\widgets\Chooser;
|
||||
use Yii;
|
||||
use yii\db\Expression;
|
||||
use yii\web\IdentityInterface;
|
||||
|
||||
final class CreateContentPermissionHelper
|
||||
{
|
||||
/**
|
||||
* Returns a list of Spaces where the user has a special permission (e.g. CreatePost).
|
||||
*
|
||||
* @param string $permissionClass
|
||||
* @param string|null $keyword
|
||||
* @param IdentityInterface|null $user
|
||||
* @return array
|
||||
*/
|
||||
public static function findSpaces(
|
||||
string $permissionClass,
|
||||
?string $keyword = null,
|
||||
?IdentityInterface $user = null,
|
||||
): array {
|
||||
$user = $user ?? Yii::$app->user->identity;
|
||||
|
||||
$spaces = Space::find()
|
||||
->visible($user)
|
||||
->filterBlockedSpaces($user)
|
||||
->andWhere(['space.status' => Space::STATUS_ENABLED]);
|
||||
|
||||
if ($keyword) {
|
||||
$spaces->search($keyword);
|
||||
}
|
||||
|
||||
if (!$user->isSystemAdmin()) {
|
||||
// Check the User can create a Post in the searched Spaces
|
||||
$spaces->leftJoin('space_membership', 'space_membership.space_id = space.id')
|
||||
->leftJoin(
|
||||
'contentcontainer_permission',
|
||||
'contentcontainer_permission.contentcontainer_id = space.contentcontainer_id
|
||||
AND contentcontainer_permission.group_id = space_membership.group_id
|
||||
AND contentcontainer_permission.permission_id = :permission_id',
|
||||
)
|
||||
->andWhere(['space_membership.user_id' => $user->id])
|
||||
->andWhere(['OR',
|
||||
// Allowed by default
|
||||
['AND',
|
||||
['IN', 'space_membership.group_id', self::getDefaultAllowedGroups($permissionClass)],
|
||||
['IS', 'contentcontainer_permission.permission_id', new Expression('NULL')],
|
||||
],
|
||||
// Set to allow
|
||||
['contentcontainer_permission.state' => $permissionClass::STATE_ALLOW],
|
||||
])
|
||||
->addParams(['permission_id' => $permissionClass]);
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($spaces->all() as $space) {
|
||||
$result[] = Chooser::getSpaceResult($space);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function getDefaultAllowedGroups(string $permissionClass): array
|
||||
{
|
||||
$defaultAllowedGroups = (new $permissionClass())->defaultAllowedGroups;
|
||||
|
||||
/* @var ContentContainerDefaultPermission[] $defaultPermissions */
|
||||
$defaultPermissions = ContentContainerDefaultPermission::find()
|
||||
->where(['contentcontainer_class' => Space::class])
|
||||
->andWhere(['permission_id' => $permissionClass])
|
||||
->all();
|
||||
|
||||
foreach ($defaultPermissions as $defaultPermission) {
|
||||
switch ($defaultPermission->state) {
|
||||
case BasePermission::STATE_ALLOW:
|
||||
if (!in_array($defaultPermission->group_id, $defaultAllowedGroups)) {
|
||||
$defaultAllowedGroups[] = $defaultPermission->group_id;
|
||||
}
|
||||
break;
|
||||
case BasePermission::STATE_DENY:
|
||||
if (($i = array_search($defaultPermission->group_id, $defaultAllowedGroups)) !== false) {
|
||||
unset($defaultAllowedGroups[$i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $defaultAllowedGroups;
|
||||
}
|
||||
}
|
@ -299,7 +299,7 @@ class Membership extends ActiveRecord
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ActiveQuery selcting all memberships for the given $user.
|
||||
* Returns an ActiveQuery selecting all memberships for the given $user.
|
||||
*
|
||||
* @param User $user
|
||||
* @param int $membershipStatus the status of the Space by default self::STATUS_MEMBER.
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace humhub\modules\space\models\forms;
|
||||
|
||||
use humhub\modules\admin\permissions\ManageSpaces;
|
||||
use humhub\modules\admin\permissions\ManageUsers;
|
||||
use humhub\modules\space\jobs\AddUsersToSpaceJob;
|
||||
use humhub\modules\space\models\Membership;
|
||||
@ -127,8 +128,10 @@ class InviteForm extends Model
|
||||
|
||||
$this->inviteExternalByEmail();
|
||||
|
||||
$this->space->auto_add_new_members = $this->addDefaultSpace ? 1 : null;
|
||||
$this->space->save();
|
||||
if (Yii::$app->user->can(ManageSpaces::class)) {
|
||||
$this->space->auto_add_new_members = $this->addDefaultSpace ? 1 : null;
|
||||
$this->space->save();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -168,7 +171,7 @@ class InviteForm extends Model
|
||||
'forceMembership' => $this->withoutInvite,
|
||||
'spaceId' => $this->space->id,
|
||||
'userIds' => $this->getInviteIds(),
|
||||
'allUsers' => $this->allRegisteredUsers,
|
||||
'allUsers' => $this->allRegisteredUsers && Yii::$app->user->can(ManageUsers::class),
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ use humhub\libs\Html;
|
||||
'action-confirm-header' => Yii::t('SpaceModule.base', 'Change visibility'),
|
||||
'confirm-text' => Yii::t('SpaceModule.base', 'Warning: If you change the visibility settings of a Space from public to private, all content within that Space, including posts, comments, attachments etc. will also be set to private. This means that non-members will no longer be able to see, access, or interact with any of the content within that Space.'),
|
||||
],
|
||||
]
|
||||
],
|
||||
); ?>
|
||||
|
||||
<?= DataSaved::widget(); ?>
|
||||
@ -52,13 +52,3 @@ use humhub\libs\Html;
|
||||
<?php ActiveForm::end(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script <?= Html::nonce() ?>>
|
||||
$('#space-visibility').on('change', function () {
|
||||
if (this.value == 0) {
|
||||
$('#space-join_policy, #space-default_content_visibility').val('0').prop('disabled', true);
|
||||
} else {
|
||||
$('#space-join_policy, #space-default_content_visibility').val('0').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -56,12 +56,18 @@ humhub.module('space', function (module, require, $) {
|
||||
};
|
||||
|
||||
var changeVisibilityOption = function (event) {
|
||||
const submitButton = event.$trigger.closest('form').find(':submit');
|
||||
const form = event.$trigger.closest('form');
|
||||
const submitButton = form.find(':submit');
|
||||
const fields = form.find('select[name*=join_policy], select[name*=default_content_visibility]');
|
||||
|
||||
if (event.$trigger.val() == 0) {
|
||||
submitButton.attr('data-action-confirm', submitButton.data('confirm-text'))
|
||||
if (event.$trigger.val() === '0') {
|
||||
// Private visibility
|
||||
submitButton.attr('data-action-confirm', submitButton.data('confirm-text'));
|
||||
fields.val(0).prop('disabled', true);
|
||||
} else {
|
||||
submitButton.removeAttr('data-action-confirm')
|
||||
// Public or guest visibility
|
||||
submitButton.removeAttr('data-action-confirm');
|
||||
fields.prop('disabled', false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace humhub\modules\space\widgets;
|
||||
|
||||
use humhub\modules\admin\permissions\ManageSpaces;
|
||||
use humhub\modules\admin\permissions\ManageUsers;
|
||||
use humhub\modules\space\models\forms\InviteForm;
|
||||
use Yii;
|
||||
@ -39,7 +40,9 @@ class InviteModal extends Widget
|
||||
'model' => $this->model,
|
||||
'attribute' => $this->attribute,
|
||||
'searchUrl' => $this->searchUrl,
|
||||
'canSelectAllRegisteredUsers' => Yii::$app->user->can(ManageUsers::class),
|
||||
'canAddWithoutInvite' => Yii::$app->user->can(ManageUsers::class) || Yii::$app->getModule('space')->membersCanAddWithoutInvite === true,
|
||||
'canAddAsDefaultSpace' => Yii::$app->user->can(ManageSpaces::class),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
namespace humhub\modules\space\widgets;
|
||||
|
||||
use humhub\modules\content\widgets\ContentContainerPickerField;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\ui\form\widgets\BasePicker;
|
||||
use Yii;
|
||||
use yii\helpers\Html;
|
||||
|
||||
/**
|
||||
* Mutliselect input field for selecting space guids.
|
||||
@ -14,30 +13,19 @@ use yii\helpers\Html;
|
||||
* @since 1.2
|
||||
* @author buddha
|
||||
*/
|
||||
class SpacePickerField extends BasePicker
|
||||
class SpacePickerField extends ContentContainerPickerField
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Min guids string value of Space model equal 2
|
||||
*/
|
||||
public $minInput = 2;
|
||||
|
||||
public $itemClass = Space::class;
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $defaultRoute = '/space/browse/search-json';
|
||||
public $itemClass = Space::class;
|
||||
public $itemKey = 'guid';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* Min guids string value
|
||||
*/
|
||||
protected function getAttributes()
|
||||
{
|
||||
return array_merge(parent::getAttributes(), [
|
||||
'data-tags' => 'false',
|
||||
]);
|
||||
}
|
||||
public $minInput = 2;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
@ -56,21 +44,4 @@ class SpacePickerField extends BasePicker
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getItemText($item)
|
||||
{
|
||||
return $item->getDisplayName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getItemImage($item)
|
||||
{
|
||||
return Image::widget(['space' => $item, 'width' => 24]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,9 @@
|
||||
/* @var $this View */
|
||||
/* @var $canInviteByEmail bool */
|
||||
/* @var $canInviteByLink bool */
|
||||
/* @var $canSelectAllRegisteredUsers bool */
|
||||
/* @var $canAddWithoutInvite bool */
|
||||
/* @var $canAddAsDefaultSpace bool */
|
||||
/* @var $submitText string */
|
||||
/* @var $submitAction string */
|
||||
/* @var $model InviteForm */
|
||||
@ -77,16 +79,20 @@ $form = ActiveForm::begin([
|
||||
<?= $form->field($model, 'invite')
|
||||
->widget(UserPickerField::class, ['disabledItems' => [Yii::$app->user->guid], 'url' => $searchUrl, 'focus' => true, 'id' => 'space-invite-user-picker']); ?>
|
||||
|
||||
<br/>
|
||||
<?= $form->field($model, 'allRegisteredUsers')->checkbox() ?>
|
||||
<?php if ($canSelectAllRegisteredUsers) : ?>
|
||||
<br/>
|
||||
<?= $form->field($model, 'allRegisteredUsers')->checkbox() ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($canAddWithoutInvite) : ?>
|
||||
<br/>
|
||||
<?= $form->field($model, 'withoutInvite')->checkbox() ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<br/>
|
||||
<?= $form->field($model, 'addDefaultSpace')->checkbox() ?>
|
||||
<?php if ($canAddAsDefaultSpace) : ?>
|
||||
<br/>
|
||||
<?= $form->field($model, 'addDefaultSpace')->checkbox() ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($canInviteByEmail) : ?>
|
||||
|
@ -80,14 +80,14 @@ abstract class BasePicker extends JsInputWidget
|
||||
public $maxSelection = 50;
|
||||
|
||||
/**
|
||||
* Minimum character input before triggering search query.
|
||||
* Minimum characters input before triggering search query.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $minInput = 3;
|
||||
|
||||
/**
|
||||
* Minimum character input before triggering search query.
|
||||
* Maximum characters input before triggering search query.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
|
@ -88,6 +88,7 @@ class InviteController extends Controller
|
||||
$userInvite->email = $email;
|
||||
$userInvite->source = Invite::SOURCE_INVITE;
|
||||
$userInvite->user_originator_id = Yii::$app->user->getIdentity()->id;
|
||||
$userInvite->language = Yii::$app->settings->get('defaultLanguage');
|
||||
|
||||
$existingInvite = Invite::findOne(['email' => $email]);
|
||||
if ($existingInvite !== null) {
|
||||
|
@ -92,7 +92,7 @@ class RegistrationController extends Controller
|
||||
$inviteRegistrationService->populateRegistration($registration);
|
||||
} elseif (Yii::$app->session->has('authClient')) {
|
||||
$authClient = Yii::$app->session->get('authClient');
|
||||
$this->handleAuthClientRegistration($authClient, $registration);
|
||||
$registration = $this->createRegistrationByAuthClient($authClient);
|
||||
} else {
|
||||
Yii::warning('Registration failed: No token (query) or authclient (session) found!', 'user');
|
||||
Yii::$app->session->setFlash('error', 'Registration failed.');
|
||||
@ -173,7 +173,7 @@ class RegistrationController extends Controller
|
||||
* @param Registration $registration
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function handleAuthClientRegistration(ClientInterface $authClient, Registration $registration)
|
||||
protected function createRegistrationByAuthClient(ClientInterface $authClient): Registration
|
||||
{
|
||||
$attributes = $authClient->getUserAttributes();
|
||||
|
||||
@ -181,7 +181,8 @@ class RegistrationController extends Controller
|
||||
throw new Exception("No user id given by authclient!");
|
||||
}
|
||||
|
||||
$registration->enablePasswordForm = false;
|
||||
$registration = new Registration(enablePasswordForm: false);
|
||||
|
||||
if ($authClient instanceof ApprovalBypass) {
|
||||
$registration->enableUserApproval = false;
|
||||
}
|
||||
@ -191,5 +192,7 @@ class RegistrationController extends Controller
|
||||
|
||||
$registration->getUser()->setAttributes($attributes, false);
|
||||
$registration->getProfile()->setAttributes($attributes, false);
|
||||
|
||||
return $registration;
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,17 @@
|
||||
namespace humhub\modules\user\models;
|
||||
|
||||
use humhub\components\ActiveRecord;
|
||||
use humhub\libs\ParameterEvent;
|
||||
use humhub\modules\admin\notifications\ExcludeGroupNotification;
|
||||
use humhub\modules\admin\notifications\IncludeGroupNotification;
|
||||
use humhub\modules\admin\permissions\ManageGroups;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\user\components\ActiveQueryUser;
|
||||
use humhub\modules\user\models\forms\Registration;
|
||||
use humhub\modules\user\Module;
|
||||
use Throwable;
|
||||
use Yii;
|
||||
use yii\base\Event;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\db\ActiveQuery;
|
||||
use yii\db\Expression;
|
||||
@ -50,6 +53,7 @@ use yii\helpers\Url;
|
||||
*/
|
||||
class Group extends ActiveRecord
|
||||
{
|
||||
public const EVENT_GET_REGISTRATION_GROUPS = 'getRegistrationGroups';
|
||||
public const SCENARIO_EDIT = 'edit';
|
||||
|
||||
/**
|
||||
@ -460,26 +464,32 @@ class Group extends ActiveRecord
|
||||
/**
|
||||
* Returns groups which are available in user registration
|
||||
*
|
||||
* @param User|null $user
|
||||
* @return Group[] the groups which can be selected in registration
|
||||
*/
|
||||
public static function getRegistrationGroups()
|
||||
public static function getRegistrationGroups(?User $user = null)
|
||||
{
|
||||
if (Yii::$app->getModule('user')->settings->get('auth.showRegistrationUserGroup')) {
|
||||
$groups = self::find()
|
||||
->where(['show_at_registration' => 1, 'is_admin_group' => 0])
|
||||
->orderBy('name ASC')
|
||||
->all();
|
||||
if (count($groups) > 0) {
|
||||
return $groups;
|
||||
}
|
||||
|
||||
if (empty($groups)) {
|
||||
$groups = [];
|
||||
if ($defaultGroup = Yii::$app->getModule('user')->getDefaultGroup()) {
|
||||
$groups[] = $defaultGroup;
|
||||
}
|
||||
}
|
||||
|
||||
$groups = [];
|
||||
if ($defaultGroup = Yii::$app->getModule('user')->getDefaultGroup()) {
|
||||
$groups[] = $defaultGroup;
|
||||
}
|
||||
$evt = new ParameterEvent([
|
||||
'user' => $user,
|
||||
'groups' => $groups,
|
||||
]);
|
||||
ParameterEvent::trigger(static::class, static::EVENT_GET_REGISTRATION_GROUPS, $evt);
|
||||
|
||||
return $groups;
|
||||
return $evt->parameters['groups'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +126,7 @@ class GroupUser extends ActiveRecord
|
||||
{
|
||||
if ($this->scenario == self::SCENARIO_REGISTRATION) {
|
||||
if ($this->group_id != '') {
|
||||
$registrationGroups = Group::getRegistrationGroups();
|
||||
$registrationGroups = Group::getRegistrationGroups($this->user);
|
||||
foreach ($registrationGroups as $group) {
|
||||
if ($this->group_id == $group->id) {
|
||||
return;
|
||||
|
@ -413,9 +413,10 @@ class Profile extends ActiveRecord
|
||||
*
|
||||
* @param string $field
|
||||
* @param bool $raw
|
||||
* @param bool $encode
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFieldValue(string $field, bool $raw = false): ?string
|
||||
public function getFieldValue(string $field, bool $raw = false, bool $encode = true): ?string
|
||||
{
|
||||
if (!$this->hasAttribute($field) || !$this->user) {
|
||||
return null;
|
||||
@ -423,6 +424,6 @@ class Profile extends ActiveRecord
|
||||
|
||||
$profileField = ProfileField::findOne(['internal_name' => $field]);
|
||||
|
||||
return $profileField?->getUserValue($this->user, $raw);
|
||||
return $profileField?->getUserValue($this->user, $raw, $encode);
|
||||
}
|
||||
}
|
||||
|
@ -309,11 +309,11 @@ class ProfileField extends ActiveRecord
|
||||
*
|
||||
* @param User $user
|
||||
* @param bool $raw
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
return $this->fieldType->getUserValue($user, $raw);
|
||||
return $this->fieldType->getUserValue($user, $raw, $encode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -699,7 +699,7 @@ class User extends ContentContainerActiveRecord implements IdentityInterface
|
||||
}
|
||||
|
||||
if ($this->profile !== null) {
|
||||
return $this->profile->getFieldValue(Yii::$app->settings->get('displayNameSubFormat', '')) ?? '';
|
||||
return $this->profile->getFieldValue(Yii::$app->settings->get('displayNameSubFormat', ''), false, false) ?? '';
|
||||
}
|
||||
|
||||
return '';
|
||||
|
@ -315,7 +315,7 @@ class BaseType extends Model
|
||||
$query = $db->getQueryBuilder()->dropColumn(Profile::tableName(), $this->profileField->internal_name);
|
||||
$db->createCommand($query)->execute();
|
||||
} else {
|
||||
Yii::error('Could not delete profile column - not exists!');
|
||||
Yii::error('Could not delete profile column "' . $columnName . '" - not exists!');
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,17 +352,14 @@ class BaseType extends Model
|
||||
*
|
||||
* @param User $user
|
||||
* @param bool $raw
|
||||
* @return string
|
||||
* @param bool $encode
|
||||
* @return string|null
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
$value = $user->profile->{$this->profileField->internal_name} ?? '';
|
||||
|
||||
if ($raw) {
|
||||
return $user->profile->$internalName;
|
||||
} else {
|
||||
return Html::encode($user->profile->$internalName);
|
||||
}
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,9 +34,9 @@ abstract class BaseTypeVirtual extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
final public function getUserValue(User $user, $raw = true): ?string
|
||||
final public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
return $this->getVirtualUserValue($user, $raw);
|
||||
return $this->getVirtualUserValue($user, $raw, $encode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,13 +71,14 @@ abstract class BaseTypeVirtual extends BaseType
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the readonly virutal value for the given User
|
||||
* Returns the readonly virtual value for the given User
|
||||
*
|
||||
* @param User $user
|
||||
* @param bool $raw
|
||||
* @return mixed
|
||||
* @param bool $encode
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getVirtualUserValue($user, $raw = true);
|
||||
abstract protected function getVirtualUserValue(User $user, bool $raw = true, bool $encode = true): string;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
|
@ -177,7 +177,7 @@ class Birthday extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
$birthdayDate = \DateTime::createFromFormat(
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
namespace humhub\modules\user\models\fieldtype;
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\user\models\Profile;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
@ -108,16 +109,19 @@ class Checkbox extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
|
||||
$value = $user->profile->$internalName;
|
||||
if (!$raw && !empty($value)) {
|
||||
$labels = $this->getLabels();
|
||||
return $labels[$internalName];
|
||||
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $value;
|
||||
if (!$raw) {
|
||||
$value = $this->getLabels()[$internalName] ?? '';
|
||||
}
|
||||
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
}
|
||||
|
@ -164,14 +164,13 @@ class CheckboxList extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
$internalNameOther = $internalName . '_other_selection';
|
||||
|
||||
$value = $user->profile->$internalName;
|
||||
if (!$raw && $value !== null) {
|
||||
|
||||
$options = $this->getSelectItems();
|
||||
$translatedValues = [];
|
||||
if (is_string($value)) {
|
||||
@ -179,15 +178,14 @@ class CheckboxList extends BaseType
|
||||
}
|
||||
foreach ($value as $v) {
|
||||
if ($v === 'other' && !empty($user->profile->$internalNameOther)) {
|
||||
$translatedValues[] = Html::encode($user->profile->$internalNameOther);
|
||||
$translatedValues[] = $user->profile->$internalNameOther;
|
||||
} elseif (isset($options[$v])) {
|
||||
$translatedValues[] = Html::encode(Yii::t($this->profileField->getTranslationCategory(), $options[$v]));
|
||||
$translatedValues[] = Yii::t($this->profileField->getTranslationCategory(), $options[$v]);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(', ', $translatedValues);
|
||||
$value = implode(', ', $translatedValues);
|
||||
}
|
||||
|
||||
return $value;
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
}
|
||||
|
@ -89,16 +89,20 @@ class CountrySelect extends Select
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
$value = $user->profile->$internalName;
|
||||
$value = $user->profile->$internalName ?? '';
|
||||
|
||||
if (!$raw) {
|
||||
return Html::encode(Iso3166Codes::country($value));
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $value;
|
||||
if (!$raw) {
|
||||
$value = Iso3166Codes::country($value);
|
||||
}
|
||||
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,20 +79,25 @@ class Date extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
$value = $user->profile->$internalName ?? '';
|
||||
$date = \DateTime::createFromFormat(
|
||||
'Y-m-d',
|
||||
$user->profile->$internalName ?? '',
|
||||
$value,
|
||||
new DateTimeZone(Yii::$app->formatter->timeZone),
|
||||
);
|
||||
|
||||
if ($date === false) {
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
|
||||
return $raw ? Html::encode($user->profile->$internalName) : Yii::$app->formatter->asDate($date, 'long');
|
||||
if (!$raw) {
|
||||
$value = Yii::$app->formatter->asDate($date, 'long');
|
||||
}
|
||||
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -110,21 +110,25 @@ class DateTime extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
|
||||
$value = $user->profile->$internalName ?? '';
|
||||
$date = \DateTime::createFromFormat(
|
||||
'Y-m-d H:i:s',
|
||||
$user->profile->$internalName ?? '',
|
||||
$value,
|
||||
new DateTimeZone(Yii::$app->formatter->timeZone),
|
||||
);
|
||||
|
||||
if ($date === false) {
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
|
||||
return $raw ? Html::encode($user->profile->$internalName) : Yii::$app->formatter->asDatetime($date, 'long');
|
||||
if (!$raw) {
|
||||
$value = Yii::$app->formatter->asDatetime($date, 'long');
|
||||
}
|
||||
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -115,19 +115,19 @@ class Select extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): ?string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
$value = $user->profile->$internalName;
|
||||
$value = $user->profile->$internalName ?? '';
|
||||
|
||||
if (!$raw) {
|
||||
$options = $this->getSelectItems();
|
||||
if (isset($options[$value])) {
|
||||
return Html::encode(Yii::t($this->profileField->getTranslationCategory(), $options[$value]));
|
||||
$value = Yii::t($this->profileField->getTranslationCategory(), $options[$value]);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ class Template extends BaseType
|
||||
];
|
||||
}
|
||||
|
||||
public function getUserValue($user, $raw = true): ?string
|
||||
public function getUserValue($user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$variables = ArrayHelper::map(
|
||||
$user->profile->getProfileFields(null, [static::class]),
|
||||
'internal_name',
|
||||
function (ProfileField $profileField) use ($user) {
|
||||
return $profileField->getUserValue($user);
|
||||
function (ProfileField $profileField) use ($user, $raw, $encode) {
|
||||
return $profileField->getUserValue($user, $raw, $encode);
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -207,17 +207,17 @@ class Text extends BaseType
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getUserValue(User $user, $raw = true): string
|
||||
public function getUserValue(User $user, bool $raw = true, bool $encode = true): ?string
|
||||
{
|
||||
$internalName = $this->profileField->internal_name;
|
||||
$value = $user->profile->$internalName;
|
||||
$value = $user->profile->$internalName ?? '';
|
||||
|
||||
if (!$raw && (in_array($this->validator, [self::VALIDATOR_EMAIL, self::VALIDATOR_URL]) || !empty($this->linkPrefix))) {
|
||||
$linkPrefix = ($this->validator === self::VALIDATOR_EMAIL) ? 'mailto:' : $this->linkPrefix;
|
||||
return Html::a(Html::encode($value), $linkPrefix . $value);
|
||||
return Html::a($encode ? Html::encode($value) : $value, $linkPrefix . $value);
|
||||
}
|
||||
|
||||
return Html::encode($value);
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\modules\user\models\fieldtype;
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\user\models\User;
|
||||
|
||||
/**
|
||||
* UserEmail is a virtual profile field
|
||||
@ -19,18 +20,20 @@ use humhub\libs\Html;
|
||||
class UserEmail extends BaseTypeVirtual
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getVirtualUserValue($user, $raw = true)
|
||||
protected function getVirtualUserValue(User $user, bool $raw = true, bool $encode = true): string
|
||||
{
|
||||
if (empty($user->email)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($raw) {
|
||||
return Html::encode($user->email);
|
||||
} else {
|
||||
return Html::a(Html::encode($user->email), 'mailto:' . $user->email);
|
||||
$value = $encode ? Html::encode($user->email) : $user->email;
|
||||
|
||||
if (!$raw) {
|
||||
return Html::a($value, 'mailto:' . $user->email);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\modules\user\models\fieldtype;
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
use yii\base\InvalidConfigException;
|
||||
|
||||
@ -21,15 +22,20 @@ use yii\base\InvalidConfigException;
|
||||
class UserLastLogin extends BaseTypeVirtual
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @inheritdoc
|
||||
* @throws InvalidConfigException
|
||||
*/
|
||||
public function getVirtualUserValue($user, $raw = true)
|
||||
protected function getVirtualUserValue(User $user, bool $raw = true, bool $encode = true): string
|
||||
{
|
||||
if (empty($user->last_login)) {
|
||||
$value = $user->last_login;
|
||||
if (empty($value)) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
return Yii::$app->formatter->asDate($user->last_login, 'long');
|
||||
if (!$raw) {
|
||||
$value = Yii::$app->formatter->asDate($value, 'long');
|
||||
}
|
||||
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\modules\user\models\fieldtype;
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
@ -20,14 +21,19 @@ use Yii;
|
||||
class UserMemberSince extends BaseTypeVirtual
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getVirtualUserValue($user, $raw = true)
|
||||
public function getVirtualUserValue(User $user, bool $raw = true, bool $encode = true): string
|
||||
{
|
||||
if (empty($user->created_at)) {
|
||||
$value = $user->created_at;
|
||||
if (empty($value)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Yii::$app->formatter->asDate($user->created_at, 'long');
|
||||
if (!$raw) {
|
||||
$value = Yii::$app->formatter->asDate($value, 'long');
|
||||
}
|
||||
|
||||
return $encode ? Html::encode($value) : $value;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\modules\user\models\fieldtype;
|
||||
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\user\models\User;
|
||||
|
||||
/**
|
||||
* UserName is a virtual profile field
|
||||
@ -21,12 +22,12 @@ class UserName extends BaseTypeVirtual
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getVirtualUserValue($user, $raw = true)
|
||||
public function getVirtualUserValue(User $user, bool $raw = true, bool $encode = true): string
|
||||
{
|
||||
if (empty($user->username)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Html::encode($user->username);
|
||||
return $encode ? Html::encode($user->username) : $user->username;
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace humhub\modules\user\models\forms;
|
||||
|
||||
use humhub\helpers\DeviceDetectorHelper;
|
||||
use humhub\modules\user\assets\UserAsset;
|
||||
use humhub\modules\user\authclient\BaseClient;
|
||||
use humhub\modules\user\authclient\BaseFormAuth;
|
||||
@ -28,6 +29,11 @@ class Login extends Model
|
||||
*/
|
||||
public $rememberMe = false;
|
||||
|
||||
/**
|
||||
* @var bool hide "Remember me" form field in the view
|
||||
*/
|
||||
public $hideRememberMe = false;
|
||||
|
||||
/**
|
||||
* @var BaseClient auth client used to authenticate
|
||||
*/
|
||||
@ -50,6 +56,7 @@ class Login extends Model
|
||||
public function init()
|
||||
{
|
||||
$this->rememberMe = Yii::$app->getModule('user')->loginRememberMeDefault;
|
||||
$this->hideRememberMe = DeviceDetectorHelper::isAppRequest();
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
@ -36,17 +36,17 @@ class Registration extends HForm
|
||||
/**
|
||||
* @var bool show password creation form
|
||||
*/
|
||||
public $enablePasswordForm = true;
|
||||
private $enablePasswordForm;
|
||||
|
||||
/**
|
||||
* @var bool show checkbox to force to change password on first log in
|
||||
*/
|
||||
public $enableMustChangePassword = false;
|
||||
private $enableMustChangePassword;
|
||||
|
||||
/**
|
||||
* @var bool show e-mail field
|
||||
*/
|
||||
public $enableEmailField = false;
|
||||
private $enableEmailField;
|
||||
|
||||
/**
|
||||
* @var bool|null require user approval by admin after registration.
|
||||
@ -73,6 +73,21 @@ class Registration extends HForm
|
||||
*/
|
||||
private $_profile = null;
|
||||
|
||||
public function __construct(
|
||||
$definition = [],
|
||||
$primaryModel = null,
|
||||
array $config = [],
|
||||
bool $enableEmailField = false,
|
||||
bool $enablePasswordForm = true,
|
||||
bool $enableMustChangePassword = false,
|
||||
) {
|
||||
$this->enableEmailField = $enableEmailField;
|
||||
$this->enablePasswordForm = $enablePasswordForm;
|
||||
$this->enableMustChangePassword = $enableMustChangePassword;
|
||||
|
||||
parent::__construct($definition, $primaryModel, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -84,16 +99,9 @@ class Registration extends HForm
|
||||
$this->enableUserApproval = false;
|
||||
}
|
||||
|
||||
return parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function render($form)
|
||||
{
|
||||
$this->setFormDefinition();
|
||||
return parent::render($form);
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,14 +109,18 @@ class Registration extends HForm
|
||||
*/
|
||||
protected function setFormDefinition()
|
||||
{
|
||||
$this->definition = [];
|
||||
$this->definition['elements'] = [];
|
||||
if (!isset($this->definition['elements']) || !is_array($this->definition['elements'])) {
|
||||
$this->definition['elements'] = [];
|
||||
}
|
||||
$this->definition['elements']['User'] = $this->getUserFormDefinition();
|
||||
$this->definition['elements']['GroupUser'] = $this->getGroupFormDefinition();
|
||||
if ($this->enablePasswordForm) {
|
||||
$this->definition['elements']['Password'] = $this->getPasswordFormDefinition();
|
||||
}
|
||||
$this->definition['elements']['Profile'] = array_merge(['type' => 'form'], $this->getProfile()->getFormDefinition());
|
||||
$this->definition['elements']['Profile'] = array_merge(
|
||||
['type' => 'form'],
|
||||
$this->getProfile()->getFormDefinition(),
|
||||
);
|
||||
$this->definition['buttons'] = [
|
||||
'save' => [
|
||||
'type' => 'submit',
|
||||
@ -185,9 +197,11 @@ class Registration extends HForm
|
||||
|
||||
protected function getGroupFormDefinition()
|
||||
{
|
||||
$groupModels = Group::getRegistrationGroups();
|
||||
$groupModels = Group::getRegistrationGroups($this->getUser());
|
||||
|
||||
$groupFieldType = (Yii::$app->getModule('user')->settings->get('auth.showRegistrationUserGroup') && count($groupModels) > 1)
|
||||
$groupFieldType = (Yii::$app->getModule('user')->settings->get('auth.showRegistrationUserGroup') && count(
|
||||
$groupModels,
|
||||
) > 1)
|
||||
? 'dropdownlist'
|
||||
: 'hidden'; // TODO: Completely hide the element instead of current <input type="hidden">
|
||||
|
||||
@ -272,7 +286,6 @@ class Registration extends HForm
|
||||
}
|
||||
|
||||
if ($this->models['User']->save()) {
|
||||
|
||||
// Save User Profile
|
||||
$this->models['Profile']->user_id = $this->models['User']->id;
|
||||
$this->models['Profile']->save();
|
||||
@ -296,7 +309,10 @@ class Registration extends HForm
|
||||
|
||||
if ($authClient !== null) {
|
||||
(new AuthClientUserService($this->models['User']))->add($authClient);
|
||||
$authClient->trigger(BaseClient::EVENT_CREATE_USER, new UserEvent(['identity' => $this->models['User']]));
|
||||
$authClient->trigger(
|
||||
BaseClient::EVENT_CREATE_USER,
|
||||
new UserEvent(['identity' => $this->models['User']]),
|
||||
);
|
||||
}
|
||||
|
||||
$this->trigger(self::EVENT_AFTER_REGISTRATION, new UserEvent(['identity' => $this->models['User']]));
|
||||
@ -368,7 +384,7 @@ class Registration extends HForm
|
||||
$this->_groupUser->scenario = GroupUser::SCENARIO_REGISTRATION;
|
||||
|
||||
// assign default value for group_id
|
||||
$registrationGroups = Group::getRegistrationGroups();
|
||||
$registrationGroups = Group::getRegistrationGroups($this->getUser());
|
||||
if (count($registrationGroups) == 1) {
|
||||
$this->_groupUser->group_id = $registrationGroups[0]->id;
|
||||
}
|
||||
|
@ -123,9 +123,7 @@ class AuthClientService
|
||||
return null;
|
||||
}
|
||||
|
||||
$registration = new Registration();
|
||||
$registration->enablePasswordForm = false;
|
||||
$registration->enableEmailField = true;
|
||||
$registration = new Registration(enableEmailField: true, enablePasswordForm: false);
|
||||
|
||||
if ($this->authClient instanceof ApprovalBypass) {
|
||||
$registration->enableUserApproval = false;
|
||||
|
@ -52,7 +52,9 @@ final class InviteRegistrationService
|
||||
{
|
||||
$invite = $this->getInvite();
|
||||
if ($invite !== null) {
|
||||
Yii::$app->setLanguage($invite->language);
|
||||
if (Yii::$app->request->post('ChooseLanguage') === null) {
|
||||
Yii::$app->setLanguage($invite->language);
|
||||
}
|
||||
$registration->getUser()->email = $invite->email;
|
||||
}
|
||||
}
|
||||
|
@ -69,14 +69,10 @@ class IncludeAllContributionsFilter extends ContentContainerStreamFilter
|
||||
$conditionUserPrivateRestriction = '';
|
||||
} else {
|
||||
// User must be a space's member OR Space and Content are public
|
||||
if ($queryUser) {
|
||||
$spaceMembership = 'space_membership.status=3 OR ';
|
||||
} else {
|
||||
$spaceMembership = '';
|
||||
}
|
||||
$spaceMembership = $queryUser ? 'space_membership.status=3 OR ' : '';
|
||||
$conditionSpaceMembershipRestriction = " AND ($spaceMembership (content.visibility=1 AND space.visibility != 0) )";
|
||||
// User can view only content of own profile
|
||||
$conditionUserPrivateRestriction = ' AND content.contentcontainer_id=' . $queryUser->contentcontainer_id;
|
||||
// User can view a private content only of own profile
|
||||
$conditionUserPrivateRestriction = $queryUser ? ' AND content.contentcontainer_id=' . $queryUser->contentcontainer_id : '';
|
||||
}
|
||||
|
||||
// Build Access Check based on Space Content Container
|
||||
|
@ -25,4 +25,5 @@ return [
|
||||
['user_id' => 5, 'firstname' => 'Disabled', 'lastname' => 'User'],
|
||||
['user_id' => 6, 'firstname' => 'UnApproved', 'lastname' => 'User'],
|
||||
['user_id' => 7, 'firstname' => 'UnApprovedNoGroup', 'lastname' => 'User'],
|
||||
['user_id' => 8, 'firstname' => 'AdminNotMember', 'lastname' => 'User'],
|
||||
];
|
||||
|
@ -31,7 +31,7 @@ class PeopleFiltersTest extends HumHubDbTestCase
|
||||
ProfileField::updateAll(['directory_filter' => 1], ['IN', 'internal_name', ['firstname', 'lastname']]);
|
||||
$peopleFilters = new PeopleFilters();
|
||||
|
||||
$this->assertEquals(['Admin', 'Andreas', 'Peter', 'Sara'], $this->getFilterOptions('fields[firstname]', $peopleFilters));
|
||||
$this->assertEquals(['Admin', 'AdminNotMember', 'Andreas', 'Peter', 'Sara'], $this->getFilterOptions('fields[firstname]', $peopleFilters));
|
||||
}
|
||||
|
||||
public function testReducedFilters()
|
||||
@ -52,8 +52,8 @@ class PeopleFiltersTest extends HumHubDbTestCase
|
||||
// Filter by firstname
|
||||
$peopleQuery = new PeopleQuery(['defaultFilters' => ['fields' => ['firstname' => 'Admin']]]);
|
||||
$peopleFilters = new PeopleFilters(['query' => $peopleQuery]);
|
||||
$this->assertEquals(['Admin'], $this->getFilterOptions('fields[firstname]', $peopleFilters));
|
||||
$this->assertEquals(['AdminLastName'], $this->getFilterOptions('fields[lastname]', $peopleFilters));
|
||||
$this->assertEquals(['Admin', 'AdminNotMember'], $this->getFilterOptions('fields[firstname]', $peopleFilters));
|
||||
$this->assertEquals(['AdminLastName', 'User'], $this->getFilterOptions('fields[lastname]', $peopleFilters));
|
||||
$this->assertEquals(['' => 'Any', 1 => 'Administrator'], $this->getFilterOptions('groupId', $peopleFilters));
|
||||
|
||||
// Filter by group
|
||||
|
@ -53,7 +53,7 @@ $this->pageTitle = Yii::t('UserModule.auth', 'Login');
|
||||
<?= $form->field($model, 'password')
|
||||
->passwordInput(['id' => 'login_password', 'placeholder' => $model->getAttributeLabel('password'), 'aria-label' => $model->getAttributeLabel('password')])
|
||||
->label(false); ?>
|
||||
<?= $form->field($model, 'rememberMe')->checkbox(); ?>
|
||||
<?= $model->hideRememberMe ? '' : $form->field($model, 'rememberMe')->checkbox(); ?>
|
||||
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
@ -69,7 +69,7 @@ use yii\widgets\ActiveForm;
|
||||
<?php $form = ActiveForm::begin(['id' => 'account-login-form-modal', 'enableClientValidation' => false]); ?>
|
||||
<?= $form->field($model, 'username')->textInput(['id' => 'login_username', 'placeholder' => $model->getAttributeLabel('username')]); ?>
|
||||
<?= $form->field($model, 'password')->passwordInput(['id' => 'login_password', 'placeholder' => $model->getAttributeLabel('password')]); ?>
|
||||
<?= $form->field($model, 'rememberMe')->checkbox(); ?>
|
||||
<?= $model->hideRememberMe ? '' : $form->field($model, 'rememberMe')->checkbox(); ?>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
|
@ -42,7 +42,7 @@ $categories = $user->profile->getProfileFieldCategories();
|
||||
</label>
|
||||
<div class="col-sm-9 field-value">
|
||||
<?= ($field->field_type_class === MarkdownEditor::class) ?
|
||||
RichText::output($field->getUserValue($user, true)) :
|
||||
RichText::output($field->getUserValue($user, true, false)) :
|
||||
$field->getUserValue($user, false) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,6 +4,7 @@ use humhub\libs\Html;
|
||||
use humhub\modules\ui\form\widgets\ActiveForm;
|
||||
use humhub\modules\user\models\forms\Registration;
|
||||
use humhub\modules\user\widgets\AuthChoice;
|
||||
use humhub\widgets\LanguageChooser;
|
||||
use humhub\widgets\SiteLogo;
|
||||
|
||||
/**
|
||||
@ -32,12 +33,15 @@ $this->pageTitle = Yii::t('UserModule.auth', 'Create Account');
|
||||
|
||||
<?php if ($showRegistrationForm): ?>
|
||||
<?php $form = ActiveForm::begin(['id' => 'registration-form', 'enableClientValidation' => false]); ?>
|
||||
<?= Html::hiddenInput('ChooseLanguage[language]', Yii::$app->language) ?>
|
||||
<?= $hForm->render($form); ?>
|
||||
<?php ActiveForm::end(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= LanguageChooser::widget() ?>
|
||||
</div>
|
||||
|
||||
<script <?= Html::nonce() ?>>
|
||||
|
@ -36,6 +36,14 @@ class Image extends BaseImage
|
||||
|
||||
public bool $showSelfOnlineStatus = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function beforeRun()
|
||||
{
|
||||
return parent::beforeRun() && $this->user instanceof User;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
@ -3,11 +3,11 @@
|
||||
namespace humhub\modules\user\widgets;
|
||||
|
||||
use humhub\libs\BasePermission;
|
||||
use humhub\modules\user\models\UserFilter;
|
||||
use Yii;
|
||||
use yii\base\Widget;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Url;
|
||||
use humhub\modules\user\models\UserFilter;
|
||||
|
||||
/**
|
||||
* UserPickerWidget displays a user picker instead of an input field.
|
||||
@ -254,7 +254,7 @@ class UserPicker extends Widget
|
||||
* @param type $permission
|
||||
* @return type
|
||||
*/
|
||||
private static function createJSONUserInfo($user, $permission = null, $priority = null)
|
||||
public static function createJSONUserInfo($user, $permission = null, $priority = null)
|
||||
{
|
||||
$disabled = false;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace humhub\modules\user\widgets;
|
||||
|
||||
use humhub\modules\ui\form\widgets\BasePicker;
|
||||
use humhub\modules\content\widgets\ContentContainerPickerField;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
use yii\helpers\Url;
|
||||
@ -13,8 +13,10 @@ use yii\helpers\Url;
|
||||
* @since 1.2
|
||||
* @author buddha
|
||||
*/
|
||||
class UserPickerField extends BasePicker
|
||||
class UserPickerField extends ContentContainerPickerField
|
||||
{
|
||||
public $itemClass = User::class;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -25,24 +27,6 @@ class UserPickerField extends BasePicker
|
||||
*/
|
||||
public $jsWidget = 'user.picker.UserPicker';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* The 'guid' value is default for UserPickerField
|
||||
*/
|
||||
public $itemKey = 'guid';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->itemClass = User::class;
|
||||
if (empty($this->itemKey)) {
|
||||
$this->itemKey = 'guid';
|
||||
}
|
||||
parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -50,26 +34,16 @@ class UserPickerField extends BasePicker
|
||||
{
|
||||
if (!$this->url) {
|
||||
// provide the space id if the widget is calling from a space
|
||||
if (Yii::$app->controller->id == 'space') {
|
||||
if (Yii::$app->controller->id === 'space') {
|
||||
return Url::to([$this->defaultRoute, 'space_id' => Yii::$app->controller->getSpace()->id]);
|
||||
} else {
|
||||
return Url::to([$this->defaultRoute]);
|
||||
}
|
||||
|
||||
return Url::to([$this->defaultRoute]);
|
||||
}
|
||||
|
||||
return parent::getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getAttributes()
|
||||
{
|
||||
return array_merge(parent::getAttributes(), [
|
||||
'data-tags' => 'false',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -88,8 +62,7 @@ class UserPickerField extends BasePicker
|
||||
if ($this->placeholder && !$this->placeholderMore) {
|
||||
$result['placeholder-more'] = $this->placeholder;
|
||||
} else {
|
||||
$result['placeholder-more'] = ($this->placeholderMore) ? $this->placeholderMore
|
||||
: Yii::t('UserModule.chooser', 'Add user');
|
||||
$result['placeholder-more'] = ($this->placeholderMore) ?: Yii::t('UserModule.chooser', 'Add user');
|
||||
}
|
||||
|
||||
$result['no-result'] = Yii::t('UserModule.chooser', 'No users found for the given query.');
|
||||
@ -103,20 +76,4 @@ class UserPickerField extends BasePicker
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getItemText($item)
|
||||
{
|
||||
return $item->displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function getItemImage($item)
|
||||
{
|
||||
return $item->getProfileImage()->getUrl();
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace tests\codeception\_support;
|
||||
|
||||
use Codeception\Module;
|
||||
use Codeception\TestInterface;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
@ -40,4 +41,35 @@ class WebHelper extends Module
|
||||
Yii::$app->moduleManager->enableModules($cfg['humhub_modules']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function _failed(TestInterface $test, $fail)
|
||||
{
|
||||
parent::_failed($test, $fail);
|
||||
|
||||
$filePath = codecept_output_dir() . str_replace(['\\', '/', ':', ' '], '.', $test->getSignature());
|
||||
|
||||
$logFilePath = Yii::getAlias('@runtime/logs') . DIRECTORY_SEPARATOR . 'app.log';
|
||||
if (file_exists($logFilePath)) {
|
||||
copy($logFilePath, $filePath . '.app.log');
|
||||
}
|
||||
|
||||
if (!Yii::$app->db->isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
preg_match('/host=([^;]+)/', Yii::$app->db->dsn, $hostMatch);
|
||||
preg_match('/dbname=([^;]+)/', Yii::$app->db->dsn, $dbMatch);
|
||||
|
||||
exec(sprintf(
|
||||
'mysqldump --skip-column-statistics -u%s -p%s -h%s %s > %s',
|
||||
escapeshellarg(Yii::$app->db->username ?? 'root'),
|
||||
escapeshellarg(Yii::$app->db->password ?? 'root'),
|
||||
escapeshellarg($hostMatch[1] ?? '127.0.0.1'),
|
||||
escapeshellarg($dbMatch[1] ?? 'humhub_test'),
|
||||
escapeshellarg($filePath . '.dump.sql'),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -23,23 +23,56 @@ class FormatterTest extends Unit
|
||||
999 => '999',
|
||||
1000 => '1K',
|
||||
1234 => '1K',
|
||||
9990 => '9K',
|
||||
9990 => '10K',
|
||||
123456 => '123K',
|
||||
123999 => '123K',
|
||||
999999 => '999K',
|
||||
123999 => '124K',
|
||||
899999 => '900K',
|
||||
999999 => '1M',
|
||||
1234567 => '1M',
|
||||
123456789 => '123M',
|
||||
123999500 => '124M',
|
||||
999999499 => '999M',
|
||||
999999500 => '1000M',
|
||||
999999499 => '1B',
|
||||
999999500 => '1B',
|
||||
1234567899 => '1B',
|
||||
123456789999 => '123B',
|
||||
12345678999999 => '12345B',
|
||||
999999999499999 => '999999B',
|
||||
12345678999999 => '12346B',
|
||||
999999999499999 => '1000000B',
|
||||
999999999500000 => '1000000B',
|
||||
];
|
||||
foreach ($testNumbers as $numberValue => $result) {
|
||||
$this->assertEquals(Yii::$app->formatter->asShortInteger($numberValue), $result);
|
||||
}
|
||||
}
|
||||
|
||||
public function testAsShortIntegerArabic()
|
||||
{
|
||||
Yii::$app->formatter->locale = 'ar';
|
||||
|
||||
$testNumbers = [
|
||||
1 => '١',
|
||||
12 => '١٢',
|
||||
123 => '١٢٣',
|
||||
999 => '٩٩٩',
|
||||
1000 => '١K',
|
||||
1234 => '١K',
|
||||
9990 => '١٠K',
|
||||
123456 => '١٢٣K',
|
||||
123999 => '١٢٤K',
|
||||
899999 => '٩٠٠K',
|
||||
999999 => '١M',
|
||||
1234567 => '١M',
|
||||
123456789 => '١٢٣M',
|
||||
123999500 => '١٢٤M',
|
||||
999999499 => '١B',
|
||||
999999500 => '١B',
|
||||
1234567899 => '١B',
|
||||
123456789999 => '١٢٣B',
|
||||
12345678999999 => '١٢٣٤٦B',
|
||||
999999999499999 => '١٠٠٠٠٠٠B',
|
||||
999999999500000 => '١٠٠٠٠٠٠B',
|
||||
];
|
||||
foreach ($testNumbers as $numberValue => $result) {
|
||||
$this->assertEquals(Yii::$app->formatter->asShortInteger($numberValue), $result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,14 @@ use yii\base\Widget;
|
||||
*/
|
||||
class LanguageChooser extends Widget
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function beforeRun()
|
||||
{
|
||||
return parent::beforeRun() && Yii::$app->user->isGuest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays / Run the Widget
|
||||
*/
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
use humhub\modules\ui\menu\MenuLink;
|
||||
use humhub\widgets\LanguageChooser;
|
||||
use humhub\widgets\PoweredBy;
|
||||
use yii\helpers\Html;
|
||||
|
||||
@ -28,7 +29,9 @@ use yii\helpers\Html;
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?= PoweredBy::widget(); ?>
|
||||
<?= PoweredBy::widget() ?>
|
||||
|
||||
<?= LanguageChooser::widget() ?>
|
||||
</small>
|
||||
</div>
|
||||
<br/>
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
use humhub\modules\ui\menu\MenuLink;
|
||||
use humhub\widgets\LanguageChooser;
|
||||
use humhub\widgets\PoweredBy;
|
||||
use yii\helpers\Html;
|
||||
|
||||
@ -30,6 +31,8 @@ use yii\helpers\Html;
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?= PoweredBy::widget(); ?>
|
||||
|
||||
<?= LanguageChooser::widget() ?>
|
||||
</small>
|
||||
</div>
|
||||
<br/>
|
||||
|
@ -92,6 +92,10 @@ humhub.module('ui.modal', function (module, require, $) {
|
||||
});
|
||||
|
||||
this.set(options);
|
||||
|
||||
// Store initial data to reset it
|
||||
this.initialOptions = options;
|
||||
this.initialDialog = this.getDialog().clone(true);
|
||||
};
|
||||
|
||||
Modal.prototype.checkAriaLabel = function () {
|
||||
@ -144,16 +148,14 @@ humhub.module('ui.modal', function (module, require, $) {
|
||||
* @returns {undefined}
|
||||
*/
|
||||
Modal.prototype.reset = function () {
|
||||
// Clear old script tags.
|
||||
var $content = this.getContent().empty();
|
||||
this.$.find('script').remove();
|
||||
$content.append('<div class="modal-body" />');
|
||||
loader.set(this.getBody());
|
||||
this.isFilled = false;
|
||||
|
||||
this.getDialog().removeClass('modal-dialog-large modal-dialog-normal modal-dialog-small modal-dialog-extra-small modal-dialog-medium');
|
||||
|
||||
//reset listeners:
|
||||
// Remove scripts from previous modal window
|
||||
this.$.find('script').remove();
|
||||
// Reset dialog to initial html
|
||||
this.getDialog().replaceWith(this.initialDialog.clone(true));
|
||||
// Reset options in order to display initial window on load new window
|
||||
this.options = this.initialOptions;
|
||||
// Reset listeners to avoid unexpected js behaviour
|
||||
this.resetListener();
|
||||
};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user