mirror of
https://github.com/humhub/humhub.git
synced 2025-01-17 14:18:27 +01:00
Merge branch 'v1.3-dev' into resend-member-invitations
This commit is contained in:
commit
04fc5b2b9d
1
.gitignore
vendored
1
.gitignore
vendored
@ -25,7 +25,6 @@ nbproject
|
||||
.idea/*
|
||||
.gitmodules
|
||||
.github
|
||||
/composer.lock
|
||||
|
||||
themes/*
|
||||
!themes/HumHub
|
||||
|
@ -11,6 +11,10 @@ RewriteEngine on
|
||||
# prevent httpd from serving dotfiles (.htaccess, .svn, .git, etc.) - except let's encrypt challenge
|
||||
RedirectMatch 403 ^/?\.(?!/well-known/acme-challenge/[\w-]{43}$)
|
||||
|
||||
# ensure permalink when url rewriting was enabled (index.php?r=content/perma&id=6 => /content/perma/?id=6
|
||||
RewriteCond %{QUERY_STRING} ^r=content(/|%2)perma&id=([0-9]*)$
|
||||
RewriteRule ^index\.php$ %{REQUEST_URI}/content/perma/?id=%2 [R=302,L]
|
||||
|
||||
RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
|
||||
RewriteRule ^(.*) - [E=BASE:%1]
|
||||
|
||||
|
@ -2,14 +2,13 @@
|
||||
"name": "humhub/humhub",
|
||||
"description": "HumHub - The flexible Open Source Social Network Kit for Collaboration",
|
||||
"keywords": ["humhub", "yii2", "framework"],
|
||||
"homepage": "http://www.humhub.com/",
|
||||
"homepage": "https://www.humhub.org/",
|
||||
"type": "project",
|
||||
"license": "AGPL-3.0",
|
||||
"support": {
|
||||
"issues": "https://github.com/humhub/humhub/issues?state=open",
|
||||
"forum": "http://community.humhub.com",
|
||||
"wiki": "http://community.humhub.com",
|
||||
"irc": "irc://irc.freenode.net/humhub",
|
||||
"forum": "https://community.humhub.com",
|
||||
"wiki": "https://community.humhub.com",
|
||||
"source": "https://github.com/humhub/humhub"
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
@ -24,35 +23,39 @@
|
||||
"raoul2000/yii2-jcrop-widget": "*",
|
||||
"kartik-v/yii2-widgets": "*",
|
||||
"phpoffice/phpexcel": "*",
|
||||
"cebe/markdown": "1.0.2",
|
||||
"cebe/markdown": "~1.0.2",
|
||||
"yiisoft/yii2-jui": "~2.0.0",
|
||||
"zendframework/zend-http": "*",
|
||||
"jbroadway/urlify": "^1.0",
|
||||
"nqxcode/zendsearch": "^2.0",
|
||||
"xj/yii2-jplayer-widget": "*",
|
||||
"zendframework/zend-ldap": "^2.5",
|
||||
"zhuravljov/yii2-queue": "^0.11",
|
||||
"bower-asset/jquery-timeago": "1.4.*",
|
||||
"bower-asset/jquery-timeago": "1.5.*",
|
||||
"bower-asset/jquery-nicescroll": "3.6.*",
|
||||
"bower-asset/jquery-knob": "1.2.*",
|
||||
"bower-asset/jquery-placeholder": "^2.3.0",
|
||||
"bower-asset/blueimp-file-upload": "9.11.*",
|
||||
"bower-asset/blueimp-file-upload": "9.18.*",
|
||||
"bower-asset/fontawesome": "^4.7.0",
|
||||
"bower-asset/bootstrap-markdown": "2.10.*",
|
||||
"bower-asset/select2": "^4.0.2",
|
||||
"bower-asset/select2": "^4.0.4",
|
||||
"bower-asset/bluebird": "^3.3.5",
|
||||
"bower-asset/select2-bootstrap-theme": "0.1.0-beta.4",
|
||||
"bower-asset/jquery.cookie": "^1.4.1",
|
||||
"bower-asset/jquery-color": "^2.1.2",
|
||||
"bower-asset/autosize": "1.*",
|
||||
"bower-asset/nprogress": "*",
|
||||
"bower-asset/At.js": "^1.5.1",
|
||||
"bower-asset/animate.css": "*",
|
||||
"bower-asset/html5shiv": "^3.7",
|
||||
"bower-asset/clipboard.js": "*",
|
||||
"bower-asset/jPlayer": "2.9.2",
|
||||
"bower-asset/jPlayer": "2.9.*",
|
||||
"bower-asset/imagesloaded": "*",
|
||||
"bower-asset/jquery-timeentry": "^2.0"
|
||||
"bower-asset/jquery-timeentry": "^2.0",
|
||||
"bower-asset/caret.js": "0.2.2",
|
||||
"npm-asset/at.js": "^1.5.1",
|
||||
"yiisoft/yii2-queue": "^2.0",
|
||||
"yiisoft/yii2-redis": "^2.0",
|
||||
"firebase/php-jwt": "^5.0",
|
||||
"npm-asset/socket.io-client": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeception/codeception": "*",
|
||||
@ -61,20 +64,18 @@
|
||||
"yiisoft/yii2-faker": "~2.0.0",
|
||||
"yiisoft/yii2-apidoc": "~2.0.0"
|
||||
},
|
||||
"config": {
|
||||
"process-timeout": 1800,
|
||||
"vendor-dir": "protected/vendor",
|
||||
"fxp-asset":{
|
||||
"installer-paths": {
|
||||
"npm-asset-library": "protected/vendor/npm",
|
||||
"bower-asset-library": "protected/vendor/bower"
|
||||
},
|
||||
"vcs-driver-options": {
|
||||
"github-no-api": true
|
||||
},
|
||||
"git-skip-update": "2 days",
|
||||
"pattern-skip-version": "(-build|-patch)"
|
||||
"repositories": [
|
||||
{
|
||||
"type": "composer",
|
||||
"url": "https://asset-packagist.org"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
"php": "5.6"
|
||||
},
|
||||
"process-timeout": 1800,
|
||||
"vendor-dir": "protected/vendor"
|
||||
},
|
||||
"scripts": {
|
||||
"post-create-project-cmd": [
|
||||
@ -94,10 +95,6 @@
|
||||
"generateCookieValidationKey": [
|
||||
"protected/config/web.php"
|
||||
]
|
||||
},
|
||||
"asset-installer-paths": {
|
||||
"npm-asset-library": "protected/vendor/npm",
|
||||
"bower-asset-library": "protected/vendor/bower"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6605
composer.lock
generated
Normal file
6605
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
protected/config/.gitignore
vendored
3
protected/config/.gitignore
vendored
@ -1 +1,4 @@
|
||||
/dynamic.php
|
||||
/common.php
|
||||
/console.php
|
||||
/web.php
|
||||
|
@ -1,4 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file provides to overwrite the default HumHub / Yii configuration by your local common (Console and Web) environments
|
||||
* @see http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html
|
||||
* @see http://docs.humhub.org/admin-installation-configuration.html
|
||||
* @see http://docs.humhub.org/dev-environment.html
|
||||
*/
|
||||
return [
|
||||
];
|
||||
|
@ -1,4 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file provides to overwrite the default HumHub / Yii configuration by your local Console environments
|
||||
* @see http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html
|
||||
* @see http://docs.humhub.org/admin-installation-configuration.html
|
||||
* @see http://docs.humhub.org/dev-environment.html
|
||||
*/
|
||||
return [
|
||||
];
|
||||
|
@ -1,5 +1,10 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file provides to overwrite the default HumHub / Yii configuration by your local Web environments
|
||||
* @see http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html
|
||||
* @see http://docs.humhub.org/admin-installation-configuration.html
|
||||
* @see http://docs.humhub.org/dev-environment.html
|
||||
*/
|
||||
return [
|
||||
];
|
||||
|
||||
|
@ -94,6 +94,7 @@ class AppAsset extends AssetBundle
|
||||
'humhub\assets\PagedownConverterAsset',
|
||||
'humhub\assets\ClipboardJsAsset',
|
||||
'humhub\assets\ImagesLoadedAsset',
|
||||
'humhub\assets\SocketIoAsset',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,7 @@ class AtJsAsset extends AssetBundle
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $sourcePath = '@bower/At.js';
|
||||
public $sourcePath = '@npm/at.js';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
|
32
protected/humhub/assets/SocketIoAsset.php
Normal file
32
protected/humhub/assets/SocketIoAsset.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\assets;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
/**
|
||||
* Socket.IO client files
|
||||
*
|
||||
* @since 1.3
|
||||
* @author luke
|
||||
*/
|
||||
class SocketIoAsset extends AssetBundle
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $sourcePath = '@npm/socket.io-client';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $js = ['dist/socket.io.slim.js'];
|
||||
|
||||
}
|
@ -8,10 +8,12 @@
|
||||
|
||||
namespace humhub\components;
|
||||
|
||||
use humhub\modules\file\libs\FileHelper;
|
||||
use humhub\modules\notification\components\BaseNotification;
|
||||
use Yii;
|
||||
use yii\helpers\Json;
|
||||
use humhub\models\Setting;
|
||||
use humhub\modules\file\libs\FileHelper;
|
||||
use humhub\modules\notification\components\BaseNotification;
|
||||
use humhub\modules\content\models\ContentContainerSetting;
|
||||
|
||||
/**
|
||||
* Base Class for Modules / Extensions
|
||||
@ -248,22 +250,9 @@ class Module extends \yii\base\Module
|
||||
}
|
||||
}
|
||||
|
||||
foreach (\humhub\modules\content\models\ContentContainerSetting::findAll(['module_id' => $this->id]) as $containerSetting) {
|
||||
$containerSetting->delete();
|
||||
}
|
||||
|
||||
foreach (\humhub\models\Setting::findAll(['module_id' => $this->id]) as $containerSetting) {
|
||||
$containerSetting->delete();
|
||||
}
|
||||
|
||||
foreach (\humhub\modules\user\models\Module::findAll(['module_id' => $this->id]) as $userModule) {
|
||||
$userModule->delete();
|
||||
}
|
||||
|
||||
foreach (\humhub\modules\space\models\Module::findAll(['module_id' => $this->id]) as $spaceModule) {
|
||||
$spaceModule->delete();
|
||||
}
|
||||
|
||||
ContentContainerSetting::deleteAll(['module_id' => $this->id]);
|
||||
Setting::deleteAll(['module_id' => $this->id]);
|
||||
|
||||
Yii::$app->moduleManager->disable($this);
|
||||
}
|
||||
|
||||
@ -347,7 +336,7 @@ class Module extends \yii\base\Module
|
||||
if (is_dir($notificationDirectory)) {
|
||||
foreach (FileHelper::findFiles($notificationDirectory, ['recursive' => false,]) as $file) {
|
||||
$notificationClass = $notificationNamespace . '\\' . basename($file, '.php');
|
||||
if(is_subclass_of($notificationClass, BaseNotification::class)) {
|
||||
if (is_subclass_of($notificationClass, BaseNotification::class)) {
|
||||
$notifications[] = $notificationClass;
|
||||
}
|
||||
}
|
||||
|
42
protected/humhub/components/UrlManager.php
Normal file
42
protected/humhub/components/UrlManager.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\components;
|
||||
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
|
||||
/**
|
||||
* UrlManager
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
class UrlManager extends \yii\web\UrlManager
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function createUrl($params)
|
||||
{
|
||||
$params = (array) $params;
|
||||
|
||||
if (isset($params['contentContainer']) && $params['contentContainer'] instanceof ContentContainerActiveRecord) {
|
||||
$params['cguid'] = $params['contentContainer']->contentContainerRecord->guid;
|
||||
unset($params['contentContainer']);
|
||||
}
|
||||
|
||||
if (isset($params['container']) && $params['container'] instanceof ContentContainerActiveRecord) {
|
||||
$params['cguid'] = $params['container']->contentContainerRecord->guid;
|
||||
unset($params['container']);
|
||||
}
|
||||
|
||||
return parent::createUrl($params);
|
||||
}
|
||||
|
||||
}
|
@ -9,18 +9,16 @@
|
||||
namespace humhub\components\queue;
|
||||
|
||||
use yii\base\Object;
|
||||
use zhuravljov\yii\queue\Job;
|
||||
|
||||
/**
|
||||
* ActiveJob
|
||||
*
|
||||
*
|
||||
* @see \humhub\modules\queue\ActiveJob
|
||||
* @deprecated since version 1.3
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
abstract class ActiveJob extends Object implements Job
|
||||
abstract class ActiveJob extends \humhub\modules\queue\ActiveJob
|
||||
{
|
||||
/**
|
||||
* Runs this job
|
||||
*/
|
||||
abstract public function run();
|
||||
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\components\queue\driver;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Event;
|
||||
use zhuravljov\yii\queue\ErrorEvent;
|
||||
use zhuravljov\yii\queue\Queue;
|
||||
|
||||
/**
|
||||
* Instant queue driver, mainly used for testing purposes
|
||||
*
|
||||
* @since 1.2
|
||||
* @author buddha
|
||||
*/
|
||||
class Instant extends Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
Event::on(Queue::class, Queue::EVENT_AFTER_ERROR, function(ErrorEvent $errorEvent) {
|
||||
/* @var $exception \Expection */
|
||||
$exception = $errorEvent->error;
|
||||
Yii::error('Could not execute queued job! Message: ' . $exception->getMessage() . ' Trace:' . $exception->getTraceAsString(), 'queue');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function sendMessage($message, $timeout)
|
||||
{
|
||||
$this->handleMessage($message);
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\components\queue\driver;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Event;
|
||||
use zhuravljov\yii\queue\ErrorEvent;
|
||||
use zhuravljov\yii\queue\db\Queue;
|
||||
|
||||
/**
|
||||
* MySQL queue driver
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
class MySQL extends Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $mutex = 'yii\mutex\MysqlMutex';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
Event::on(Queue::class, Queue::EVENT_AFTER_ERROR, function(ErrorEvent $errorEvent) {
|
||||
/* @var $exception \Expection */
|
||||
$exception = $errorEvent->error;
|
||||
Yii::error('Could not execute queued job! Message: ' . $exception->getMessage() . ' Trace:' . $exception->getTraceAsString(), 'queue');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\components\queue\driver;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Event;
|
||||
use yii\base\Application;
|
||||
use yii\base\NotSupportedException;
|
||||
use zhuravljov\yii\queue\ErrorEvent;
|
||||
use zhuravljov\yii\queue\Queue;
|
||||
|
||||
/**
|
||||
* Sync queue driver
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
class Sync extends Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
public $handle = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $messages = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
|
||||
parent::init();
|
||||
|
||||
if ($this->handle) {
|
||||
Yii::$app->on(Application::EVENT_AFTER_REQUEST, function () {
|
||||
ob_start();
|
||||
$this->run();
|
||||
|
||||
// Important, breaks downloads
|
||||
ob_end_clean();
|
||||
});
|
||||
}
|
||||
|
||||
Event::on(Queue::class, Queue::EVENT_AFTER_ERROR, function(ErrorEvent $errorEvent) {
|
||||
/* @var $exception \Expection */
|
||||
$exception = $errorEvent->error;
|
||||
Yii::error('Could not execute queued job! Message: ' . $exception->getMessage() . ' Trace:' . $exception->getTraceAsString(), 'queue');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all jobs from queue.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
while (($message = array_shift($this->messages)) !== null) {
|
||||
$this->handleMessage($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function sendMessage($message, $timeout)
|
||||
{
|
||||
if ($timeout) {
|
||||
throw new NotSupportedException('Delayed work is not supported in the driver.');
|
||||
}
|
||||
|
||||
$this->messages[] = $message;
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,10 @@ $config = [
|
||||
'basePath' => dirname(__DIR__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR,
|
||||
'bootstrap' => ['log', 'humhub\components\bootstrap\ModuleAutoLoader', 'queue'],
|
||||
'sourceLanguage' => 'en',
|
||||
'aliases' => [
|
||||
'@bower' => '@vendor/bower-asset',
|
||||
'@npm' => '@vendor/npm-asset',
|
||||
],
|
||||
'components' => [
|
||||
'moduleManager' => [
|
||||
'class' => '\humhub\components\ModuleManager'
|
||||
@ -120,7 +124,7 @@ $config = [
|
||||
'dsn' => 'mysql:host=localhost;dbname=humhub',
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'charset' => 'utf8',
|
||||
'charset' => 'utf8mb4',
|
||||
'enableSchemaCache' => true,
|
||||
'on afterOpen' => ['humhub\libs\Helpers', 'SqlMode'],
|
||||
],
|
||||
@ -129,12 +133,15 @@ $config = [
|
||||
'clients' => [],
|
||||
],
|
||||
'queue' => [
|
||||
'class' => 'humhub\components\queue\driver\Sync',
|
||||
'class' => 'humhub\modules\queue\driver\Sync',
|
||||
],
|
||||
'urlManager' => [
|
||||
'class' => 'humhub\components\UrlManager',
|
||||
],
|
||||
'live' => [
|
||||
'class' => 'humhub\modules\live\components\Sender',
|
||||
'driver' => [
|
||||
'class' => 'humhub\modules\live\driver\Database',
|
||||
'class' => 'humhub\modules\live\driver\Poll',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
@ -27,11 +27,10 @@ $config = [
|
||||
'loginUrl' => ['/user/auth/login']
|
||||
],
|
||||
'errorHandler' => [
|
||||
'errorAction' => 'error/index',
|
||||
'errorAction' => '/error/index',
|
||||
],
|
||||
'session' => [
|
||||
'class' => 'humhub\modules\user\components\Session',
|
||||
'sessionTable' => 'user_http_session',
|
||||
],
|
||||
],
|
||||
'modules' => [],
|
||||
|
25
protected/humhub/docs/CHANGELOG_DEV.md
Normal file
25
protected/humhub/docs/CHANGELOG_DEV.md
Normal file
@ -0,0 +1,25 @@
|
||||
HumHub Change Log - v1.3-dev Branch
|
||||
===================================
|
||||
|
||||
1.3.0-beta.1 (Not released yet)
|
||||
--------------------------------
|
||||
|
||||
- Enh: Added file search indexing
|
||||
- Enh: Updated composer.json (acs-ferreira)
|
||||
- Chg: Switched from Composer FXP plugin to Asset Packagist repository
|
||||
- Enh: Committed composer.lock
|
||||
- Enh: Refactored ContentContainer Controller
|
||||
- Chg: Added ContentContainer ModuleManager, instead of individual handling (Space/User)
|
||||
- Fix: Rebind LDAP connection after successful login with administrative user
|
||||
- Enh: Make utf8_mb4 as default database charset
|
||||
- Enh: Moved queueing into own submodule and updated to yii2/queue extension
|
||||
- Enh: Added user soft deletion without contributions
|
||||
- Enh: Moved user deletion into asynchronous tasks
|
||||
- Enh: Improved user grid view design (Administration, User Approval, Space Members)
|
||||
- Enh: Moved SyncUsers (LDAP) and session table cleanup handling into ActiveJob
|
||||
- Enh: Added Push live module driver using Redis and Node.JS
|
||||
- Enh: Added tooltip option to space Image widget.
|
||||
- Enh: Added option ContentContainerController to restrict container type
|
||||
- Enh: Ensure valid permalinks when URL rewriting is enabled
|
||||
|
||||
|
@ -22,6 +22,9 @@ Administration Topics
|
||||
* [Backup HumHub](backup.md)
|
||||
* [Performance Tuning](performance.md)
|
||||
* [Custom Configurations](advanced-configuration.md)
|
||||
* [Redis Integration](redis.md)
|
||||
* [Asynchronous Task Processing](asynchronous-tasks.md)
|
||||
* [Push Updates](push-updates.md)
|
||||
* [Authentication and LDAP](authentication.md)
|
||||
* [Search System](search.md)
|
||||
* [Translations](translations.md)
|
||||
|
@ -6,10 +6,10 @@ You can overwrite the default HumHub / Yii configuration in the folder `/protect
|
||||
File Overview
|
||||
-------------
|
||||
|
||||
- **common.php** - Configuration used in Console & Web Application
|
||||
- **web.php** - Configuration used in Web Application only
|
||||
- **console.log** - Configuration used in Console Application only
|
||||
- **dynamic.php** - Dynamic generated configuration - do not edit manually!
|
||||
- **common.php** - Configuration used for the Console and the Web Application
|
||||
- **web.php** - Configuration used for the Web Application only
|
||||
- **console.log** - Configuration used for the Console Application only
|
||||
- **dynamic.php** - Dynamically generated configuration - do not edit manually!
|
||||
|
||||
|
||||
|
||||
@ -37,7 +37,10 @@ Configuration file loading order
|
||||
|
||||
# Application Params
|
||||
|
||||
Some application behaviours can be configured, by changing application parameters within your `common.php`, `web.php` or `console.php`:
|
||||
Some application behaviour can be configured by changing the application parameters within your `common.php`, `web.php` or `console.php`:
|
||||
|
||||
|
||||
The following configuration block will disable pjax support on your site for example:
|
||||
|
||||
```
|
||||
return [
|
||||
@ -47,7 +50,6 @@ return [
|
||||
];
|
||||
```
|
||||
|
||||
Thre previous configuration will disable pjax support on your site.
|
||||
|
||||
Available params:
|
||||
|
||||
@ -59,7 +61,7 @@ Available params:
|
||||
|
||||
Your tracking code can be managed under `Administration -> Settings -> Advanced -> Statistics`.
|
||||
|
||||
In order to send the tracking code in case of pjax page loads as well as full page loads, you have to add the following to your statistics code by the example of google analytics:
|
||||
In order to send the tracking code in case that both, the pjax as well as the full page loads, you have to add the following to your statistics code (refers to Google Analytics):
|
||||
|
||||
|
||||
```javascript
|
||||
|
116
protected/humhub/docs/guide/admin/asynchronous-tasks.md
Normal file
116
protected/humhub/docs/guide/admin/asynchronous-tasks.md
Normal file
@ -0,0 +1,116 @@
|
||||
Asynchronous Task Processing
|
||||
============================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
To provide a fast and responive user experience, extensive processes are handeld activly by background processes instead being directly executed on request.
|
||||
|
||||
Some examples for such background processes are:
|
||||
|
||||
- Notifications (informing the users via e-ails or mobile push notifications)
|
||||
- Search index rebuilds
|
||||
- File indexing
|
||||
|
||||
|
||||
Queue Driver
|
||||
------------
|
||||
|
||||
### Sychronous Driver
|
||||
|
||||
By default this driver is used to immediately execute asychronous tasks.
|
||||
It doesn't require any Worker configuration below.
|
||||
|
||||
We recommend to switch to the MySQL or Redis driver on production environments.
|
||||
|
||||
### MySQL Database Driver
|
||||
|
||||
If you don't have Redis or any other supported queuing software (RabbitMQ, Beanstalk or Gearman) running, this is the recommended driver.
|
||||
To enable this driver you need to add following block to your local configuration file (protected/config/common.php):
|
||||
|
||||
```
|
||||
// ...
|
||||
'components' => [
|
||||
// ...
|
||||
|
||||
'queue' => [
|
||||
'class' => 'humhub\components\queue\driver\MySQL',
|
||||
],
|
||||
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
|
||||
```
|
||||
|
||||
> Note: You'll need to configure Workers (see description below).
|
||||
|
||||
### Redis
|
||||
|
||||
If you're already using Redis (e.g. for caching or push) we recommend this queue driver.
|
||||
Please make sure you already configured Redis as described here: [Redis Configuration](redis.md).
|
||||
|
||||
|
||||
To enable this driver you need to add following block to your local configuration file (protected/config/common.php):
|
||||
|
||||
```
|
||||
// ...
|
||||
'components' => [
|
||||
// ...
|
||||
|
||||
'queue' => [
|
||||
'class' => 'humhub\components\queue\driver\Redis',
|
||||
],
|
||||
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
|
||||
```
|
||||
|
||||
> Note: You'll need to configure Workers (see description below).
|
||||
|
||||
|
||||
Workers
|
||||
------
|
||||
|
||||
### Cronjob
|
||||
|
||||
You can start workers using cron by executing the queue/run command. It works as long as the queues contain jobs.
|
||||
|
||||
CronTab Example:
|
||||
|
||||
```
|
||||
* * * * * /usr/bin/php <INSERT HUMHUB PATH HERE>/yii queue/run
|
||||
```
|
||||
|
||||
In this case the cron will start the command every minute and execute schedulded tasks.
|
||||
|
||||
|
||||
### Daemon
|
||||
|
||||
You can start a worker deamon using following command:
|
||||
|
||||
```
|
||||
cd protected
|
||||
php yii queue/listen
|
||||
```
|
||||
|
||||
***Using Supervisor (recommended)***
|
||||
|
||||
Supervisor is a process monitoring tool for Linux. It automatically starts, monitors and restarts your workers if they crash.
|
||||
|
||||
Example configuration (e.g. /etc/supervisor/conf.d/humhub.conf):
|
||||
|
||||
```conf
|
||||
[program:humhub-workers]
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
command=/usr/bin/php <INSERT HUMHUB PATH HERE>/protected/yii queue/listen --verbose=1 --color=0
|
||||
autostart=true
|
||||
autorestart=true
|
||||
user=www-data
|
||||
numprocs=4
|
||||
redirect_stderr=true
|
||||
stdout_logfile=<INSERT HUMHUB PATH HERE>/protected/runtime/logs/yii-queue-worker.log
|
||||
```
|
||||
|
64
protected/humhub/docs/guide/admin/push-updates.md
Normal file
64
protected/humhub/docs/guide/admin/push-updates.md
Normal file
@ -0,0 +1,64 @@
|
||||
Push Updates / Push Service
|
||||
===========================
|
||||
|
||||
The PushService directly sends updates (e.g. new notifications) to the users using WebSockets or Long Polling techniques.
|
||||
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The PushService requires following additional installed software:
|
||||
|
||||
- NodeJS
|
||||
- Redis
|
||||
|
||||
|
||||
PushService Installation
|
||||
------------------------
|
||||
|
||||
You can install the HumHub PushService as NPM Package by entering following command:
|
||||
|
||||
```
|
||||
npm install humhub-pushservice
|
||||
```
|
||||
|
||||
Once the installation is finished, you need to create a configuration file:
|
||||
|
||||
```
|
||||
cp config.json.dist config.json
|
||||
```
|
||||
|
||||
Modify the config.json file and adjust the available settings.
|
||||
|
||||
|
||||
Now you can start the PushService using following command:
|
||||
|
||||
```
|
||||
node pushService.js
|
||||
```
|
||||
|
||||
|
||||
HumHub - Configuration
|
||||
----------------------
|
||||
|
||||
Once the PushService NodeJS application is up and running you need to add following
|
||||
configuration options to the HumHub file (protected/config/common.php):
|
||||
|
||||
```
|
||||
// ...
|
||||
'components' => [
|
||||
// ...
|
||||
|
||||
'live' => [
|
||||
'driver' => [
|
||||
'class' => \humhub\modules\live\driver\Push::class,
|
||||
'pushServiceUrl' => 'http://example.com:3000/',
|
||||
'jwtKey' => '---EnteraSuperSecretKeyToSignAuthorizationHere---'
|
||||
]
|
||||
],
|
||||
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
|
||||
```
|
47
protected/humhub/docs/guide/admin/redis.md
Normal file
47
protected/humhub/docs/guide/admin/redis.md
Normal file
@ -0,0 +1,47 @@
|
||||
Redis
|
||||
=====
|
||||
|
||||
We recommend installing an additional Redis server which can act as a caching, push service and job queuing service for HumHub.
|
||||
|
||||
|
||||
Basic Configuration
|
||||
------------------
|
||||
|
||||
To enable Redis, you have to add following block to your local configuration file (protected/config/common.php):
|
||||
|
||||
```
|
||||
// ...
|
||||
'components' => [
|
||||
// ...
|
||||
|
||||
'redis' => [
|
||||
'class' => 'yii\redis\Connection',
|
||||
'hostname' => 'localhost',
|
||||
'port' => 6379,
|
||||
'database' => 0,
|
||||
],
|
||||
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
|
||||
```
|
||||
|
||||
Caching
|
||||
-------
|
||||
|
||||
Once Redis is configured, you can also select it as a caching service: Administration -> Settings -> Advanced -> Caching.
|
||||
|
||||
|
||||
Queuing of Asychronous Tasks
|
||||
----------------------------
|
||||
|
||||
See [Asychronous Tasks](asychornous-tasks.md) for further information.
|
||||
|
||||
|
||||
Push Updates
|
||||
------------
|
||||
|
||||
See [Push Updates](push-updates.md) for further information.
|
||||
|
||||
|
@ -24,6 +24,49 @@ or by means of [grunt](../developer/core-build.md):
|
||||
grunt build-search
|
||||
```
|
||||
|
||||
|
||||
File Indexing
|
||||
-------------
|
||||
|
||||
If you like to also index contents of a file (e.g. PDF documents) you need to specify additional parsers.
|
||||
|
||||
These parsers are defined in the [configuration file](advanced-configuration.md).
|
||||
|
||||
Parsers:
|
||||
- Apache Tika (https://tika.apache.org/)
|
||||
- Poppler PDF Utils (https://poppler.freedesktop.org/)
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
return [
|
||||
// ...
|
||||
'modules' => [
|
||||
// ...
|
||||
'file' => [
|
||||
'converterOptions' => [
|
||||
'humhub\modules\file\converter\TextConverter' => [
|
||||
'converter' => [
|
||||
[
|
||||
'cmd' => '/usr/bin/pdftotext -q -enc UTF-8 {fileName} {outputFileName}',
|
||||
'only' => ['pdf']
|
||||
],
|
||||
[
|
||||
'cmd' => '/usr/bin/java -jar /opt/tika-app-1.16.jar --text {fileName} 2>/dev/null',
|
||||
'except' => ['image/']
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
];
|
||||
```
|
||||
|
||||
|
||||
Zend Lucence Engine
|
||||
--------------------
|
||||
|
||||
@ -34,12 +77,11 @@ Default database folder: `/protected/runtime/searchdb/`
|
||||
You can modify the default search directory in the [configuration](advanced-configuration.md):
|
||||
|
||||
```php
|
||||
return [
|
||||
// ...
|
||||
'params' => [
|
||||
'search' => [
|
||||
'zendLucenceDataDir' => '/some/other/path',
|
||||
]
|
||||
return [
|
||||
// ...
|
||||
'params' => [
|
||||
'search' => [
|
||||
'zendLucenceDataDir' => '/some/other/path',
|
||||
]
|
||||
// ...
|
||||
];
|
||||
|
@ -5,7 +5,7 @@ Disable Errors / Debugging
|
||||
--------------------------
|
||||
|
||||
- Modify *index.php* in your humhub root directory
|
||||
|
||||
|
||||
```php
|
||||
[...]
|
||||
// comment out the following two lines when deployed to production
|
||||
@ -16,19 +16,21 @@ Disable Errors / Debugging
|
||||
|
||||
- Delete *index-test.php* in your humhub root directory if exists
|
||||
|
||||
|
||||
Protected Directories
|
||||
---------------------
|
||||
|
||||
Make sure the following directories are not accessible by web:
|
||||
Make sure following directories are not accessible by web:
|
||||
- protected
|
||||
- uploads/file
|
||||
|
||||
By default these folders are protected with a ".htaccess" file.
|
||||
|
||||
|
||||
Limit User Access
|
||||
-----------------
|
||||
|
||||
If you're running a private social network, make sure the user registration has been disabled or the approval system for new users has been enabled.
|
||||
If you're running a private social network, make sure the user registration is disabled or the approval system for new users is enabled.
|
||||
|
||||
- Disable user registration: `Administration -> Users -> Settings -> Anonymous users can register`
|
||||
- Enable user approvals: `Administration -> Users -> Settings -> Require group admin approval after registration`
|
||||
@ -37,6 +39,9 @@ If you're running a private social network, make sure the user registration has
|
||||
Keep up with the latest HumHub version
|
||||
---------------------------------------
|
||||
|
||||
As an admin you'll receive a notification when a new HumHub version has been released. We strongly recommend to always use the latest stable version when possible.
|
||||
As admin you'll receive a notification when a new HumHub version is released. We recommend to always use the latest stable version.
|
||||
|
||||
We take security very seriously and continuously improving the security features of HumHub.
|
||||
|
||||
|
||||
|
||||
We take security very seriously, and we're continuously improving the security features of HumHub.
|
||||
|
@ -13,10 +13,12 @@ Module Development
|
||||
* [Introduction](modules-index.md)
|
||||
* [Basic Structure](modules-structure.md)
|
||||
* [Migration/Updates](modules-migrate.md)
|
||||
* [Content](content.md)
|
||||
* [Content](modules-content.md)
|
||||
* [Users](modules-users.md)
|
||||
* [Events](modules-events.md)
|
||||
* [Settings and Configuration](modules-settings.md)
|
||||
* [Models / Database](modules-db.md)
|
||||
* [Models / Database](modules-db.md)
|
||||
* [Internationalization](modules-i18n.md)
|
||||
|
||||
Javascript API
|
||||
|
@ -32,8 +32,7 @@ git clone https://github.com/humhub/humhub.git
|
||||
3. Navigate to your HumHub webroot and fetch dependencies:
|
||||
|
||||
```
|
||||
php composer.phar global require "fxp/composer-asset-plugin:^1.4.2"
|
||||
php composer.phar update
|
||||
php composer.phar install
|
||||
```
|
||||
|
||||
> Note: The composer update may have to be executed again after an update of your local repository by a git pull. Read more about updating ([Update Guide](admin-updating.html#gitcomposer-based-installations))
|
||||
|
@ -1,5 +1,5 @@
|
||||
Content
|
||||
=======
|
||||
Users
|
||||
=====
|
||||
|
||||
## ContentContainer
|
||||
|
@ -1,8 +1,31 @@
|
||||
# Module Migration Guide
|
||||
Module Migration Guide
|
||||
======================
|
||||
|
||||
Here you will learn how you can adapt existing modules to working fine with actually versions.
|
||||
|
||||
## Migrate from 1.1 to 1.2
|
||||
Migrate from 1.2 to 1.3
|
||||
-----------------------
|
||||
|
||||
### ContentContainer Controller
|
||||
|
||||
The base controller attributes `autoCheckContainerAccess` and `hideSidebar` are not longer available.
|
||||
|
||||
### Removed Deprecated
|
||||
|
||||
- formatterApp Application Component (Yii::$app->formatterApp)
|
||||
|
||||
### Queuing
|
||||
|
||||
The queuing is now moved into an own module `humhub\modues\queue`.
|
||||
The existing `humhub\components\queue\ActiveJob` is declared as deprecated and will be removed in 1.4.
|
||||
|
||||
### Partial user deletion (Soft Delete)
|
||||
|
||||
Added new user status (User::SOFT_DELETED). You can find more information here: [Users](modules-users.md)
|
||||
|
||||
|
||||
Migrate from 1.1 to 1.2
|
||||
-----------------------
|
||||
|
||||
### Stream / Content Changes
|
||||
|
||||
@ -53,7 +76,8 @@ within your controller for pjax topmenu support.
|
||||
TBD
|
||||
|
||||
|
||||
## Migrate from 1.0 to 1.1
|
||||
Migrate from 1.0 to 1.1
|
||||
-----------------------
|
||||
|
||||
- Dropped unused space attribute "website"
|
||||
|
||||
@ -77,9 +101,11 @@ TBD
|
||||
|
||||
- New administration menu structure
|
||||
|
||||
## Migrate from 0.20 to 1.0
|
||||
|
||||
|
||||
Migrate from 0.20 to 1.0
|
||||
------------------------
|
||||
|
||||
## Migrate from 0.12 to 0.20
|
||||
|
||||
**Important: This release upgrades from Yii1 to Yii2 Framework!**
|
||||
@ -87,12 +113,17 @@ TBD
|
||||
This requires an extensive migration of all custom modules/themes.
|
||||
Find more details here: [HumHub 0.20 Migration](modules-migrate-0.20.md)
|
||||
|
||||
## Migrate from 0.11 to 0.12
|
||||
|
||||
|
||||
Migrate from 0.11 to 0.12
|
||||
-------------------------
|
||||
|
||||
- Rewritten Search
|
||||
|
||||
## Migrate from 0.10 to 0.11
|
||||
|
||||
|
||||
Migrate from 0.10 to 0.11
|
||||
-------------------------
|
||||
No breaking changes.
|
||||
|
||||
- Now handle ContentContainerController layouts, new option showSidebar
|
||||
|
76
protected/humhub/docs/guide/developer/modules-users.md
Normal file
76
protected/humhub/docs/guide/developer/modules-users.md
Normal file
@ -0,0 +1,76 @@
|
||||
Users
|
||||
=====
|
||||
|
||||
Deleting Users
|
||||
---------------------
|
||||
|
||||
Users can either be deleted with all their contributions (hard delete) or without, means only their personal/profile data will be deleted (soft delete)
|
||||
|
||||
### Soft delete
|
||||
|
||||
A common use cases for the soft delete option is:
|
||||
|
||||
- Delete participation statuses (e.g. task assignments)
|
||||
- Delete personal information and images
|
||||
|
||||
You can manage the soft delete option by intercepting the event [[\humhub\modules\user\models\User::EVENT_BEFORE_SOFT_DELETE]].
|
||||
|
||||
Example 'config.php':
|
||||
|
||||
```php
|
||||
<?php
|
||||
use humhub\modules\user\models\User;
|
||||
// ...
|
||||
return [
|
||||
// ...
|
||||
'events' => [
|
||||
[User::class, User::EVENT_BEFORE_SOFT_DELETE, [Events::class, 'onUserSoftDelete']],
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
];
|
||||
?>
|
||||
```
|
||||
|
||||
Example callback in your modules **Events** class:
|
||||
|
||||
```php
|
||||
public static function onUserSoftDelete(UserEvent $event)
|
||||
{
|
||||
$user = $event->user;
|
||||
MyParticipations::deleteAll(['user_id' => $user->id]);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Hard delete
|
||||
|
||||
The hard delete option will wipe all data in relation with the deleted user.
|
||||
HumHub objects created by the user like comments, files, posts, notification or activities will automatically be removed with the user profile.
|
||||
|
||||
Example 'config.php':
|
||||
|
||||
```php
|
||||
<?php
|
||||
use humhub\modules\user\models\User;
|
||||
// ...
|
||||
return [
|
||||
// ...
|
||||
'events' => [
|
||||
[User::class, User::EVENT_BEFORE_DELETE, [Events::class, 'onUserDelete']],
|
||||
// ...
|
||||
],
|
||||
// ...
|
||||
];
|
||||
?>
|
||||
```
|
||||
|
||||
Example callback in your modules **Events** class:
|
||||
|
||||
```php
|
||||
public static function onUserDelete(Event $event)
|
||||
{
|
||||
$user = $event->sender;
|
||||
MyRecord::deleteAll(['user_id' => $user->id]);
|
||||
}
|
||||
```
|
5
protected/humhub/docs/guide/theme/migrate-1.3.md
Normal file
5
protected/humhub/docs/guide/theme/migrate-1.3.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Theme Migration to HumHub 1.3
|
||||
|
||||
## Space & Profile Layouts
|
||||
|
||||
The sidebars are now moved into own files `_sidebar.php` view files.
|
106
protected/humhub/libs/ActionColumn.php
Normal file
106
protected/humhub/libs/ActionColumn.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\libs;
|
||||
|
||||
use yii\grid\Column;
|
||||
use humhub\libs\Html;
|
||||
|
||||
/**
|
||||
* Description of ActionColumn
|
||||
*
|
||||
* @author Luke
|
||||
*/
|
||||
class ActionColumn extends Column
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string the ID attribute of the model, to generate action URLs.
|
||||
*/
|
||||
public $modelIdAttribute = 'id';
|
||||
|
||||
/**
|
||||
* @var array list of actions (key = title, value = url)
|
||||
*/
|
||||
public $actions = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->options['style'] = 'width:56px';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function renderDataCellContent($model, $key, $index)
|
||||
{
|
||||
|
||||
$actions = $this->getActions($model, $key, $index);
|
||||
|
||||
if (empty($actions)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$html = Html::beginTag('div', ['class' => 'btn-group dropdown-navigation']);
|
||||
$html .= Html::button('<i class="fa fa-cog"></i> <span class="caret"></span>', ['class' => 'btn btn-default dropdown-toggle', 'data-toggle' => 'dropdown']);
|
||||
$html .= Html::beginTag('ul', ['class' => 'dropdown-menu pull-right']);
|
||||
foreach ($actions as $title => $url) {
|
||||
if ($url === '---') {
|
||||
$html .= '<li class="divider"></li>';
|
||||
} else {
|
||||
$linkOptions = null;
|
||||
if (isset($url['linkOptions'])) {
|
||||
$linkOptions = $url['linkOptions'];
|
||||
unset($url['linkOptions']);
|
||||
}
|
||||
|
||||
$html .= Html::beginTag('li');
|
||||
$html .= Html::a($title, $this->handleUrl($url, $model), $linkOptions);
|
||||
$html .= Html::endTag('li');
|
||||
}
|
||||
}
|
||||
$html .= Html::endTag('ul');
|
||||
$html .= Html::endTag('div');
|
||||
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
protected function getActions($model, $key, $index)
|
||||
{
|
||||
if ($this->actions === null) {
|
||||
return [];
|
||||
} elseif (is_callable($this->actions)) {
|
||||
return call_user_func($this->actions, $model, $key, $index, $this);
|
||||
}
|
||||
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the URL for a given Action
|
||||
*
|
||||
* @param array $url
|
||||
* @param \yii\base\Model $model
|
||||
* @return string the url
|
||||
*/
|
||||
protected function handleUrl($url, $model)
|
||||
{
|
||||
if (!isset($url[$this->modelIdAttribute])) {
|
||||
$url[$this->modelIdAttribute] = $model->getAttribute($this->modelIdAttribute);
|
||||
}
|
||||
|
||||
return \yii\helpers\Url::to($url);
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\libs;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Object;
|
||||
use yii\helpers\ArrayHelper;
|
||||
|
||||
/**
|
||||
@ -16,7 +17,7 @@ use yii\helpers\ArrayHelper;
|
||||
*
|
||||
* @author luke
|
||||
*/
|
||||
class DynamicConfig extends \yii\base\Object
|
||||
class DynamicConfig extends Object
|
||||
{
|
||||
|
||||
/**
|
||||
@ -26,7 +27,7 @@ class DynamicConfig extends \yii\base\Object
|
||||
*/
|
||||
public static function merge($new)
|
||||
{
|
||||
$config = \yii\helpers\ArrayHelper::merge(self::load(), $new);
|
||||
$config = ArrayHelper::merge(self::load(), $new);
|
||||
self::save($config);
|
||||
}
|
||||
|
||||
@ -49,7 +50,7 @@ class DynamicConfig extends \yii\base\Object
|
||||
$config = eval($configContent);
|
||||
|
||||
if (!is_array($config))
|
||||
return array();
|
||||
return [];
|
||||
|
||||
return $config;
|
||||
}
|
||||
@ -61,15 +62,14 @@ class DynamicConfig extends \yii\base\Object
|
||||
*/
|
||||
public static function save($config)
|
||||
{
|
||||
$content = "<" . "?php return ";
|
||||
$content = '<' . '?php return ';
|
||||
$content .= var_export($config, true);
|
||||
$content .= "; ?" . ">";
|
||||
$content .= '; ?' . '>';
|
||||
|
||||
$configFile = self::getConfigFilePath();
|
||||
file_put_contents($configFile, $content);
|
||||
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_reset();
|
||||
opcache_invalidate($configFile);
|
||||
}
|
||||
|
||||
@ -91,14 +91,14 @@ class DynamicConfig extends \yii\base\Object
|
||||
|
||||
// Add Default language
|
||||
$defaultLanguage = Yii::$app->settings->get('defaultLanguage');
|
||||
if ($defaultLanguage !== null && $defaultLanguage != "") {
|
||||
if ($defaultLanguage !== null && $defaultLanguage != '') {
|
||||
$config['language'] = Yii::$app->settings->get('defaultLanguage');
|
||||
} else {
|
||||
$config['language'] = Yii::$app->language;
|
||||
}
|
||||
|
||||
$timeZone = Yii::$app->settings->get('timeZone');
|
||||
if ($timeZone != "") {
|
||||
if ($timeZone != '') {
|
||||
$config['timeZone'] = $timeZone;
|
||||
$config['components']['formatter']['defaultTimeZone'] = $timeZone;
|
||||
$config['components']['formatterApp']['defaultTimeZone'] = $timeZone;
|
||||
@ -118,17 +118,22 @@ class DynamicConfig extends \yii\base\Object
|
||||
'keyPrefix' => Yii::$app->id,
|
||||
'useApcu' => (function_exists('apcu_add'))
|
||||
];
|
||||
} elseif ($cacheClass === \yii\redis\Cache::class) {
|
||||
$config['components']['cache'] = [
|
||||
'class' => \yii\redis\Cache::class,
|
||||
'keyPrefix' => Yii::$app->id,
|
||||
];
|
||||
}
|
||||
|
||||
// Add User settings
|
||||
$config['components']['user'] = array();
|
||||
$config['components']['user'] = [];
|
||||
if (Yii::$app->getModule('user')->settings->get('auth.defaultUserIdleTimeoutSec')) {
|
||||
$config['components']['user']['authTimeout'] = Yii::$app->getModule('user')->settings->get('auth.defaultUserIdleTimeoutSec');
|
||||
}
|
||||
|
||||
// Install Mail Component
|
||||
$mail = [];
|
||||
$mail['transport'] = array();
|
||||
$mail['transport'] = [];
|
||||
if (Yii::$app->settings->get('mailer.transportType') == 'smtp') {
|
||||
$mail['transport']['class'] = 'Swift_SmtpTransport';
|
||||
|
||||
|
@ -11,6 +11,8 @@ namespace humhub\libs;
|
||||
use Yii;
|
||||
use yii\base\InvalidParamException;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\space\models\Space;
|
||||
|
||||
/**
|
||||
* HTML Helpers
|
||||
@ -94,9 +96,12 @@ class Html extends \yii\bootstrap\Html
|
||||
*/
|
||||
public static function containerLink(ContentContainerActiveRecord $container, $options = [])
|
||||
{
|
||||
if ($container instanceof \humhub\modules\space\models\Space) {
|
||||
if ($container instanceof Space) {
|
||||
return static::a(static::encode($container->name), $container->getUrl(), $options);
|
||||
} elseif ($container instanceof \humhub\modules\user\models\User) {
|
||||
} elseif ($container instanceof User) {
|
||||
if ($container->status == User::STATUS_SOFT_DELETED) {
|
||||
return static::beginTag('strike') . static::encode($container->displayName) . static::endTag('strike');
|
||||
}
|
||||
return static::a(static::encode($container->displayName), $container->getUrl(), $options);
|
||||
} else {
|
||||
throw new InvalidParamException('Content container type not supported!');
|
||||
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
use yii\db\Migration;
|
||||
|
||||
class m171015_155102_contentcontainer_module extends Migration
|
||||
{
|
||||
|
||||
public function safeUp()
|
||||
{
|
||||
$this->createTable('contentcontainer_module', [
|
||||
'contentcontainer_id' => $this->integer()->notNull(),
|
||||
'module_id' => $this->char(100),
|
||||
'module_state' => $this->smallInteger(),
|
||||
]);
|
||||
$this->addPrimaryKey('pk_contentcontainer_module', 'contentcontainer_module', ['contentcontainer_id', 'module_id']);
|
||||
$this->addForeignKey('fk_contentcontainer', 'contentcontainer_module', 'contentcontainer_id', 'contentcontainer', 'id', 'CASCADE', 'CASCADE');
|
||||
|
||||
$sqlInsert = 'INSERT INTO contentcontainer_module (contentcontainer_id, module_id, module_state) ';
|
||||
$this->db->createCommand($sqlInsert . 'SELECT space.contentcontainer_id, module_id, state FROM space_module LEFT JOIN space ON space_module.space_id=space.id WHERE space.id IS NOT NULL')->execute();
|
||||
$this->db->createCommand($sqlInsert . 'SELECT user.contentcontainer_id, module_id, state FROM user_module LEFT JOIN user ON user_module.user_id=user.id WHERE user.id IS NOT NULL')->execute();
|
||||
|
||||
$rows = (new \yii\db\Query())->select("*")->from('space_module')->where('space_id IS NULL OR space_id=0')->all();
|
||||
foreach ($rows as $row) {
|
||||
$reflect = new ReflectionClass(humhub\modules\space\models\Space::class);
|
||||
$module = Yii::$app->getModule($row['module_id']);
|
||||
$module->settings->set('moduleManager.defaultState.' . $reflect->getShortName(), $row['state']);
|
||||
}
|
||||
|
||||
|
||||
$rows = (new \yii\db\Query())->select("*")->from('user_module')->where('user_id IS NULL OR user_id=0')->all();
|
||||
foreach ($rows as $row) {
|
||||
$reflect = new ReflectionClass(\humhub\modules\user\models\User::class);
|
||||
$module = Yii::$app->getModule($row['module_id']);
|
||||
$module->settings->set('moduleManager.defaultState.' . $reflect->getShortName(), $row['state']);
|
||||
}
|
||||
|
||||
$this->dropTable('user_module');
|
||||
$this->dropTable('space_module');
|
||||
}
|
||||
|
||||
public function safeDown()
|
||||
{
|
||||
echo "m171015_155102_contentcontainer_module cannot be reverted.\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// Use up()/down() to run migration code without a transaction.
|
||||
public function up()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
echo "m171015_155102_contentcontainer_module cannot be reverted.\n";
|
||||
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
namespace humhub\modules\activity\jobs;
|
||||
|
||||
use Yii;
|
||||
use humhub\components\queue\ActiveJob;
|
||||
use humhub\modules\queue\ActiveJob;
|
||||
use humhub\modules\activity\components\MailSummaryProcessor;
|
||||
use humhub\modules\activity\components\MailSummary;
|
||||
|
||||
|
@ -48,6 +48,11 @@ class Module extends \humhub\components\Module
|
||||
*/
|
||||
public $dailyCheckForNewVersion = true;
|
||||
|
||||
/**
|
||||
* @var boolean allow admins to impersonate other users
|
||||
*/
|
||||
public $allowUserImpersonate = true;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
@ -15,6 +15,8 @@ use humhub\modules\admin\libs\OnlineModuleManager;
|
||||
use humhub\modules\content\components\ContentContainerModule;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\admin\models\forms\ModuleSetAsDefaultForm;
|
||||
use humhub\modules\content\components\ContentContainerModuleManager;
|
||||
|
||||
/**
|
||||
* Module Controller controls all third party modules in a humhub installation.
|
||||
@ -300,45 +302,13 @@ class ModuleController extends Controller
|
||||
throw new HttpException(500, 'Invalid module type!');
|
||||
}
|
||||
|
||||
$model = new \humhub\modules\admin\models\forms\ModuleSetAsDefaultForm();
|
||||
|
||||
$spaceDefaultModule = null;
|
||||
if ($module->hasContentContainerType(Space::className())) {
|
||||
$spaceDefaultModule = \humhub\modules\space\models\Module::find()->where(['module_id' => $moduleId])->andWhere(['IS', 'space_id', new \yii\db\Expression('NULL')])->one();
|
||||
if ($spaceDefaultModule === null) {
|
||||
$spaceDefaultModule = new \humhub\modules\space\models\Module();
|
||||
$spaceDefaultModule->module_id = $moduleId;
|
||||
$spaceDefaultModule->state = \humhub\modules\space\models\Module::STATE_DISABLED;
|
||||
}
|
||||
$model->spaceDefaultState = $spaceDefaultModule->state;
|
||||
}
|
||||
|
||||
$userDefaultModule = null;
|
||||
if ($module->hasContentContainerType(User::className())) {
|
||||
$userDefaultModule = \humhub\modules\user\models\Module::find()->where(['module_id' => $moduleId])->andWhere(['IS', 'user_id', new \yii\db\Expression('NULL')])->one();
|
||||
if ($userDefaultModule === null) {
|
||||
$userDefaultModule = new \humhub\modules\user\models\Module();
|
||||
$userDefaultModule->module_id = $moduleId;
|
||||
$userDefaultModule->state = \humhub\modules\user\models\Module::STATE_DISABLED;
|
||||
}
|
||||
$model->userDefaultState = $userDefaultModule->state;
|
||||
}
|
||||
$model = new ModuleSetAsDefaultForm();
|
||||
$model->spaceDefaultState = ContentContainerModuleManager::getDefaultState(Space::class, $moduleId);
|
||||
$model->userDefaultState = ContentContainerModuleManager::getDefaultState(User::class, $moduleId);
|
||||
|
||||
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
|
||||
if ($module->hasContentContainerType(Space::className())) {
|
||||
$spaceDefaultModule->state = $model->spaceDefaultState;
|
||||
if (!$spaceDefaultModule->save()) {
|
||||
throw new HttpException('Could not save: ' . print_r($spaceDefaultModule->getErrors(), 1));
|
||||
}
|
||||
}
|
||||
|
||||
if ($module->hasContentContainerType(User::className())) {
|
||||
$userDefaultModule->state = $model->userDefaultState;
|
||||
if (!$userDefaultModule->save()) {
|
||||
throw new HttpException('Could not save: ' . print_r($userDefaultModule->getErrors(), 1));
|
||||
}
|
||||
}
|
||||
|
||||
ContentContainerModuleManager::setDefaultState(User::class, $moduleId, $model->userDefaultState);
|
||||
ContentContainerModuleManager::setDefaultState(Space::class, $moduleId, $model->spaceDefaultState);
|
||||
return $this->renderModalClose();
|
||||
}
|
||||
|
||||
|
@ -49,10 +49,7 @@ class SpaceController extends Controller
|
||||
public function getAccessRules()
|
||||
{
|
||||
return [
|
||||
['permissions' => [
|
||||
ManageSpaces::className(),
|
||||
ManageSettings::className()
|
||||
]],
|
||||
['permissions' => [ManageSpaces::className(), ManageSettings::className()]],
|
||||
];
|
||||
}
|
||||
|
||||
@ -61,21 +58,42 @@ class SpaceController extends Controller
|
||||
*/
|
||||
public function actionIndex()
|
||||
{
|
||||
if (Yii::$app->user->can(new ManageSpaces())) {
|
||||
$searchModel = new SpaceSearch();
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel
|
||||
]);
|
||||
} else if (Yii::$app->user->can(new ManageSettings())) {
|
||||
return $this->redirect([
|
||||
'settings'
|
||||
]);
|
||||
if (!Yii::$app->user->can(new ManageSpaces())) {
|
||||
return $this->redirect(['settings']);
|
||||
}
|
||||
|
||||
throw new HttpException(403);
|
||||
$searchModel = new SpaceSearch();
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep link into space
|
||||
*/
|
||||
public function actionOpen($id, $section)
|
||||
{
|
||||
$space = Space::findOne(['id' => $id]);
|
||||
if ($space === null) {
|
||||
throw new HttpException(404);
|
||||
}
|
||||
|
||||
if ($section == 'members') {
|
||||
return $this->redirect($space->createUrl('/space/manage/member'));
|
||||
} elseif ($section == 'owner') {
|
||||
return $this->redirect($space->createUrl('/space/manage/member/change-owner'));
|
||||
} elseif ($section == 'edit') {
|
||||
return $this->redirect($space->createUrl('/space/manage'));
|
||||
} elseif ($section == 'modules') {
|
||||
return $this->redirect($space->createUrl('/space/manage/module'));
|
||||
} elseif ($section == 'delete') {
|
||||
return $this->redirect($space->createUrl('/space/manage/default/delete'));
|
||||
} else {
|
||||
return $this->redirect($space->getUrl());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,11 +127,11 @@ class SpaceController extends Controller
|
||||
Content::VISIBILITY_PUBLIC => Yii::t('SpaceModule.base', 'Public')];
|
||||
|
||||
return $this->render('settings', [
|
||||
'model' => $form,
|
||||
'joinPolicyOptions' => $joinPolicyOptions,
|
||||
'visibilityOptions' => $visibilityOptions,
|
||||
'contentVisibilityOptions' => $contentVisibilityOptions
|
||||
]
|
||||
'model' => $form,
|
||||
'joinPolicyOptions' => $joinPolicyOptions,
|
||||
'visibilityOptions' => $visibilityOptions,
|
||||
'contentVisibilityOptions' => $contentVisibilityOptions
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -12,14 +12,16 @@ use Yii;
|
||||
use yii\helpers\Url;
|
||||
use yii\web\HttpException;
|
||||
use humhub\compat\HForm;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\user\models\Invite;
|
||||
use humhub\modules\user\models\forms\Registration;
|
||||
use humhub\modules\admin\components\Controller;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\admin\models\forms\UserEditForm;
|
||||
use humhub\modules\admin\permissions\ManageUsers;
|
||||
use humhub\modules\admin\permissions\ManageGroups;
|
||||
use humhub\modules\admin\permissions\ManageSettings;
|
||||
use humhub\modules\space\models\Membership;
|
||||
use humhub\modules\admin\models\forms\UserDeleteForm;
|
||||
use humhub\modules\admin\models\UserSearch;
|
||||
|
||||
/**
|
||||
* User management
|
||||
@ -34,12 +36,15 @@ class UserController extends Controller
|
||||
*/
|
||||
public $adminOnly = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->appendPageTitle(Yii::t('AdminModule.base', 'Users'));
|
||||
$this->subLayout = '@admin/views/layouts/user';
|
||||
|
||||
return parent::init();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,36 +53,37 @@ class UserController extends Controller
|
||||
public function getAccessRules()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'permissions' => [
|
||||
ManageUsers::class,
|
||||
ManageGroups::class,
|
||||
]
|
||||
],
|
||||
[
|
||||
'permissions' => [ManageSettings::class],
|
||||
'actions' => ['index']
|
||||
]
|
||||
['permissions' => [ManageUsers::class, ManageGroups::class]],
|
||||
['permissions' => [ManageSettings::class], 'actions' => ['index']]
|
||||
];
|
||||
}
|
||||
|
||||
public function actionIndex()
|
||||
{
|
||||
if (Yii::$app->user->can([new ManageUsers(), new ManageGroups()])) {
|
||||
return $this->redirect(['list']);
|
||||
} else if (Yii::$app->user->can(ManageSettings::class)) {
|
||||
return $this->redirect(['/admin/authentication']);
|
||||
} else {
|
||||
return $this->forbidden();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a List of Users
|
||||
*/
|
||||
public function actionIndex()
|
||||
public function actionList()
|
||||
{
|
||||
if (Yii::$app->user->can([new ManageUsers(), new ManageGroups()])) {
|
||||
$searchModel = new \humhub\modules\admin\models\UserSearch();
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
return $this->render('index', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel
|
||||
]);
|
||||
} else if (Yii::$app->user->can(ManageSettings::class)) {
|
||||
$this->redirect(['/admin/authentication']);
|
||||
} else {
|
||||
$this->forbidden();
|
||||
}
|
||||
$searchModel = new UserSearch();
|
||||
$searchModel->status = User::STATUS_ENABLED;
|
||||
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
|
||||
$showPendingRegistrations = (Invite::find()->count() > 0 && Yii::$app->user->can([new ManageUsers(), new ManageGroups()]));
|
||||
|
||||
return $this->render('list', [
|
||||
'dataProvider' => $dataProvider,
|
||||
'searchModel' => $searchModel,
|
||||
'showPendingRegistrations' => $showPendingRegistrations
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,12 +154,6 @@ class UserController extends Controller
|
||||
'label' => Yii::t('AdminModule.controllers_UserController', 'Save'),
|
||||
'class' => 'btn btn-primary',
|
||||
],
|
||||
'become' => [
|
||||
'type' => 'submit',
|
||||
'label' => Yii::t('AdminModule.controllers_UserController', 'Become this user'),
|
||||
'class' => 'btn btn-danger',
|
||||
'isVisible' => $this->canBecomeUser($user)
|
||||
],
|
||||
'delete' => [
|
||||
'type' => 'submit',
|
||||
'label' => Yii::t('AdminModule.controllers_UserController', 'Delete'),
|
||||
@ -172,15 +172,8 @@ class UserController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// This feature is used primary for testing, maybe remove this in future
|
||||
if ($form->submitted('become') && $this->canBecomeUser($user)) {
|
||||
|
||||
Yii::$app->user->switchIdentity($form->models['User']);
|
||||
return $this->redirect(Url::home());
|
||||
}
|
||||
|
||||
if ($form->submitted('delete')) {
|
||||
return $this->redirect(['/admin/user/delete', 'id' => $user->id]);
|
||||
return $this->redirect(['delete', 'id' => $user->id]);
|
||||
}
|
||||
|
||||
return $this->render('edit', [
|
||||
@ -189,11 +182,6 @@ class UserController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function canBecomeUser($user)
|
||||
{
|
||||
return Yii::$app->user->isAdmin() && $user->id != Yii::$app->user->getIdentity()->id;
|
||||
}
|
||||
|
||||
public function actionAdd()
|
||||
{
|
||||
$registration = new Registration();
|
||||
@ -209,33 +197,109 @@ class UserController extends Controller
|
||||
/**
|
||||
* Deletes a user permanently
|
||||
*/
|
||||
public function actionDelete()
|
||||
public function actionDelete($id)
|
||||
{
|
||||
$id = (int) Yii::$app->request->get('id');
|
||||
$doit = (int) Yii::$app->request->get('doit');
|
||||
$user = User::findOne(['id' => $id]);
|
||||
if ($user == null) {
|
||||
throw new HttpException(404, Yii::t('AdminModule.user', 'User not found!'));
|
||||
} elseif (Yii::$app->user->id == $id) {
|
||||
throw new HttpException(400, Yii::t('AdminModule.user', 'You cannot delete yourself!'));
|
||||
}
|
||||
|
||||
$model = new UserDeleteForm(['user' => $user]);
|
||||
if ($model->load(Yii::$app->request->post()) && $model->performDelete()) {
|
||||
$this->view->info(Yii::t('AdminModule.user', 'User deletion process queued.'));
|
||||
return $this->redirect(['list']);
|
||||
}
|
||||
|
||||
return $this->render('delete', ['model' => $model]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to user profile
|
||||
*
|
||||
* @param int $id
|
||||
* @return \yii\base\Response the response
|
||||
* @throws HttpException
|
||||
*/
|
||||
public function actionViewProfile($id)
|
||||
{
|
||||
$user = User::findOne(['id' => $id]);
|
||||
if ($user === null) {
|
||||
throw new HttpException(404);
|
||||
}
|
||||
|
||||
return $this->redirect($user->getUrl());
|
||||
}
|
||||
|
||||
public function actionEnable($id)
|
||||
{
|
||||
$this->forcePostRequest();
|
||||
|
||||
$user = User::findOne(['id' => $id]);
|
||||
|
||||
if ($user == null) {
|
||||
throw new HttpException(404, Yii::t('AdminModule.controllers_UserController', 'User not found!'));
|
||||
} elseif (Yii::$app->user->id == $id) {
|
||||
throw new HttpException(400, Yii::t('AdminModule.controllers_UserController', 'You cannot delete yourself!'));
|
||||
if ($user === null) {
|
||||
throw new HttpException(404);
|
||||
}
|
||||
|
||||
if ($doit == 2) {
|
||||
$this->forcePostRequest();
|
||||
$user->status = User::STATUS_ENABLED;
|
||||
$user->save();
|
||||
|
||||
foreach (Membership::GetUserSpaces($user->id) as $space) {
|
||||
if ($space->isSpaceOwner($user->id)) {
|
||||
$space->addMember(Yii::$app->user->id);
|
||||
$space->setSpaceOwner(Yii::$app->user->id);
|
||||
}
|
||||
}
|
||||
$user->delete();
|
||||
return $this->redirect(['/admin/user']);
|
||||
return $this->redirect(['list']);
|
||||
}
|
||||
|
||||
public function actionDisable($id)
|
||||
{
|
||||
$this->forcePostRequest();
|
||||
|
||||
$user = User::findOne(['id' => $id]);
|
||||
if ($user === null) {
|
||||
throw new HttpException(404);
|
||||
}
|
||||
|
||||
return $this->render('delete', ['model' => $user]);
|
||||
$user->status = User::STATUS_DISABLED;
|
||||
$user->save();
|
||||
|
||||
return $this->redirect(['list']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to user profile
|
||||
*
|
||||
* @param int $id
|
||||
* @return \yii\base\Response the response
|
||||
* @throws HttpException
|
||||
*/
|
||||
public function actionImpersonate($id)
|
||||
{
|
||||
$this->forcePostRequest();
|
||||
|
||||
$user = User::findOne(['id' => $id]);
|
||||
if ($user === null) {
|
||||
throw new HttpException(404);
|
||||
}
|
||||
|
||||
if (!static::canImpersonate($user)) {
|
||||
throw new HttpException(403);
|
||||
}
|
||||
|
||||
Yii::$app->user->switchIdentity($user);
|
||||
|
||||
return $this->goHome();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the current user can impersonate given user.
|
||||
*
|
||||
* @param User $user
|
||||
* @return boolean can impersonate
|
||||
*/
|
||||
public static function canImpersonate($user)
|
||||
{
|
||||
if (!Yii::$app->getModule('admin')->allowUserImpersonate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Yii::$app->user->isAdmin() && $user->id != Yii::$app->user->getIdentity()->id;
|
||||
}
|
||||
|
||||
}
|
||||
|
43
protected/humhub/modules/admin/grid/SpaceActionColumn.php
Normal file
43
protected/humhub/modules/admin/grid/SpaceActionColumn.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\grid;
|
||||
|
||||
use Yii;
|
||||
use humhub\libs\ActionColumn;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\admin\controllers\UserController;
|
||||
|
||||
/**
|
||||
* SpaceActionColumn
|
||||
*
|
||||
* @author Luke
|
||||
*/
|
||||
class SpaceActionColumn extends ActionColumn
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function renderDataCellContent($model, $key, $index)
|
||||
{
|
||||
$actions = [];
|
||||
$actions[Yii::t('base', 'Edit')] = ['open', 'section' => 'edit'];
|
||||
$actions[] = '---';
|
||||
$actions[Yii::t('AdminModule.space', 'Manage members')] = ['open', 'section' => 'members'];
|
||||
$actions[Yii::t('AdminModule.space', 'Change owner')] = ['open', 'section' => 'owner'];
|
||||
$actions[Yii::t('AdminModule.space', 'Manage modules')] = ['open', 'section' => 'modules'];
|
||||
$actions[Yii::t('base', 'Delete')] = ['open', 'section' => 'delete'];
|
||||
$actions[] = '---';
|
||||
$actions[Yii::t('AdminModule.space', 'Open space')] = ['open'];
|
||||
$this->actions = $actions;
|
||||
|
||||
return parent::renderDataCellContent($model, $key, $index);
|
||||
}
|
||||
|
||||
}
|
44
protected/humhub/modules/admin/grid/SpaceBaseColumn.php
Normal file
44
protected/humhub/modules/admin/grid/SpaceBaseColumn.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\grid;
|
||||
|
||||
use yii\db\ActiveRecord;
|
||||
use yii\grid\DataColumn;
|
||||
|
||||
/**
|
||||
* BaseColumn for space grid fields
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
abstract class SpaceBaseColumn extends DataColumn
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string|null name of space model attribute
|
||||
*/
|
||||
public $spaceAttribute = null;
|
||||
|
||||
/**
|
||||
* Returns the space record
|
||||
*
|
||||
* @param ActiveRecord $record
|
||||
* @return \humhub\modules\space\models\Space the space model
|
||||
*/
|
||||
public function getSpace(ActiveRecord $record)
|
||||
{
|
||||
if ($this->spaceAttribute === null) {
|
||||
return $record;
|
||||
}
|
||||
|
||||
$attributeName = $this->spaceAttribute;
|
||||
return $record->$attributeName;
|
||||
}
|
||||
|
||||
}
|
40
protected/humhub/modules/admin/grid/SpaceImageColumn.php
Normal file
40
protected/humhub/modules/admin/grid/SpaceImageColumn.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\grid;
|
||||
|
||||
use humhub\modules\space\widgets\Image as SpaceImage;
|
||||
use humhub\modules\space\models\Space;
|
||||
|
||||
/**
|
||||
* SpaceColumn
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
class SpaceImageColumn extends SpaceBaseColumn
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
$this->options['style'] = 'width:38px';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function renderDataCellContent($model, $key, $index)
|
||||
{
|
||||
return SpaceImage::widget(['space' => $this->getSpace($model), 'width' => 34, 'link' => true]);
|
||||
}
|
||||
|
||||
}
|
56
protected/humhub/modules/admin/grid/SpaceTitleColumn.php
Normal file
56
protected/humhub/modules/admin/grid/SpaceTitleColumn.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\grid;
|
||||
|
||||
use Yii;
|
||||
use yii\bootstrap\Html;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\libs\Helpers;
|
||||
/**
|
||||
* TitleColumn
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
class SpaceTitleColumn extends SpaceBaseColumn
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if ($this->attribute === null) {
|
||||
$this->attribute = 'name';
|
||||
}
|
||||
|
||||
if ($this->label === null) {
|
||||
$this->label = Yii::t('SpaceModule.base', 'Name');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function renderDataCellContent($model, $key, $index)
|
||||
{
|
||||
$space = $this->getSpace($model);
|
||||
|
||||
$badge = '';
|
||||
if ($space->status == Space::STATUS_ARCHIVED) {
|
||||
$badge = ' <span class="badge">'.Yii::t('SpaceModule.base', 'Archived').'</span>';
|
||||
}
|
||||
|
||||
return '<div>' . Html::encode($space->name) . $badge . '<br> ' .
|
||||
'<small>' . Html::encode(Helpers::trimText($space->description, 100)) . '</small></div>';
|
||||
}
|
||||
|
||||
}
|
55
protected/humhub/modules/admin/grid/UserActionColumn.php
Normal file
55
protected/humhub/modules/admin/grid/UserActionColumn.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\grid;
|
||||
|
||||
use Yii;
|
||||
use humhub\libs\ActionColumn;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\admin\controllers\UserController;
|
||||
|
||||
/**
|
||||
* UserActionColumn
|
||||
*
|
||||
* @author Luke
|
||||
*/
|
||||
class UserActionColumn extends ActionColumn
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function renderDataCellContent($model, $key, $index)
|
||||
{
|
||||
$actions = [];
|
||||
if ($model->status == User::STATUS_SOFT_DELETED) {
|
||||
$actions[Yii::t('AdminModule.user', 'Permanently delete')] = ['delete'];
|
||||
} else {
|
||||
$actions[Yii::t('base', 'Edit')] = ['edit'];
|
||||
$actions[] = '---';
|
||||
if ($model->status == User::STATUS_DISABLED) {
|
||||
$actions[Yii::t('AdminModule.user', 'Enable')] = ['enable', 'linkOptions' => ['data-method' => 'post', 'data-confirm' => Yii::t('AdminModule.user', 'Are you really sure that you want to enable this user?')]];
|
||||
} elseif ($model->status == User::STATUS_ENABLED) {
|
||||
$actions[Yii::t('AdminModule.user', 'Disable')] = ['disable', 'linkOptions' => ['data-method' => 'post', 'data-confirm' => Yii::t('AdminModule.user', 'Are you really sure that you want to disable this user?')]];
|
||||
}
|
||||
$actions[Yii::t('base', 'Delete')] = ['delete'];
|
||||
|
||||
if ($model->status == User::STATUS_ENABLED) {
|
||||
$actions[] = '---';
|
||||
if (UserController::canImpersonate($model)) {
|
||||
$actions[Yii::t('AdminModule.user', 'Impersonate')] = ['impersonate', 'linkOptions' => ['data-method' => 'post', 'data-confirm' => Yii::t('AdminModule.user', 'Are you really sure that you want to impersonate this user?')]];
|
||||
}
|
||||
$actions[Yii::t('AdminModule.user', 'View profile')] = ['view-profile'];
|
||||
}
|
||||
}
|
||||
$this->actions = $actions;
|
||||
|
||||
return parent::renderDataCellContent($model, $key, $index);
|
||||
}
|
||||
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
namespace humhub\modules\admin\jobs;
|
||||
|
||||
use Yii;
|
||||
use humhub\components\queue\ActiveJob;
|
||||
use humhub\modules\queue\ActiveJob;
|
||||
use humhub\modules\user\models\Group;
|
||||
use humhub\modules\admin\libs\HumHubAPI;
|
||||
use humhub\modules\admin\notifications\NewVersionAvailable;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
namespace humhub\modules\admin\jobs;
|
||||
|
||||
use humhub\components\queue\ActiveJob;
|
||||
use humhub\modules\queue\ActiveJob;
|
||||
use humhub\modules\admin\models\Log;
|
||||
|
||||
/**
|
||||
|
@ -8,24 +8,32 @@
|
||||
|
||||
namespace humhub\modules\admin\models;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\data\ActiveDataProvider;
|
||||
use humhub\modules\space\models\Space;
|
||||
|
||||
use humhub\modules\space\models\Membership;
|
||||
|
||||
/**
|
||||
* Description of UserSearch
|
||||
* SpaceSearch for administration
|
||||
*
|
||||
* @author luke
|
||||
*/
|
||||
class SpaceSearch extends Space
|
||||
{
|
||||
|
||||
public $freeText;
|
||||
public $memberCount;
|
||||
public $owner;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['id', 'visibility', 'join_policy'], 'integer'],
|
||||
[['name'], 'safe'],
|
||||
[['freeText'], 'safe'],
|
||||
];
|
||||
}
|
||||
|
||||
@ -34,10 +42,28 @@ class SpaceSearch extends Space
|
||||
*/
|
||||
public function scenarios()
|
||||
{
|
||||
// bypass scenarios() implementation in the parent class
|
||||
//Bypass scenarios() implementation in the parent class
|
||||
return Model::scenarios();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function className()
|
||||
{
|
||||
return Space::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array_merge(parent::attributeLabels(), [
|
||||
'memberCount' => 'Members'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates data provider instance with search query applied
|
||||
*
|
||||
@ -47,7 +73,10 @@ class SpaceSearch extends Space
|
||||
*/
|
||||
public function search($params)
|
||||
{
|
||||
$query = Space::find();
|
||||
$memberCountSubSelect = Membership::find()->select('COUNT(*) as counter')->where('space_id=space.id')->andWhere(['space_membership.status' => Membership::STATUS_MEMBER]);
|
||||
$query = self::find();
|
||||
$query->joinWith(['ownerUser', 'ownerUser.profile']);
|
||||
$query->addSelect(['space.*', 'memberCount' => $memberCountSubSelect]);
|
||||
|
||||
$dataProvider = new ActiveDataProvider([
|
||||
'query' => $query,
|
||||
@ -60,22 +89,56 @@ class SpaceSearch extends Space
|
||||
'name',
|
||||
'visibility',
|
||||
'join_policy',
|
||||
'memberCount',
|
||||
]
|
||||
]);
|
||||
|
||||
$dataProvider->sort->attributes['ownerUser.profile.lastname'] = [
|
||||
'asc' => ['profile.lastname' => SORT_ASC],
|
||||
'desc' => ['profile.lastname' => SORT_DESC],
|
||||
];
|
||||
$this->load($params);
|
||||
|
||||
if (!$this->validate()) {
|
||||
$query->where('0=1');
|
||||
$query->emulateExecution();
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
$query->andFilterWhere(['id' => $this->id]);
|
||||
$query->andFilterWhere(['join_policy' => $this->join_policy]);
|
||||
$query->andFilterWhere(['visibility' => $this->visibility]);
|
||||
$query->andFilterWhere(['like', 'name', $this->name]);
|
||||
|
||||
// Freetext filters
|
||||
if (!empty($this->freeText)) {
|
||||
$query->andWhere([
|
||||
'OR',
|
||||
['like', 'space.name', $this->freeText],
|
||||
['like', 'user.id', $this->freeText],
|
||||
['like', 'user.username', $this->freeText],
|
||||
['like', 'user.email', $this->freeText],
|
||||
['like', 'profile.firstname', $this->freeText],
|
||||
['like', 'profile.lastname', $this->freeText]
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->visibility == Space::VISIBILITY_NONE) {
|
||||
$query->andFilterWhere(['space.visibility' => Space::VISIBILITY_NONE]);
|
||||
} else {
|
||||
$query->andWhere([
|
||||
'OR',
|
||||
['space.visibility' => Space::VISIBILITY_REGISTERED_ONLY],
|
||||
['space.visibility' => Space::VISIBILITY_ALL]
|
||||
]);
|
||||
}
|
||||
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
public function getVisibilityAttributes()
|
||||
{
|
||||
$countPublic = Space::find()->where(['visibility' => Space::VISIBILITY_ALL])->orWhere(['visibility' => Space::VISIBILITY_REGISTERED_ONLY])->count();
|
||||
$countPrivate = Space::find()->where(['visibility' => Space::VISIBILITY_NONE])->count();
|
||||
|
||||
return [
|
||||
Space::VISIBILITY_REGISTERED_ONLY => Yii::t('SpaceModule.base', 'Public') . ' (' . $countPublic . ')',
|
||||
Space::VISIBILITY_NONE => Yii::t('SpaceModule.base', 'Private') . ' (' . $countPrivate . ')',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
namespace humhub\modules\admin\models;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use yii\data\ActiveDataProvider;
|
||||
use humhub\modules\user\models\User;
|
||||
@ -20,19 +21,33 @@ use humhub\modules\user\models\User;
|
||||
class UserSearch extends User
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \humhub\modules\user\components\ActiveQueryUser
|
||||
*/
|
||||
public $query;
|
||||
|
||||
/**
|
||||
* @var string a free text search
|
||||
*/
|
||||
public $freeText;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributes()
|
||||
{
|
||||
// add related fields to searchable attributes
|
||||
return array_merge(parent::attributes(), ['profile.firstname', 'profile.lastname']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
[['id'], 'integer'],
|
||||
[['username', 'email', 'created_at', 'profile.firstname', 'profile.lastname', 'last_login'], 'safe'],
|
||||
[['id', 'status'], 'integer'],
|
||||
[['username', 'email', 'created_at', 'profile.firstname', 'profile.lastname', 'last_login', 'freeText'], 'safe'],
|
||||
];
|
||||
}
|
||||
|
||||
@ -55,38 +70,62 @@ class UserSearch extends User
|
||||
public function search($params)
|
||||
{
|
||||
$query = ($this->query == null) ? User::find()->joinWith('profile') : $this->query;
|
||||
|
||||
/* @var $query \humhub\modules\user\components\ActiveQueryUser */
|
||||
|
||||
$dataProvider = new ActiveDataProvider([
|
||||
'query' => $query,
|
||||
'pagination' => ['pageSize' => 50],
|
||||
]);
|
||||
|
||||
$dataProvider->setSort([
|
||||
'attributes' => [
|
||||
'id',
|
||||
'username',
|
||||
'email',
|
||||
'last_login',
|
||||
'last_login',
|
||||
'profile.firstname',
|
||||
'profile.lastname',
|
||||
'created_at',
|
||||
]
|
||||
]);
|
||||
$dataProvider->sort->defaultOrder = ['id' => SORT_DESC];
|
||||
|
||||
$this->load($params);
|
||||
|
||||
if (!$this->validate()) {
|
||||
$query->where('0=1');
|
||||
$query->emulateExecution();
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
|
||||
$query->joinWith(['profile']);
|
||||
|
||||
|
||||
// Freetext filters
|
||||
if (!empty($this->freeText)) {
|
||||
$query->andWhere([
|
||||
'OR',
|
||||
['like', 'user.id', $this->freeText],
|
||||
['like', 'user.username', $this->freeText],
|
||||
['like', 'user.email', $this->freeText],
|
||||
['like', 'profile.firstname', $this->freeText],
|
||||
['like', 'profile.lastname', $this->freeText]
|
||||
]);
|
||||
|
||||
if (!empty($this->status)) {
|
||||
$query->andFilterWhere(['user.status' => $this->status]);
|
||||
}
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
$query->andFilterWhere(['id' => $this->id]);
|
||||
$query->andFilterWhere(['user.status' => $this->status]);
|
||||
$query->andFilterWhere(['like', 'user.id', $this->id]);
|
||||
$query->andFilterWhere(['like', 'user.username', $this->username]);
|
||||
$query->andFilterWhere(['like', 'user.email', $this->email]);
|
||||
$query->andFilterWhere(['like', 'profile.firstname', $this->getAttribute('profile.firstname')]);
|
||||
$query->andFilterWhere(['like', 'profile.lastname', $this->getAttribute('profile.lastname')]);
|
||||
|
||||
|
||||
if ($this->getAttribute('last_login') != "") {
|
||||
try {
|
||||
$last_login = \humhub\libs\DateHelper::parseDateTime($this->getAttribute('last_login'));
|
||||
@ -94,8 +133,8 @@ class UserSearch extends User
|
||||
$query->andWhere([
|
||||
'=',
|
||||
new \yii\db\Expression("DATE(last_login)"),
|
||||
new \yii\db\Expression("DATE(:last_login)", [':last_login'=>$last_login])
|
||||
]);
|
||||
new \yii\db\Expression("DATE(:last_login)", [':last_login' => $last_login])
|
||||
]);
|
||||
} catch (InvalidParamException $e) {
|
||||
// do not change the query if the date is wrong formatted
|
||||
}
|
||||
@ -104,4 +143,17 @@ class UserSearch extends User
|
||||
return $dataProvider;
|
||||
}
|
||||
|
||||
public function getStatusAttributes()
|
||||
{
|
||||
$countActive = User::find()->where(['user.status' => User::STATUS_ENABLED])->count();
|
||||
$countDisabled = User::find()->where(['user.status' => User::STATUS_DISABLED])->count();
|
||||
$countSoftDeleted = User::find()->where(['user.status' => User::STATUS_SOFT_DELETED])->count();
|
||||
|
||||
return [
|
||||
User::STATUS_ENABLED => Yii::t('AdminModule.user', 'Active users') . ' (' . $countActive . ')',
|
||||
User::STATUS_DISABLED => Yii::t('AdminModule.user', 'Disabled users') . ' (' . $countDisabled . ')',
|
||||
User::STATUS_SOFT_DELETED => Yii::t('AdminModule.user', 'Deleted users') . ' (' . $countSoftDeleted . ')',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,11 +57,17 @@ class CacheSettingsForm extends Model
|
||||
*/
|
||||
public function getTypes()
|
||||
{
|
||||
return [
|
||||
$cacheTypes = [
|
||||
'yii\caching\DummyCache' => \Yii::t('AdminModule.forms_CacheSettingsForm', 'No caching'),
|
||||
'yii\caching\FileCache' => \Yii::t('AdminModule.forms_CacheSettingsForm', 'File'),
|
||||
'yii\caching\ApcCache' => \Yii::t('AdminModule.forms_CacheSettingsForm', 'APC(u)'),
|
||||
];
|
||||
|
||||
if (isset(Yii::$app->redis)) {
|
||||
$cacheTypes['yii\redis\Cache'] = \Yii::t('AdminModule.forms_CacheSettingsForm', 'Redis');
|
||||
}
|
||||
|
||||
return $cacheTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
137
protected/humhub/modules/admin/models/forms/UserDeleteForm.php
Normal file
137
protected/humhub/modules/admin/models/forms/UserDeleteForm.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\admin\models\forms;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Model;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\user\jobs\SoftDeleteUser;
|
||||
use humhub\modules\user\jobs\DeleteUser;
|
||||
use humhub\modules\space\helpers\MembershipHelper;
|
||||
use humhub\modules\space\models\Space;
|
||||
|
||||
/**
|
||||
* UserDeleteForm shows the deletion options for the admin.
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
class UserDeleteForm extends Model
|
||||
{
|
||||
|
||||
/**
|
||||
* @var User the user record to delete
|
||||
*/
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* @var boolean delete also user contributions
|
||||
*/
|
||||
public $deleteContributions = false;
|
||||
|
||||
/**
|
||||
* @var boolean delete also user spaces
|
||||
*/
|
||||
public $deleteSpaces = false;
|
||||
|
||||
/**
|
||||
* @var Space[]
|
||||
*/
|
||||
protected $_spaces = null;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ($this->user->status == User::STATUS_SOFT_DELETED) {
|
||||
$this->deleteContributions = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$rules = [];
|
||||
$rules[] = [['deleteSpaces'], 'boolean'];
|
||||
|
||||
if ($this->user->status != User::STATUS_SOFT_DELETED) {
|
||||
$rules[] = [['deleteContributions'], 'boolean'];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeLabels()
|
||||
{
|
||||
return array(
|
||||
'deleteContributions' => Yii::t('AdminModule.user', 'Delete all contributions of this user'),
|
||||
'deleteSpaces' => Yii::t('AdminModule.user', 'Delete spaces which are owned by this user'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function attributeHints()
|
||||
{
|
||||
return array(
|
||||
'deleteContributions' => Yii::t('AdminModule.user', 'Using this option any contributions (e.g. contents, comments or likes) of this user will be irrevocably deleted.'),
|
||||
'deleteSpaces' => Yii::t('AdminModule.user', 'If this option is not selected, the ownership of the spaces will be transferred to your account.'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform user deletion
|
||||
* @since 1.3
|
||||
*/
|
||||
public function performDelete()
|
||||
{
|
||||
if (!$this->validate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle owned spaces by the deleted user
|
||||
$ownedSpaces = MembershipHelper::getOwnSpaces($this->user);
|
||||
if (count($ownedSpaces) !== 0 && empty($this->deleteSpaces)) {
|
||||
foreach ($ownedSpaces as $space) {
|
||||
$space->addMember(Yii::$app->user->id);
|
||||
$space->setSpaceOwner(Yii::$app->user->id);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->deleteContributions)) {
|
||||
Yii::$app->queue->push(new SoftDeleteUser(['user_id' => $this->user->id]));
|
||||
} else {
|
||||
Yii::$app->queue->push(new DeleteUser(['user_id' => $this->user->id]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all spaces which are owned by the user
|
||||
*
|
||||
* @return Space[] the spaces
|
||||
*/
|
||||
public function getOwningSpaces()
|
||||
{
|
||||
if ($this->_spaces !== null) {
|
||||
return $this->_spaces;
|
||||
}
|
||||
|
||||
$this->_spaces = MembershipHelper::getOwnSpaces($this->user);
|
||||
return $this->_spaces;
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,8 @@
|
||||
use yii\helpers\Url;
|
||||
use yii\helpers\Html;
|
||||
use humhub\widgets\GridView;
|
||||
use humhub\modules\user\grid\ImageColumn;
|
||||
use humhub\modules\user\grid\DisplayNameColumn;
|
||||
?>
|
||||
|
||||
<div class="panel-body">
|
||||
@ -15,15 +17,12 @@ use humhub\widgets\GridView;
|
||||
<?=
|
||||
GridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
'filterModel' => $searchModel,
|
||||
# 'filterModel' => $searchModel,
|
||||
'columns' => [
|
||||
'username',
|
||||
'email',
|
||||
'profile.firstname',
|
||||
'profile.lastname',
|
||||
'profile.lastname',
|
||||
['class' => ImageColumn::class],
|
||||
['class' => DisplayNameColumn::class],
|
||||
[
|
||||
'header' => Yii::t('AdminModule.views_approval_index', 'Actions'),
|
||||
# 'header' => Yii::t('AdminModule.views_approval_index', 'Actions'),
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'options' => ['width' => '150px'],
|
||||
'buttons' => [
|
||||
|
@ -5,6 +5,10 @@ use yii\helpers\Html;
|
||||
use humhub\widgets\GridView;
|
||||
?>
|
||||
<div class="panel-body">
|
||||
<div class="pull-right">
|
||||
<?= Html::a('<i class="fa fa-plus" aria-hidden="true"></i> ' . Yii::t('AdminModule.views_groups_index', "Create new group"), Url::to(['edit']), ['class' => 'btn btn-sm btn-success']); ?>
|
||||
</div>
|
||||
|
||||
<h4><?= Yii::t('AdminModule.views_group_index', 'Manage groups'); ?></h4>
|
||||
|
||||
<div class="help-block">
|
||||
@ -15,9 +19,6 @@ use humhub\widgets\GridView;
|
||||
<?= \humhub\modules\admin\widgets\GroupMenu::widget(); ?>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="pull-right">
|
||||
<?= Html::a('<i class="fa fa-plus" aria-hidden="true"></i> ' . Yii::t('AdminModule.views_groups_index', "Create new group"), Url::to(['edit']), ['class' => 'btn btn-success']); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo GridView::widget([
|
||||
@ -37,20 +38,13 @@ use humhub\widgets\GridView;
|
||||
}
|
||||
],
|
||||
[
|
||||
'header' => Yii::t('AdminModule.views_group_index', 'Actions'),
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'options' => ['width' => '80px'],
|
||||
'buttons' => [
|
||||
'view' => function() {
|
||||
return;
|
||||
},
|
||||
'delete' => function() {
|
||||
return;
|
||||
},
|
||||
'update' => function($url, $model) {
|
||||
return Html::a('<i class="fa fa-pencil"></i>', Url::toRoute(['edit', 'id' => $model->id]), ['class' => 'btn btn-primary btn-xs tt']);
|
||||
},
|
||||
],
|
||||
'class' => \humhub\libs\ActionColumn::class,
|
||||
'actions' => [
|
||||
Yii::t('AdminModule.user', 'Settings') => ['edit'],
|
||||
'---',
|
||||
Yii::t('AdminModule.user', "Permissions") => ['manage-permissions'],
|
||||
Yii::t('AdminModule.user', "Members") => ['manage-group-users'],
|
||||
]
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
@ -4,90 +4,100 @@ use yii\helpers\Url;
|
||||
use yii\helpers\Html;
|
||||
use yii\widgets\ActiveForm;
|
||||
use humhub\widgets\GridView;
|
||||
use humhub\modules\user\grid\ImageColumn;
|
||||
use humhub\modules\user\grid\DisplayNameColumn;
|
||||
|
||||
\humhub\modules\admin\assets\AdminGroupAsset::register($this);
|
||||
|
||||
?>
|
||||
|
||||
<?php $this->beginContent('@admin/views/group/_manageLayout.php', ['group' => $group]) ?>
|
||||
<div class="panel-body">
|
||||
<?php $form = ActiveForm::begin(['action' => ['/admin/group/add-members']]); ?>
|
||||
<div class="form-group">
|
||||
<div class="input-group select2-humhub-append">
|
||||
<?=
|
||||
humhub\modules\user\widgets\UserPickerField::widget([
|
||||
'model' => $addGroupMemberForm,
|
||||
'attribute' => 'userGuids',
|
||||
'url' => Url::to(['/admin/group/new-member-search', 'id' => $group->id]),
|
||||
'placeholder' => Yii::t('AdminModule.views_group_manageGroupUser', 'Add new members...'),
|
||||
'focus' => true,
|
||||
])
|
||||
?>
|
||||
<?= Html::activeHiddenInput($addGroupMemberForm, 'groupId', ['value' => $group->id]) ?>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-primary" style="height:40px;" data-ui-loader><i class="fa fa-plus"></i></button>
|
||||
</span>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<?php $form = ActiveForm::begin(['action' => ['/admin/group/add-members']]); ?>
|
||||
<div class="input-group select2-humhub-append">
|
||||
<?=
|
||||
humhub\modules\user\widgets\UserPickerField::widget([
|
||||
'model' => $addGroupMemberForm,
|
||||
'attribute' => 'userGuids',
|
||||
'url' => Url::to(['/admin/group/new-member-search', 'id' => $group->id]),
|
||||
'placeholder' => Yii::t('AdminModule.views_group_manageGroupUser', 'Add new members...'),
|
||||
'focus' => true,
|
||||
])
|
||||
?>
|
||||
<?= Html::activeHiddenInput($addGroupMemberForm, 'groupId', ['value' => $group->id]) ?>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" class="btn btn-primary" style="height:40px;" data-ui-loader><i class="fa fa-plus"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
<?php ActiveForm::end(); ?>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<?php $form = ActiveForm::begin(['method' => 'get']); ?>
|
||||
<div class="input-group">
|
||||
<?= Html::activeTextInput($searchModel, 'freeText', ['class' => 'form-control', 'placeholder' => Yii::t('AdminModule.user', 'Search by name, email or id.')]); ?>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="submit"><i class="fa fa-search"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
<?php ActiveForm::end(); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php ActiveForm::end(); ?>
|
||||
|
||||
<div class="table-responsive">
|
||||
<?php
|
||||
$actionUrl = Url::to(['edit-manager-role']);
|
||||
echo GridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
'filterModel' => $searchModel,
|
||||
'columns' => [
|
||||
[
|
||||
'attribute' => 'id',
|
||||
'options' => ['style' => 'width:40px;'],
|
||||
'format' => 'raw',
|
||||
'value' => function($data) {
|
||||
return $data->id;
|
||||
$actionUrl = Url::to(['edit-manager-role']);
|
||||
echo GridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
#'filterModel' => $searchModel,
|
||||
'summary' => '',
|
||||
'columns' => [
|
||||
['class' => ImageColumn::class],
|
||||
['class' => DisplayNameColumn::class],
|
||||
[
|
||||
'attribute' => 'created_at',
|
||||
'label' => Yii::t('AdminModule.user', 'Member since'),
|
||||
'format' => 'datetime',
|
||||
'options' => ['style' => 'width:160px; min-width:160px;'],
|
||||
],
|
||||
[
|
||||
'attribute' => 'is_manager',
|
||||
'visible' => $isManagerApprovalSetting,
|
||||
'label' => Yii::t('AdminModule.user', 'Group Manager'),
|
||||
'format' => 'raw',
|
||||
'value' => function ($data) use ($group, $actionUrl) {
|
||||
$isManager = $group->isManager($data);
|
||||
$yesSelected = ($isManager) ? 'selected' : '';
|
||||
$noSelected = ($isManager) ? '' : 'selected';
|
||||
$result = '<select class="editableCell form-control" data-action-change="admin.group.setManagerRole" data-action-url="' . $actionUrl . '" data-userid="' . $data->id . '" data-groupid="' . $group->id . '">';
|
||||
$result .= '<option value="0" ' . $noSelected . '>' . Yii::t('AdminModule.views_group_manageGroupUser', 'No') . '</option>';
|
||||
$result .= '<option value="1" ' . $yesSelected . '>' . Yii::t('AdminModule.views_group_manageGroupUser', 'Yes') . '</option>';
|
||||
return $result;
|
||||
}
|
||||
],
|
||||
[
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'options' => ['style' => 'width:40px; min-width:40px;'],
|
||||
'buttons' => [
|
||||
'view' => function($url, $model) {
|
||||
return false;
|
||||
},
|
||||
],
|
||||
'username',
|
||||
'email',
|
||||
'profile.firstname',
|
||||
'profile.lastname',
|
||||
[
|
||||
'attribute' => 'is_manager',
|
||||
'visible' => $isManagerApprovalSetting,
|
||||
'label' => Yii::t('AdminModule.views_user_index', 'Group Manager'),
|
||||
'format' => 'raw',
|
||||
'value' => function ($data) use ($group, $actionUrl) {
|
||||
$isManager = $group->isManager($data);
|
||||
$yesSelected = ($isManager) ? 'selected' : '';
|
||||
$noSelected = ($isManager) ? '' : 'selected';
|
||||
$result = '<select class="editableCell form-control" data-action-change="admin.group.setManagerRole" data-action-url="'.$actionUrl.'" data-userid="' . $data->id . '" data-groupid="' . $group->id . '">';
|
||||
$result .= '<option value="0" ' . $noSelected . '>' . Yii::t('AdminModule.views_group_manageGroupUser', 'No') . '</option>';
|
||||
$result .= '<option value="1" ' . $yesSelected . '>' . Yii::t('AdminModule.views_group_manageGroupUser', 'Yes') . '</option>';
|
||||
return $result;
|
||||
'update' => function($url, $model) use ($group) {
|
||||
return false;
|
||||
},
|
||||
'delete' => function($url, $model) use ($group) {
|
||||
return Html::a('<i class="fa fa-times"></i>', '#', [
|
||||
'data-action-click' => 'admin.group.removeMember',
|
||||
'data-action-url' => Url::to(['remove-group-user', 'id' => $group->id, 'userId' => $model->id]),
|
||||
'title' => Yii::t('AdminModule.views_group_manageGroupUser', 'Remove from group'),
|
||||
'class' => 'btn btn-danger btn-xs tt']);
|
||||
}
|
||||
],
|
||||
[
|
||||
'header' => Yii::t('AdminModule.views_user_index', 'Actions'),
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'options' => ['style' => 'width:80px; min-width:80px;'],
|
||||
'buttons' => [
|
||||
'view' => function($url, $model) {
|
||||
return false;
|
||||
},
|
||||
'update' => function($url, $model) use ($group) {
|
||||
return false;
|
||||
},
|
||||
'delete' => function($url, $model) use ($group) {
|
||||
return Html::a('<i class="fa fa-times"></i>', '#', [
|
||||
'data-action-click' => 'admin.group.removeMember',
|
||||
'data-action-url' => Url::to(['remove-group-user', 'id' => $group->id, 'userId' => $model->id]),
|
||||
'title' => Yii::t('AdminModule.views_group_manageGroupUser', 'Remove from group'),
|
||||
'class' => 'btn btn-danger btn-xs tt']);
|
||||
}
|
||||
],
|
||||
],
|
||||
],
|
||||
]
|
||||
);?>
|
||||
],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php $this->endContent(); ?>
|
@ -1,81 +1,56 @@
|
||||
<?php
|
||||
|
||||
use yii\helpers\Html;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\widgets\ActiveForm;
|
||||
use humhub\modules\admin\widgets\SpaceGridView;
|
||||
use humhub\modules\admin\grid\SpaceActionColumn;
|
||||
use humhub\modules\admin\grid\SpaceTitleColumn;
|
||||
use humhub\modules\admin\grid\SpaceImageColumn;
|
||||
use humhub\modules\admin\models\SpaceSearch;
|
||||
?>
|
||||
|
||||
<?= Html::a('<i class="fa fa-plus" aria-hidden="true"></i> ' . Yii::t('AdminModule.space', 'Add new space'), ['/space/create'], ['class' => 'btn btn-sm btn-success pull-right', 'data-target' => '#globalModal']); ?>
|
||||
|
||||
<h4><?= Yii::t('AdminModule.views_space_index', 'Overview'); ?></h4>
|
||||
<div class="help-block">
|
||||
<?= Yii::t('AdminModule.views_space_index', 'This overview contains a list of each space with actions to view, edit and delete spaces.'); ?>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<?php $form = ActiveForm::begin(['method' => 'get']); ?>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="input-group">
|
||||
<?= Html::activeTextInput($searchModel, 'freeText', ['class' => 'form-control', 'placeholder' => Yii::t('AdminModule.space', 'Search by name, description, id or owner.')]); ?>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="submit"><i class="fa fa-search"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<?= Html::activeDropDownList($searchModel, 'visibility', SpaceSearch::getVisibilityAttributes(), ['class' => 'form-control', 'onchange' => 'this.form.submit()']); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php ActiveForm::end(); ?>
|
||||
|
||||
|
||||
<div class="table-responsive">
|
||||
<?= Html::a('<i class="fa fa-plus" aria-hidden="true"></i> ' . Yii::t('AdminModule.space', 'Add new space'), ['/space/create'], ['class' => 'btn btn-success pull-right', 'data-target' => '#globalModal']); ?>
|
||||
<?php
|
||||
$visibilities = [
|
||||
Space::VISIBILITY_NONE => Yii::t('SpaceModule.base', 'Private (Invisible)'),
|
||||
Space::VISIBILITY_REGISTERED_ONLY => Yii::t('SpaceModule.base', 'Public (Visible)'),
|
||||
Space::VISIBILITY_ALL => 'All',
|
||||
];
|
||||
|
||||
$joinPolicies = [
|
||||
Space::JOIN_POLICY_NONE => Yii::t('SpaceModule.base', 'Only by invite'),
|
||||
Space::JOIN_POLICY_APPLICATION => Yii::t('SpaceModule.base', 'Invite and request'),
|
||||
Space::JOIN_POLICY_FREE => Yii::t('SpaceModule.base', 'Everyone can enter'),
|
||||
];
|
||||
|
||||
echo SpaceGridView::widget([
|
||||
<?=
|
||||
SpaceGridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
'filterModel' => $searchModel,
|
||||
'summary' => '',
|
||||
'columns' => [
|
||||
['class' => SpaceImageColumn::class],
|
||||
['class' => SpaceTitleColumn::class],
|
||||
'memberCount',
|
||||
['class' => \humhub\modules\user\grid\ImageColumn::class, 'userAttribute' => 'ownerUser'],
|
||||
[
|
||||
'attribute' => 'id',
|
||||
'options' => ['width' => '40px'],
|
||||
'format' => 'raw',
|
||||
'value' => function($data) {
|
||||
return $data->id;
|
||||
},
|
||||
],
|
||||
'name',
|
||||
[
|
||||
'attribute' => 'visibility',
|
||||
'filter' => \yii\helpers\Html::activeDropDownList($searchModel, 'visibility', array_merge(['' => ''], $visibilities)),
|
||||
'options' => ['width' => '40px'],
|
||||
'format' => 'raw',
|
||||
'value' => function($data) use ($visibilities) {
|
||||
if (isset($visibilities[$data->visibility]))
|
||||
return $visibilities[$data->visibility];
|
||||
return Html::encode($data->visibility);
|
||||
},
|
||||
],
|
||||
[
|
||||
'attribute' => 'join_policy',
|
||||
'options' => ['width' => '40px'],
|
||||
'filter' => \yii\helpers\Html::activeDropDownList($searchModel, 'join_policy', array_merge(['' => ''], $joinPolicies)),
|
||||
'format' => 'raw',
|
||||
'value' => function($data) use ($joinPolicies) {
|
||||
if (isset($joinPolicies[$data->join_policy]))
|
||||
return $joinPolicies[$data->join_policy];
|
||||
return Html::encode($data->join_policy);
|
||||
},
|
||||
],
|
||||
[
|
||||
'header' => Yii::t('AdminModule.views_space_index', 'Actions'),
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'options' => ['width' => '80px'],
|
||||
'buttons' => [
|
||||
'view' => function($url, $model) {
|
||||
return Html::a('<i class="fa fa-eye"></i>', $model->getUrl(), ['class' => 'btn btn-primary btn-xs tt']);
|
||||
},
|
||||
'update' => function($url, $model) {
|
||||
return Html::a('<i class="fa fa-pencil"></i>', $model->createUrl('/space/manage'), ['class' => 'btn btn-primary btn-xs tt']);
|
||||
},
|
||||
'delete' => function($url, $model) {
|
||||
return Html::a('<i class="fa fa-times"></i>', $model->createUrl('/space/manage/default/delete'), ['class' => 'btn btn-danger btn-xs tt']);
|
||||
}
|
||||
],
|
||||
'attribute' => 'ownerUser.profile.lastname',
|
||||
'class' => \humhub\modules\user\grid\DisplayNameColumn::class,
|
||||
'userAttribute' => 'ownerUser',
|
||||
'label' => 'Owner'
|
||||
],
|
||||
['class' => SpaceActionColumn::class],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
|
@ -7,7 +7,12 @@ humhub\assets\TabbedFormAsset::register($this);
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="clearfix">
|
||||
<?= Html::backButton(['index'], ['label' => Yii::t('AdminModule.base', 'Back to overview'), 'class' => 'pull-right']); ?>
|
||||
|
||||
<div class="pull-right">
|
||||
<?= Html::backButton(['index'], ['label' => Yii::t('AdminModule.base', 'Back to overview')]); ?>
|
||||
<?= Html::a('<i class="fa fa-paper-plane" aria-hidden="true"></i> ' . Yii::t('AdminModule.views_user_index', 'Send invite'), ['/user/invite'], ['class' => 'btn btn-success', 'data-target' => '#globalModal']); ?>
|
||||
</div>
|
||||
|
||||
<h4 class="pull-left"><?= Yii::t('AdminModule.views_user_index', 'Add new user'); ?></h4>
|
||||
</div>
|
||||
<br>
|
||||
|
@ -1,36 +1,56 @@
|
||||
<?php
|
||||
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Url;
|
||||
use humhub\libs\Html;
|
||||
use humhub\modules\user\widgets\Image as UserImage;
|
||||
use humhub\modules\space\widgets\Image as SpaceImage;
|
||||
use humhub\widgets\ActiveForm;
|
||||
|
||||
/* @var $model \yii\base\Model */
|
||||
?>
|
||||
<div class="panel-body">
|
||||
<h4><?= Yii::t('AdminModule.views_user_delete', 'Confirm user deletion'); ?></h4>
|
||||
<h4><?= Yii::t('AdminModule.user', 'Confirm user deletion'); ?></h4>
|
||||
<br>
|
||||
<p><?= Yii::t('AdminModule.views_user_delete', 'Are you sure you want to delete this user?'); ?></p>
|
||||
<p><strong><?= Yii::t('AdminModule.user', 'Are you sure that you want to delete following user?'); ?></strong></p>
|
||||
|
||||
<ul>
|
||||
<li><?= Yii::t('AdminModule.views_user_delete', 'All created contents of this user will be <b>deleted</b>.'); ?></li>
|
||||
<li><?= Yii::t('AdminModule.views_user_delete', 'If this user is owner of some spaces, <b>you</b> will automatically become owner of these spaces.'); ?></li>
|
||||
</ul>
|
||||
<div class="media">
|
||||
<div class="media-left" style="padding-right:6px">
|
||||
<?= UserImage::widget(['user' => $model->user, 'width' => 38, 'link' => true]); ?>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<h4 class="media-heading"><?= Html::containerLink($model->user); ?></h4>
|
||||
<?= Html::encode($model->user->email) ?>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<p><?= Yii::t('AdminModule.account', 'All the personal data of this user will be irrevocably deleted.'); ?></p>
|
||||
<?php if (count($model->getOwningSpaces()) !== 0): ?>
|
||||
<br />
|
||||
<p><?= Yii::t('AdminModule.account', 'The user is the owner of these spaces:'); ?></p>
|
||||
<?php foreach ($model->getOwningSpaces() as $space): ?>
|
||||
<div class="media">
|
||||
<div class="media-left" style="padding-right:6px">
|
||||
<?= SpaceImage::widget(['space' => $space, 'width' => 38, 'link' => true]); ?>
|
||||
</div>
|
||||
<div class="media-body">
|
||||
<h4 class="media-heading"><?= Html::containerLink($space); ?></h4>
|
||||
<?= Yii::t('SpaceModule.base', '{count} members', ['count' => $space->getMemberships()->count()]); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<br />
|
||||
<?php endif; ?>
|
||||
|
||||
<br>
|
||||
<br />
|
||||
<?php $form = ActiveForm::begin(); ?>
|
||||
<?= $form->field($model, 'deleteContributions')->checkbox(['disabled' => !$model->isAttributeSafe('deleteContributions')]); ?>
|
||||
<?php if (count($model->getOwningSpaces()) !== 0): ?>
|
||||
<?= $form->field($model, 'deleteSpaces')->checkbox(); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?=
|
||||
\yii\widgets\DetailView::widget([
|
||||
'model' => $model,
|
||||
'attributes' => [
|
||||
'username',
|
||||
'profile.firstname',
|
||||
'profile.lastname',
|
||||
'email:email',
|
||||
'created_at:datetime',
|
||||
],
|
||||
]);
|
||||
?>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<?= Html::a(Yii::t('AdminModule.views_user_delete', 'Delete user'), Url::to(['/admin/user/delete', 'id' => $model->id, 'doit' => 2]), ['class' => 'btn btn-danger', 'data-method' => 'POST']); ?>
|
||||
<?= Html::a(Yii::t('AdminModule.views_user_delete', 'Cancel'), Url::to(['/admin/user/edit', 'id' => $model->id]), ['class' => 'btn btn-primary pull-right']); ?>
|
||||
<br />
|
||||
<hr>
|
||||
<?= Html::submitButton(Yii::t('UserModule.account', 'Delete account'), ['class' => 'btn btn-danger', 'data-ui-loader' => '']); ?>
|
||||
<?= Html::a(Yii::t('AdminModule.user', 'Cancel'), Url::to(['/admin/user/edit', 'id' => $model->user->id]), ['class' => 'btn btn-primary pull-right']); ?>
|
||||
<?php ActiveForm::end(); ?>
|
||||
</div>
|
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
use yii\helpers\Url;
|
||||
use yii\helpers\Html;
|
||||
use humhub\widgets\GridView;
|
||||
?>
|
||||
|
||||
<div class="panel-body">
|
||||
<h4><?= Yii::t('AdminModule.user', 'Overview'); ?></h4>
|
||||
<div class="help-block">
|
||||
<?= Yii::t('AdminModule.views_user_index', 'This overview contains a list of each registered user with actions to view, edit and delete users.'); ?>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<div class="pull-right">
|
||||
<?= Html::a('<i class="fa fa-plus" aria-hidden="true"></i> ' . Yii::t('AdminModule.views_user_index', 'Add new user'), ['/admin/user/add'], ['class' => 'btn btn-success', 'data-ui-loader'=>'']); ?>
|
||||
<?= Html::a('<i class="fa fa-paper-plane" aria-hidden="true"></i> ' . Yii::t('AdminModule.views_user_index', 'Send invite'), ['/user/invite'], ['class' => 'btn btn-success', 'data-target' => '#globalModal']); ?>
|
||||
<?= humhub\widgets\Button::defaultType('Registrations overview')
|
||||
->link(Url::to(['/admin/pending-registrations']))
|
||||
->visible(\humhub\modules\user\models\Invite::find()->count() > 0 && Yii::$app->user->can([new \humhub\modules\admin\permissions\ManageUsers(), new \humhub\modules\admin\permissions\ManageGroups()])); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
echo GridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
'filterModel' => $searchModel,
|
||||
'columns' => [
|
||||
[
|
||||
'attribute' => 'id',
|
||||
'options' => ['style' => 'width:40px;'],
|
||||
'format' => 'raw',
|
||||
'value' => function($data) {
|
||||
return $data->id;
|
||||
},
|
||||
],
|
||||
'username',
|
||||
'email',
|
||||
'profile.firstname',
|
||||
'profile.lastname',
|
||||
[
|
||||
'attribute' => 'last_login',
|
||||
'label' => Yii::t('AdminModule.views_user_index', 'Last login'),
|
||||
'filter' => \yii\jui\DatePicker::widget([
|
||||
'model' => $searchModel,
|
||||
'attribute' => 'last_login',
|
||||
'options' => ['style' => 'width:86px;', 'class' => 'form-control'],
|
||||
]),
|
||||
'value' => function ($data) {
|
||||
return ($data->last_login == NULL) ? Yii::t('AdminModule.views_user_index', 'never') : Yii::$app->formatter->asDate($data->last_login);
|
||||
}
|
||||
],
|
||||
[
|
||||
'header' => Yii::t('AdminModule.views_user_index', 'Actions'),
|
||||
'class' => 'yii\grid\ActionColumn',
|
||||
'options' => ['style' => 'width:80px; min-width:80px;'],
|
||||
'buttons' => [
|
||||
'view' => function($url, $model) {
|
||||
return Html::a('<i class="fa fa-eye"></i>', $model->getUrl(), ['class' => 'btn btn-primary btn-xs tt']);
|
||||
},
|
||||
'update' => function($url, $model) {
|
||||
return Html::a('<i class="fa fa-pencil"></i>', Url::toRoute(['edit', 'id' => $model->id]), ['class' => 'btn btn-primary btn-xs tt']);
|
||||
},
|
||||
'delete' => function($url, $model) {
|
||||
return Html::a('<i class="fa fa-times"></i>', Url::toRoute(['delete', 'id' => $model->id]), ['class' => 'btn btn-danger btn-xs tt']);
|
||||
}
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
69
protected/humhub/modules/admin/views/user/list.php
Normal file
69
protected/humhub/modules/admin/views/user/list.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use yii\helpers\Url;
|
||||
use yii\helpers\Html;
|
||||
use yii\widgets\ActiveForm;
|
||||
use humhub\widgets\GridView;
|
||||
use humhub\widgets\Button;
|
||||
use humhub\modules\admin\models\UserSearch;
|
||||
use humhub\modules\user\grid\ImageColumn;
|
||||
use humhub\modules\user\grid\DisplayNameColumn;
|
||||
use humhub\modules\admin\grid\UserActionColumn;
|
||||
?>
|
||||
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="pull-right">
|
||||
<?= Html::a('<i class="fa fa-plus" aria-hidden="true"></i> ' . Yii::t('AdminModule.user', 'Add new user'), ['/admin/user/add'], ['class' => 'btn btn-success btn-sm', 'data-ui-loader' => '']); ?>
|
||||
</div>
|
||||
|
||||
<h4><?= Yii::t('AdminModule.user', 'Overview'); ?></h4>
|
||||
<div class="help-block">
|
||||
<?= Yii::t('AdminModule.user', 'This overview contains a list of each registered user with actions to view, edit and delete users.'); ?>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<?php $form = ActiveForm::begin(['method' => 'get']); ?>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="input-group">
|
||||
<?= Html::activeTextInput($searchModel, 'freeText', ['class' => 'form-control', 'placeholder' => Yii::t('AdminModule.user', 'Search by name, email or id.')]); ?>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="submit"><i class="fa fa-search"></i></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<?= Html::activeDropDownList($searchModel, 'status', UserSearch::getStatusAttributes(), ['class' => 'form-control', 'onchange' => 'this.form.submit()']); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php ActiveForm::end(); ?>
|
||||
|
||||
<div class="table-responsive">
|
||||
<?=
|
||||
GridView::widget([
|
||||
'dataProvider' => $dataProvider,
|
||||
'summary' => '',
|
||||
'columns' => [
|
||||
['class' => ImageColumn::class],
|
||||
['class' => DisplayNameColumn::class],
|
||||
'email',
|
||||
[
|
||||
'attribute' => 'last_login',
|
||||
'label' => Yii::t('AdminModule.user', 'Last login'),
|
||||
'options' => ['style' => 'width:120px;'],
|
||||
'value' => function ($data) {
|
||||
return ($data->last_login == NULL) ? Yii::t('AdminModule.user', 'never') : Yii::$app->formatter->asDate($data->last_login);
|
||||
}
|
||||
],
|
||||
['class' => UserActionColumn::class],
|
||||
],
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php if ($showPendingRegistrations): ?>
|
||||
<br />
|
||||
<?= Button::defaultType(Yii::t('AdminModule.user', 'List pending registrations'))->link(Url::to(['/admin/pending-registrations']))->right()->sm(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
@ -33,19 +33,19 @@ class GroupManagerMenu extends \humhub\widgets\BaseMenu
|
||||
public function init()
|
||||
{
|
||||
$this->addItem([
|
||||
'label' => Yii::t('AdminModule.views_user_index', 'Settings'),
|
||||
'label' => Yii::t('AdminModule.user', 'Settings'),
|
||||
'url' => Url::toRoute(['/admin/group/edit', 'id' => $this->group->id]),
|
||||
'sortOrder' => 100,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'group' && Yii::$app->controller->action->id == 'edit'),
|
||||
]);
|
||||
$this->addItem([
|
||||
'label' => Yii::t('AdminModule.views_groups_index', "Permissions"),
|
||||
'label' => Yii::t('AdminModule.user', "Permissions"),
|
||||
'url' => Url::toRoute(['/admin/group/manage-permissions', 'id' => $this->group->id]),
|
||||
'sortOrder' => 200,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'group' && Yii::$app->controller->action->id == 'manage-permissions'),
|
||||
]);
|
||||
$this->addItem([
|
||||
'label' => Yii::t('AdminModule.views_groups_index', "Members"),
|
||||
'label' => Yii::t('AdminModule.user', "Members"),
|
||||
'url' => Url::toRoute(['/admin/group/manage-group-users', 'id' => $this->group->id]),
|
||||
'sortOrder' => 200,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'group' && Yii::$app->controller->action->id == 'manage-group-users'),
|
||||
|
@ -8,21 +8,25 @@
|
||||
|
||||
namespace humhub\modules\admin\widgets;
|
||||
|
||||
use humhub\modules\admin\models\UserApprovalSearch;
|
||||
use humhub\modules\user\models\Invite;
|
||||
use Yii;
|
||||
use yii\helpers\Url;
|
||||
use humhub\modules\admin\models\UserApprovalSearch;
|
||||
use humhub\modules\admin\permissions\ManageUsers;
|
||||
use humhub\modules\admin\permissions\ManageGroups;
|
||||
use humhub\modules\admin\permissions\ManageSettings;
|
||||
use humhub\modules\user\models\Invite;
|
||||
use humhub\widgets\BaseMenu;
|
||||
|
||||
/**
|
||||
* User Administration Menu
|
||||
*
|
||||
* @author Basti
|
||||
*/
|
||||
class UserMenu extends \humhub\widgets\BaseMenu
|
||||
class UserMenu extends BaseMenu
|
||||
{
|
||||
|
||||
public $template = "@humhub/widgets/views/tabMenu";
|
||||
public $type = "adminUserSubNavigation";
|
||||
public $template = '@humhub/widgets/views/tabMenu';
|
||||
public $type = 'adminUserSubNavigation';
|
||||
|
||||
public function init()
|
||||
{
|
||||
@ -32,8 +36,8 @@ class UserMenu extends \humhub\widgets\BaseMenu
|
||||
'sortOrder' => 100,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && (Yii::$app->controller->id == 'user' || Yii::$app->controller->id == 'pending-registrations')),
|
||||
'isVisible' => Yii::$app->user->can([
|
||||
new \humhub\modules\admin\permissions\ManageUsers(),
|
||||
new \humhub\modules\admin\permissions\ManageGroups(),
|
||||
new ManageUsers(),
|
||||
new ManageGroups(),
|
||||
])
|
||||
]);
|
||||
|
||||
@ -43,7 +47,7 @@ class UserMenu extends \humhub\widgets\BaseMenu
|
||||
'sortOrder' => 200,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'authentication'),
|
||||
'isVisible' => Yii::$app->user->can([
|
||||
new \humhub\modules\admin\permissions\ManageSettings()
|
||||
new ManageSettings()
|
||||
])
|
||||
]);
|
||||
|
||||
@ -55,8 +59,8 @@ class UserMenu extends \humhub\widgets\BaseMenu
|
||||
'sortOrder' => 300,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'approval'),
|
||||
'isVisible' => Yii::$app->user->can([
|
||||
new \humhub\modules\admin\permissions\ManageUsers(),
|
||||
new \humhub\modules\admin\permissions\ManageGroups()
|
||||
new ManageUsers(),
|
||||
new ManageGroups()
|
||||
])
|
||||
]);
|
||||
}
|
||||
@ -67,7 +71,7 @@ class UserMenu extends \humhub\widgets\BaseMenu
|
||||
'sortOrder' => 400,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'user-profile'),
|
||||
'isVisible' => Yii::$app->user->can([
|
||||
new \humhub\modules\admin\permissions\ManageUsers()
|
||||
new ManageUsers()
|
||||
])
|
||||
]);
|
||||
|
||||
@ -77,7 +81,7 @@ class UserMenu extends \humhub\widgets\BaseMenu
|
||||
'sortOrder' => 500,
|
||||
'isActive' => (Yii::$app->controller->module && Yii::$app->controller->module->id == 'admin' && Yii::$app->controller->id == 'group'),
|
||||
'isVisible' => Yii::$app->user->can(
|
||||
new \humhub\modules\admin\permissions\ManageGroups()
|
||||
new ManageGroups()
|
||||
)
|
||||
]);
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
@ -10,6 +10,7 @@ namespace humhub\modules\content;
|
||||
|
||||
use Yii;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\user\events\UserEvent;
|
||||
|
||||
/**
|
||||
* Events provides callbacks to handle events.
|
||||
@ -19,23 +20,43 @@ use humhub\modules\content\models\Content;
|
||||
class Events extends \yii\base\Object
|
||||
{
|
||||
|
||||
/**
|
||||
* Callback when a user is soft deleted.
|
||||
*
|
||||
* @param UserEvent $event
|
||||
*/
|
||||
public static function onUserSoftDelete(UserEvent $event)
|
||||
{
|
||||
// Delete user profile content on soft delete
|
||||
foreach (Content::findAll(['contentcontainer_id' => $event->user->contentcontainer_id]) as $content) {
|
||||
$content->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when a user is completely deleted.
|
||||
*
|
||||
* @param \yii\base\Event $event
|
||||
*/
|
||||
public static function onUserDelete($event)
|
||||
{
|
||||
$user = $event->sender;
|
||||
foreach (Content::findAll(['created_by' => $user->id]) as $content) {
|
||||
$content->delete();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback when a user is completely deleted.
|
||||
*
|
||||
* @param \yii\base\Event $event
|
||||
*/
|
||||
public static function onSpaceDelete($event)
|
||||
{
|
||||
$space = $event->sender;
|
||||
foreach (Content::findAll(['contentcontainer_id' => $space->contentContainerRecord->id]) as $content) {
|
||||
$content->delete();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,33 +2,35 @@
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\Url;
|
||||
use humhub\components\ActiveRecord;
|
||||
use humhub\libs\BasePermission;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\libs\ProfileBannerImage;
|
||||
use humhub\libs\ProfileImage;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\components\ActiveRecord;
|
||||
use humhub\modules\content\models\Content;
|
||||
use humhub\modules\content\models\ContentContainer;
|
||||
use humhub\modules\content\components\ContentContainerModuleManager;
|
||||
|
||||
/**
|
||||
* ContentContainerActiveRecord for ContentContainer Models e.g. Space or User.
|
||||
*
|
||||
* Required Methods:
|
||||
* - getProfileImage()
|
||||
* - getUrl()
|
||||
*
|
||||
* @property integer $id
|
||||
* @property integer $visibility
|
||||
* @property integer $contentcontainer_id
|
||||
* @property ContentContainerPermissionManager $permissionManager
|
||||
* @property ContentContainerSettingsManager $settings
|
||||
* @property ContentContainerModuleManager $moduleManager
|
||||
*
|
||||
* @since 1.0
|
||||
* @author Luke
|
||||
@ -41,6 +43,25 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
*/
|
||||
protected $permissionManager = null;
|
||||
|
||||
/**
|
||||
* @var ModuleManager
|
||||
*/
|
||||
protected $moduleManager = null;
|
||||
|
||||
/**
|
||||
* The behavior which will be attached to the base controller.
|
||||
*
|
||||
* @since 1.3
|
||||
* @see \humhub\modules\contentcontainer\components\Controller
|
||||
* @var string class name of additional the controller behavior
|
||||
*/
|
||||
public $controllerBehavior = null;
|
||||
|
||||
/**
|
||||
* @var string the default route
|
||||
*/
|
||||
public $defaultRoute = '/';
|
||||
|
||||
/**
|
||||
* Returns the Profile Image Object for this Content Base
|
||||
*
|
||||
@ -74,15 +95,17 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
|
||||
/**
|
||||
* Creates url in content container scope.
|
||||
* E.g. add uguid or sguid parameter to parameters.
|
||||
*
|
||||
* @param string $route
|
||||
* @param array $params
|
||||
* @param boolean|string $scheme
|
||||
*/
|
||||
public function createUrl($route = null, $params = array(), $scheme = false)
|
||||
public function createUrl($route = null, $params = [], $scheme = false)
|
||||
{
|
||||
return "";
|
||||
array_unshift($params, ($route !== null) ? $route : $this->defaultRoute);
|
||||
$params['contentContainer'] = $this;
|
||||
|
||||
return Url::to($params, $scheme);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -117,7 +140,7 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
{
|
||||
return "Default Wall Output for Class " . get_class($this);
|
||||
}
|
||||
|
||||
|
||||
public static function findByGuid($token)
|
||||
{
|
||||
return static::findOne(['guid' => $token]);
|
||||
@ -169,10 +192,14 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
*/
|
||||
public function getContentContainerRecord()
|
||||
{
|
||||
if ($this->hasAttribute('contentcontainer_id')) {
|
||||
return $this->hasOne(ContentContainer::className(), ['id' => 'contentcontainer_id']);
|
||||
}
|
||||
|
||||
return $this->hasOne(ContentContainer::className(), ['pk' => 'id'])
|
||||
->andOnCondition(['class' => self::className()]);
|
||||
->andOnCondition(['class' => $this->className()]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the current user has the given Permission on this ContentContainerActiveRecord.
|
||||
* This is a shortcut for `$this->getPermisisonManager()->can()`.
|
||||
@ -204,7 +231,7 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
*/
|
||||
public function getPermissionManager(User $user = null)
|
||||
{
|
||||
if($user && !$user->is(Yii::$app->user->getIdentity())) {
|
||||
if ($user && !$user->is(Yii::$app->user->getIdentity())) {
|
||||
return new ContentContainerPermissionManager([
|
||||
'contentContainer' => $this,
|
||||
'subject' => $user
|
||||
@ -220,6 +247,23 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ModuleManager
|
||||
*
|
||||
* @since 1.3
|
||||
* @param User $user
|
||||
* @return ModuleManager
|
||||
*/
|
||||
public function getModuleManager()
|
||||
{
|
||||
|
||||
if ($this->moduleManager !== null) {
|
||||
return $this->moduleManager;
|
||||
}
|
||||
|
||||
return $this->moduleManager = new ContentContainerModuleManager(['contentContainer' => $this]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns user group for the given $user or current logged in user if no $user instance was provided.
|
||||
*
|
||||
@ -238,7 +282,7 @@ abstract class ContentContainerActiveRecord extends ActiveRecord
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns weather or not the contentcontainer is archived. (Default false).
|
||||
* @return boolean
|
||||
|
@ -2,108 +2,95 @@
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
use humhub\components\Controller;
|
||||
use humhub\modules\space\behaviors\SpaceController;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\modules\space\widgets\Image;
|
||||
use humhub\modules\user\behaviors\ProfileController;
|
||||
use humhub\modules\user\models\User;
|
||||
use Yii;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Json;
|
||||
use yii\web\HttpException;
|
||||
use humhub\components\Controller;
|
||||
use humhub\modules\content\models\ContentContainer;
|
||||
use humhub\modules\content\components\ContentContainerModule;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\content\components\ContentContainerControllerAccess;
|
||||
|
||||
/**
|
||||
* ContainerController is the base controller for all space or user profile controllers.
|
||||
* It automatically detects the Container by request parameters.
|
||||
* Use [[ContentContainerActiveCreated::createUrl]] method to generate URLs.
|
||||
* e.g. $this->contentContainer->createUrl();
|
||||
* Depends on the loaded the Container Type a Behavior with additional methods will be attached.
|
||||
* - Space \humhub\modules\space\behaviors\SpaceController
|
||||
* - User attached Behavior: \humhub\modules\user\behaviors\ProfileController
|
||||
*
|
||||
* @since 0.6
|
||||
* Controller is the base class of web controllers which acts in scope of a ContentContainer (e.g. Space or User).
|
||||
*
|
||||
* To automatically load the current contentcontainer the containers guid must be passed as GET parameter 'cguid'.
|
||||
* You can create URLs in the scope of an ContentContainer by passing the contentContainer instance as 'container' or 'contentContainer'
|
||||
* as parameter to the URLManager.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* $url = Url::to(['my/action', 'container' => $this->contentContainer');
|
||||
* ```
|
||||
*
|
||||
* Based on the current ContentContainer a behavior (defined in ContentContainerActiveRecord::controllerBehavior) will be automatically
|
||||
* attached to this controller instance.
|
||||
|
||||
* The attached behavior will perform basic access checks, adds the container sublayout and perform other tasks
|
||||
* (e.g. the space behavior will update the last visit membership attribute).
|
||||
*
|
||||
* @see \humhub\modules\space\behaviors\SpaceController
|
||||
* @see \humhub\modules\user\behaviors\ProfileController
|
||||
*/
|
||||
class ContentContainerController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ContentContainerActiveRecord
|
||||
* Specifies if a contentContainer (e.g. Space or User) is required to run this controller.
|
||||
* Set this to false, if your controller should also act on global scope.
|
||||
*
|
||||
* @var boolean require cguid container parameter
|
||||
*/
|
||||
public $requireContainer = true;
|
||||
|
||||
/**
|
||||
* @var ContentContainerActiveRecord the content container (e.g. Space or User record)
|
||||
*/
|
||||
public $contentContainer = null;
|
||||
|
||||
/**
|
||||
* @var boolean automatic check user access permissions to this container
|
||||
* Limit this controller only for usage on given contentcontainer types (e.g. Space).
|
||||
*
|
||||
* @since 1.3
|
||||
* @var array|null an array of valid content container classes. if null all container types (User & Space) are allowed.
|
||||
*/
|
||||
public $autoCheckContainerAccess = true;
|
||||
public $validContentContainerClasses = null;
|
||||
|
||||
/**
|
||||
* @var boolean hides containers sidebar in layout
|
||||
* @since 0.11
|
||||
*/
|
||||
public $hideSidebar = true;
|
||||
|
||||
/**
|
||||
* Automatically loads the underlying contentContainer (User/Space) by using
|
||||
* the uguid/sguid request parameter
|
||||
*
|
||||
* @return bool
|
||||
* @throws HttpException
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$request = Yii::$app->request;
|
||||
$spaceGuid = $request->get('sguid');
|
||||
$userGuid = $request->get('uguid');
|
||||
|
||||
if ($spaceGuid !== null) {
|
||||
|
||||
$this->contentContainer = Space::findOne(['guid' => $spaceGuid]);
|
||||
if ($this->contentContainer == null) {
|
||||
throw new HttpException(404, Yii::t('base', 'Space not found!'));
|
||||
}
|
||||
|
||||
$this->attachBehavior('SpaceControllerBehavior', [
|
||||
'class' => SpaceController::className(),
|
||||
'space' => $this->contentContainer,
|
||||
]);
|
||||
$this->subLayout = "@humhub/modules/space/views/space/_layout";
|
||||
|
||||
// Handle case, if a non-logged user tries to acccess a hidden space
|
||||
// Redirect to Login instead of showing error
|
||||
if ($this->contentContainer->visibility == Space::VISIBILITY_NONE && Yii::$app->user->isGuest) {
|
||||
|
||||
}
|
||||
|
||||
} elseif ($userGuid !== null) {
|
||||
|
||||
$this->contentContainer = User::findOne(['guid' => $userGuid]);
|
||||
if ($this->contentContainer == null) {
|
||||
throw new HttpException(404, Yii::t('base', 'User not found!'));
|
||||
}
|
||||
|
||||
$this->attachBehavior('ProfileControllerBehavior', [
|
||||
'class' => ProfileController::className(),
|
||||
'user' => $this->contentContainer,
|
||||
]);
|
||||
|
||||
$this->subLayout = "@humhub/modules/user/views/profile/_layout";
|
||||
|
||||
} else {
|
||||
throw new HttpException(500, Yii::t('base', 'Could not determine content container!'));
|
||||
}
|
||||
|
||||
|
||||
if (!$this->checkModuleIsEnabled()) {
|
||||
throw new HttpException(405, Yii::t('base', 'Module is not enabled on this content container!'));
|
||||
}
|
||||
|
||||
parent::init();
|
||||
|
||||
// Load the ContentContainer
|
||||
$guid = Yii::$app->request->get('cguid', Yii::$app->request->get('sguid', Yii::$app->request->get('uguid')));
|
||||
if (!empty($guid)) {
|
||||
$contentContainerModel = ContentContainer::findOne(['guid' => $guid]);
|
||||
if ($contentContainerModel !== null) {
|
||||
$this->contentContainer = $contentContainerModel->getPolymorphicRelation();
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->requireContainer && $this->contentContainer === null) {
|
||||
throw new HttpException(404, Yii::t('base', 'Could not find requested page.'));
|
||||
}
|
||||
|
||||
if ($this->validContentContainerClasses !== null) {
|
||||
if ($this->contentContainer === null || !in_array($this->contentContainer->className(), $this->validContentContainerClasses)) {
|
||||
throw new HttpException(400);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->contentContainer !== null && $this->contentContainer->controllerBehavior) {
|
||||
$this->attachBehavior('containerControllerBehavior', ['class' => $this->contentContainer->controllerBehavior]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -111,7 +98,7 @@ class ContentContainerController extends Controller
|
||||
*/
|
||||
public function beforeAction($action)
|
||||
{
|
||||
if (parent::beforeAction($action) === false) {
|
||||
if (!parent::beforeAction($action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -121,43 +108,11 @@ class ContentContainerController extends Controller
|
||||
return false;
|
||||
}
|
||||
|
||||
// Auto check access rights to this container
|
||||
if ($this->contentContainer != null && $this->autoCheckContainerAccess) {
|
||||
$this->checkContainerAccess();
|
||||
}
|
||||
|
||||
if ($this->contentContainer instanceof Space && (Yii::$app->request->isPjax || !Yii::$app->request->isAjax)) {
|
||||
$options = [
|
||||
'guid' => $this->contentContainer->guid,
|
||||
'name' => Html::encode($this->contentContainer->name),
|
||||
'archived' => $this->contentContainer->isArchived(),
|
||||
'image' => Image::widget([
|
||||
'space' => $this->contentContainer,
|
||||
'width' => 32,
|
||||
'htmlOptions' => [
|
||||
'class' => 'current-space-image',
|
||||
],
|
||||
]),
|
||||
];
|
||||
|
||||
$this->view->registerJs('humhub.modules.space.setSpace(' . Json::encode($options) . ', ' .
|
||||
Json::encode(Yii::$app->request->isPjax) . ')');
|
||||
}
|
||||
$this->checkModuleIsEnabled();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current user can access current ContentContainer by using
|
||||
* underlying behavior ProfileControllerBehavior/SpaceControllerBehavior.
|
||||
* If access check failed, an CHttpException is thrown.
|
||||
*/
|
||||
public function checkContainerAccess()
|
||||
{
|
||||
// Implemented by behavior
|
||||
$this->checkAccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -167,18 +122,16 @@ class ContentContainerController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if current module is enabled on this content container.
|
||||
*
|
||||
* @todo Also support submodules
|
||||
* @return boolean is current module enabled
|
||||
* Checks if the requested module is available in this contentContainer.
|
||||
*
|
||||
* @throws HttpException if the module is not enabled
|
||||
*/
|
||||
public function checkModuleIsEnabled()
|
||||
protected function checkModuleIsEnabled()
|
||||
{
|
||||
if ($this->module instanceof ContentContainerModule && $this->contentContainer !== null) {
|
||||
return $this->contentContainer->isModuleEnabled($this->module->id);
|
||||
if ($this->module instanceof ContentContainerModule && $this->contentContainer !== null &&
|
||||
!$this->contentContainer->moduleManager->isEnabled($this->module->id)) {
|
||||
throw new HttpException(405, Yii::t('base', 'Module is not enabled on this content container!'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
|
||||
use humhub\components\Module;
|
||||
use humhub\modules\content\models\ContentContainerModuleState;
|
||||
|
||||
/**
|
||||
* Base Module with ContentContainer support.
|
||||
@ -23,6 +23,25 @@ use humhub\components\Module;
|
||||
class ContentContainerModule extends Module
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
// disable in content containers
|
||||
$contentContainerQuery = ContentContainerModuleManager::getContentContainerQueryByModule($this->id);
|
||||
foreach ($contentContainerQuery->all() as $contentContainer) {
|
||||
/* @var $contentContainer \humhub\modules\content\models\ContentContainer */
|
||||
$this->disableContentContainer($contentContainer->getPolymorphicRelation());
|
||||
}
|
||||
|
||||
foreach (ContentContainerModuleState::findAll(['module_id' => $this->id]) as $moduleState) {
|
||||
$moduleState->delete();
|
||||
}
|
||||
|
||||
parent::disable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of valid content container classes this module supports.
|
||||
*
|
||||
|
@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\components;
|
||||
|
||||
use ReflectionClass;
|
||||
use Yii;
|
||||
use yii\db\ActiveQuery;
|
||||
use humhub\modules\content\components\ContentContainerModule;
|
||||
use humhub\modules\content\models\ContentContainerModuleState;
|
||||
use humhub\modules\content\models\ContentContainer;
|
||||
|
||||
/**
|
||||
* ModuleManager handles modules of a content container.
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
class ContentContainerModuleManager extends \yii\base\Component
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \humhub\modules\content\components\ContentContainerActiveRecord
|
||||
*/
|
||||
public $contentContainer;
|
||||
|
||||
/**
|
||||
* @var array the available module ids
|
||||
*/
|
||||
private $_available;
|
||||
|
||||
/**
|
||||
* Disables a module for the content container
|
||||
*
|
||||
* @param string $id the module id
|
||||
* @return boolean
|
||||
*/
|
||||
public function disable($id)
|
||||
{
|
||||
if ($this->canDisable($id)) {
|
||||
Yii::$app->moduleManager->getModule($id)->disableContentContainer($this->contentContainer);
|
||||
|
||||
$moduleState = $this->getModuleStateRecord($id);
|
||||
$moduleState->module_state = ContentContainerModuleState::STATE_DISABLED;
|
||||
$moduleState->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a module for this content container
|
||||
*
|
||||
* @param string $id the module id
|
||||
* @return boolean
|
||||
*/
|
||||
public function enable($id)
|
||||
{
|
||||
if ($this->canEnable($id)) {
|
||||
Yii::$app->moduleManager->getModule($id)->enableContentContainer($this->contentContainer);
|
||||
|
||||
$moduleState = $this->getModuleStateRecord($id);
|
||||
$moduleState->module_state = ContentContainerModuleState::STATE_ENABLED;
|
||||
$moduleState->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the module is activated or not
|
||||
*
|
||||
* @param string $id the module id
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEnabled($id)
|
||||
{
|
||||
return in_array($id, $this->getEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the module can be enabled or not
|
||||
*
|
||||
* @param string $id the module id
|
||||
* @return boolean
|
||||
*/
|
||||
public function canEnable($id)
|
||||
{
|
||||
$available = $this->getAvailable();
|
||||
if (!$this->isEnabled($id) && array_key_exists($id, $available)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the module can be disabled or not
|
||||
*
|
||||
* @param string $id the module id
|
||||
* @return boolean
|
||||
*/
|
||||
public function canDisable($id)
|
||||
{
|
||||
if (!$this->isEnabled($id) || self::getDefaultState($this->contentContainer->className(), $id) === ContentContainerModuleState::STATE_FORCE_ENABLED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all enabled module ids
|
||||
*
|
||||
* @return array a list of enabled module ids
|
||||
*/
|
||||
public function getEnabled()
|
||||
{
|
||||
$enabled = [];
|
||||
$available = $this->getAvailable();
|
||||
foreach ($this->getStates() as $id => $state) {
|
||||
if (array_key_exists($id, $available) && ($state === ContentContainerModuleState::STATE_ENABLED || $state === ContentContainerModuleState::STATE_FORCE_ENABLED)) {
|
||||
$enabled[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all available modules
|
||||
*
|
||||
* @return ContentContainerModule[] a list of modules
|
||||
*/
|
||||
public function getAvailable()
|
||||
{
|
||||
if ($this->_available !== null) {
|
||||
return $this->_available;
|
||||
}
|
||||
|
||||
$this->_available = [];
|
||||
|
||||
foreach (Yii::$app->moduleManager->getModules() as $id => $module) {
|
||||
if ($module instanceof ContentContainerModule && Yii::$app->hasModule($module->id) &&
|
||||
$module->hasContentContainerType($this->contentContainer->className())) {
|
||||
$this->_available[$module->id] = $module;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->_available;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all module states.
|
||||
*
|
||||
* @see Module
|
||||
* @return array a list of modules with the corresponding state
|
||||
*/
|
||||
protected function getStates()
|
||||
{
|
||||
$states = [];
|
||||
|
||||
// Get states for this contentcontainer from database
|
||||
foreach (ContentContainerModuleState::findAll(['contentcontainer_id' => $this->contentContainer->contentcontainer_id]) as $module) {
|
||||
$states[$module->module_id] = $module->module_state;
|
||||
}
|
||||
|
||||
// Get default states, when no state is stored
|
||||
foreach ($this->getAvailable() as $module) {
|
||||
if (!isset($states[$module->id])) {
|
||||
$states[$module->id] = self::getDefaultState($this->contentContainer->className(), $module->id);
|
||||
}
|
||||
}
|
||||
|
||||
return $states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default state for a module based on the contentcontainer class
|
||||
*
|
||||
* @param string $class the class name (e.g. Space or User)
|
||||
* @param string $id the module id
|
||||
* @param int $state the state
|
||||
*/
|
||||
public static function setDefaultState($class, $id, $state)
|
||||
{
|
||||
$reflect = new ReflectionClass($class);
|
||||
Yii::$app->getModule($id)->settings->set('moduleManager.defaultState.' . $reflect->getShortName(), $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default module state for a given contentcontainer class
|
||||
*
|
||||
* @param string $class the class name (e.g. Space or User)
|
||||
* @param string $id the module id
|
||||
* @return int|null the default state or null when no default state is defined
|
||||
*/
|
||||
public static function getDefaultState($class, $id)
|
||||
{
|
||||
$reflect = new ReflectionClass($class);
|
||||
$state = Yii::$app->getModule($id)->settings->get('moduleManager.defaultState.' . $reflect->getShortName());
|
||||
|
||||
if ($state === null) {
|
||||
return null;
|
||||
} else {
|
||||
return (int) $state;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Module record instance for the given module id
|
||||
*
|
||||
* @see Module
|
||||
* @param string $id the module id
|
||||
* @return Module the Module record instance
|
||||
*/
|
||||
protected function getModuleStateRecord($id)
|
||||
{
|
||||
$moduleState = ContentContainerModuleState::findOne(['module_id' => $id, 'contentcontainer_id' => $this->contentContainer->contentcontainer_id]);
|
||||
if ($moduleState === null) {
|
||||
$moduleState = new ContentContainerModuleState;
|
||||
$moduleState->contentcontainer_id = $this->contentContainer->contentcontainer_id;
|
||||
$moduleState->module_id = $id;
|
||||
}
|
||||
|
||||
return $moduleState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a query for \humhub\modules\content\models\ContentContainer where the given module is enabled.
|
||||
*
|
||||
* @param string $id the module mid
|
||||
* @return \yii\db\ActiveQuerythe list of content container
|
||||
*/
|
||||
public static function getContentContainerQueryByModule($id)
|
||||
{
|
||||
$query = ContentContainer::find();
|
||||
|
||||
$query->leftJoin('contentcontainer_module', 'contentcontainer_module.contentcontainer_id=contentcontainer.id AND contentcontainer_module.module_id=:moduleId', [':moduleId' => $id]);
|
||||
$query->andWhere(['contentcontainer_module.module_state' => ContentContainerModuleState::STATE_ENABLED]);
|
||||
$query->orWhere(['contentcontainer_module.module_state' => ContentContainerModuleState::STATE_FORCE_ENABLED]);
|
||||
|
||||
$moduleSettings = Yii::$app->getModule($id)->settings;
|
||||
|
||||
// Add default enabled modules
|
||||
$contentContainerClasses = [\humhub\modules\user\models\User::class, \humhub\modules\space\models\Space::class];
|
||||
foreach ($contentContainerClasses as $class) {
|
||||
$reflect = new ReflectionClass($class);
|
||||
$defaultState = (int) $moduleSettings->get('moduleManager.defaultState.' . $reflect->getShortName());
|
||||
if ($defaultState === ContentContainerModuleState::STATE_ENABLED || $defaultState === ContentContainerModuleState::STATE_FORCE_ENABLED) {
|
||||
$query->orWhere(['contentcontainer.class' => $class]);
|
||||
}
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\components\behaviors;
|
||||
|
||||
use yii\base\Behavior;
|
||||
|
||||
/**
|
||||
* Compatiblity layer for old ContentContainer ModuleManager calls.
|
||||
*
|
||||
* @see \humhub\modules\contentcontainer\components\ModuleManager
|
||||
* @see \humhub\modules\content\components\ContentContainerActiveRecord
|
||||
* @since 1.3
|
||||
* @author luke
|
||||
*/
|
||||
class CompatModuleManager extends Behavior
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \humhub\modules\contentcontainer\components\ModuleManager
|
||||
*/
|
||||
public $moduleManager;
|
||||
|
||||
public function attach($owner)
|
||||
{
|
||||
parent::attach($owner);
|
||||
$this->moduleManager = $this->owner->moduleManager;
|
||||
}
|
||||
|
||||
public function getAvailableModules()
|
||||
{
|
||||
return $this->moduleManager->getAvailable();
|
||||
}
|
||||
|
||||
public function getEnabledModules()
|
||||
{
|
||||
return $this->moduleManager->getEnabled();
|
||||
}
|
||||
|
||||
public function isModuleEnabled($moduleId)
|
||||
{
|
||||
return $this->moduleManager->isEnabled($moduleId);
|
||||
}
|
||||
|
||||
public function enableModule($moduleId)
|
||||
{
|
||||
return $this->moduleManager->enable($moduleId);
|
||||
}
|
||||
|
||||
public function canDisableModule($id)
|
||||
{
|
||||
return $this->moduleManager->canDisable($id);
|
||||
}
|
||||
|
||||
public function disableModule($moduleId)
|
||||
{
|
||||
return $this->moduleManager->disable($moduleId);
|
||||
}
|
||||
|
||||
}
|
@ -17,6 +17,7 @@ return [
|
||||
['class' => IntegrityController::className(), 'event' => IntegrityController::EVENT_ON_RUN, 'callback' => array(Events::className(), 'onIntegrityCheck')],
|
||||
['class' => WallEntryAddons::className(), 'event' => WallEntryAddons::EVENT_INIT, 'callback' => array(Events::className(), 'onWallEntryAddonInit')],
|
||||
['class' => User::className(), 'event' => User::EVENT_BEFORE_DELETE, 'callback' => [Events::className(), 'onUserDelete']],
|
||||
['class' => User::className(), 'event' => User::EVENT_BEFORE_SOFT_DELETE, 'callback' => [Events::className(), 'onUserSoftDelete']],
|
||||
['class' => Space::className(), 'event' => User::EVENT_BEFORE_DELETE, 'callback' => [Events::className(), 'onSpaceDelete']],
|
||||
['class' => Search::className(), 'event' => Search::EVENT_ON_REBUILD, 'callback' => [Events::className(), 'onSearchRebuild']],
|
||||
['class' => ContentActiveRecord::className(), 'event' => ContentActiveRecord::EVENT_AFTER_INSERT, 'callback' => [Events::className(), 'onContentActiveRecordSave']],
|
||||
|
@ -16,6 +16,12 @@ class m150927_190830_create_contentcontainer extends Migration
|
||||
'owner_user_id' => Schema::TYPE_INTEGER,
|
||||
'wall_id' => Schema::TYPE_INTEGER,
|
||||
), '');
|
||||
|
||||
|
||||
# 1.3 - prepare utf8_mb4 support
|
||||
$this->alterColumn('contentcontainer', 'guid', 'char(36) NOT NULL');
|
||||
$this->alterColumn('contentcontainer', 'class', 'char(60) NOT NULL');
|
||||
|
||||
$this->createIndex('unique_target', 'contentcontainer', ['class', 'pk'], true);
|
||||
$this->createIndex('unique_guid', 'contentcontainer', ['guid'], true);
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\models;
|
||||
|
||||
/**
|
||||
* This is the model class for table "contentcontainer_module".
|
||||
*
|
||||
* @property integer $contentcontainer_id
|
||||
* @property string $module_id
|
||||
* @property integer $module_state
|
||||
*/
|
||||
class ContentContainerModuleState extends \yii\db\ActiveRecord
|
||||
{
|
||||
|
||||
const STATE_DISABLED = 0;
|
||||
const STATE_ENABLED = 1;
|
||||
const STATE_FORCE_ENABLED = 2;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public static function tableName()
|
||||
{
|
||||
return 'contentcontainer_module';
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\models;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This is the model class for table "contentcontainer_permission".
|
||||
*
|
||||
@ -16,6 +20,7 @@ namespace humhub\modules\content\models;
|
||||
*/
|
||||
class ContentContainerPermission extends \yii\db\ActiveRecord
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
@ -50,4 +55,5 @@ class ContentContainerPermission extends \yii\db\ActiveRecord
|
||||
'state' => 'State',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ use humhub\modules\search\engine\Search;
|
||||
use humhub\modules\file\models\File;
|
||||
use yii\base\Event;
|
||||
use humhub\modules\search\events\SearchAttributesEvent;
|
||||
use humhub\modules\file\converter\TextConverter;
|
||||
|
||||
/**
|
||||
* Events provides callbacks to handle events.
|
||||
@ -113,8 +114,16 @@ class Events extends \yii\base\Object
|
||||
|
||||
foreach (File::findAll(['object_model' => $event->record->className(), 'object_id' => $event->record->id]) as $file) {
|
||||
/* @var $file File */
|
||||
|
||||
$textContent = null;
|
||||
$textConverter = new TextConverter();
|
||||
if ($textConverter->applyFile($file)) {
|
||||
$textContent = $textConverter->getContentAsText();
|
||||
}
|
||||
|
||||
$event->attributes['files'][$file->id] = [
|
||||
'name' => $file->file_name
|
||||
'name' => $file->file_name,
|
||||
'content' => $textContent
|
||||
];
|
||||
|
||||
// Add comment related attributes
|
||||
|
141
protected/humhub/modules/file/converter/TextConverter.php
Normal file
141
protected/humhub/modules/file/converter/TextConverter.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\file\converter;
|
||||
|
||||
use Yii;
|
||||
use humhub\modules\file\models\File;
|
||||
use humhub\modules\file\libs\FileHelper;
|
||||
|
||||
/**
|
||||
* Text Converter
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
class TextConverter extends BaseConverter
|
||||
{
|
||||
|
||||
/**
|
||||
* List of installed text conversion converters
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* [
|
||||
* 'cmd' => '/usr/bin/pdftotext -q -enc UTF-8 {fileName} {outputFileName}',
|
||||
* 'only' => ['pdf']
|
||||
* ],
|
||||
* [
|
||||
* 'cmd' => '/usr/bin/java -jar /path/to/tika-app-1.16.jar --text {fileName} 2>/dev/null',
|
||||
* 'except' => ['image/']
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $converter = [];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function canConvert(File $file)
|
||||
{
|
||||
$originalFile = $file->store->get();
|
||||
|
||||
if (!is_file($originalFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->getConverter() === null) {
|
||||
// No text converter found for given file
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function convert($fileName)
|
||||
{
|
||||
$convertedFile = $this->file->store->get($fileName);
|
||||
|
||||
if (is_file($convertedFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$textContent = '';
|
||||
$converter = $this->getConverter();
|
||||
|
||||
if ($converter !== null) {
|
||||
if (Yii::$app->request->isConsoleRequest) {
|
||||
print "C";
|
||||
}
|
||||
|
||||
$command = str_replace('{fileName}', $this->file->store->get(), $converter['cmd']);
|
||||
if (strpos($command, "{outputFileName}") !== false) {
|
||||
$command = str_replace('{outputFileName}', $convertedFile, $command);
|
||||
shell_exec($command);
|
||||
} else {
|
||||
$textContent = shell_exec($command) . "\n";
|
||||
file_put_contents($convertedFile, $textContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first matching converter for the file
|
||||
*
|
||||
* @return array the converter definitions
|
||||
*/
|
||||
public function getConverter()
|
||||
{
|
||||
foreach ($this->converter as $converter) {
|
||||
// Check Exceptions
|
||||
if (!empty($converter['except']) && is_array($converter['except'])) {
|
||||
foreach ($converter['except'] as $except) {
|
||||
if (strpos($this->file->mime_type, $except) !== false || FileHelper::getExtension($this->file) == $except) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($converter['only']) && is_array($converter['only'])) {
|
||||
foreach ($converter['only'] as $only) {
|
||||
if (strpos($this->file->mime_type, $only) !== false || FileHelper::getExtension($this->file) == $only) {
|
||||
return $converter;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Valid for all file types
|
||||
return $converter;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file content as text
|
||||
*
|
||||
* @return string the text output
|
||||
*/
|
||||
public function getContentAsText()
|
||||
{
|
||||
$fileName = $this->getFilename();
|
||||
$convertedFile = $this->file->store->get($fileName);
|
||||
|
||||
if (is_file($convertedFile)) {
|
||||
return file_get_contents($convertedFile);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -2,9 +2,15 @@
|
||||
|
||||
namespace humhub\modules\file\widgets;
|
||||
|
||||
use humhub\modules\file\libs\FileHelper;
|
||||
use humhub\widgets\JsWidget;
|
||||
use Yii;
|
||||
use yii\helpers\ArrayHelper;
|
||||
use yii\helpers\Html;
|
||||
use humhub\widgets\JsWidget;
|
||||
use humhub\modules\file\models\File;
|
||||
use humhub\modules\file\libs\FileHelper;
|
||||
use humhub\modules\search\libs\SearchHelper;
|
||||
use humhub\modules\search\controllers\SearchController;
|
||||
use humhub\modules\file\converter\TextConverter;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -14,13 +20,19 @@ use yii\helpers\Html;
|
||||
class FilePreview extends JsWidget
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $jsWidget = "file.Preview";
|
||||
public $items;
|
||||
public $model;
|
||||
public $hideImageFileInfo = false;
|
||||
public $edit = false;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $visible = false;
|
||||
|
||||
public $preventPopover = false;
|
||||
public $popoverPosition = 'right';
|
||||
|
||||
@ -58,12 +70,12 @@ class FilePreview extends JsWidget
|
||||
protected function getFileData()
|
||||
{
|
||||
$files = $this->getFiles();
|
||||
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
if($file) {
|
||||
$result[] = FileHelper::getFileInfos($file);
|
||||
if ($file) {
|
||||
$result[] = ArrayHelper::merge(FileHelper::getFileInfos($file), ['highlight' => $this->isHighlighed($file)]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,14 +88,36 @@ class FilePreview extends JsWidget
|
||||
return [];
|
||||
}
|
||||
|
||||
if($this->items) {
|
||||
if ($this->items) {
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
if($this->showInStream === null) {
|
||||
if ($this->showInStream === null) {
|
||||
return $this->model->fileManager->findAll();
|
||||
} else {
|
||||
return $this->model->fileManager->findStreamFiles($this->showInStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the file should be highlighed in the results or not.
|
||||
*
|
||||
* @param File $file
|
||||
* @return boolean is highlighed
|
||||
*/
|
||||
protected function isHighlighed(File $file)
|
||||
{
|
||||
if (Yii::$app->controller instanceof SearchController) {
|
||||
if (SearchController::$keyword !== null) {
|
||||
$converter = new TextConverter();
|
||||
if ($converter->applyFile($file) &&
|
||||
SearchHelper::matchQuery(SearchController::$keyword, $converter->getContentAsText())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class Events extends \yii\base\Object
|
||||
*/
|
||||
public static function onMemberEvent(MemberEvent $event)
|
||||
{
|
||||
Yii::$app->cache->delete(Module::$legitimateCachePrefix . $event->user->id);
|
||||
Yii::$app->getModule('live')->refreshLegitimateContentContainerIds($event->user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,8 +47,8 @@ class Events extends \yii\base\Object
|
||||
*/
|
||||
public static function onFriendshipEvent(FriendshipEvent $event)
|
||||
{
|
||||
Yii::$app->cache->delete(Module::$legitimateCachePrefix . $event->user1->id);
|
||||
Yii::$app->cache->delete(Module::$legitimateCachePrefix . $event->user2->id);
|
||||
Yii::$app->getModule('live')->refreshLegitimateContentContainerIds($event->user1);
|
||||
Yii::$app->getModule('live')->refreshLegitimateContentContainerIds($event->user2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,7 +58,7 @@ class Events extends \yii\base\Object
|
||||
public static function onFollowEvent(FollowEvent $event)
|
||||
{
|
||||
if ($event->target instanceof ContentContainerActiveRecord) {
|
||||
Yii::$app->cache->delete(Module::$legitimateCachePrefix . $event->user->id);
|
||||
Yii::$app->getModule('live')->refreshLegitimateContentContainerIds($event->user);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,36 +22,11 @@ use humhub\modules\friendship\models\Friendship;
|
||||
class Module extends \humhub\components\Module
|
||||
{
|
||||
|
||||
/**
|
||||
* Defines the minimum polling interval in seconds if the default polling client is active.
|
||||
*/
|
||||
public $minPollInterval = 15;
|
||||
|
||||
/**
|
||||
* Defines the maximum polling interval in seconds if the default polling client is active.
|
||||
*/
|
||||
public $maxPollInterval = 45;
|
||||
|
||||
/**
|
||||
* Factor used in the actual interval calculation in case of user idle.
|
||||
*/
|
||||
public $idleFactor = 0.1;
|
||||
|
||||
/**
|
||||
* Interval for updating the update delay in case of user idle in seconds.
|
||||
*/
|
||||
public $idleInterval = 20;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $isCoreModule = true;
|
||||
|
||||
/**
|
||||
* @var int seconds to delete old live events
|
||||
*/
|
||||
public $maxLiveEventAge = 600;
|
||||
|
||||
/**
|
||||
* @var string cache prefix for legitimate content container ids by user
|
||||
*/
|
||||
@ -81,6 +56,12 @@ class Module extends \humhub\components\Module
|
||||
Content::VISIBILITY_OWNER => [],
|
||||
];
|
||||
|
||||
// When no content container record exists (yet)
|
||||
// This may happen during the registration process
|
||||
if ($user->contentContainerRecord === null) {
|
||||
return $legitimation;
|
||||
}
|
||||
|
||||
// Add users own content container (user == contentcontainer)
|
||||
$legitimation[Content::VISIBILITY_OWNER][] = $user->contentContainerRecord->id;
|
||||
|
||||
@ -103,9 +84,16 @@ class Module extends \humhub\components\Module
|
||||
}
|
||||
|
||||
Yii::$app->cache->set(self::$legitimateCachePrefix . $user->id, $legitimation);
|
||||
Yii::$app->live->driver->onContentContainerLegitimationChanged($user, $legitimation);
|
||||
};
|
||||
|
||||
return $legitimation;
|
||||
}
|
||||
|
||||
public function refreshLegitimateContentContainerIds(User $user)
|
||||
{
|
||||
Yii::$app->cache->delete(self::$legitimateCachePrefix . $user->id);
|
||||
$this->getLegitimateContentContainerIds($user);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ class LiveAsset extends AssetBundle
|
||||
public $css = [];
|
||||
public $js = [
|
||||
'js/humhub.live.js',
|
||||
'js/humhub.live.poll.js'
|
||||
'js/humhub.live.poll.js',
|
||||
'js/humhub.live.push.js',
|
||||
];
|
||||
|
||||
public $publishOptions = [
|
||||
'forceCopy' => false,
|
||||
];
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class PollController extends Controller
|
||||
}
|
||||
|
||||
if (parent::beforeAction($action)) {
|
||||
if (!Yii::$app->live->driver instanceof \humhub\modules\live\driver\Database) {
|
||||
if (!Yii::$app->live->driver instanceof \humhub\modules\live\driver\Poll) {
|
||||
throw new Exception('Polling is only available when using the live database driver!');
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ namespace humhub\modules\live\driver;
|
||||
|
||||
use yii\base\Object;
|
||||
use humhub\modules\live\components\LiveEvent;
|
||||
use humhub\modules\user\models\User;
|
||||
|
||||
/**
|
||||
* Base driver for live event storage and distribution
|
||||
@ -27,4 +28,26 @@ abstract class BaseDriver extends Object
|
||||
* @return boolean indicates the sent was successful
|
||||
*/
|
||||
abstract public function send(LiveEvent $liveEvent);
|
||||
|
||||
/**
|
||||
* Returns the JavaScript Configuration for this driver
|
||||
*
|
||||
* @since 1.3
|
||||
* @see \humhub\widgets\CoreJsConfig
|
||||
* @return array the JS Configuratoin
|
||||
*/
|
||||
abstract public function getJsConfig();
|
||||
|
||||
/**
|
||||
* This callback will be executed whenever the access rules for a
|
||||
* contentcontainer is changed. e.g. user joined a new space as member.
|
||||
*
|
||||
* @since 1.3
|
||||
* @see \humhub\modules\live\Module::getLegitimateContentContainerIds()
|
||||
*/
|
||||
public function onContentContainerLegitimationChanged(User $user, $legitimation = [])
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\live\driver;
|
||||
|
||||
use humhub\modules\live\driver\BaseDriver;
|
||||
use humhub\modules\live\components\LiveEvent;
|
||||
use humhub\modules\live\models\Live;
|
||||
|
||||
/**
|
||||
* Database driver for live events
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
class Database extends BaseDriver
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function send(LiveEvent $liveEvent)
|
||||
{
|
||||
$model = new Live();
|
||||
$model->serialized_data = serialize($liveEvent);
|
||||
$model->created_at = time();
|
||||
$model->visibility = $liveEvent->visibility;
|
||||
$model->contentcontainer_id = $liveEvent->contentContainerId;
|
||||
$model->created_at = time();
|
||||
return $model->save();
|
||||
}
|
||||
|
||||
}
|
84
protected/humhub/modules/live/driver/Poll.php
Normal file
84
protected/humhub/modules/live/driver/Poll.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\live\driver;
|
||||
|
||||
use Yii;
|
||||
use yii\helpers\Json;
|
||||
use yii\helpers\Url;
|
||||
use humhub\modules\live\driver\BaseDriver;
|
||||
use humhub\modules\live\components\LiveEvent;
|
||||
use humhub\modules\live\models\Live;
|
||||
|
||||
/**
|
||||
* Database driver for live events
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
class Poll extends BaseDriver
|
||||
{
|
||||
|
||||
/**
|
||||
* Defines the minimum polling interval in seconds if the default polling client is active.
|
||||
*/
|
||||
public $minPollInterval = 15;
|
||||
|
||||
/**
|
||||
* Defines the maximum polling interval in seconds if the default polling client is active.
|
||||
*/
|
||||
public $maxPollInterval = 45;
|
||||
|
||||
/**
|
||||
* Factor used in the actual interval calculation in case of user idle.
|
||||
*/
|
||||
public $idleFactor = 0.1;
|
||||
|
||||
/**
|
||||
* Interval for updating the update delay in case of user idle in seconds.
|
||||
*/
|
||||
public $idleInterval = 20;
|
||||
|
||||
/**
|
||||
* @var int seconds to delete old live events
|
||||
*/
|
||||
public $maxLiveEventAge = 600;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function send(LiveEvent $liveEvent)
|
||||
{
|
||||
$model = new Live();
|
||||
$model->serialized_data = serialize($liveEvent);
|
||||
$model->created_at = time();
|
||||
$model->visibility = $liveEvent->visibility;
|
||||
$model->contentcontainer_id = $liveEvent->contentContainerId;
|
||||
$model->created_at = time();
|
||||
return $model->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getJsConfig()
|
||||
{
|
||||
return [
|
||||
'type' => 'humhub.modules.live.poll.PollClient',
|
||||
'options' => [
|
||||
'url' => Url::to(['/live/poll']),
|
||||
'initTime' => time(),
|
||||
'minInterval' => $this->minPollInterval, // Minimal polling request interval in seconds.
|
||||
'maxInterval' => $this->maxPollInterval, // Maximal polling request interval in seconds.
|
||||
'idleFactor' => $this->idleFactor, // Factor used in the actual interval calculation in case of user idle.
|
||||
'idleInterval' => $this->idleInterval // Interval for updating the update delay in case of user idle in seconds.
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
}
|
124
protected/humhub/modules/live/driver/Push.php
Normal file
124
protected/humhub/modules/live/driver/Push.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\live\driver;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Yii;
|
||||
use yii\helpers\Json;
|
||||
use yii\helpers\Url;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\redis\Connection;
|
||||
use yii\di\Instance;
|
||||
use humhub\modules\user\models\User;
|
||||
use humhub\modules\live\driver\BaseDriver;
|
||||
use humhub\modules\live\components\LiveEvent;
|
||||
use humhub\modules\live\live\LegitimationChanged;
|
||||
|
||||
/**
|
||||
* Database driver for live events
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
class Push extends BaseDriver
|
||||
{
|
||||
|
||||
/**
|
||||
* @var string the used Redis push channel
|
||||
*/
|
||||
public $pushChannel = 'push';
|
||||
|
||||
/**
|
||||
* @var string the URL to the push service
|
||||
*/
|
||||
public $pushServiceUrl = '';
|
||||
|
||||
/**
|
||||
* @var string the JWT secret key
|
||||
*/
|
||||
public $jwtKey = '';
|
||||
|
||||
/**
|
||||
* @var Connection|string|array the Redis [[Connection]] object or the application component ID of the Redis [[Connection]].
|
||||
* This can also be an array that is used to create a redis [[Connection]] instance in case you do not want do configure
|
||||
* redis connection as an application component.
|
||||
* After the Cache object is created, if you want to change this property, you should only assign it
|
||||
* with a Redis [[Connection]] object.
|
||||
*/
|
||||
public $redis = 'redis';
|
||||
|
||||
/**
|
||||
* Initializes the live push component.
|
||||
* This method will initialize the [[redis]] property to make sure it refers to a valid redis connection.
|
||||
*
|
||||
* @throws \yii\base\InvalidConfigException if [[redis]] is invalid.
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->redis = Instance::ensure($this->redis, Connection::className());
|
||||
|
||||
if (empty($this->jwtKey)) {
|
||||
throw new InvalidConfigException('Push driver JWT key is not specified.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function send(LiveEvent $liveEvent)
|
||||
{
|
||||
$this->redis->publish($this->pushChannel, Json::encode($liveEvent->getData()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getJsConfig()
|
||||
{
|
||||
return [
|
||||
'type' => 'humhub.modules.live.push.PushClient',
|
||||
'options' => [
|
||||
'url' => $this->pushServiceUrl,
|
||||
'jwt' => $this->generateJwtAuthorization(),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an JWT authorization of the current user including
|
||||
* the contentContainer id legitmation.
|
||||
*
|
||||
* @return string the JWT string
|
||||
*/
|
||||
public function generateJwtAuthorization()
|
||||
{
|
||||
if (Yii::$app->user->isGuest) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$user = Yii::$app->user->getIdentity();
|
||||
$token = [
|
||||
'iss' => Url::to(['/'], true),
|
||||
'sub' => Yii::$app->user->id,
|
||||
'legitmation' => Yii::$app->getModule('live')->getLegitimateContentContainerIds($user)
|
||||
];
|
||||
return JWT::encode($token, $this->jwtKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function onContentContainerLegitimationChanged(User $user, $legitimation = [])
|
||||
{
|
||||
$this->send(new LegitimationChanged(['contentContainerId' => $user->contentcontainer_id, 'userId' => $user->id, 'legitimation' => $legitimation]));
|
||||
}
|
||||
|
||||
}
|
@ -10,7 +10,8 @@ namespace humhub\modules\live\jobs;
|
||||
|
||||
use Yii;
|
||||
use humhub\modules\live\models\Live;
|
||||
use humhub\components\queue\ActiveJob;
|
||||
use humhub\modules\queue\ActiveJob;
|
||||
use humhub\modules\live\driver\Poll;
|
||||
|
||||
/**
|
||||
* DatabaseCleanup removes old live events
|
||||
@ -26,7 +27,9 @@ class DatabaseCleanup extends ActiveJob
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
Live::deleteAll('created_at +' . Yii::$app->getModule('live')->maxLiveEventAge . ' < ' . time());
|
||||
if (Yii::$app->live->driver instanceof Poll) {
|
||||
Live::deleteAll('created_at +' . Yii::$app->live->maxLiveEventAge . ' < ' . time());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
42
protected/humhub/modules/live/live/LegitimationChanged.php
Normal file
42
protected/humhub/modules/live/live/LegitimationChanged.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\live\live;
|
||||
|
||||
use humhub\modules\live\components\LiveEvent;
|
||||
use humhub\modules\content\models\Content;
|
||||
|
||||
/**
|
||||
* Live event for push driver when contentContainerId legitimation was changed
|
||||
*
|
||||
* @since 1.3
|
||||
*/
|
||||
class LegitimationChanged extends LiveEvent
|
||||
{
|
||||
|
||||
/**
|
||||
* @var array the legitimation array
|
||||
*/
|
||||
public $legitimation;
|
||||
|
||||
/**
|
||||
* @var int the user id
|
||||
*/
|
||||
public $userId;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
$this->visibility = Content::VISIBILITY_OWNER;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
humhub.module('live.push', function (module, require, $) {
|
||||
var client = require('client');
|
||||
var event = require('event');
|
||||
var object = require('util').object;
|
||||
|
||||
var PushClient = function (options) {
|
||||
if (!options) {
|
||||
module.log.error('Could not initialize PushClient. No options given!');
|
||||
return;
|
||||
}
|
||||
this.options = options;
|
||||
this.init();
|
||||
};
|
||||
|
||||
PushClient.prototype.init = function () {
|
||||
if (!this.options.url) {
|
||||
module.log.error('Could not initialize PushClient. No url option given!');
|
||||
return;
|
||||
}
|
||||
|
||||
var that = this;
|
||||
var socket = io.connect(this.options.url);
|
||||
socket.on('connect', function () {
|
||||
socket.emit('authenticate', {token: that.options.jwt});
|
||||
});
|
||||
socket.on('error', function (err) {
|
||||
module.log.error(err);
|
||||
});
|
||||
socket.on('message', function (data) {
|
||||
message = JSON.parse(data);
|
||||
event.trigger(message.type.replace(/\./g, ':'), [[message]]);
|
||||
});
|
||||
};
|
||||
|
||||
var _handleUpdateError = function (e) {
|
||||
module.log.error(e);
|
||||
};
|
||||
|
||||
module.export({
|
||||
PushClient: PushClient
|
||||
});
|
||||
});
|
@ -8,7 +8,7 @@
|
||||
namespace humhub\modules\notification\jobs;
|
||||
|
||||
use Yii;
|
||||
use humhub\components\queue\ActiveJob;
|
||||
use humhub\modules\queue\ActiveJob;
|
||||
|
||||
/**
|
||||
* Description of SendNotification
|
||||
@ -22,17 +22,17 @@ class SendBulkNotification extends ActiveJob
|
||||
* @var array Basenotification data as array.
|
||||
*/
|
||||
public $notification;
|
||||
|
||||
|
||||
/**
|
||||
* @var integer[] Recepient userids.
|
||||
*/
|
||||
public $recepients;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
Yii::$app->notification->sendBulk($this->notification, $this->recepients);
|
||||
{
|
||||
Yii::$app->notification->sendBulk($this->notification, $this->recepients);
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
namespace humhub\modules\notification\jobs;
|
||||
|
||||
use Yii;
|
||||
use humhub\components\queue\ActiveJob;
|
||||
use humhub\modules\queue\ActiveJob;
|
||||
|
||||
/**
|
||||
* Description of SendNotification
|
||||
@ -23,17 +23,17 @@ class SendNotification extends ActiveJob
|
||||
* @var humhub\modules\notification\components\BaseNotification notification instance
|
||||
*/
|
||||
public $notification;
|
||||
|
||||
|
||||
/**
|
||||
* @var \humhub\modules\user\models\User Recepient user id.
|
||||
*/
|
||||
public $recepient;
|
||||
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
Yii::$app->notification->send($this->notification, $this->recepient);
|
||||
Yii::$app->notification->send($this->notification, $this->recepient);
|
||||
}
|
||||
}
|
||||
|
36
protected/humhub/modules/queue/ActiveJob.php
Normal file
36
protected/humhub/modules/queue/ActiveJob.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue;
|
||||
|
||||
use yii\base\Object;
|
||||
use humhub\modules\queue\interfaces\JobInterface;
|
||||
|
||||
/**
|
||||
* ActiveJob
|
||||
*
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
abstract class ActiveJob extends Object implements JobInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Runs this job
|
||||
*/
|
||||
abstract public function run();
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function execute($queue)
|
||||
{
|
||||
return $this->run();
|
||||
}
|
||||
|
||||
}
|
80
protected/humhub/modules/queue/Events.php
Normal file
80
protected/humhub/modules/queue/Events.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Object;
|
||||
use yii\base\Event;
|
||||
use yii\queue\ErrorEvent;
|
||||
use yii\queue\PushEvent;
|
||||
use humhub\modules\queue\jobs\CleanupExclusiveJobs;
|
||||
use humhub\modules\queue\interfaces\ExclusiveJobInterface;
|
||||
use humhub\modules\queue\helpers\QueueHelper;
|
||||
|
||||
/**
|
||||
* Events provides callbacks to handle events.
|
||||
*
|
||||
* @since 1.3
|
||||
* @author luke
|
||||
*/
|
||||
class Events extends Object
|
||||
{
|
||||
|
||||
/**
|
||||
* Cron call back
|
||||
*
|
||||
* @param Event $event
|
||||
*/
|
||||
public static function onCronRun(Event $event)
|
||||
{
|
||||
//Yii::$app->queue->push(new CleanupExclusiveJobs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for errors while queue execution
|
||||
*
|
||||
* @param ErrorEvent $event
|
||||
*/
|
||||
public static function onQueueError(ErrorEvent $event)
|
||||
{
|
||||
/* @var $exception \Expection */
|
||||
$exception = $event->error;
|
||||
Yii::error('Could not execute queued job! Message: ' . $exception->getMessage() . ' Trace:' . $exception->getTraceAsString(), 'queue');
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback before new jobs in the queue.
|
||||
* Handles exclusive jobs.
|
||||
*
|
||||
* @param PushEvent $event
|
||||
*/
|
||||
public static function onQueueBeforePush(PushEvent $event)
|
||||
{
|
||||
if ($event->job instanceof ExclusiveJobInterface) {
|
||||
// Do not add exclusive jobs if already exists in queue
|
||||
if (QueueHelper::isQueued($event->job)) {
|
||||
$event->handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback after new jobs in the queue.
|
||||
* Handles exclusive jobs.
|
||||
*
|
||||
* @param PushEvent $event
|
||||
*/
|
||||
public static function onQueueAfterPush(PushEvent $event)
|
||||
{
|
||||
if ($event->job instanceof ExclusiveJobInterface) {
|
||||
QueueHelper::markAsQueued($event->id, $event->job);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
22
protected/humhub/modules/queue/Module.php
Normal file
22
protected/humhub/modules/queue/Module.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue;
|
||||
|
||||
use humhub\components\Module as BaseModule;
|
||||
|
||||
/**
|
||||
* Queue base module
|
||||
*
|
||||
* @author Lucas Bartholemy <lucas@bartholemy.com>
|
||||
* @since 1.3
|
||||
*/
|
||||
class Module extends BaseModule
|
||||
{
|
||||
|
||||
}
|
23
protected/humhub/modules/queue/config.php
Normal file
23
protected/humhub/modules/queue/config.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
use humhub\commands\CronController;
|
||||
use humhub\modules\queue\Events;
|
||||
use humhub\modules\queue\Module;
|
||||
use yii\queue\Queue;
|
||||
|
||||
return [
|
||||
'id' => 'queue',
|
||||
'class' => Module::class,
|
||||
'isCoreModule' => true,
|
||||
'events' => [
|
||||
[CronController::class, CronController::EVENT_ON_DAILY_RUN, [Events::class, 'onCronRun']],
|
||||
[Queue::class, Queue::EVENT_AFTER_ERROR, [Events::class, 'onQueueError']],
|
||||
[Queue::class, Queue::EVENT_BEFORE_PUSH, [Events::class, 'onQueueBeforePush']],
|
||||
[Queue::class, Queue::EVENT_AFTER_PUSH, [Events::class, 'onQueueAfterPush']]
|
||||
],
|
||||
];
|
44
protected/humhub/modules/queue/driver/Instant.php
Normal file
44
protected/humhub/modules/queue/driver/Instant.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue\driver;
|
||||
|
||||
use yii\queue\Queue;
|
||||
|
||||
/**
|
||||
* Instant queue driver, mainly used for testing purposes
|
||||
*
|
||||
* @since 1.2
|
||||
* @author buddha
|
||||
*/
|
||||
class Instant extends Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* @var int the message counter
|
||||
*/
|
||||
protected $messageId = 1;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function pushMessage($message, $ttr, $delay, $priority)
|
||||
{
|
||||
$this->handleMessage($this->messageId, $message, $ttr);
|
||||
$this->messageId++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
protected function status($id)
|
||||
{
|
||||
return Queue::STATUS_DONE;
|
||||
}
|
||||
|
||||
}
|
27
protected/humhub/modules/queue/driver/MySQL.php
Normal file
27
protected/humhub/modules/queue/driver/MySQL.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue\driver;
|
||||
|
||||
use yii\queue\db\Queue;
|
||||
|
||||
/**
|
||||
* MySQL queue driver
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
class MySQL extends Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $mutex = 'yii\mutex\MysqlMutex';
|
||||
|
||||
}
|
22
protected/humhub/modules/queue/driver/Redis.php
Normal file
22
protected/humhub/modules/queue/driver/Redis.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue\driver;
|
||||
|
||||
use yii\queue\redis\Queue;
|
||||
|
||||
/**
|
||||
* Redis queue driver
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
class Redis extends Queue
|
||||
{
|
||||
|
||||
}
|
27
protected/humhub/modules/queue/driver/Sync.php
Normal file
27
protected/humhub/modules/queue/driver/Sync.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue\driver;
|
||||
|
||||
use yii\queue\sync\Queue;
|
||||
|
||||
/**
|
||||
* Sync queue driver
|
||||
*
|
||||
* @since 1.2
|
||||
* @author Luke
|
||||
*/
|
||||
class Sync extends Queue
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $handle = true;
|
||||
|
||||
}
|
62
protected/humhub/modules/queue/helpers/QueueHelper.php
Normal file
62
protected/humhub/modules/queue/helpers/QueueHelper.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue\helpers;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Object;
|
||||
use yii\base\InvalidParamException;
|
||||
use yii\queue\Queue;
|
||||
use humhub\modules\queue\interfaces\ExclusiveJobInterface;
|
||||
use humhub\modules\queue\models\QueueExclusive;
|
||||
|
||||
/**
|
||||
* Queue Helpers
|
||||
*
|
||||
* @author Luke
|
||||
*/
|
||||
class QueueHelper extends Object
|
||||
{
|
||||
|
||||
public static function isQueued(ExclusiveJobInterface $job)
|
||||
{
|
||||
$queueExclusive = QueueExclusive::findOne(['id' => $job->getExclusiveJobId()]);
|
||||
if ($queueExclusive === null || $queueExclusive->job_status == Queue::STATUS_DONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$jobInQueue = true;
|
||||
try {
|
||||
if (Yii::$app->queue->isDone($queueExclusive->job_message_id)) {
|
||||
$jobInQueue = false;
|
||||
}
|
||||
} catch (InvalidParamException $ex) {
|
||||
// not exists
|
||||
$jobInQueue = false;
|
||||
}
|
||||
|
||||
if (!$jobInQueue) {
|
||||
$queueExclusive->delete();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function markAsQueued($jobQueueId, ExclusiveJobInterface $job)
|
||||
{
|
||||
$queueExclusive = QueueExclusive::findOne(['id' => $job->getExclusiveJobId()]);
|
||||
if ($queueExclusive === null) {
|
||||
$queueExclusive = new QueueExclusive();
|
||||
$queueExclusive->id = $job->getExclusiveJobId();
|
||||
}
|
||||
$queueExclusive->job_message_id = $jobQueueId;
|
||||
$queueExclusive->save();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue\interfaces;
|
||||
|
||||
/**
|
||||
* ExclusiveJobInterface can be added to an ActiveJob to ensure this task is only
|
||||
* queued once. As example this is useful for asynchronous jobs like search index rebuild.
|
||||
*
|
||||
* @see \humhub\modules\queue\ActiveJob
|
||||
* @author Luke
|
||||
*/
|
||||
interface ExclusiveJobInterface
|
||||
{
|
||||
|
||||
public function getExclusiveJobId();
|
||||
}
|
22
protected/humhub/modules/queue/interfaces/JobInterface.php
Normal file
22
protected/humhub/modules/queue/interfaces/JobInterface.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\queue\interfaces;
|
||||
|
||||
use yii\queue\Job;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
* @see Job
|
||||
* @since 1.3
|
||||
* @author Luke
|
||||
*/
|
||||
interface JobInterface extends Job
|
||||
{
|
||||
|
||||
}
|
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