Revert "Merge branch 'v1.3-dev' into master"

This reverts commit 895156b2a5113f3ac87a20616e599e37ed853e7a, reversing
changes made to 28acd4040a3a7e84c90520b093eff6e977cb4f82.
This commit is contained in:
Lucas Bartholemy 2018-01-23 09:40:29 +01:00
parent 895156b2a5
commit 955d83be8b
224 changed files with 2951 additions and 13960 deletions

1
.gitignore vendored
View File

@ -25,6 +25,7 @@ nbproject
.idea/*
.gitmodules
.github
/composer.lock
themes/*
!themes/HumHub

View File

@ -11,10 +11,6 @@ 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]

View File

@ -2,13 +2,14 @@
"name": "humhub/humhub",
"description": "HumHub - The flexible Open Source Social Network Kit for Collaboration",
"keywords": ["humhub", "yii2", "framework"],
"homepage": "https://www.humhub.org/",
"homepage": "http://www.humhub.com/",
"type": "project",
"license": "AGPL-3.0",
"support": {
"issues": "https://github.com/humhub/humhub/issues?state=open",
"forum": "https://community.humhub.com",
"wiki": "https://community.humhub.com",
"forum": "http://community.humhub.com",
"wiki": "http://community.humhub.com",
"irc": "irc://irc.freenode.net/humhub",
"source": "https://github.com/humhub/humhub"
},
"minimum-stability": "stable",
@ -23,39 +24,35 @@
"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",
"bower-asset/jquery-timeago": "1.5.*",
"zhuravljov/yii2-queue": "^0.11",
"bower-asset/jquery-timeago": "1.4.*",
"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.18.*",
"bower-asset/blueimp-file-upload": "9.11.*",
"bower-asset/fontawesome": "^4.7.0",
"bower-asset/bootstrap-markdown": "2.10.*",
"bower-asset/select2": "^4.0.4",
"bower-asset/select2": "^4.0.2",
"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.*",
"bower-asset/jPlayer": "2.9.2",
"bower-asset/imagesloaded": "*",
"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"
"bower-asset/jquery-timeentry": "^2.0"
},
"require-dev": {
"codeception/codeception": "*",
@ -64,18 +61,20 @@
"yiisoft/yii2-faker": "~2.0.0",
"yiisoft/yii2-apidoc": "~2.0.0"
},
"repositories": [
{
"type": "composer",
"url": "https://asset-packagist.org"
}
],
"config": {
"platform": {
"php": "5.6"
},
"process-timeout": 1800,
"vendor-dir": "protected/vendor"
"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)"
}
},
"scripts": {
"post-create-project-cmd": [
@ -95,6 +94,10 @@
"generateCookieValidationKey": [
"protected/config/web.php"
]
},
"asset-installer-paths": {
"npm-asset-library": "protected/vendor/npm",
"bower-asset-library": "protected/vendor/bower"
}
}
}

6605
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1 @@
/dynamic.php
/common.php
/console.php
/web.php

View File

@ -1,9 +1,4 @@
<?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 [
];

View File

@ -1,9 +1,4 @@
<?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 [
];

View File

@ -1,10 +1,5 @@
<?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 [
];

View File

@ -94,7 +94,6 @@ class AppAsset extends AssetBundle
'humhub\assets\PagedownConverterAsset',
'humhub\assets\ClipboardJsAsset',
'humhub\assets\ImagesLoadedAsset',
'humhub\assets\SocketIoAsset',
];
/**

View File

@ -21,7 +21,7 @@ class AtJsAsset extends AssetBundle
/**
* @inheritdoc
*/
public $sourcePath = '@npm/at.js';
public $sourcePath = '@bower/At.js';
/**
* @inheritdoc

View File

@ -1,32 +0,0 @@
<?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'];
}

View File

@ -8,12 +8,10 @@
namespace humhub\components;
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;
use Yii;
use yii\helpers\Json;
/**
* Base Class for Modules / Extensions
@ -250,9 +248,22 @@ class Module extends \yii\base\Module
}
}
ContentContainerSetting::deleteAll(['module_id' => $this->id]);
Setting::deleteAll(['module_id' => $this->id]);
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();
}
Yii::$app->moduleManager->disable($this);
}
@ -336,7 +347,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;
}
}

View File

@ -1,42 +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;
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);
}
}

View File

@ -9,16 +9,18 @@
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 \humhub\modules\queue\ActiveJob
abstract class ActiveJob extends Object implements Job
{
/**
* Runs this job
*/
abstract public function run();
}

View File

@ -0,0 +1,47 @@
<?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);
}
}

View 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\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');
});
}
}

View 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\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;
}
}

View File

@ -16,10 +16,6 @@ $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'
@ -124,7 +120,7 @@ $config = [
'dsn' => 'mysql:host=localhost;dbname=humhub',
'username' => '',
'password' => '',
'charset' => 'utf8mb4',
'charset' => 'utf8',
'enableSchemaCache' => true,
'on afterOpen' => ['humhub\libs\Helpers', 'SqlMode'],
],
@ -133,15 +129,12 @@ $config = [
'clients' => [],
],
'queue' => [
'class' => 'humhub\modules\queue\driver\Sync',
],
'urlManager' => [
'class' => 'humhub\components\UrlManager',
'class' => 'humhub\components\queue\driver\Sync',
],
'live' => [
'class' => 'humhub\modules\live\components\Sender',
'driver' => [
'class' => 'humhub\modules\live\driver\Poll',
'class' => 'humhub\modules\live\driver\Database',
],
],
],

View File

@ -27,10 +27,11 @@ $config = [
'loginUrl' => ['/user/auth/login']
],
'errorHandler' => [
'errorAction' => '/error/index',
'errorAction' => 'error/index',
],
'session' => [
'class' => 'humhub\modules\user\components\Session',
'sessionTable' => 'user_http_session',
],
],
'modules' => [],

View File

@ -1,26 +0,0 @@
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
- Fix: Birthday field refactoring (@danielkesselberg)
- Enh #2811: Added option to resend invites (@danielkesselberg)

View File

@ -1,13 +1,13 @@
Welcome
=======
Here you will find helpful information on how to create, maintain, and make the most of a social network built using the HumHub solution.
Here you will find helpful information on how to create, maintain, and make the most of an social network built using the HumHub solution.
All documentation located on docs.humhub.org refers to the latest version of HumHub. If you're using an older version, you can find the related documentation in the folder /protected/humhub/docs.
All documentations located on docs.humhub.org refers to the latest version of HumHub. If you're using an older version, you can find the related documentation in the
folder /protected/humhub/docs.
Documentations
--------------
- [Basics](basics/README.md) (Note: This directory stores basic knowledge on HumHub Features)
- [Installation and Administration](admin/README.md)
- [Theming](theme/README.md)
- [Core and Module Development](developer/README.md)

View File

@ -52,30 +52,9 @@ Thre previous configuration will disable pjax support on your site.
Available params:
- `allowedLanguages` see the [Translations Section](translations.md)
- `defaultPermissions` see [Permissions Section (TBD)]()
- `enablePjax` used to disable/enable pjax support (default true)
## Overwrite default Permissions
Default permission can be overwritten within `humhub/config/common.php` by means of the `defaultPermissions` params array.
The following example overwrites the default permission of `humhub\modules\mymodule\permissions\MyPermission` for the
given groups.
```
return [
'params' => [
'defaultPermissions' => [
'humhub\modules\mymodule\permissions\MyPermission' => [
\humhub\modules\user\models\User::USERGROUP_SELF => \humhub\libs\BasePermission::STATE_ALLOW,
\humhub\modules\user\models\User::USERGROUP_USER => \humhub\libs\BasePermission::STATE_ALLOW,
\humhub\modules\user\models\User::USERGROUP_FRIEND => \humhub\libs\BasePermission::STATE_ALLOW,
\humhub\modules\user\models\User::USERGROUP_GUEST => \humhub\libs\BasePermission::STATE_ALLOW,
],
]
]
]
```
# Statistics/Tracking
Your tracking code can be managed under `Administration -> Settings -> Advanced -> Statistics`.

View File

@ -1,116 +0,0 @@
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
```

View File

@ -81,16 +81,14 @@ return [
Google
------
In order to use Google OAuth you must create a **project** at <https://console.developers.google.com/project>
and set up its credentials at <https://console.developers.google.com/project/[yourProjectId]/apiui/credential>.
and setup its credentials at <https://console.developers.google.com/project/[yourProjectId]/apiui/credential>.
In order to enable using scopes for retrieving user attributes, you should also enable Google+ API at
In order to enable using scopes for retrieving user attributes, you have to enable Google+ API at
<https://console.developers.google.com/project/[yourProjectId]/apiui/api/plus>.
Authorization callback URLs:
Add one of the following **authorization callback URLs** to your googles **Credentials** configuration:
- http://domain/path-to-humhub/user/auth/external?authclient=google (With clean urls enabled)
- http://domain/path-to-humhub/index.php?r=user%2Fauth%2Fexternal&authclient=google (Without clean urls)
- http://<domain>/<path-to-humhub>/user/auth/external?authclient=google (With clean urls enabled)
- http://<domain>/<path-to-humhub>/index.php?r=user%2Fauth%2Fexternal&authclient=google (Without clean urls)
>Note: Replace **domain** and **path-to-humhub** in the mentioned redirect urls.
@ -125,7 +123,7 @@ Authorization callback URLs:
- http://domain/path-to-humhub/user/auth/external (With clean urls enabled)
- http://domain/path-to-humhub/index.php?r=user%2Fauth%2Fexternal (Without clean urls)
Add the following block to your configuration (protected/config/common.php):
Add following block to your configuration (protected/config/common.php):
```php
return [
@ -155,7 +153,7 @@ Microsoft Live
--------------
In order to use Microsoft Live OAuth you must register your application at <https://account.live.com/developers/applications>.
Also, add a new Platform and allow following Redirect URI.
Also add a new Platform and allow following Redirect URI.
- https://domain/path-to-humhub/user/auth/external (With clean urls enabled)
- https://domain/path-to-humhub/index.php (Without clean urls)
@ -210,6 +208,33 @@ return [
];
```
Instagram
--------
In order to use Instagram OAuth you must register your application at <https://www.instagram.com/developer/clients/manage/>.
Add the following block to your configuration (protected/config/common.php):
```php
return [
// ...
'components' => [
// ...
'authClientCollection' => [
'clients' => [
// ...
'instagram' => [
'class' => 'humhub\modules\user\authclient\Instagram',
'clientId' => 'Your Instagram App ID here',
'clientSecret' => 'Your Instagram App Secret here',
],
],
],
// ...
],
// ...
];
```
Other providers
---------------
Please see [Development - Authentication](dev-authentication.md) for more information

View File

@ -1,12 +1,5 @@
Console
=======
Some administrative tasks can also or exclusively be executed by console. All available console commands can be displayed
by executing the following command within the `protected` directory of your humhub installation.
```
php yii
```
![Command Overview](images/commandOverview.png)
TBD

View File

@ -1,71 +0,0 @@
Cron Job Setup
=======
The following guides are meant to help you with your Cron Job setup, since those settings are highly dependent on your actual environment we can't assure those setting will work for your.
> Note: Make sure to use the right [php cli executable](http://php.net/manual/en/features.commandline.introduction.php) for your jobs!
### CloudLinux (CentOS) 6
The following is a default setup for CloudLinux (CentOS) 6 and may not work for all users.
```
/usr/local/bin/php /home/USERNAME/public_html/WEB-DIRECTORY/protected/yii cron/hourly >/dev/null 2>&1
30 * * * *
/usr/local/bin/php /home/USERNAME/public_html/WEB-DIRECTORY/protected/yii cron/daily >/dev/null 2>&1
00 18 * * *
```
### cPanel Hosted Server
The following is a default setup for cPanel Hosted Server and may not work for all users.
```
/usr/local/bin/php /home/USERNAME/public_html/WEB-DIRECTORY/protected/yii cron/hourly >/dev/null 2>&1
0,30 * * * *
/usr/local/bin/php /home/USERNAME/public_html/WEB-DIRECTORY/protected/yii cron/daily >/dev/null 2>&1
00 0,12 * * *
```
### IIS Windows Server
Using [Schtasks](https://technet.microsoft.com/en-us/library/cc725744.aspx) would be recommended over many other options for Windows 2012 and Windows 8 users.
`Example TBA`
### Plesk
Refer to this [post](https://stackoverflow.com/questions/16700749/setting-up-cron-task-in-plesk-11)
![](http://i.imgur.com/TbWEsjC.png)
### OVH
[Follow this link](https://www.ovh.com/us/g1990.hosting_automated_taskscron)!
Create the following files then follow the above link.
**cronh.php**
`<?php $humhubh = '/usr/local/php5.6/bin/php '.__DIR__.'/protected/yii cron/hourly '; exec($humhubh); ?>`
**crond.php**
`<?php $humhubd = '/usr/local/php5.6/bin/php '.__DIR__.'/protected/yii cron/daily '; exec($humhubd); ?>`
### Debian
Please read up on this [article](https://debian-administration.org/article/56/Command_scheduling_with_cron).
`Example TBA`
### Ubuntu
Please read up on this [how-to guide](https://help.ubuntu.com/community/CronHowto).
`Example TBA`
### Other Server(s)
`TBA`
### *IMPORTANT NOTICE*
*This guide is subject to changes and all information provided are for example use, it is best to speak with your service providers about how best to setup your Cron Jobs with their services.*

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

View File

@ -3,6 +3,23 @@ Configuration
> NOTE: Before going to production, see also the [Security Chapter](security.md)
Basic Settings
-------
Once installed, you should have a look at the basic application settings under `Administration/Settings/Basic`
for settings as:
- Base Url
- Default language
- Time zone
- etc.
Within this view you can also select **default spaces**, which will be automatically assigned to new members.
Advanced Settings
-------
You may also check the advanced settings under `Administration/Settings/Advanced` and Notification settings to set
some default values for your user.
E-Mails
-------
@ -10,8 +27,7 @@ E-Mails
Depending on your environment you are using, you may want to specify a local or remote SMTP Server.
You can change the mail-server settings under `Administration -> Mailing -> Server Settings`.
By default, the PHP Mail Transport is used. <http://php.net/manual/en/mail.setup.php>
By default the PHP Mail Transport is used. <http://php.net/manual/en/mail.setup.php>
CronJobs
@ -26,7 +42,7 @@ Example Tab:
30 * * * * /path/to/humhub/protected/yii cron/hourly >/dev/null 2>&1
00 18 * * * /path/to/humhub/protected/yii cron/daily >/dev/null 2>&1
```
> Note: For more help refer to [here](cron-jobs.md)!
Url Rewriting (Optional)
------------------------
@ -52,4 +68,4 @@ return [
Job Scheduling
--------------
TBD
TBD

View File

@ -4,27 +4,28 @@ Installation
> Note: It's also possible to install and build HumHub directly from our **Git Repository**.
Please see [Developer Installation](../developer/git-installation.md) for more details.
Database
--------
Create a MySQL Database, e.g.:
```sql
CREATE DATABASE `humhub` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE `humhub` CHARACTER SET utf8 COLLATE utf8_general_ci;
GRANT ALL ON `humhub`.* TO `humhub_dbuser`@localhost IDENTIFIED BY 'password_changeme';
FLUSH PRIVILEGES;
```
> Note: Do not forget to change the `humhub_dbuser` and `password_changeme` placeholders!
> Note: `utf8mb4` is prefered over `utf8` since MySQL 5.5.3 please refer to the [mysql documentation](https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html) for more infos.
> Warning: Make sure to use the **utf8mb4_unicode_ci** database collation!
> Warning: Make sure to use the **utf8_general_ci** database collation!
Download HumHub Core Files
---------------------------
The easiest way to get HumHub, is the direct download of the complete package under [https://www.humhub.org/download](https://www.humhub.org/download).
The easiest way to get HumHub, is the direct download of the complete package under [https://www.humhub.org/en/download](https://www.humhub.org/en/download).
After the download completed, just extract the package into the htdocs folder of your webserver.

View File

@ -1,64 +0,0 @@
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---'
]
],
// ...
],
// ...
```

View File

@ -1,47 +0,0 @@
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.

View File

@ -1,9 +1,11 @@
Requirements
============
> Note: All vital requirements will be also checked during the web installer.
Server Requirements
-------------------
* Shell access (e.g. ssh) to server
* PHP 5.6 or later
* MySQL (5.1 or later) or MariaDB with InnoDB storage engine installed
@ -11,23 +13,27 @@ Server Requirements
* A minimum 64 MB of memory allocated to PHP
* A minimum of 50 MB of database space
Required PHP Extensions
-----------------------
* PHP CUrl Extension (w/ SSL Support) <https://secure.php.net/manual/en/curl.setup.php>
* PHP Multibyte String Support <https://secure.php.net/manual/en/mbstring.setup.php>
* PHP PDO MySQL Extension (https://secure.php.net/manual/en/ref.pdo-mysql.php)
* PHP Zip Extension (https://secure.php.net/manual/en/book.zip.php)
* PHP EXIF Extension (https://secure.php.net/manual/en/book.exif.php)
* PHP INTL Extension (https://secure.php.net/manual/en/intro.intl.php)
* PHP FileInfo Extension (https://secure.php.net/manual/en/fileinfo.installation.php)
* PHP CUrl Extension (w/ SSL Support) <http://de1.php.net/manual/en/curl.setup.php>
* PHP Multibyte String Support <http://php.net/manual/en/mbstring.setup.php>
* PHP PDO MySQL Extension (http://www.php.net/manual/en/ref.pdo-mysql.php)
* PHP Zip Extension (http://php.net/manual/en/book.zip.php)
* PHP EXIF Extension (http://php.net/manual/en/book.exif.php)
* PHP INTL Extension (http://php.net/manual/en/intro.intl.php)
* PHP FileInfo Extension (http://php.net/manual/en/fileinfo.installation.php)
Optional PHP Extensions
-----------------------
* ImageMagick
* PHP LDAP Support
* PHP APC
* PHP Memcached
Database
--------
The database user you tell HumHub to connect with must have the following privileges:

View File

@ -18,7 +18,7 @@ cd /path/to/humhub/protected
php yii search/rebuild
```
or by means of [grunt](../developer/build.md):
or by means of [grunt](../developer/core-build.md):
```
grunt build-search
@ -27,7 +27,7 @@ grunt build-search
Zend Lucence Engine
--------------------
By default, HumHub is using a *Lucence* Index (Zend Lucence) to store search data.
By default HumHub is using a *Lucence* Index (Zend Lucence) to store search data.
Default database folder: `/protected/runtime/searchdb/`
@ -43,4 +43,32 @@ You can modify the default search directory in the [configuration](advanced-conf
]
// ...
];
```
```
### Limitations
The Zend Lucence Engine runs inside the PHP process and is limited by the
settings of the PHP environment in terms of memory usage and execution time.
By default Zend Lucence Engine sets a limit on the number of terms in a search query,
which also results in a limitation of the number of items a search term can match.
For the space search this must be set at least as high as the number of spaces.
In general the limit depends on the number of items a search term can match so it
highly depends on the content. To be sure all searches work you can set it higher than the
number of spaces/users/content you have.
It can be set to 0 for no limitation, but that may result in search queries
to fail caused by high memory usage.
You can [configure](advanced-configuration.md) the limit by setting `searchItemLimit` on the `search` application component:
```php
return [
'components' => [
'search' => [
'searchItemLimit' => 10000,
],
],
];
```

View File

@ -1,24 +1,24 @@
Spaces
=======
Spaces are one of the main concepts of HumHub for separating and categorizing content like posts, wikis and polls. A space
Spaces are one of the main concepts of HumHub for seperating and categorizing content like posts, wikis and polls. A space
can be described as an independent content container with its own users, permissions and access settings.
A space can be used by space members to share content with other users.
## Add Spaces
Administrators can configure which groups are allowed to create new spaces under **Administration->Groups->Permissions**.
Please read the [Group Section](admin-groups.md) for more information about groups.
Please read the [Group Section](admin-groups.md) for more information about goups.
Spaces can be added by clicking _Add Space_ within the _Space Navigation_.
A new space will require at least a space name. Furthermore, you are able to define a space color, a description and advanced access settings.
A new space will require at least a space name. Futhermore you are able to define a space color, a description and advanced access settings.
The access settings consists of:
- **Join Policy**: Describes who can join the new space.
- **Only by invitation**: Only invited users can join the space.
- **Invite and request**: Users can request a space membership besides beeing invited.
- **Only by invite**: Only invited users can join the space.
- **Invite and request**: Users can request a space membership beside beeing invited.
- **Everyone can enter**: All members can join a space
- **Visibility**: Who can view the space content.
- **Public**: All Users (Registered and Guests users). Available when allowing limited access for non-authenticated users (guests) by admin settings.
- **Public**: All Users (Registered and Guests users). Available when allow limited access for non-authenticated users (guests) by admin settings.
- **Public (registered only)**: All registered users in Humbub (no guests)
- **Private**: This space is invisible for non-space-members
@ -28,7 +28,7 @@ Users can be invited by clicking on the _Invite_ button within the space top men
## Approve New User
New user requests can be viewed, declined or approved under _Space Settings -> Members -> Pending Approvals_
New user requests can be viewed, declinded or approved under _Space Settings -> Members -> Pending Approvals_
## Pending Invites
@ -37,13 +37,13 @@ Pending Invites can be viewed and rejected under _Space Settings -> Members -> P
## Manage Space Members
All members of a Space can be viewed under _Space Settings -> Members_. In this view space administrators are able to remove members
and assign a specific space group to members.
and assign a specfic space group to members.
## Manage Space Permission
Space Permissions can be configured under _Space Settings -> Members -> Permissions.
The permissions can be assigned to specific space groups which can either be assigned
to a user in the _Members_ configuration or are assigned by default (guests/normal user)
to an user in the _Members_ configuration or are assigned by default (guests/normal user)
The available space groups are:
- Owner: The owner of this space (the owner can be assigned by the founder of the group)

View File

@ -19,7 +19,7 @@ Github - Bugtracker
**When filing a new bug, please include:**
- Descriptive title - use keywords so others can find your bug (avoiding duplicates)
- Specific and repeatable steps that trigger the problem
- Steps to trigger the problem that are specific, and repeatable
- What happens when you follow the steps, and what you expected to happen instead.
- Include the exact text of any error messages if applicable (or upload screenshots).
- HumHub version (or if you're pulling directly from Git, your current commit SHA - use git rev-parse HEAD)
@ -28,16 +28,6 @@ Github - Bugtracker
- Modules? Confirm that you've tested with Debug > Reload Without Extensions first (see below).
- Any errors logged in Debug > Show Developer Tools - Console view
Cron Job Setup
----------------------------------------
- Do you have access to setup Cron Jobs?
- Does your server use Cron or Crontab?
- Does your server use a third-party Cron Job provider?
- Are you using VPS or Dedicated/Shared/Other Hosting?
- Can you provide screenshots of your Cron Job settings? (With personal information blurred out!)
- What type of server are you using? (CloudLinux CentOS 6, Windows IIS, or etc)
> Note: For more help refer to [here](cron-jobs.md)!
Direct Support (Enterprise Edition only)
----------------------------------------

View File

@ -1,8 +1,9 @@
Updating to 0.20
================
> NOTE: This guide only affects updates from HumHub 0.11.2 or lower to HumHub 0.20
1. Before you run an update please check, if your installed modules and themes are compatible with your targeted version. If not, you can follow the [Theme Migration Guide](../theme/migrate.md) and [Module Migration Guide](../developer/migration-guide.md) to make everything ready for the new version.
1. Before you run an update please check, if your installed modules and themes are compatible with your targeted version. If not, you can follow the [Theme Migration Guide](theming-migrate.md) and [Module Migration Guide](dev-migrate.md) to make everything ready for the new version.
2. Backup your data:
- Backup the whole HumHub installation folder from your webroot
@ -11,7 +12,7 @@ Updating to 0.20
## Migration Steps
1. Delete your current HumHub installation (Don't forget to make a backup as mentioned above, you will need these files later!)
2. Download the latest HumHub package directly from [https://www.humhub.org/download](https://www.humhub.org/download) and extract it to your webroot or install it via [GitHub/Composer](../developer/git-installation.md).
2. Download the latest HumHub package directly from [http://www.humhub.org/downloads](http://www.humhub.org/downloads) and extract it to your webroot or install it via [GitHub/Composer](admin-installation.md).
3. **IMPORTANT**: Before starting the Web installer you have to restore the /uploads/ directory form your backup to your new installation
4. Start the Web installer (e.g. [http://localhost/humhub](http://localhost/humhub)) and follow the instructions. If you enter the database name from your previous installation, HumHub will automatically migrate your existing database to the new version
5. Reinstall all previously installed modules/themes

View File

@ -3,7 +3,7 @@ Automatic Updating
> Warning: Please check before you run an update, that your installed modules and themes are compatible with the new version. If not, you can follow the migration guides.
- [Theme Migration Guide](../theme/migrate.md)
- [Module Migration Guide](../developer/migration-guide.md)
- [Module Migration Guide](../developer/modules-migrate.md)
> NOTE: Backup your data before updating! See: [Backup Chapter](backup.md)
@ -24,4 +24,4 @@ Updater Module Installation
Troubleshooting
---------------
TBD
TBD

View File

@ -1,16 +1,18 @@
Updating
========
> Warning: Please check before you run an update, that your installed modules and themes are compatible with the new version. If not, you can follow the migration guides.
- [Theme Migration Guide](../theme/migrate.md)
- [Module Migration Guide](../developer/migration-guide.md)
- [Module Migration Guide](../developer/modules-migrate.md)
> NOTE: Only use this guide if you want to update from HumHub 0.20 or higher!
> If you want to update from an older version (e.g. 0.11.2 or lower) to HumHub 0.20+, you have to use this guide: **[Upgrade to 0.20 and above](updating-020.md "Guide: Upgrade to 0.20 and above")**
> If you want to update from an older version (e.g. 0.11.2 or lower) to HumHub 0.20+, you have to use this guide: **[Upgrade to 0.20 and above](admin-updating-020.md "Guide: Upgrade to 0.20 and above")**
> NOTE: Backup your data before updating! See: [Backup Chapter](backup.md)
1. Delete your current HumHub installation (Don't forget to make a backup as mentioned above, you will need these files later!)
2. Download the latest HumHub package from [https://www.humhub.org/download](https://www.humhub.org/download) and extract the package to your webroot
2. Download the latest HumHub package from [http://www.humhub.org/downloads](http://www.humhub.org/downloads) and extract the package to your webroot
3. Restore the following files from backup:
- /uploads/*
- /protected/runtime

View File

@ -1,11 +0,0 @@
# Basics
Core Features
---------------
* [Markdown Cheatsheet](core/md-cheatsheet.md)
* [Emoji Cheatsheet](core/emoji-cheatsheet.md)
Module Features
---------------
`TBA`

View File

@ -1,11 +0,0 @@
# Emoji Cheatsheet
The following is a cheatsheet for the Emoji feature of HumHub
| Emoji Code | Emoji Rendered|
| --- | --- |
| `:smile:` | :smile: |
| `:frown:` | :frown: (Doesn't render on GitHub because it is `frowning`) |
| `:tongue:`| :tongue: |
> Will add more later as it will take some time to finish...

View File

@ -1,113 +0,0 @@
# Markdown Cheatsheet
The following are supported Markdown syntax for the Social Networking Kit [HumHub](https://www.humhub.org)
### Headers
```
# This is an <h1> tag
## This is an <h2> tag
### This is an <h3> tag
#### This is an <h4> tag
##### This is an <h5> tag
###### This is an <h6> tag
```
### Blockquotes
```
As Kanye West said:
> We're living the future so
> the present is our past.
```
### Emphasis
#### Bold
```
**This text will be bold**
__This will also be bold__
```
#### Italic
```
*This text will be italic*
_This will also be italic_
```
> Note: `_You **can** combine both as well_`
### Code
#### Inline Code
```
I think you should use an
`<addr>` element here instead.
```
#### Syntax highlighting
```
\```javascript
function fancyAlert(arg) {
if(arg) {
$.facebox({div:'#foo'})
}
}
```\
```
> Note: That all "`\`" must be removed and all "<code>```</code>" must be on its own line for Syntax highlighting to work!
### Lists
#### Unordered
```
* Item 1
* Item 2
* Item 2a
* Item 2b
```
#### Ordered
```
1. Item 1
2. Item 2
3. Item 3
a. Item 3a
b. Item 3b
```
### Links
```
http://github.com - automatic!
[GitHub](http://github.com)
```
### Images
#### Non-Linked Images
```
![GitHub Logo](/images/logo.png)
Format: ![Alt Text](image url) - Note: Must have a image file type or won't work.
```
#### Linked Images
```
[![Alt Text](/images/logo.png)](www.example.com) - Note: Must have a image file type or won't work.
```
### Tables
```
First Header | Second Header
------------ | -------------
Content from cell 1 | Content from cell 2
Content in the first column | Content in the second column
```
### Strikethrough
```
~~this~~
```
### Ignoring Markdown formatting
```
Let's rename \*our-new-project\* to \*our-old-project\*.
```

View File

@ -1,12 +1,12 @@
Bundled Software / Libaries
===========================
> This list may be incomplete!
> This list may incomplete!
* Yii Framework (Core Framework) http://www.yiiframework.com/ (protected/vendors/yii/LICENSE)
* Zend Framework http://framework.zend.com/ (protected/vendors/Zend/LICENSE.txt, protected/vendors/Zend2/LICENSE.txt)
* Yii Framework (Core Framework) http://www.yiiframework.com/ (protected/vendor/yiisoft/yii2/LICENSE.md)
* Zend Framework http://framework.zend.com/ (protected/vendor/zendframework/zend-\*/LICENSE.md)
* Code Igniter (Security Functions) http://ellislab.com/codeigniter
* Yii Extensions (See /protected/extensions/)
* Various Yii Extensions
* Yii-Mail - http://www.yiiframework.com/extension/mail/
* SwiftMailer - http://swiftmailer.org
* jQuery - http://jquery.com

View File

@ -4,54 +4,41 @@ Developement Guide
Getting Started
---------------
* [Overview](overview.md)
* [Git/Composer Installation](git-installation.md)
* [Coding Standards](coding-standards.md)
* [Git Installation](git-installation.md)
* [Development Environment](environment.md)
* [Migration Guide](migration-guide.md)
* [Coding Standards](coding-standards.md)
Modules
---------------
* [Getting Started](modules.md)
* [Asset Management](assets.md)
* [Change core behavior](module-change-behavior.md)
* [Embedded Themes](embedded-themes.md)
* [Migration / Updates](migration.md)
Basic Concepts
Module Development
------------------
* [Introduction](modules-index.md)
* [Basic Structure](modules-structure.md)
* [Migration/Updates](modules-migrate.md)
* [Content](content.md)
* [Streams](stream.md)
* [Events](events.md)
* [Settings and Configuration](settings.md)
* [Models / Database](models.md)
* [Permissions](permissions.md)
* [Notifications](notifications.md)
* [Activities](activities.md)
* [File Handling](files.md)
* [Widgets](widgets.md)
* [Snippets](snippet.md)
* [Internationalization](i18n.md)
* [Events](modules-events.md)
* [Settings and Configuration](modules-settings.md)
* [Models / Database](modules-db.md)
* [Internationalization](modules-i18n.md)
Javascript API
------------------
* [Modules](javascript-index.md)
* [Components](javascript-components.md)
* [Additions](javascript-components.md)
* [Additions](javascript-uiadditions.md)
* [Actions](javascript-actions.md)
* [Client](javascript-client.md)
* [Modals](javascript-modals.md)
* [Events](javascript-events.md)
* [Widgets](javascript-widgets.md)
* [Pjax](javascript-pjax.md)
Advanced Topics
Special Topics
--------------
* [HumHub Build](build.md)
* [Notifications](notifications.md)
* [Activities](activities.md)
* [Authentication](authentication.md)
* [Events](events.md)
* [Live Updates](live.md)
* [Search](search.md)
* [Security](security.md)
* [Console Application](console.md)
* [Streams](stream.md)
* [Permissions](permissions.md)
* [Widgets](widgets.md)

View File

@ -1,5 +0,0 @@
Asset Management
=====================
(TBD)
(TBD:getPublishedUrl)

View File

@ -1,63 +0,0 @@
HumHub Build
============
## Setup
1. Install NPM
2. Install Grunt (http://gruntjs.com/getting-started)
3. call `npm update` in humhub root
> Note: Since symlinks are not supported in some virtual machine shared folders the update command should be called from the host.
## Setup grunt dependencies
Call the following commands in your humhub root directory:
- `npm update`
- `npm install grunt --save-dev`
## Build Assets
HumHub uses Yiis build in mechanism for compressing and combining assets as javascript or stylesheet files in combination with grunt.
Your compressed files will be saved under `/humhub/js/all-*.js` respectively `static/css/all-*.css`.
> Note: HumHub will only use the compressed assets if operated in [production mode](admin-installation.md#disable-errors-debugging), otherwise
all assets will be served seperatly.
### Grunt Asset Built
The simples way to build your production assets is using the following grunt task:
```
grunt build-assets
```
### Manual Asset Built
1. Delete the content of your `static/assets` directory.
2. Delete the old compressed file `static/js/all-*.js` and `static/css/all-*.css`
2. Run:
```
php yii asset humhub/config/assets.php humhub/config/assets-prod.php
```
> Info: More information is available in the [Yii Asset Guide](http://www.yiiframework.com/doc-2.0/guide-structure-assets.html#combining-compressing-assets).
## Build Community Theme
To rebuild the community themes `theme.css` file you can execute one of the following commands:
```
lessc -x themes/HumHub/less/build.less themes/HumHub/css/theme.css
```
or with grunt:
```
grunt build-theme
```
### Other Grunt Tasks
- `grunt build-search` Rebuild your [Search Index](../admin/search.md)

View File

@ -1,196 +1,6 @@
Content
=======
Content record classes as for example `Post`, `Poll` and `Wiki` are subclasses of
[[\humhub\modules\content\components\ContentContainerActiveRecord]].
Instances ofand are related to a
[[humhub\modules\content\models\Content]] record.
A ContentContainerActiveRecord subclass provides all features of a basic
Yii [ActiveRecords](http://www.yiiframework.com/doc-2.0/yii-db-activerecord.html) as validation and data access methods,
please refer to the [Yii Guide](http://www.yiiframework.com/doc-2.0/guide-db-active-record.html) for more information
about [ActiveRecords](http://www.yiiframework.com/doc-2.0/yii-db-activerecord.html).
While the ContentContainerActiveRecord class contains the actual content data as texts and content settings, the related Content instance is beside others used to check **Permissions**, the **ContentContainer** relation, content **visibility** and is furthermore connected to ContentAddons as Like and Comments.
Beside the basic ActiveRecord methods your ContentContainerActiveRecord class should at least implement the following functions
- `getContentName()` - short name/type of content
- `getContentDescription()` - returns a short description of the content instance used to preview the content for example in activities etc.
```php
class Example extends \humhub\modules\content\components\ContentContainerActiveRecord
{
public static function tableName()
{
return 'example_content';
}
public function getContentName()
{
return Yii::t('ExampleModule.models_Example', "Example");
}
public function getContentDescription()
{
return $this->question;
}
public function rules()
{
//return validation rules
}
.....
}
```
Your content model should be **instantiated** as follows:
```php
// Instantiate my model assign a content container and visibility.
$model = new MyModel();
$model->content->container = $someSpace;
$model->content->container = Content::VISIBILITY_PRIVATE;
...
// Save model and content
$model->save();
```
Get the model instance from a given content instance:
```php
$model = $content->getPolymorphicRelation();
```
Calling [[\humhub\modules\content\components\ContentActiveRecord::find()]] will return a [[\humhub\modules\content\components\ActiveQueryContent]] with additional methods to select specific content:
```php
// Returns all MyModels related to the given $space
$models = MyModel::find()->contentContainer($space)->all();
// Returns all MyModels related to the given $space and readable by the current user
$models = MyModel::find()->contentContainer($space)->readable()->all();
// Loads all MyModels of the current users member spaces
$models = MyModel::find()->userRelated([ActiveQueryContent::USER_RELATED_SCOPE_SPACES])->all();
// Loads all readable MyModels of the current users spaces and also followed spaces
$models = MyModel::find()->userRelated([
ActiveQueryContent::USER_RELATED_SCOPE_SPACES,
ActiveQueryContent::USER_RELATED_SCOPE_FOLLOWED_SPACES
])->readable()->all();
```
There are the following user related scopes available:
- `USER_RELATED_SCOPE_OWN` Content created by the given user itself (`content.created_by`)
- `USER_RELATED_SCOPE_SPACES` Content related to the users member spaces
- `USER_RELATED_SCOPE_FOLLOWED_SPACES` = Content related to the users followed spaces
- `USER_RELATED_SCOPE_FOLLOWED_USERS` = Content related to the users followed user profiles
- `USER_RELATED_SCOPE_OWN_PROFILE` = Content related to the users own profile
### Content features
**Content visibility**
The content visibility can be checked by calling `isPublic()` and `isPrivate()`.
```php
$model->content->isPublic();
$model->content->isPrivate();
// Set visibility
$model->content->container = Content::VISIBILITY_PRIVATE;
```
**Pin content**
The default space stream supports the pinning of content, which will load the pinned entries at the top of the
stream. Normally you won't need to call the pin/unpin methods by yourself, since this is part of the default stream
entry logic. In case your content is not part of the default stream, you may use these functions for your own module logic.
```php
$model->content->pin();
$model->content->unpin();
$model->content->isPinned();
$model->content->canPin();
```
**Archive content**
Archived content is by default excluded from the streams. As with the pin logic, you won't have to handle this by yourself.
```php
$model->content->archive();
$model->content->unarchive();
$model->content->isArchived();
$model->content->canArchive();
```
**Content Url**
By default the `Content::getUrl()` returns the permalink of the wallentry. In case the content is used outside of the default stream, this behaviour can be changed by implementing a `getUrl()` method in your ContentActiveRecord class.
```php
$permaLink = $model->content->getUrl();
```
### Check content permissions
By default a user can edit a content if one of the following conditions defined in `Content::canEdit()` are met:
- User is the owner of the content
- User is system administrator and the content module setting `adminCanEditAllContent` is set to true (default)
- The user is granted the space ManagePermission set by the model record class. Since v1.2.1 a ContentContainerActiveRecord can define an own `$managePermission` which will be described later.
- The user meets the additional condition, which is defined in the ContentContainerActiveRecords `canEdit()` function.
You can check the edit permission of a user by means of the `Content::canEdit()` function as
```php
// Check edit permission for current logged user
if($model->content->canEdit()) {...}
// Check edit permission for a given user
if($model->content->canEdit($someUserIdentity)) {...}
// Check other permission for the current logged user on the contents contentContainer
if($model->content->can(new MyCustomPermission()) {...}
```
Since HumHub v1.2.1 you can overwrite the default ManageContent permission as follows:
```php
class Example extends ContentContainerActiveRecord
{
$managePermission = MyCustomManagePermission::class;
.....
}
```
The default `Content::canView()` permission behaviour of content is handled as follows
- Guests can only access public content of visible spaces/users
- Other users can access all public content within the network
- System admins can access all content if the `adminCanViewAllContent` setting of the `content` modules is enabled (default)
- All space members can access private space content
- Non space members can only access public space content
- Only friend users can access prviate profile content of a user.
```php
if($model->content->canView()) {...}
```
>Info: For more information about permissions, please see the [Permission Section](module-permissions.md).
## ContentContainer
A [[humhub\modules\content\models\ContentContainer|ContentContainer]] in HumHub is the base concept for assigning content entries to a specific container instance (user or space).
@ -217,6 +27,8 @@ The [[humhub\modules\content\components\ContentContainerController|ContentContai
- Layout selection based on container type (User or Space)
- Create URL's for the given ContentContainer
For example:
```php
class ExampleController extends \humhub\modules\content\components\ContentContainerController
{
@ -229,7 +41,8 @@ class ExampleController extends \humhub\modules\content\components\ContentContai
}
```
Urls pointing to a ContentContainer action should be created by using the `createUrl()` function of your ContentContainer instance. This will add the required sguid or uguid to your request.
Url's pointing to a ContentContainer action should be created by using the `createUrl()` function
of your ContentContainer instance. This will add the required sguid or uguid to your request.
```php
// Direct ContentContainer call
@ -262,19 +75,112 @@ if($profileImage->hasImage()) {
### ContentContainerModule
See the [Getting Started](modules-index.md) section
If a module should appear in the content containers module section, the module class must extend [[humhub\modules\content\components\ContentContainerModule]].
A ContentContainerModule can be enabled or disabled for a specific ContentContainer. The calendar module, for example, can be enabled for a specific space or a specific user account.
#### Content Streams
See the [[humhub\modules\content\components\ContentContainerModule]] class for a full list of options.
See the [Stream](stream.md) section
Example of a modules `Module.php` file:
## Global content
```php
class Module extends \humhub\modules\content\components\ContentContainerModule
{
// Defines for which content container type this module is appropriate
public function getContentContainerTypes()
{
// This content container can be assigned to Spaces and User
return [
Space::className(),
User::className(),
];
}
// Is called when the whole module is disabled
public function disable()
{
// Clear all Module data and call parent disable
parent::disable();
}
// Is called when the module is disabled on a specific container
public function disableContentContainer(ContentContainerActiveRecord $container)
{
parent::disableContentContainer($container);
//Here you can clear all data related to the given container
}
// Can be used to define a specific description text for different container types
public function getContentContainerDescription(ContentContainerActiveRecord $container)
{
if ($container instanceof Space) {
return Yii::t('MyModule.base', 'Description related to spaces.');
} elseif ($container instanceof User) {
return Yii::t('MyModule.base', 'Description related to user.');
}
}
```
> Note: If you're working with content or other persistent data, make sure to delete container related data when the module is disabled on a contentcontainer. This can be archieved by overwriting the [[humhub\modules\content\components\ContentContainerModule::disableContentContainer]] function.
## Content
TBD
### ContentActiveRecord
Each Content ActiveRecord (derived from [[\humhub\modules\content\components\ContentActiveRecord]]) is automatically linked to a [[humhub\modules\content\models\Content]] record via the *content* attribute.
This Content record holds all neccessary information and provides common methods:
- ContentContainer which the Content belongs to
- Meta Information (created_at, created_by, updated_at, updated_by)
- Wall Assignments / Methods
- Archiving / Pinning
- And more...
If you're implementing an ActiveRecord based on [[humhub\modules\content\components\ContentContainerActiveRecord]] you need to implement the following abstract methods:
- `getContentName()` - Returns the displayed name of the Content (e.g. Post or Poll)
- `getContentDescription()` - Returns a preview of the Content - which is used in Notifications for example.
Example:
```php
(TBD)
```
#### Wall/Stream Output
(TBD)
## Content addons
#### Querying Content
If you're calling find() on a [[\humhub\modules\content\components\ContentActiveRecord]] instance you'll get a special [[\humhub\modules\content\components\ActiveQueryContent]] which provides additional methods to select content.
- contentContainer($container) - Find content only inside a given container
- readable($user) - Return only user readable content
- ...
### Controller
TBD
## ContentAddon
TBD
- Always linked to particual Content, inherits access rules from it
- Examples: Like, File, Comment
- Can be nested (e.g. Container -> Content -> Addon (Comment) -> Addon (Like)
### ActiveRecord
TBD
Provides access to the related content via *content *Attribute
### Controller
TBD

View File

@ -1,24 +1,3 @@
# Contributing
## Report an Issue
**Do not report an issue if**
- *you are asking how to use a HumHub feature. You should use [the community](https://community.humhub.com) for this purpose.*
- *your issue is about security. Please [contact us directly](mailto:info@humhub.com) to report security issues.*
**Avoid duplicated issues**
Before you report an issue, please search through [existing issues](https://github.com/buddh4/humhub-docs/issues) to see if your issue is already reported or fixed to make sure you are not reporting a duplicated issue.
Also make sure you have the latest version of HumHub and see if the issue still exists.
## Contribute to the Docs or fix grammar errors (Pull Requests)
Third-party patches are essential for keeping the HumHub Docs great.
We want to keep it as easy as possible to contribute changes that get things working in your environment.
There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
- *Make sure you have a [GitHub account](https://github.com/signup/free)*
- *Fork the repository on GitHub*
- *Make sure there isn't an issue created for the thing you are working on if it requires significant effort to fix*
- *Open a pull request*
TBD

View File

@ -1,2 +0,0 @@
Embedded themes
=================

View File

@ -4,53 +4,50 @@ Development Environment
Quick Notes
-----------
- Make sure you are using a [Git/Composer HumHub installation](git-installation.md)
- Enable the debug mode, see [Disable Errors Section](../admin/security.md#disable-errors-debugging)
- Disable caching under `Administration -> Settings -> Advanced -> Caching -> None`
- Make sure you are using a [Git/Composer HumHub Installation](git-installation.md)
- Enable development mode, see [Disable Errors Section](../admin/security.md#disable-errors-debugging)
- Disable Caching under `Administration -> Settings -> Advanced -> Caching -> None`
External Modules Directory
> Tip: If you are working on a windows machine, but wan't to operate your test environment on linux, you should consider using a virtual machine with a shared host directory.
Modules Directory
-----------------
Custom modules can also be located outside of the default HumHub modules directory by
setting the `moduleAutoloadPaths` parameter in your `/protected/config/common.php` configuration. This seperation can
be useful while working with custom modules.
You can locate your custom modules outside of the HumHub project directory by means of the following [configuration](../admin/advanced-configuration.md#application-params)
```php
return [
//...
'params' => [
'moduleAutoloadPaths' => ['/some/folder/modules'],
],
//...
]
]
```
Yii Debug Module
----------------
Add following block to your local web configuration `/protected/config/web.php` in order
to allow [Yii's debug Module](http://www.yiiframework.com/doc-2.0/ext-debug-index.html).
Add the following block to your local web configuration `/protected/config/web.php` to enable the [Debug Extension for Yii 2](http://www.yiiframework.com/doc-2.0/ext-debug-index.html)
```php
<?php
return [
// ...
'bootstrap' => ['debug'],
'modules' => [
// ...
'debug' => [
'class' => 'yii\debug\Module',
'allowedIPs' => ['127.0.0.1', '::1'],
],
// ...
]
'modules' => [
'debug' => [
'class' => 'yii\debug\Module',
'allowedIPs' => ['127.0.0.1', '::1'],
],
]
];
?>
```
Gii Code Generator
-------------------
Add following block to your local web configuration `/protected/config/web.php` in order to
enable the [Gii Code Generator Module](http://www.yiiframework.com/doc-2.0/guide-start-gii.html)
Add following block to your local web configuration `/protected/config/web.php` to enable the [Gii Code Generator](http://www.yiiframework.com/doc-2.0/guide-start-gii.html)
```php
return [
@ -67,7 +64,7 @@ return [
?>
```
Furthermore add the following block to your local console configuration `/protected/config/console.php`
Furthermore add the following block to your local console configuration (/protected/config/console.php)
```php
return [
@ -80,7 +77,76 @@ return [
];
```
Developer Tools Module
-------------------
> Tip: Check out the [HumHub devtools](https://github.com/humhub/humhub-modules-devtools) module for a HumHub module generator and some showcases and tutorials. At the time of writing, the devtools Module is still under developement.
HumHub Build
-----------
Some of the tasks
### Setup
1. Install NPM
2. Install Grunt (http://gruntjs.com/getting-started)
3. call `npm update` in humhub root
> Note: Since symlinks are not supported in some virtual machine shared folders the update command should be called from the host.
#### Setup grunt dependencies
Call the following commands in your humhub root directory:
- `npm update`
- `npm install grunt --save-dev`
### Build Production Assets
HumHub uses Yiis build-in mechanism for compressing and combining assets as javascript or stylesheet files in combination with grunt.
Your compressed files will be saved under `/humhub/js/all-*.js` respectively `static/css/all-*.css`. The task will also rebuild your `static/assets` folder, which contains dependent production assets.
> Info: HumHub will only use the compressed assets if operated in [production mode](admin-installation.md#disable-errors-debugging), otherwise all assets will be served seperatly.
##### Grunt Asset Built
The simples way to build your production assets is using the following grunt task:
```
grunt build-assets
```
##### Manual Asset Built
1. Delete the content of your `static/assets` directory.
2. Delete the old compressed file `static/js/all-*.js` and `static/css/all-*.css`
2. Run:
```
php yii asset humhub/config/assets.php humhub/config/assets-prod.php
```
> Info: More information is available in the [Yii Asset Guide](http://www.yiiframework.com/doc-2.0/guide-structure-assets.html#combining-compressing-assets).
### Build Theme
To rebuild the community themes `theme.css` file you can execute one of the following commands:
```
lessc -x themes/HumHub/less/build.less themes/HumHub/css/theme.css
```
or with grunt:
```
grunt build-theme
```
You can also build other themes within your `themes` folder as follows
```
grunt build-theme --name=myTheme
```
### Other Grunt Tasks
- `grunt build-search` Rebuild your [Search Index](../admin/search.md)
The [devtools Module](https://github.com/humhub/humhub-modules-devtools) provides useful showcases of widgets and also a Module generator based on Gii.

View File

@ -1,41 +0,0 @@
Events
======
TBD
[http://www.yiiframework.com/doc-2.0/guide-concept-events.html](http://www.yiiframework.com/doc-2.0/guide-concept-events.html)
### Catching an Event
Example event section of the config.php file:
```php
// ...
'events' => [
[
'class' => \humhub\widgets\TopMenu::className(),
'event' => \humhub\widgets\TopMenu::EVENT_INIT,
'callback' => [Module::className(), 'onTopMenuInit'],
],
// ...
]
// ...
```
### Processing
Example of event callback:
```php
public static function onTopMenuInit($event)
{
$event->sender->addItem(array(
'label' => "Example",
'icon' => '<i class="fa fa-tachometer"></i>',
'url' => '#',
'sortOrder' => 200,
));
}
```

View File

@ -1,9 +1,11 @@
Installation (Developers)
Git Installation (Developers)
=========================
> Warning: This installation method allows you to fetch the latest branch from the repository which may not stable enough for production use.
> Warning: This installation method allows you to fetch the latest version from our git repository. Since the master branch is not always in a stable state, this branch is not intended for production use.
Preparation
-----------
Create a MySQL Database, e.g.:
```sql
@ -14,23 +16,53 @@ FLUSH PRIVILEGES;
> Note: Do not forget to change the `humhub_dbuser` and `password_changeme` placeholders!
Get HumHub
----------
- Install [git](https://git-scm.com/)
- Clone git Repository:
In order to be able to install a branch fetched by git, you'll have to run a composer update to download external dependencies.
1. Clone Git Repository:
```
git clone https://github.com/humhub/humhub.git
```
- Install composer ([https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md))
- Navigate to your HumHub webroot and fetch dependencies:
2. Install composer ([https://getcomposer.org/doc/00-intro.md](https://getcomposer.org/doc/00-intro.md))
3. Navigate to your HumHub webroot and fetch dependencies:
```
php composer.phar global require "fxp/composer-asset-plugin:~1.3"
php composer.phar global require "fxp/composer-asset-plugin:^1.4.2"
php composer.phar update
```
> 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.md))
- Follow further instructions of the [Installation Guide](../admin/installation.md)
> 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))
File Settings & Permissions
---------------------------
Make the following directories/files writable by the webserver
- /assets
- /protected/config/
- /protected/modules
- /protected/runtime
- /uploads/*
Make the following files executable:
- /protected/yii
- /protected/yii.bat
> Warning: Make sure the following directories are not accessible through the webserver!
Start Web Installer
---------------
Open the installation guide in your browser (e.g. [http://localhost/humhub](http://localhost/humhub))

View File

@ -1,28 +0,0 @@
Internationalization (I18N)
===========================
**Optionally** you can use following module translation method instead of Yii's standard approach (<http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html#translating-module-messages>).
For Internationalization to work properly, you should also consider the notes on [Setting Up PHP Environment](http://www.yiiframework.com/doc-2.0/guide-tutorial-i18n.html#setup-environment)
from the Yii Guide.
### Message Category
Following message category syntax is automatically mapped against your modules *messages* folder.
```php
Yii::t('ExampleModule.some_own_category', 'Translate me');
```
Base Category Naming Examples:
- polls -> PollsModule
- custom_pages -> CustomPagesModule
### (Re-) Generate message files
Example message creation command for module with id *example*:
> php yii message/extract-module *example*

View File

@ -1,7 +1,7 @@
Javascript UI Components
=======
UI Components can be used to bind specific dom parts of your view to a Javascript Widgets defined in your module. This can be achieved by extending the `action.Component` or the more powerful `ui.Widget` class.
UI Components can be used to bind specific parts of your view to a Javascript Widgets defined in your module. This can be achieved by extending the `action.Component` or the more powerful `ui.Widget` class.
## Simple Components
@ -29,13 +29,13 @@ humhub.module('example.MyComponent', function(module, require, $) {
Component.call(this, node, options);
}
// Make sure this is called before your function definitions, otherwise they will be lost!
object.inhertis(MyComponent, Component);
MyComponent.prototype.hello = function(evt) {
this.$.find('.message').text('Hi!');
}
// Export a single class
module.export = MyComponent;
});
```
@ -46,7 +46,7 @@ After clicking the button of the previous example the `action` module will searc
If you need the instance of your component, for example in another module, you can retrieve it by calling `Component.instance`:
```Javascript
```javascript
humhub.module('example.two', function(module, require, $) {
var Component = require('action').Component;
@ -75,12 +75,12 @@ Components can be nested, which can be handy for example if you want to implemen
###### Module:
```Javascript
```javascript
humhub.module('example.mylist', function(module, require, $) {
var object = require('util').object;
var Component = require('action').Component;
// our parent component
// our parent component
var List = function(node, options) {
Component.call(this, node, options);
}
@ -115,21 +115,22 @@ humhub.module('example.mylist', function(module, require, $) {
});
});
```
> Note: The `data` function of a component will search for a given data attribute on the components own root node and if not present will search the parent components for the data attribute.
## Widgets
The `humhub.modules.ui.widget.Widget` class extends the `Component` class and provides some additional functionality as:
The `humhub.modules.ui.widget.Widget` class extends the `action.Component` class and provides some additional functionality as:
- Advanced event handling
- Eager or lazy initialization
- Eager initialization
- Widget options
#### Widget Initialization
A Widgets `init` function is called once the widget is created. A Widget is created either immediately within the humhub initialization phase in case the widgets root node contains a `data-ui-init` flag or by lazily creating it when calling a widget action or initializing the Widget by means of calling `Widget.instance('#myWidget')`.
A Widgets `init` function is called once the widget is created. A Widget is created either immediately within the humhub initialization phase in case the widgets root node contains a `data-ui-init` flag or lazily by calling a widget action or initializing the Widget by means of calling `Widget.instance('#myWidget')`.
> Note: If you load a Widget by an ajax call, make sure to apply the `ui.additions` on your inserted dom nodes, otherwise the `data-ui-init` behavriour won't be recognized.
> Note: If you load a Widget by an ajax call, make sure to apply the [ui.additions](javascript-uiadditions.md) on your inserted dom node, otherwise the `data-ui-init` behaviour won't be recognized.
###### View:
```php
@ -156,14 +157,13 @@ humhub.module('example.MyWidget', function(module, require, $) {
this.$.fadeIn('fast');
}
// Export a single class
module.export = MyWidget;
});
```
#### Widget Options
Your widgets option can be set by using `data-*` attributes on your Widgets root node.
Your Widget options can be set by using `data-*` attributes on your Widgets root node.
The Widgets `getDefaultOptions()` method can be used to define default Widget options.
###### View:
@ -184,7 +184,6 @@ humhub.module('example.MyWidget', function(module, require, $) {
Widget.call(this, node, options);
}
// Make sure this is called before your function definitions, otherwise they will be lost!
object.inhertis(MyWidget, Widget);
var MyWidget.prototype.getDefaultOptions = function() {
@ -201,7 +200,6 @@ humhub.module('example.MyWidget', function(module, require, $) {
}
}
// Export a single class
module.export = MyWidget;
});
```
@ -213,26 +211,9 @@ TBD
#### JsWidget class
In order to implement a Yii widget responsible for rendering your widgets markup, you can implement a PHP class derivated of [[humhub\widgets\JSWidget]] as in the following examples.
In order to implement a Yii widget responsible for rendering your widgets markup, you can extend hte [[humhub\widgets\JSWidget]] class as in the following examples.
Here are some of the available attributes of the JSWidget class:
- `id`: the widget root id, if not provided a generated id will be used by default
- `jsWidget`: defines the Javascript widget namespace
- `init`: will add the data-ui-init flag if set to true
- `visible`: can be set to false in case the root node should be rendered hidden on startup
- `options`: used to overwrite or set the Widgets htmlOptions
- `events`: defines widget action events
- `container`: defines the root node name when using the default rendering mechanism
- `content`: defines the content of the root node when using the default rendering mechanism
Functions:
- `getData()`: returns an array of widget settings which will be transformed into `data-*` attributes.
- `getAttributes()`: returns an array of html attributes/values
- `getOptions()`: merges the given `options` with the result of `getData()` and `getAttributes()` and is used as root node options in most of the cases
###### Default widget rendering:
##### Default widget rendering:
The following example shows a simple JsWidget implementation without overwriting the widgets `run` method.
@ -267,6 +248,24 @@ class MyWidget extends \humhub\widgets\JsWidget
}
}
```
The following `JSWidget` attributes are available:
- `id`: the widget root id, if not provided a generated id will be used by default
- `jsWidget`: defines the Javascript widget namespace
- `init`: will add the data-ui-init flag if set to true
- `visible`: can be set to false in case the root node should be rendered hidden on startup
- `options`: used to overwrite or set the Widgets htmlOptions
- `events`: defines widget action events
- `container`: defines the root node name when using the default rendering mechanism
- `content`: defines the content of the root node when using the default rendering mechanism
Functions:
- `getData()`: returns an array of widget settings which will be transformed into `data-*` attributes.
- `getAttributes()`: returns an array of html attributes/values
- `getOptions()`: merges the given `options` with the result of `getData()` and `getAttributes()` and is used as root node options in most of the cases
> Note: in this case the `container` setting could be omitted, since `div` is the default container name.
The widget could be used within a view as follows:
@ -286,7 +285,7 @@ which would render the following output:
<div class="myWidget" data-some-setting="0" data-ui-init="1">Some content</div>
```
###### Custom widget rendering:
##### Custom widget rendering:
For more complex JsWidgets, you can overwrite your widgets `run` method and use the `getOptions` method to merge the widgets `options` with the default options provided by `getData` und `getAttributes` as follows.

View File

@ -1,19 +1,18 @@
Javascript API Getting Started
Javascript Modules
=======
Since version 1.2, HumHub provides a module based Javascript API within the `humhub` namespace.
Instead of embeding inline script blocks into your views, it's highly recommended to store your Javascript code in external script files and use the HumHub module system.
Instead of embeding inline script blocks into your views, it's highly recommended to store your Javascript code in external script files and ideally use the HumHub module system.
Your module scripts should reside in the `resources/js` directory of your modules root directory.
## Modules System
### Publish a Module Asset
Your script files should reside within the `resources/js` folder of your humhub module and should ideally be appended at the bottom of the document.
In order to add a Javascript module file to your view, you should use a [Asset Bundle](http://www.yiiframework.com/doc-2.0/guide-structure-assets.html) class residing within the `assets` directory of your module. By setting `public $jsOptions = ['position' => \yii\web\View::POS_END];`, your assets will be appended to the end of the document body. This will assure all core modules are already registered.
Be careful though, when you want to edit your files in `resources/js`. All asset files are bundled and then copied to the `@webroot`-folder of your application, when registered in the view for the first time (see below). In order to force your module assets to be re-published with each requests, you can add the publish option `forceCopy` as in the following example. This can be useful while developing your module, but don't forget to disable this option in official releases!
In order to add your script files to your view, you should use an [Asset Bundle](http://www.yiiframework.com/doc-2.0/guide-structure-assets.html) residing within the `assets` directory of your module.
By setting `public $jsOptions = ['position' => \yii\web\View::POS_END];`, your assets will be appended to the end of the document body. This will assure all core modules are already registered. If you require your script beeing loaded ealrier you can also set `\yii\web\View::POS_BEGIN`, which will add you script at the beginning of the document body.
```php
namespace humhub\modules\example\assets;
@ -22,9 +21,6 @@ use yii\web\AssetBundle;
class ExampleAsset extends AssetBundle
{
public $publishOptions = [
'forceCopy' => true
];
public $jsOptions = ['position' => \yii\web\View::POS_END];
public $sourcePath = '@example/resources';
public $js = [
@ -41,23 +37,24 @@ The [Asset Bundle](http://www.yiiframework.com/doc-2.0/guide-structure-assets.ht
Where `$this` is the view instance. More infos about Asset Bundles are available in the [Yii Guide](http://www.yiiframework.com/doc-2.0/guide-structure-assets.html).
If your bundle is registered to a view retrieved by an ajax call, make sure to render your view by using your controllers `$this->renderAjaxContent()` function. In contrast to `renderPartial()`, this function will add all your asset dependencies to your partial content.
> Note: Make sure to add your assets after the core scripts, which are added within the documents head section.
> Note: Yii loads Javascript Files only once per page load, therefore all your script files will only be loaded and executed once. This can lead to unexpected behaviour especially with [Pjax](javascript-client.md) single page loading enabled.
> Note: Yii loads Javascript Files only once per page load, therefore all your script files will only be loaded and executed once. This can lead to unexpected behaviour especially with [Pjax](javascript-client.md#pjax) single page loading enabled.
> Note: If your bundle is registered to a view retrieved by an ajax call, make sure to render your view by using your controllers `$this->renderAjaxContent()` function. In contrast to `renderPartial()`, this function will add all your asset dependencies to your partial content. Don't use the `renderAjaxContent` to include a view into your page outside of an ajax call, this will include some script twice and will lead to unexpected behaviour.
### Register Modules
Modules are registered by calling the `humhub.module` function as follows
Modules are registered by calling the `humhub.module()` function as follows
```javascript
humhub.module('example', function(module, require, $) {
...
});
```
**Submodules** can be registered as follows
The previous `example` module will be added to the following namespace `humhub.modules.example`.
You can also register sub modules as in the following example
```javascript
humhub.module('example.mySubModule', function(module, require, $) {
@ -65,9 +62,9 @@ humhub.module('example.mySubModule', function(module, require, $) {
});
```
The first argument of the `humhub.module` function defines the **module id** which will be appended to the `humhub` namespace. The previous `example` module will be added to the following namespace `humhub.modules.example`. The second argument is the actual **module function**.
The first argument of the `humhub.module()` function defines the **module id** which also defines the namespace appended to the `humhub.modules`. The second argument is the actual **module function**.
> Note: Your module id has to be unique amongst all available modules and should ideally be consistent with your backend module id.
> Note: You should use an unique namespace for your custom modules as `myproject.mymodule`, otherwise it may interfere with other modules.
Your module function is provided with the following arguments:
@ -75,15 +72,18 @@ Your module function is provided with the following arguments:
2. `require` - Used for injecting other modules.
3. `$` - jQuery instance.
##### Export Module Logic
#### Export Module Logic
Module functions and attributes can only be accessed outside of the module if they are exported, either by directly appending them to the `module` instance or by calling `module.export`.
```javascript
humhub.module('example', function(module, require, $) {
// private function
var private = function() { /* ... */ }
// export public function
module.myPublicFunction = function() {/* ... */}
// direct export of public function
module.publicFunction = function() {/* ... */}
// another public function exported later
var publicTwo = function() { /* ... */}
@ -95,28 +95,27 @@ humhub.module('example', function(module, require, $) {
});
});
```
In case you only want to **export a single object/function/class** you can use the following syntax:
```javascript
[...]
/* ... */
var MyClass = function() {/*...*/};
MyClass.prototype.myFunction = function() {/*..*/}
module.export = MyClass;
[...]
/* ... */
```
> Note: When exporting a single object or class, the exported object won't have the usual module attributes and utilities. The plain object or function will simply be added to the namespace.
> Note: When exporting a single object or class, the plain object or function will be added to the given namespace without including the usual module attributes and utilities mentioned later in this guide.
##### Module Initialization
#### Module Initialization
Your module can define its initialization logic by implementing and exporting an `init` function.
Your module can define its initialization logic by exporting an `init` function.
By default this function is only called once after a full page load or directly after the registration in case the module was loaded per ajax. If your module requires an initialization also after [Pjax](javascript-client.md) page loads, your module has to set the `initOnPjaxLoad` flag. In this case the `init` function will provide an `isPjax` parameter for beeing able to distinguish between full page loads and [Pjax](javascript-client.md) page loads.
By default this function is only called once after a full page load or directly after the registration in case the module was loaded per ajax. If your module requires an initialization also after [Pjax](javascript-client.md) page loads, your module has to set the `initOnPjaxLoad` flag. In this case the `init` function will provide an `isPjax` flag for beeing able to distinguish between full page loads and [Pjax](javascript-client.md) page loads.
```javascript
[...]
/* ... */
module.initOnPjaxLoad = true;
var init = function(isPjax) {
@ -131,14 +130,15 @@ var init = function(isPjax) {
module.export({
init: init
});
[...]
/* ... */
```
> Tip: You'll need the `initOnPjaxLoad` flag for modules which rely on specific dom elements or specific views.
> Warning: Once registered, your modules `init` function may be called even if you are not currently in your desired modules view. This occures especially if [Pjax](javascript-pjax.md) is enabled and `initOnPjaxLoad` is set to `true`. Therfore, if your modules initialization logic only makes sense in a specific context, make sure you reside in the desired view before running your actual initialization code e.g: `if(!$('#mySpecialElement').length) {return;}`.
> Warning: Once registered, your modules `init` function may be called even if you are not currently in your desired modules view. This occures especially if [Pjax](javascript-pjax.md) is enabled and `initOnPjaxLoad` is set to `true`. Therfore, if your modules initialization logic only makes sense in a specific context, make sure you reside in the desired view before running your actual initialization code e.g: `if(!$('#mySpecialViewElement').length) {return;}`.
##### Module Unload
#### Module Unload
For the purpose of cleaning up module related dom nodes etc. there is also an `unload` function which is called before each Pjax page load. This function is mainly used to remove obsolete dom nodes, prevent memory leaks, remove obsolete dom listeners or clear some module data.
For the purpose of cleaning up module related dom nodes etc. your module can export an `unload` function which is called before each Pjax page load. This function is mainly used to remove obsolete dom nodes outside of the main content area, prevent memory leaks, remove obsolete dom listeners or clear up some module data.
```javascript
var unload = function($pjax) {
@ -152,7 +152,7 @@ module.export({
> Note: Some third party libraries append helper elements to the document body. Make sure to remove such elements in the `unload` function.
##### Module Dependencies
#### Module Dependencies
Other modules can be injected into your module by using the `require` function as follows
@ -169,7 +169,7 @@ require('example').myFunction();
humhub.modules.example.myFunction();
```
It is a good practice to require all dependent modules at the beginning of your module. You should only require modules at the beginning of your module, if you are sure the required module is already registered. Since all core modules are registered in the head section of your document, they are available within the document body.
It's good practice to require all dependent modules at the beginning of your module. When doing so consider the loading order of those modules. Since all core modules are registered in the head section of your document, they are available within the document body.
If your module requires another module, which is not part of the core API, you can ensure the order by means of the `$depends` attribute of your Asset Bundle class.
@ -180,7 +180,9 @@ public $depends = [
];
```
In case you can't assure the module registration order of a required module, but need to import the module, you can either require the module on demand within your module function or use the `lazy` flag of the require function.
> Note: You can only `depend` Assets with a higher or equal `$jsOption position`.
In case you can't assure the registration order of a required module, but need to import the module, you can either require the module on demand within your module function or use the `lazy` flag of the require function.
The call to `require('anotherModule', true)` will return an empty namespace object in case the dependent module has not been registered yet. The actual module logic will be available after the dependent module is registered.
@ -205,7 +207,7 @@ humhub.module('example', function(module, require, $) {
});
```
> Info: All core modules are appended to the head section of your document, so they should not be any dependency problem if you append your assets either at the begin or the end of the document body.
> Info: All core modules are appended to the head section of your document, so there should not be any dependency problem for those modules if you append your assets either at the begin or the end of the document body.
### Module Lifecycle
@ -216,7 +218,7 @@ A module runs through the following lifecycle (by the example of our `example` m
3. **Document Ready**
4. `humhub:beforeInitModule`
5. `humhub:modules:example:beforeInit`
6. Calling the modules `init` function
6. Calling the modules `init` function with `isPjax = false`
7. `humhub:modules:example:afterInit`
8. `humhub:afterInitModule`
9. `humhub:ready`
@ -225,6 +227,7 @@ A module runs through the following lifecycle (by the example of our `example` m
12. Calling the modules `unload` function
13. `humhub:modules:client:pjax:success`
14. Reinitialize all modules with `initOnPjaxLoad=true` by calling `init` with `isPjax = true`
15. `humhub:ready`
### Module Configuration
@ -235,7 +238,7 @@ humhub.module('example', function(module, require, $) {
...
var myAction = function() {
if(module.config['showMore']) {
if(module.config.showMore) {
// Do something
}
};
@ -259,7 +262,7 @@ $this->registerJsConfig([
);
```
Setting configurations in javascript:
Setting configurations in Javascript:
```javascript
// Set config values for multiple modules
@ -291,12 +294,12 @@ Beside the `config` array, the module instance furthermore provides a `text` uti
//Configurate your text in your php view.
$this->registerJSConfig('example', [
'text' => [
'error.notallowed' => Yii::t('ExampleModule.views.example', 'You are not allowed to access example!');
'error.notallowed' => Yii::t('ExampleModule.views_example', 'You are not allowed to access example!');
]
]);
```
Access your text within your js module as this
Access your text as
```javascript
module.text('error.notallowed');
@ -341,7 +344,7 @@ module.log.error('error.default', new Error('xy'), true);
The trace level of your module can be configured by setting the `traceLevel` configuration. If your module does not define an own trace level the log modules's traceLevel configuration will be used instread. In production mode the default log level is set to `INFO`, in dev mode its set to `DEBUG`.
> Info: Your module logger will try to resolve a given text key to a module or global text.
> Info: Your module logger will try to resolve a given text key to a module or global text configuration.
> Info: The `module.log.success()` function will trigger a status bar update by default.

View File

@ -1,3 +0,0 @@
Live Updates
=================
(TBD)

View File

@ -1,100 +0,0 @@
# 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
### Stream / Content Changes
The models WallEntry and Wall were removed. So all corresponding methods like getFirstWallEntryId() are not longer available.
The stream handling is now handled directly by the Content model. Also all stream classes (widgets, actions) are moved into the humhub\modules\stream package.
### File module changes
Please refer the new [File Handling](files.md) documentation section for more details regarding the new file management API.
- Deprecated widgets:
- humhub\modules\user\widgets\UserPicker (replaced with humhub\modules\user\widgets\UserPickerField)
- humhub\modules\space\widgets\Picker (replaced with humhub\modules\space\widgets\SpackePickerField)
- humhub\widgets\DataSaved (replaced with humhub\components\View::saved)
- Removed Content models 'attachFileGuidsAfterSave' attribute and handling
- Deprecated File model methods
- \humhub\modules\file\models\File::attachPrecreated
- \humhub\modules\file\models\File::getFilesOfObject
- \humhub\modules\file\models\File::getStoredFilePath
- \humhub\modules\file\models\File::getPreviewImageUrl
- \humhub\modules\file\models\File::attachPrecreated
- \humhub\modules\file\models\File::getFilename
- \humhub\modules\file\models\File::getInfoArray
- \humhub\modules\file\models\File::getMimeBaseType
- \humhub\modules\file\models\File::getMimeSubType
- \humhub\modules\file\models\File::getExtension
- Removed configuration option 'showFilesWidgetBlacklist' use WallEntry showFiles attribute instead.
- File models title attributes is not longer automatically populated with the filename when empty
- Moved file upload capabilities (UploadedFile) from File model to FileUpload model
- Moved file store content by attribute capabilities from File model to FileContent model
- Created UploadAction/DownloadAction classes
### Javascript API changes
TBD
#### Pjax + TopNavigation:
Use
public $topMenuRoute = '/dashboard/dashboard';
within your controller for pjax topmenu support.
### Asset Handling changes
TBD
## Migrate from 1.0 to 1.1
- Dropped unused space attribute "website"
- ContentContainer Model Changes
- Removed canWrite method (now requires own implementation using permissions)
- Content Model Changes
- Removed space_id / user_id columns - added contentcontainer_id
- Not longer validates content visibility (private/public) permissions
- system_admin attribute in user table was removed
see [[humhub\modules\user\models\User::isSystemAdmin]]
- Renamed space header settings menu dropdown class
from [[humhub\modules\space\modules\manage\widgets\Menu]] to [[humhub\modules\space\widgets\HeaderControlsMenu]]
- Refactored settings system. see [Settings Documentation](settings.md) for more details.
Old settings api is still available in 1.1.x
- Refactored user group system
- New administration menu structure
## Migrate from 0.20 to 1.0
## Migrate from 0.12 to 0.20
**Important: This release upgrades from Yii1 to Yii2 Framework!**
This requires an extensive migration of all custom modules/themes.
Find more details here: [HumHub 0.20 Migration](old/modules-migrate-0.20.md)
## Migrate from 0.11 to 0.12
- Rewritten Search
## Migrate from 0.10 to 0.11
No breaking changes.
- Now handle ContentContainerController layouts, new option showSidebar
- New ContentAddonController Class
- New Wiki Parser / Editor Widget

View File

@ -1,7 +0,0 @@
Module - Migration
=================
## Installation
## Uninstallation
## Compatibility
(TBD)

View File

@ -1,87 +0,0 @@
(TBD:getPublishedUrl)Database and Models
====================
## Conventions
- prefix your tables with the module id. e.g. example_foo
- singular table names
- use underscorce in fieldnames/attributes e.g. user_id
## ActiveRecord (Model)
To be able to provide persistent data a module has to implement model class derived from [[humhub\components\ActiveRecord]].
Yii follows the concept of rich models, which means a model class can contain content in form of attributes as well as domain logic.
More information about the use of ActiveRecords is available in the [Yii2 guide](http://www.yiiframework.com/doc-2.0/guide-db-active-record.html).
> Info: [[humhub\components\ActiveRecord]] is derived from [[yii\db\ActiveRecord]] and provides some automatic attribute settings as `created_by` and `crated_at` if the underlying table contains these fields.
## Migrations
See Yii 2.0 guide for more details about migrations [http://www.yiiframework.com/doc-2.0/guide-db-migrations.html](http://www.yiiframework.com/doc-2.0/guide-db-migrations.html).
HumHub provides an enhanced Migration class [[humhub\components\Migration]] which provides the ability to rename class files. This is required because HumHub also stores some class names in database for Polymorphic relations.
#### Usage
- Create a module migration
`> php yii migrate/create example --migrationPath='@app/modules/polls/migrations'`
- Execute module migration
`> php yii migrate/up --migrationPath='@app/modules/polls/migrations'`
- Execute all migrations (including enabled modules)
`> php yii migrate/up --includeModuleMigrations=1`
#### Uninstall
There is a special migration file called 'uninstall.php' - which is executed after the module is uninstalled.
Use this drop created tables & columns.
Example file: *migrations/uninstall.php*
```php
<?php
use yii\db\Migration;
class uninstall extends Migration
{
public function up()
{
$this->dropTable('poll');
$this->dropTable('poll_answer');
$this->dropTable('poll_answer_user');
}
public function down()
{
echo "uninstall does not support migration down.\n";
return false;
}
}
```
## Data Integrity
The integrity checker is a command which validates and if necessary repairs the application database.
If you want to add own checking methods for your module to it, you can intercept the [[humhub\controllers\IntegrityController::EVENT_ON_RUN]] event.
Example callback implementation:
```php
public static function onIntegrityCheck($event)
{
$integrityController = $event->sender;
$integrityController->showTestHeadline("Polls Module - Answers (" . PollAnswer::find()->count() . " entries)");
foreach (PollAnswer::find()->joinWith('poll')->all() as $answer) {
if ($answer->poll === null) {
if ($integrityController->showFix("Deleting poll answer id " . $answer->id . " without existing poll!")) {
$answer->delete();
}
}
}
}
```

View File

@ -1,12 +0,0 @@
Change the behavior of core features
=================
This guide describes possible ways for modules to change the behavior of core features.
## Events
## Widgets
## Views
## Controller
## ActiveRecord
## Javascript
## Configuration

View File

@ -1,186 +0,0 @@
Users
=====
## ContentContainer
A [[humhub\modules\content\models\ContentContainer|ContentContainer]] in HumHub is the base concept for assigning content entries to a specific container instance (user or space).
Each [[humhub\modules\content\models\ContentContainer|ContentContainer]] is assigned with an unique guid, which is used in controllers to identify the context of its actions.
Currently there are two types of ContentContainer:
- [[humhub\modules\user\models\User|User]]
- [[humhub\modules\space\models\Space|Space]]
![Application Layers](images/contentContainerClassDiag.jpg)
> Note: It's not possible to create own ContentContainer classes, yet.
### ContentContainerController
The [[humhub\modules\content\components\ContentContainerController|ContentContainerController]] class is extended by controllers working in the context of a specific [[humhub\modules\content\models\ContentContainer|ContentContainer]].
A [[humhub\modules\content\components\ContentContainerController|ContentContainerController]] will automatically search for a **sguid** (Space) or **uguid** (User) request parameter in every request and will instantiate the corresponding [[humhub\modules\content\models\ContentContainer|ContentContainer]].
The [[humhub\modules\content\components\ContentContainerController|ContentContainerController]] provides common tasks like:
- Automatic container loading based on URL
- Access checks
- Layout selection based on container type (User or Space)
- Create URL's for the given ContentContainer
For example:
```php
class ExampleController extends \humhub\modules\content\components\ContentContainerController
{
public function actionIndex()
{
if ($this->contentContainer instanceof Space) {
//Space related stuff...
}
}
}
```
Url's pointing to a ContentContainer action should be created by using the `createUrl()` function
of your ContentContainer instance. This will add the required sguid or uguid to your request.
```php
// Direct ContentContainer call
$space->createUrl('/module/controller/action');
// Within a ContentContainerController:
$this->contentContainer->createUrl('/module/controller/action');
```
> Note: Requests for a [[humhub\modules\content\components\ContentContainerController|ContentContainerController]] action without providing a sguid or uguid parameter will fail!
### ContentContainerActiveRecord
Each ContentContainer class is derived from [[\humhub\modules\content\components\ContentContainerActiveRecord]].
Beside others, this abstract class provides the following functionality:
- [Permission Management](dev-permissions.md) `getPermissionManager()`
- Profile-/Banner-image access `getProfileImage()`, `getProfileBannerImage()`
- Rendering the container stream `getWallOut()` (see [Permission Management](dev-stream.md))
Profile image example:
```php
//Get Profile Image Url
$profileImage = $space->getProfileImage();
if($profileImage->hasImage()) {
$url = $profileImage->getUrl();
}
```
### ContentContainerModule
If a module should appear in the content containers module section, the module class must extend [[humhub\modules\content\components\ContentContainerModule]].
A ContentContainerModule can be enabled or disabled for a specific ContentContainer. The calendar module, for example, can be enabled for a specific space or a specific user account.
See the [[humhub\modules\content\components\ContentContainerModule]] class for a full list of options.
Example of a modules `Module.php` file:
```php
class Module extends \humhub\modules\content\components\ContentContainerModule
{
// Defines for which content container type this module is appropriate
public function getContentContainerTypes()
{
// This content container can be assigned to Spaces and User
return [
Space::className(),
User::className(),
];
}
// Is called when the whole module is disabled
public function disable()
{
// Clear all Module data and call parent disable
parent::disable();
}
// Is called when the module is disabled on a specific container
public function disableContentContainer(ContentContainerActiveRecord $container)
{
parent::disableContentContainer($container);
//Here you can clear all data related to the given container
}
// Can be used to define a specific description text for different container types
public function getContentContainerDescription(ContentContainerActiveRecord $container)
{
if ($container instanceof Space) {
return Yii::t('MyModule.base', 'Description related to spaces.');
} elseif ($container instanceof User) {
return Yii::t('MyModule.base', 'Description related to user.');
}
}
```
> Note: If you're working with content or other persistent data, make sure to delete container related data when the module is disabled on a contentcontainer. This can be archieved by overwriting the [[humhub\modules\content\components\ContentContainerModule::disableContentContainer]] function.
## Content
TBD
### ContentActiveRecord
Each Content ActiveRecord (derived from [[\humhub\modules\content\components\ContentActiveRecord]]) is automatically linked to a [[humhub\modules\content\models\Content]] record via the *content* attribute.
This Content record holds all neccessary information and provides common methods:
- ContentContainer which the Content belongs to
- Meta Information (created_at, created_by, updated_at, updated_by)
- Wall Assignments / Methods
- Archiving / Pinning
- And more...
If you're implementing an ActiveRecord based on [[humhub\modules\content\components\ContentContainerActiveRecord]] you need to implement the following abstract methods:
- `getContentName()` - Returns the displayed name of the Content (e.g. Post or Poll)
- `getContentDescription()` - Returns a preview of the Content - which is used in Notifications for example.
Example:
```php
(TBD)
```
#### Wall/Stream Output
(TBD)
#### Querying Content
If you're calling find() on a [[\humhub\modules\content\components\ContentActiveRecord]] instance you'll get a special [[\humhub\modules\content\components\ActiveQueryContent]] which provides additional methods to select content.
- contentContainer($container) - Find content only inside a given container
- readable($user) - Return only user readable content
- ...
### Controller
TBD
## ContentAddon
TBD
- Always linked to particual Content, inherits access rules from it
- Examples: Like, File, Comment
- Can be nested (e.g. Container -> Content -> Addon (Comment) -> Addon (Like)
### ActiveRecord
TBD
Provides access to the related content via *content *Attribute
### Controller
TBD

View File

@ -1,31 +1,8 @@
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.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
-----------------------
## Migrate from 1.1 to 1.2
### Stream / Content Changes
@ -76,8 +53,7 @@ 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"
@ -101,11 +77,9 @@ Migrate from 1.0 to 1.1
- 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!**
@ -113,17 +87,12 @@ Migrate from 0.20 to 1.0
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

View File

@ -1,76 +0,0 @@
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]);
}
```

View File

@ -1,247 +0,0 @@
Module - Getting Started
=================
The following guide describes the basic module structure and extended module features as well as important considerations regarding your own custom module.
## Before starting
Before even starting the developement of a custom module, you first have to consider the following **module options**:
- [Can my module be enabled on profile and/or space level?](modules.md#container-module)
- Does my module produce [stream entries](stream.md) or other [content](content.md)?
- Does my module produce [global](content.md#global-content) content or views (not bound to a profile/space) ?
- Does my module provide any kind of sidebar [snippet](snippet.md)?
- Do I need to [change the default behaviour](module-change-behavior.md) of some core components?
- Do I need specific [permissions](permissions.md) for my module?
- Does my module create any [notifications](notifications.md) or [activities](activities.md)?
- Should [guest](permissions.md#guests-access) users have access to some of my module views and functions?
Furthermore you may have to consider the following **issues**:
- [Module settings and configuration](settings.md)
- [Append my module to a specific navigation](module-change-behavior.md)
- [Client side developement](javascript-index.md)
- [Asset Management](assets.md)
- [Data Integrity](models.md#data-integrity)
- [Migrations and Uninstallation and Compatibility](migration.md)
- [Testing](testing.md)
- [File handling](files.md)
- [Events](events.md)
- [Translation](i18n.md)
- [Live UI updates](live.md)
- [Submodules](#submodules)
- [Security](security.md)
- [Theming](embedded-themes.md)
## Basic Module Structure
Basically modules in HumHub are identical to [Yii2 modules](http://www.yiiframework.com/doc-2.0/guide-structure-modules.html).
A very basic module consists of the following elements:
```
controllers/ - contains controller classes
migrations/ - contains database migration files and uninstall script
models/ - contains model classes
views/ - contains the modules view files
widgets/ - contains widget classes
Module.php - the main module class which can contain enable/disable logic for contentcontainer etc.
config.php - base module configuration.
module.json - module metadata
```
### config.php
The `config.php` file enables automatic module loading and event configuration, without the need to manually modify the main application config, by returning an array including the following fields:
- **id** - Unqiue ID of the module (required)
- **class** - Namespaced classname of the module class (required)
- **namespace** - The namespace of your module (required)
- **events** - Array containing the modules event configuration (optional)
- **urlManagerRules** - Array of [URL Manager Rules](http://www.yiiframework.com/doc-2.0/yii-web-urlmanager.html#addRules()-detail) (optional)
- **modules** - Submodules (optional)
Example `config.php` file:
```php
<?php
use johndoe\example\Module;
use humhub\widgets\TopMenu;
return [
'id' => 'example',
'class' => 'johndoe\example\Module',
'namespace' => 'johndoe\example',
'events' => [
['class' => TopMenu::className(), 'event' => TopMenu::EVENT_INIT, 'callback' => ['johndoe\example\Module', 'onTopMenuInit']],
]
];
?>
```
> Note: Do not execute any code in the `config.php` since the result will be cached!
### Module.php
The `Module.php` file contains the actual module class which should either extend the [[humhub\components\Module]] or [[humhub\modules\content\components\ContentContainerModule]] class.
The [[humhub\components\Module|Module]] class provides some basic module functions used for installing/uninstalling and retrieving metadata, whereas the [[humhub\modules\content\components\ContentContainerModule]] class has to be extended in case your module requires to be enabled on space or profile level.
The Module class is responsible for:
**Handling the enabling and disabling of the module**
The modules `disable()` function is called if the module is disabled.
```php
class Module extends \humhub\components\Module
{
public function disable()
{
// Clear module related contentent etc...
foreach (MyContentModel::find()->all() as $model) {
$model->delete();
}
// Don't forget to call this!!
parent::disable();
}
}
```
>Note: The default implementation of `disable()` will clear some module data automatically as the module global and ContentContainer settings, profile/space module relations.
#### Handling the enabling and disabling of this module for a given space or profile
See the [Container Module]() section for more information.
#### Export Module Permissions
Module specific permissions are exported by means of the [[humhub\components\Module::getPermissions()]] function. See the [Permissions]() section for more information.
#### Export Module Notification
Modules can export Notificaions in order to make them configurable in the notificaiton settings.
See the [Notifications]() section for more information.
#### Module Assets and `$resourcesPath`
The [[humhub\components\Module::resourcesPath]] defines the modules resource directory, containing images, javascript files or other assets.
See the [Module Assets]() section for more information.
### module.json
This file holds basic metadata which is for example used by the markeplace.
Example `module.php` file:
```json
{
"id": "example",
"name": "My Example Module",
"description": "My testing module.",
"keywords": ["my", "cool", "module"],
"screenshots": ["assets/screen_1.jpg"],
"version": "1.0",
"humhub": {
"minVersion": "0.20"
}
}
```
- **id** - The module ID
- **name** - The modules name
- **description** - A short module description
- **keywords** - Array of significant keywords
- **screenshots** - Some screenshots for the marketplace
- **version** - Current module version
- **minVersion** - Defines the minimum HumHub core version this module version is compatible with.
## Extended Module Structure
The following structure contains some additional directories and files, which should be added for specific usecases or features.
```
activities - activity classes
assets/ - asset bundle classes
components/ - component and services classes
controllers/ - see above
live/ - live event classes
jobs/ - queue job classes
messages/ - contains the modules message files
migrations/ - see above
models/ - see above
modules/ - contains any submodules
notifications/ - notification classes
permissions/ - permission classes
resources/ - contains web assets as javascript files or stylesheets
tests/ - module tests
views/ - see above
widgets/ - see above
Events.php - is often used for static event handlers
Module.php - see above
config.php - see above
module.json - see above
```
>Note: the extended module structure and it's directory names is just a recommendation.
## Container Module
In case your module can be enabled on space or profile level your `Module` class has to extend from [[humhub\modules\content\components\ContentContainerModule]]. You should extend this class if your module provides space or profile specific views or content.
- The `getContentContainerTypes()` method defines for which ContentContainer type (space or profile) this module can be enabled.
- The `disableContentContainer()` method is called when this module is disabled for a given ContentContainer (Space or Profile).
- The `getContentContentContainerDescription()` method provides a general description of this module for the given ContentContainer.
The following example module can be enabled on space and profile level:
```php
class Module extends \humhub\modules\content\components\ContentContainerModule
{
// Defines for which content container type this module can be enabled
public function getContentContainerTypes()
{
// This content container can be assigned to Spaces and User
return [
Space::className(),
User::className(),
];
}
// Is called when the whole module is disabled
public function disable()
{
// Clear all Module data and call parent disable
[...]
parent::disable();
}
// Is called when the module is disabled on a specific container
public function disableContentContainer(ContentContainerActiveRecord $container)
{
parent::disableContentContainer($container);
//Here you can clear all data related to the given container
}
// Can be used to define a specific description text for different container types
public function getContentContainerDescription(ContentContainerActiveRecord $container)
{
if ($container instanceof Space) {
return Yii::t('MyModule.base', 'Description related to spaces.');
} elseif ($container instanceof User) {
return Yii::t('MyModule.base', 'Description related to user.');
}
}
}
```
> Note: If you're working with content or other persistent data, make sure to delete container related data when the module is disabled on a contentcontainer. This can be archieved by overwriting the [[humhub\modules\content\components\ContentContainerModule::disableContentContainer]] function.
## Creating a Module Template with Gii
(TBD)

View File

@ -1,335 +0,0 @@
Javascript API
=======
Since version 1.2, HumHub provides a module based Javascript API within the `humhub` namespace.
Instead of embeding inline script blocks into your view files, it's highly recommended to use the new module system for your modules frontend logic.
## Modules
### Module Asset
Module script files should reside within the `resources/js` folder of your humhub module and should ideally be appended at the bottom of your document. This can be achieved by using [Asset Bundles](http://www.yiiframework.com/doc-2.0/guide-structure-assets.html).
```php
namespace humhub\modules\example\assets;
use yii\web\AssetBundle;
class ExampleAsset extends AssetBundle
{
// You can also use View::POS_BEGIN to append your scripts to the beginning of the body element.
public $jsOptions = ['position' => \yii\web\View::POS_END];
public $sourcePath = '@example/resources';
public $js = [
'js/humhub.example.js'
];
}
```
> Note: Make sure to add your assets after the core scripts, which are added within the html head.
> Note: Your Asset Bundle should reside in the `assets` subdirectory of your module.
In your view you can register your Asset Bundle by calling
```php
\humhub\modules\example\assets\ExampleAsset::register($this);
```
Where `$this` is the view instance. More infos about the use of Asset Bundles are available in the [Yii Guide](http://www.yiiframework.com/doc-2.0/guide-structure-assets.html).
### Module Registration
Modules are added to the `humhub.modules` namespace by calling the `humhub.module` function.
```javascript
humhub.module('example', function(module, require, $) {
...
});
```
Example of a submodule:
```javascript
humhub.initModule('example.mySubmodule', function(module, require, $) {
...
}
```
The first argument of the `humhub.module` function defines the module id, which should be unique within your network. The second argument is the actual module function itself.
> Note: You should use an unique namespace for your custom modules as `myproject.mymodule` otherwise it may interfere with other modules.
Your module function will be called with the following arguments:
1. `module` - Your module instance, used for exporting module logic and accessing module specific utilities
2. `require` - Used for injecting other modules.
3. `$` - jQuery instance.
##### Module Exports
Module functions and attributes can only be accessed outside of the module if they are exported, either by directly appending them to the `module` object or by calling `module.export`.
```javascript
humhub.module('example', function(module, require, $) {
// private function
var private = function() { /* ... */ }
// direct export of public function
module.publicFunction = function() {/* ... */}
// another public function exported later
var publicTwo = function() { /* ... */}
// Exports multiple values
module.export({
publicTwo: publicTwo,
publicThree: function() {/** Test function **/}
});
});
```
##### Module Initialization
Your module's initialization logic can be implemented by exporting an `init` function. This function will automatically be called after the page is loaded.
By default this function is only called once after a full page load (or directly after the registration if it was loaded per ajax). If your module requires a reinitialization also after Pjax page loads, your module has to set the `initOnPjaxLoad` setting.
```javascript
module.initOnPjaxLoad = true;
var init = function($pjax) {
// Do some global initialization work, which needs to run in any case
if($pjax) {
// Runs only after a pjax page load
} else {
// Runs only after fresh page load
}
}
module.export({
init: init
});
```
##### Module Unload
For the purpose of cleaning up module related dom nodes etc. there is also an `unload` function, which is called before each Pjax page load. This function is mainly used to remove obsolete dom nodes in order to prevent memory leaks, remove obsolete dom listeners, or clear some module data.
```javascript
var unload = function($pjax) {
$('.moduleResidues').remove();
}
module.export({
unload: unload
});
```
##### Module Dependencies
Other modules can be injected into your module by using the `require` function.
```javascript
// Import of the core client module.
var client = require('client');
//Calling myFunction within another module
require('example').myFunction();
//Calling myFunction within another module (full path)
require('humhub.modules.example').myFunction();
//Also a valid call
require('modules.example').myFunction();
//Calling myFunction outside of a module
humhub.modules.example.myFunction();
```
> Note: You should only require modules at the beginning of your own module, if you are sure the required module is already registered.
If your module requires other modules, which are not part of the core you can ensure the order by means of the `$depends` attribute of your Asset Bundle:
```php
public $depends = [
'humhub\modules\anotherModule\assets\AnotherModuleAsset'
];
```
If you can't assure the module registration order for another module, but need to require the module, you can either require it within your module function or use the `lazy` flag of the require function.
The call of `require('anotherModule', true)` will return an empty namespace object, in case the module was not registered yet. The module logic will be available after the registration of the dependent module.
>Note: When using the `lazy` flag, you can't assure the required module will be initialized within your own module's `init` logic.
```javascript
humhub.initModule('example', function(module, require, $) {
// We can't ensure the initial logic of module2
var module2 = require('module2', true);
// at this point module2 might be empty
var myFunction = function() {
// myFunction should only be used outside of the init logic
module2.executeSomeFunction();
}
});
```
>Info: Since core modules are appended to the head section of your document, there shouldn't be any dependency problem.
### Module Configuration
If you need to transfer values as texts, settings or urls from your php backend to your frontend module, you can use the `module.config` array which is automatically available within your module as in the following example:
```javascript
humhub.initModule('example', function(module, require, $) {
var myAction = function() {
if(module.config.showMore) {
// Do something
}
};
});
```
In your view you can set the module configuration as follows
```php
// Single module
$this->registerJsConfig('example', ['showMore' => true]);
// Multiple modules
$this->registerJsConfig([
'example' => [
'showMore' => true
],
'anotherModule' => [
...
]
);
```
Setting configurations in javascript:
```javascript
//Set config values for multiple modules,
humhub.config.set({
'myModule': {
'myKey': 'value'
},
'moduleXY': {
...
}
});
//Set single value
humhub.config.set('myModule', {
'myKey': 'value'
});
//You can also call
humhub.config.set('myModule', 'myKey', 'value');
```
>Note: Since the configuration can easily be manipulated, you should not set values which can compromise the security of your application.
> TIP: Module setter are normally called within views or widgets to inject urls or translated text for user feedback or modals.
### Module Texts
Beside the configuration addition, the module instance does furthermore provide a `module.text` function for easily accessing texts of your configuration.
Example of an error text.
```php
//Configurate your text in your php view.
$this->registerJsConfig([
'example' => [
'showMore' => true,
'text' => [
'error.notallowed' => Yii::t('ExampleModule.views.example', 'You are not allowed to access example!');
]
]
);
```
Access your text within your module function as this
```javascript
module.text('error.notallowed');
// which is a short form of:
module.config['text']['error.notallowed'];
```
### Module Log
Your module is able to create module specific log entries by using the `module.log` object of your module instance.
The log object supports the following log level functions:
1. *trace* - For detailed trace output
2. *debug* - For debug output
3. *info* - Info messages
4. *success* - Used for success info logs
5. *warn* - Warnings
6. *error* - For error messages
7. *fatal* - Fatal errors
All log functions accept up to three arguments:
1. The actual message
2. Details about the message (or errors in case of warn/error/fatal)
3. A setStatus flag, which will trigger a global `humhub:modules:log:setStatus` event. This can be used to give user-feedback (status bar).
Instead of an actual message, you can also just provide a text key as the first argument.
The following calls are valid:
```javascript
// Log config text 'error.notallowed' and give user feedback.
module.log.error('error.notallowed', true);
// In the following example we received an error response by our humhub.modules.client. The response message will try to resolve a default
// message for the status of your response. Those default messages are configured in the core configuration texts.
module.log.error(response, true);
// The error.default text message is available through the configuration of the log module see humhub\widgets\JSConfig
module.log.error('error.default', new Error('xy'), true);
```
> Info: Your module logger will try resolving your message string to a module or global text.
> Note: The success log will by default trigger a status log event.
The trace level of your module can be configured by setting the `traceLevel` of your module configuration.
If your module does not define an own trace level the log modules's traceLevel configuration will be used.
> Info: In production mode the default log level is set to `INFO`, in dev mode its set to `DEBUG`.
> Note: If you change the `traceLevel` of a module at runtime, you'll have to call `module.log.update()`.
## Core Modules
### Config Module
Beside the `module.config` utility you can also use the global configuration as follows
```javascript
// Retrieves the whole config object of 'myModule'
var moduleConfig = require('config').get('myModule');
var myValue = config['myKey'];
//Single value getter with default value
var myValue = humhub.config.get('myModule', 'myKey', 'myDefaultValue');
```
With `humhub.config.is`, you are able to check if a value is true
```javascript
//Check if the configkey enabled is true, default false
if(humhub.config.is('myModule', 'enabled', 'false')) {
...
}
```

View File

@ -1,182 +0,0 @@
# Module Migration Guide to HumHub 0.20
This document briefly describes the module api changes in HumHub 0.20.
Since HumHub 0.20 is now based on Yii 2 you also need to migrate your modules to it.
See more information about Yii 2.0 here:
- [Yii: Upgrading from Version 1.1](http://www.yiiframework.com/doc-2.0/guide-intro-upgrade-from-v1.html)
- [Yii2 Migration Notes](dev-migrate-0.20-yii2.md)
## Migration
### General
- Namespace classes e.g. module\example or create own Namespace
- Migrate to Yii 2.0 (Controllers, Models, Views, Assets, ...)
- Migrate to HumHub Namespaced classes
- Raname e.g. ExampleModule.php && ExampleEvents.php to Module.php / Events.php
- Changed former autostart.php to config.php: [config.php](dev-module-index.md#configphp)
- Migrate database (see below)
### Database / Migrations
Also the existing migration script needs to use Namespaces now.
Because also class names of your module may stored in database (e.g. for Activities, Likes, Notification, ...)
It's neccessary to create a new migration derived from [[humhub\components\Migration]] which uses **renameClass** method class to fix these records.
Example Migration:
```php
<?php
use humhub\components\Migration;
use module\wiki\models\WikiPage;
use module\wiki\models\WikiPageRevision;
class m150705_081309_namespace extends Migration
{
public function up()
{
$this->renameClass('WikiPage', WikiPage::className());
$this->renameClass('WikiPageRevision', WikiPageRevision::className());
}
public function down()
{
echo "m150705_081309_namespace cannot be reverted.\n";
return false;
}
}
```
### Content & ContentAddon
getContentTitle is now divided into
- getContentTitle
- getContentPreview
### autostart.php
TBD
- Renamed to config.php
- Removed imports
- Return array
- Namespaces
### Urls
[[\humhub\modules\content\components\activerecords\ContentContainer::createUrl]] (Space/User) still provides the method createUrl to build URLs in container context (sguid/uguid).
Use [http://www.yiiframework.com/doc-2.0/yii-helpers-url.html](http://www.yiiframework.com/doc-2.0/yii-helpers-url.html) for other URLs.
### Activities
Please recreate Activities as described here: [[dev-module-activities.md]]
Since 0.20 there is an automatic "created" Activity for Content.
To migrate existing Activities to the new Scheme you need to create an migration.
Example Migration:
```php
// Rename Custom Activities
$this->update('activity', ['class' => 'exampleModule\activities\MyActivity'], ['class' => 'OldActivityName']);
// Rename own "Created" Activities to core
$this->update('activity', ['class' => 'humhub\modules\content\activities\ContentCreated', 'module' => 'content'], ['class' => 'PollCreated']);
```
### Assets
The asset/resources folder will not longer automatically published.
Find more details about assets here:
http://www.yiiframework.com/doc-2.0/guide-structure-assets.html
The default path for module resources (javascripts, images, css, ...) was changed from asset to resources. ('/modules/example/resources').
Also all HumHub module related files like Module Image or Screenshots should be located there.
You can change this path back to 'assets' by overwriting the 'resourcesPath' Attribute in your Module class.
e.g.
```php
class Module extends \humhub\components\Module
{
public $resourcesPath = 'assets';
```
### Module Configuration
The URL handling to configure your module in **Administration -> Module** has changed.
The method "getConfigUrl" in Module class is not longer used.
Set configRoute attribute instead.
e.g.
```php
class Module extends \humhub\components\Module
{
public $configRoute = '/example/admin/config';
```
## (Incomplete) List of changed Helpers/Widgets:
#### EnrichText
```php
// New
echo humhub\widgets\RichText::widget(['text' => $text]);
// Old
echo HHtml::enrichTest($text);
```
#### TimeAgo
```php
// New
echo \humhub\widgets\TimeAgo::widget(['timestamp' => $time]);
// Old
echo HHtml::timeAgo($time);
```
#### PostLink
```php
// New
echo Html::a($label, $url, ['data-method'=>'POST']);
// Old:
echo HHtml::postLink(...);
```
#### AjaxButton/Submit/...
```php
echo \humhub\widgets\AjaxButton::widget([
'label' => "Save",
'ajaxOptions' => [
'type' => 'POST',
'beforeSend' => new yii\web\JsExpression('function(){ setModalLoader(); }'),
'success' => new yii\web\JsExpression('function(html){ $("#globalModal").html(html); }'),
'url' => $space->createUrl('/space/admin/crop-image'),
],
'htmlOptions' => [
'class' => 'btn btn-primary'
]
]);
```
#### Yii::app()->input->stripClean
Stripclean is not longer available. use Html::encode() user input on output _and_ create validators.

View File

@ -1,41 +0,0 @@
[Back to 0.20 Migration](modules-migrate-0.20.md)
# Yii2 Migration Notes
See Yii Migration Guide: [http://www.yiiframework.com/doc-2.0/guide-intro-upgrade-from-v1.html](http://www.yiiframework.com/doc-2.0/guide-intro-upgrade-from-v1.html)
Notes:
- Use Namespaces!
- Yii::app() -> Yii::$app
- Use [] instead of array() - Optional
- Model: Validator
- Use array for multiple attributes
- Validator changes Numeric->Integer ...
- String validator doesn't allow Integer Types (cast!)
- Scenarios now in separate methods secenarios()
- User::model()->findByPk($idy); -> User::findOne(['id'=>$id);
- Check beforeSave/afterSave when overwriting they may have parameters
- Better use $insert when available instead of $this->isNewRecord
- Make tableName method static
- Views:
- ClientScript removed e.g. Yii::app()->clientScript->registerScriptFile
- New Widget calls WidgetClass::widget([options]) & echo it!
- Controllers
- Always return render action (also Widgets)
- camel case actions e.g. actionEditItem new Url: edit-item
- Easier: JSON Output
Yii::$app->response->format = 'json'; return $json;
- createUrl removed -> Url::to()
- Behaviors
- $this->getOwner() replaced by $this->owner
- Html (CHtml)
- reduced (e.g. no AjaxButton - use: \humhub\widgets\AjaxButton instead
- Html::link -> confirm changed to data-confirm
-

View File

@ -1,40 +1,48 @@
Overview
========
HumHub provides a powerful modular platform based on the [Yii2 Framework](http://www.yiiframework.com).
The modular nature of the HumHub platform allows you to add new features or change existing core features by means of
custom modules.
The main power of the HumHub platform lies in its flexibility and extensibility through modules and configuration of runtime behaviour.
HumHub is written mostly in PHP and is based on the [Yii Framework](http://www.yiiframework.com/). Other languages used throughout the platform are *JavaScript*, *HTML*, *SQL* and *CSS*.
Other languages used throughout the platform, besides PHP, are JavaScript, HTML, SQL and CSS/Less.
HumHub is based on the Model-View-Controller (MVC) pattern and uses frontend technologies such as [jQuery](https://jquery.com/), [Bootstrap](http://getbootstrap.com/) and [Less](http://lesscss.org/).
In this guide, you will find all the necessary information to customize your HumHub installation and implement your own modules.
As HumHub is based on the [Yii 2.0 PHP Framework](http://www.yiiframework.com/) make sure you're also familiar with the basic concepts this framework:
- [The Definitive Guide to Yii 2.0](http://www.yiiframework.com/doc-2.0/guide-index.html)
## HumHub Core
HumHub uses a [Model-View-Controller (MVC)](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) based software architecture and utilizes technologies such as [Yii2](http://www.yiiframework.com/), [jQuery](https://jquery.com/), [Bootstrap](http://getbootstrap.com/) and [Less](http://lesscss.org/), to name a few.
![Application Layers](images/appLayer.svg)
The HumHub core consists of a set of core components, modules, widgets, helpers and views.
HumHub extends several Yii base components such as:
> Note: Since HumHub v1.2 the minimum PHP version is 5.6
- [[humhub\components\ActiveRecord|ActiveRecord]]
- [[humhub\components\Application|Application]]
- [[humhub\components\Controller|Controller]]
- [[humhub\components\Migration|Migration]]
- [[humhub\components\Module|Module]]
- [[humhub\components\ModuleManager|ModuleManager]]
- [[humhub\components\Request|Request]]
- [[humhub\components\Theme|Theme]]
- [[humhub\components\User|User]]
- [[humhub\components\View|View]]
- [[humhub\components\Widget|Widget]]
- and more...
As HumHub is based on the [Yii 2.0 PHP Framework](http://www.yiiframework.com/) make sure you're also familiar with the concepts of this framework in order to beeing able to write own modules or extend the core platform.
and consists of the following core modules:
Here are some recommendet resources for learning Yii:
- [The Definitive Guide to Yii 2.0](http://www.yiiframework.com/doc-2.0/guide-index.html)
- [Yii 2.0 Community Cookbook](https://yii2-cookbook.readthedocs.io/)
The HumHub core platform consists of several modules as well as extended Yii components:
**Core Components:**
- [[humhub\components\ActiveRecord]]
- [[humhub\components\Application]]
- [[humhub\components\console\Application]]
- [[humhub\components\AssetManager]] -
- [[humhub\components\Controller]]
- [[humhub\components\Migration]]
- [[humhub\components\Module]]
- [[humhub\components\ModuleManager]]
- [[humhub\components\Request]]
- [[humhub\components\Response]]
- [[humhub\components\SettingsManager]]
- [[humhub\components\Theme]]
- [[humhub\components\SocialActivity]]
- [[humhub\components\View]]
- [[humhub\components\Widget]]
- **humhub\components\i18n**
- **humhub\components\mail**
- **humhub\components\queue**
- **humhub\components\rendering**
- **humhub\components\validators**
**Core Modules:**
- **activity:** User/Space activities
- **admin:** Responsible for admin/configuration related issues
@ -43,29 +51,14 @@ and consists of the following core modules:
- **dashboard:** Dashboard related functionality
- **directory:** Directory related functionality
- **file:** Basic file module for accessing the filesystem
- **friendship:** User friendship module
- **friendship:** Friendship system functionality
- **installer:** HumHub installer module
- **like:** Content addon for likes
- **live:** Used for frontend live updates
- **notification:** User Notifications
- **live:** Live frontend update functionality
- **notification:** User notifications (e.g. e-mail, web)
- **post:** Simple user-post related functionality
- **search:** Luceene Search Module
- **space:** Space related functionality
- **stream:** Content streams and walls
- **tour:** HumHub user-guide
- **user:** Basic user module
### Application structure
```
assets/ - contains published asset files
protected/ - protected files as sources, modules, configuration etc.
protected/config - dynamic and user configuration
protected/humhub - humhub core directory
protected/modules - default directory for non core modules
protected/runtime - runtime files as cache, search index, logs etc.
protected/vendor - third party libraries loaded by composer
static/ - static asset files as production assets core javascript/less files etc.
themes/ - contains standalone themes (not bundled within a module)
uploads/ - uploaded files profile images etc.
```
- **stream:** Content stream related functionality
- **tour:** HumHub user-guide tour
- **user:** User and authentication

View File

@ -205,7 +205,7 @@ In the following, we'll show some more use cases for the [[humhub\components\beh
return [
'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(),
'adminOnly' => true
'adminOnly' => true,
]
];
@ -213,26 +213,23 @@ return [
return [
'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(),
'guestAllowedActions' => ['index']
'guestAllowedActions' => ['index'],
'rules' => [
['permissions' => SpecialPermission::className(), 'actions' => ['secret']]
];
]
['permissions' => SpecialPermission::className(), 'actions' => ['secret']],
],
],
];
// Combined rules: Every action is only granted for users with SpecialPermission except 'secret' action, which is accessible by SpecialPermission and SpecialAdminPermission users.
return [
'acl' => [
'class' => \humhub\components\behaviors\AccessControl::className(),
'guestAllowedActions' => ['index']
'guestAllowedActions' => ['index'],
'rules' => [
['permissions' => SpecialPermission::className()]
['permissions' => [SpecialPermission::className(), SpecialAdminPermission::className()], 'actions' => ['secret']]
];
]
['permissions' => SpecialPermission::className()],
['permissions' => [SpecialPermission::className(), SpecialAdminPermission::className()], 'actions' => ['secret']],
],
],
];
```
## Guest Access
(TBD)

View File

@ -1,4 +0,0 @@
Security
=================
(TBD)

View File

@ -1,75 +0,0 @@
Settings Manager
================
The SettingsManager allows you to easily store key/value based configuration settings
based on module components and also optionally bound to a contentcontainer (e.g. users or spaces).
If you need to categorize key names, use this syntax: category.subcategory.camelCaseKeyName
The SettingsManager component is automatically added all to humhub\components\Module classes.
Module settings
---------------
Get desired module / application instance:
```php
$module = Yii::$app;
// or
$module = Yii::$app->getModule('polls');
// or
$module = $controller->module;
```
Create or update existing setting in settings manager:
```php
$module->settings->set('key', $value);
```
Get value of setting manager:
```php
$value = $module->settings->get('key');
```
Delete setting:
```php
$module->settings->delete('key');
// or
$module->settings->set('key', null);
```
ContentContainer related settings
---------------------------------
If you want to store settings related to an user or space - use the ContentContainerSettingsManager:
```php
$module->settings->contentContainer($user)->get('key');
$module->settings->contentContainer($user)->set('key', $value);
$module->settings->contentContainer($user)->delete('key');
```
Shortcuts for currently logged in user settings:
```php
$module->settings->user()->get('key');
$module->settings->user()->set('key', $value);
$module->settings->user()->delete('key');
```
Shortcuts for current space settings:
Note: This is only available if current controller is instance of ContentContainerController.
```php
$module->settings->space()->get('key');
$module->settings->space()->set('key', $value);
$module->settings->space()->delete('key');
```

View File

@ -1,6 +0,0 @@
Snippets
=================
Snippets are self contained panels which can be added to the sidebar of for exaple the space or dashboard layout.
(TBD)

View File

@ -1,136 +1,18 @@
Content Streams
=================
Streams are used to asynchronously load batches of content entries which can be filtered or sorted.
The stream concept is used for example in _space and profile walls_, the _dashboard_ and
_activity stream_.
# Streams / Walls
Custom modules can use own streams for example to filter content by a specific type, or other custom
filters.
TBD
### Stream Channel
- Define Streaming/Wall
The `stream_channel` attribute of a [[humhub\modules\content\models\Content]] entry defines the relation of this content to
a specific type of stream. The `default` stream channel for example is used by _space/profile_ and _dashboard_
streams and the `activity` stream channel is exclusively used in activity streams.
You can also implement Creanown Stream/Wall output for your module content only.
The stream channel of your content type can be overwritten by setting the [[humhub\modules\content\components\ContentActiveRecord::streamChannel|ContentActiveRecord::streamChannel]] attribute.
Example Implementations:
You can consider the following stream channel options for your own [[humhub\modules\content\components\ContentActiveRecord|ContentActiveRecord]]:
- Tasks
- Polls
- `default` stream channel will include your content to default _space/profile walls_ and the _dashboard_. You are still able to create a custom stream view which filters content by type.
- `null` will exclude the content from the default streams
- Use a custom stream channel if you exclusively want your content to be included in your own custom stream (similar to activity concept).
> Note: A custom stream channel should be unique, so choose a meaningful name preferably with module prefix.
Of course your modules Content implementation needs to provides a WallEntry widget. See Content Section for more details.
### WallEntry Widget
A [[humhub\modules\content\widgets\WallEntry|WallEntry widget]] is responsible for rendering the individual stream entries
of a stream and is defined by [[humhub\modules\content\components\ContentActiveRecord::wallEntryClass|ContentActiveRecord::wallEntryClass]].
The following example shows a very basic WallEntry widget implementation.
> Note: By default your WallEntry view only have to render the actual content, the default WallEntry layout is available in `@humhub/modules/content/widgets/views/wallEntry.php`
```php
class WallEntry extends \humhub\modules\content\widgets\WallEntry
{
public function run()
{
return $this->render('wallEntry', [
'model' => $this->contentObject
]);
}
}
```
wallEntry.php:
```php
<div>
<?= $model->title ?>
<?= $model->myContent ?>
...
</div>
```
The WallEntry widget will be provided with a [[humhub\modules\content\widgets\WallEntry::contentObject|contentObject]] which holds the
[humhub\modules\content\components\ContentActiveRecord|ContentActiveRecord]] model to be rendered.
Your [[humhub\modules\content\widgets\WallEntry|WallEntry]] class can also set the following attributes:
- [[humhub\modules\content\widgets\WallEntry::editRoute|editRoute]] defines an edit route to your edit action which will be used to render an edit link (see WallEntryControls section)
- [[humhub\modules\content\widgets\WallEntry::editMode|editMode]] defines the way the edit action is triggered (see WallEntryControls section)
- [[humhub\modules\content\widgets\WallEntry::wallEntryLayout|wallEntryLayout]] defines the layout used to embed the result of `render()`, by default you only have to care about rendering the content section of your WallEntry
#### WallEntryControls
The default WallEntry layout contains a context menu with content actions like `edit`, `delete`, `archive` etc.
This menu can be manipulated by overwriting the [[humhub\modules\content\widgets\WallEntry::getContextMenu()|getContextMenu()]] function and
or use the [[humhub\modules\content\widgets\WallEntry::controlsOptions|controlsOptions]] property as in the following example.
By setting the [[humhub\modules\content\widgets\WallEntry::editRoute|editRoute]] we automatically add an edit link to our WallEntryControls in
case the current user is allowed to edit the content. The type of the edit action is defined by the [[humhub\modules\content\widgets\WallEntry::editMode|editMode]].
There are the following edit modes available:
- `EDIT_MODE_MODAL` the response of `editRoute` will be loaded into a modal.
- `EDIT_MODE_INLINE` the response of `editRoute` will be embeded into the WallEntry content.
- `EDIT_MODE_NEW_WINDOW` the page response of `editRoute` will be fully loaded.
```php
class WallEntry extends \humhub\modules\content\widgets\WallEntry
{
public $editRoute = "/my-module/entry/edit";
public $editMode = self::EDIT_MODE_MODAL;
// Will prevent the default DeleteLink and always add a MySpecialLink
$this->controlsOptions = [
'prevent' => [\humhub\modules\content\widgets\DeleteLink::class],
'add' => [MySpecialLink::class]
];
//...
public function getContextMenu()
{
$result = parent::getContextMenu();
// Only add a CloseLink if the user is allowed to edit the content.
if($this->contentObject->content->canEdit()) {
$this->addControl($result, [CloseLink::class, ['model' => $this->contentObject], ['sortOrder' => 200]]);
}
return $result;
]
}
```
CloseLink example:
```php
class CloseLink extends humhub\modules\content\widgets\WallEntryControlLink
{
public $model;
public function init()
{
if($this->model->closed) {
$this->label = Yii::t('MyModule.base', 'Reopen');
$this->icon = 'fa-check';
} else {
$this->label = Yii::t('MyModule.base', 'Close');
$this->icon = 'fa-times';
}
$this->options = [
// set some further html options
];
parent::init();
}
}
```
## Create own Module Content Stream
@ -141,14 +23,24 @@ Derived from [[humhub\modules\content\components\actions\ContentContainerStream]
Example:
```php
class StreamAction extends humhub\modules\content\components\actions\ContentContainerStream
<?php
namespace humhub\modules\polls\components;
use humhub\modules\content\components\actions\ContentContainerStream;
use humhub\modules\polls\models\Poll;
class StreamAction extends ContentContainerStream
{
public function setupFilters()
{
// Limit output to specific content type
$this->activeQuery->andWhere(['content.object_model' => Poll::className()]);
}
}
```
Specify Action in Controller

View File

@ -1,17 +1,6 @@
Testing (since v1.2)
====================
## Testing basics
Testing in Humhub/Yii extends the paradigm of unit testing. I.e. testing models and controllers is complemented by functional and acceptance tests. Acceptance tests cover scenarios from a user's perspective: Opening the browser, accessing the site, click links and buttons etc. This behaviour can be simulated. Therefore a webserver as well as an automated browser instance are necessary (see below).
Functional tests are similar to acceptance tests but run without a running webserver.
Codeception allows integrated testing with acceptance, functional and unit tests.
*ATTENTION: Some of the test libraries are developed for use with PHP 7 only*
Details: [Codeception](http://codeception.com/docs/01-Introduction)
## Test Environment Setup
- Install codeception ([http://codeception.com/install](http://codeception.com/install))
@ -24,7 +13,7 @@ composer global require "codeception/codeception=2.0.*" "codeception/specify=*"
- Create test Database:
```
CREATE DATABASE `humhub_test` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE `humhub_test` CHARACTER SET utf8 COLLATE utf8_general_ci;
```
- Configure database access:
@ -32,7 +21,7 @@ CREATE DATABASE `humhub_test` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
Configure the database connection for your test environment in `@humhub/tests/config/common.php`:
```
'components' => [
'db' => [
'dsn' => 'mysql:host=localhost;dbname=humhub_test',
@ -41,33 +30,36 @@ Configure the database connection for your test environment in `@humhub/tests/co
'charset' => 'utf8',
],
]
```
- Run Database Migrations:
`cd protected/humhub/tests/codeception/bin`
```cd protected/humhub/tests/codeception/bin```
`php yii migrate/up --includeModuleMigrations=1 --interactive=0`
```php yii migrate/up --includeModuleMigrations=1 --interactive=0```
`php yii installer/auto`
```php yii installer/auto```
>Note: You'll have to run the migrations for your test environment manually in order to keep your test environment up to date.
- Install test environment:
`php yii installer/auto`
```cd protected/humhub/tests/codeception/bin```
```php yii migrate/up --includeModuleMigrations=1 --interactive=0```
```php yii installer/auto```
- Set `HUMHUB_PATH` system variable
The `HUMHUB_PATH` is used by your test environment to determine the humhub root path.
This is only required for non core module tests and can also be set in your modules test configuration `/tests/config/test.php`:
```
return [
'humhub_root' => '/path/to/my/humhub/root',
];
```
## Test configuration
@ -82,11 +74,11 @@ The following configuration files can be used to overwrite the test configuratio
The configurations for a suite will be merged in the following order:
- `@humhub/protected/humhub/tests/config/functional.php`
- `@myModule/tests/config/common.php`
- `@myModule/tests/config/functional.php`
- `@myModule/tests/config/env/myenv/common.php (if exists)`
- `@myModule/tests/config/env/myenv/functional.php (if exists)`
- @humhub/protected/humhub/tests/config/functional.php
- @myModule/tests/config/common.php
- @myModule/tests/config/functional.php
- @myModule/tests/config/env/myenv/common.php (if exists)
- @myModule/tests/config/env/myenv/functional.php (if exists)
### Environments
@ -114,17 +106,17 @@ humhub_root settings you want to use for this test run.
### Run all core tests:
```
´´´
cd protected/humhub/tests/
codecept run
```
´´´
### Run core module test
```
´´´
cd myModule/tests
codecept run unit
```
´´´
### Run non core module tests
@ -155,20 +147,18 @@ return [
### Run single test
`codecept run codeception/acceptance/TestCest:testFunction`
```
codecept run codeception/acceptance/TestCest:testFunction
```
### Run acceptance tests
Phantom.js and Selenium are needed as servers to run acceptance tests on your system. You can simply run codeception but selenium or phantomjs must be running.
Hint: If your already installed webserver is listening on port 8080 you do not need to start the test server, because Humhub tests are run on port 8080. However if your `DocumentRoot` directory is not configured to directly open humhub via `localhost` you have to do some adjustments in the `codeception.yml` file of our `test` folder (`test-entry-url`) and the `acceptance.suite.yml` file. Alternatively start the test server as described below (in humhub root directory).
#### with phantomjs
- Run phantomjs server (is installed with composer update)
`cd protected/vendor/bin`
```cd protected/vendor/bin```
`phantomjs --webdriver=44444`
```phantomjs --webdriver=44444```
#### with chrome driver (selenium)
@ -182,10 +172,11 @@ java -Dwebdriver.chrome.driver=chromedriver.exe -jar selenium-server-standalone-
Start test server:
`cd /myhumHubInstallation`
```cd /myhumHubInstallation```
`php -S localhost:8080`
```php -S localhost:8080```
run with chrome environment:
`codecept run acceptance --env chrome`
```codecept run acceptance --env chrome```

View File

@ -1,8 +1,47 @@
Custom Assets
=============
TBD
Structure
---------
Put your custom assets (e.g. images, fonts or javascripts) directly in the theme base directory.
Example:
- /themes/mytheme/img (Images)
- /themes/mytheme/js (Javascript files)
- /themes/mytheme/css (CSS Stylesheets)
- /themes/mytheme/font (Fonts)
In order to load additional **CSS** or **JavaScript** files in your theme, add them to `/themes/mytheme/views/layouts/head.php`
Usage
------
You can access the assets using the [[humhub/components/theme]] component.
Example:
```
<a href="<?= Url::to(['/']); ?>"><img src="<?= $this->theme->getBaseUrl() . '/img/mylogo.png'; ?>" alt="My logo"></a>
```
Javascript and Stylesheets
---------------------------
In order to load additional **CSS** or **JavaScript** files in your theme, add them to `/themes/mytheme/views/layouts/head.php`
e.g.
```
<link href="<?= $this->theme->getBaseUrl() . '/font/nexa/typography.css'; ?>" rel="stylesheet">
```
Overwrite default images
------------------------
You can also overwrite default images (stored in /static/img/) by placing a custom image with the same file name in your theme image directory.
If you want to replace the default user image as example, you need to create a file called **default_user.jpg** in your `/theme/mytheme/img` directory.

View File

@ -27,7 +27,7 @@ If you are using the command line tool [lessc](http://lesscss.org/), you can bui
lessc -x themes/Example/less/build.less themes/Example/css/theme.css
```
or respectively by using [grunt](../developer/build.md):
or respectively by using [grunt](../developer/core-build.md):
```
grunt build-theme --name=Example

View File

@ -1,5 +0,0 @@
# Theme Migration to HumHub 1.3
## Space & Profile Layouts
The sidebars are now moved into own files `_sidebar.php` view files.

View File

@ -11,7 +11,7 @@ All changes or additions will be automatically applied to your theme.
## View Files
As mentioned in the [View Files](views.md) section, you may need to manually adjust overwritten view files if there are any changes made in the new **HumHub** version.
As mentioned in the [View Files](view.md) section, you may need to manually adjust overwritten view files if there are any changes made in the new **HumHub** version.
### Identifing changes using Git command

View File

@ -1,8 +1,10 @@
Tutorial
========
Foreword
--------
This quick tutorial shows you all necessary steps to create a custom **HumHub** theme.
- Step 1: Create a theme folder ([Theme Folder Structure](structure.md))
@ -12,21 +14,23 @@ This quick tutorial shows you all necessary steps to create a custom **HumHub**
Step 1: Create an own theme folder
---------------------------------
- Go to the HumHub installation directory
- Switch to the directory `themes`
- Copy the folder `HumHub` and rename it to `Example`
- Enable the new `Example` theme under `Administration -> Settings -> Appearance`
Step 2: Adjust colors and build CSS
-----------------------------------
### Installing prerequisites
**Install NodeJS**
** Install NodeJS **
See: https://nodejs.org/en/download/
**Install LESS**
** Install LESS **
Open the command console and execute:
@ -35,6 +39,7 @@ npm -g install less
```
### Modify theme colors
Add modifed color variables to the file `/themes/Example/less/variables.less`.
```
@ -47,6 +52,7 @@ Add modifed color variables to the file `/themes/Example/less/variables.less`.
```
### Compile LESS file
Open the command console and change to the themes `less` directory
```
@ -60,21 +66,25 @@ lessc build.less ../css/theme.css
```
### Test the result
- Flush your browsers cache
- Flush the HumHub cache (if enabled): `Administration -> Settings -> Advanced -> Cache -> Flush`
- Fully reload the page
![Example](images/color-example.png)
Step 3: Modify login template
------------------------------
In this step we're adding some text to the login template.
### Create a themed view file
Copy the view file `humhub/modules/user/views/auth/login.php` to `Example/views/user/auth/login.php`
### Modify the view file
Add some additional text below the application name.
```php
@ -90,9 +100,11 @@ Add some additional text below the application name.
```
Text Example:
![Example Text](images/modify-template.png)
### Result
![Result](images/modify-template-result.png)

View File

@ -1,106 +0,0 @@
<?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);
}
}

View File

@ -9,7 +9,6 @@
namespace humhub\libs;
use Yii;
use yii\base\Object;
use yii\helpers\ArrayHelper;
/**
@ -17,7 +16,7 @@ use yii\helpers\ArrayHelper;
*
* @author luke
*/
class DynamicConfig extends Object
class DynamicConfig extends \yii\base\Object
{
/**
@ -27,7 +26,7 @@ class DynamicConfig extends Object
*/
public static function merge($new)
{
$config = ArrayHelper::merge(self::load(), $new);
$config = \yii\helpers\ArrayHelper::merge(self::load(), $new);
self::save($config);
}
@ -50,7 +49,7 @@ class DynamicConfig extends Object
$config = eval($configContent);
if (!is_array($config))
return [];
return array();
return $config;
}
@ -62,14 +61,15 @@ class DynamicConfig extends 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 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,22 +118,17 @@ class DynamicConfig extends 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'] = [];
$config['components']['user'] = array();
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'] = [];
$mail['transport'] = array();
if (Yii::$app->settings->get('mailer.transportType') == 'smtp') {
$mail['transport']['class'] = 'Swift_SmtpTransport';

View File

@ -11,8 +11,6 @@ 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
@ -96,12 +94,9 @@ class Html extends \yii\bootstrap\Html
*/
public static function containerLink(ContentContainerActiveRecord $container, $options = [])
{
if ($container instanceof Space) {
if ($container instanceof \humhub\modules\space\models\Space) {
return static::a(static::encode($container->name), $container->getUrl(), $options);
} elseif ($container instanceof User) {
if ($container->status == User::STATUS_SOFT_DELETED) {
return static::beginTag('strike') . static::encode($container->displayName) . static::endTag('strike');
}
} elseif ($container instanceof \humhub\modules\user\models\User) {
return static::a(static::encode($container->displayName), $container->getUrl(), $options);
} else {
throw new InvalidParamException('Content container type not supported!');

View File

@ -1,62 +0,0 @@
<?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;
}
*/
}

View File

@ -9,7 +9,7 @@
namespace humhub\modules\activity\jobs;
use Yii;
use humhub\modules\queue\ActiveJob;
use humhub\components\queue\ActiveJob;
use humhub\modules\activity\components\MailSummaryProcessor;
use humhub\modules\activity\components\MailSummary;

View File

@ -48,11 +48,6 @@ class Module extends \humhub\components\Module
*/
public $dailyCheckForNewVersion = true;
/**
* @var boolean allow admins to impersonate other users
*/
public $allowUserImpersonate = true;
/**
* @inheritdoc
*/

View File

@ -1,23 +1,15 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
* @copyright Copyright (c) 2017 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\admin\controllers;
use Exception;
use humhub\modules\admin\components\Controller;
use humhub\modules\admin\models\forms\AuthenticationLdapSettingsForm;
use humhub\modules\admin\models\forms\AuthenticationSettingsForm;
use humhub\modules\admin\permissions\ManageSettings;
use humhub\modules\user\authclient\ZendLdapClient;
use humhub\modules\user\libs\LdapHelper;
use humhub\modules\user\models\Group;
use Yii;
use Zend\Ldap\Exception\LdapException;
use Zend\Ldap\Ldap;
use humhub\modules\admin\components\Controller;
/**
* ApprovalController handels new user approvals
@ -42,8 +34,8 @@ class AuthenticationController extends Controller
]);
$this->subLayout = '@admin/views/layouts/user';
return parent::init();
return parent::init();
}
/**
@ -52,48 +44,38 @@ class AuthenticationController extends Controller
public function getAccessRules()
{
return [
['permissions' => ManageSettings::className()]
['permissions' => \humhub\modules\admin\permissions\ManageSettings::className()]
];
}
/**
* Returns a List of Users
* @return string
*/
public function actionIndex()
{
$form = new AuthenticationSettingsForm;
$form = new \humhub\modules\admin\models\forms\AuthenticationSettingsForm;
if ($form->load(Yii::$app->request->post()) && $form->validate() && $form->save()) {
$this->view->saved();
}
// Build Group Dropdown
$groups = [
'' => Yii::t(
'AdminModule.controllers_SettingController',
'None - shows dropdown in user registration.'
)
];
foreach (Group::find()->all() as $group) {
$groups = [];
$groups[''] = Yii::t('AdminModule.controllers_SettingController', 'None - shows dropdown in user registration.');
foreach (\humhub\modules\user\models\Group::find()->all() as $group) {
if (!$group->is_admin_group) {
$groups[$group->id] = $group->name;
}
}
return $this->render('authentication', [
'model' => $form,
'groups' => $groups
]);
'model' => $form,
'groups' => $groups
]);
}
/**
* Configure Ldap authentication
* @return string
*/
public function actionAuthenticationLdap()
{
$form = new AuthenticationLdapSettingsForm;
$form = new \humhub\modules\admin\models\forms\AuthenticationLdapSettingsForm;
if ($form->load(Yii::$app->request->post()) && $form->validate() && $form->save()) {
$this->view->saved();
return $this->redirect(['/admin/authentication/authentication-ldap']);
@ -106,16 +88,16 @@ class AuthenticationController extends Controller
if (Yii::$app->getModule('user')->settings->get('auth.ldap.enabled')) {
$enabled = true;
try {
$ldapAuthClient = new ZendLdapClient();
$ldapAuthClient = new \humhub\modules\user\authclient\ZendLdapClient();
$ldap = $ldapAuthClient->getLdap();
$userCount = $ldap->count(
Yii::$app->getModule('user')->settings->get('auth.ldap.userFilter'),
Yii::$app->getModule('user')->settings->get('auth.ldap.baseDn'),
Ldap::SEARCH_SCOPE_SUB
\Zend\Ldap\Ldap::SEARCH_SCOPE_SUB
);
} catch (LdapException $ex) {
} catch (\Zend\Ldap\Exception\LdapException $ex) {
$errorMessage = $ex->getMessage();
} catch (Exception $ex) {
} catch (\Exception $ex) {
$errorMessage = $ex->getMessage();
}
}

View File

@ -15,8 +15,6 @@ 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.
@ -302,13 +300,45 @@ class ModuleController extends Controller
throw new HttpException(500, 'Invalid module type!');
}
$model = new ModuleSetAsDefaultForm();
$model->spaceDefaultState = ContentContainerModuleManager::getDefaultState(Space::class, $moduleId);
$model->userDefaultState = ContentContainerModuleManager::getDefaultState(User::class, $moduleId);
$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;
}
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
ContentContainerModuleManager::setDefaultState(User::class, $moduleId, $model->userDefaultState);
ContentContainerModuleManager::setDefaultState(Space::class, $moduleId, $model->spaceDefaultState);
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));
}
}
return $this->renderModalClose();
}

View File

@ -6,42 +6,34 @@
*
*/
/**
* Created by PhpStorm.
* User: buddha
* Date: 31.07.2017
* Time: 13:25
*/
namespace humhub\modules\admin\controllers;
use DateTime;
use humhub\components\ActiveRecord;
use humhub\modules\admin\components\Controller;
use humhub\modules\admin\models\PendingRegistrationSearch;
use humhub\modules\admin\permissions\ManageGroups;
use humhub\modules\admin\permissions\ManageUsers;
use humhub\modules\user\models\Invite;
use PHPExcel;
use PHPExcel_Cell;
use PHPExcel_Exception;
use PHPExcel_IOFactory;
use PHPExcel_Shared_Date;
use PHPExcel_Style_NumberFormat;
use PHPExcel_Worksheet;
use PHPExcel_Writer_Excel2007;
use function PHPSTORM_META\type;
use Yii;
use yii\helpers\Url;
use yii\web\HttpException;
use yii\helpers\ArrayHelper;
class PendingRegistrationsController extends Controller
{
const EXPORT_CSV = 'csv';
const EXPORT_XLSX = 'xsls';
const EXPORT_PREFIX = 'pur_export';
const EXPORT_COLUMNS = [
'email',
'originator.username',
'language',
'source',
'created_at',
];
/**
* @inheritdoc
*/
public function init()
{
$this->subLayout = '@admin/views/layouts/user';
@ -64,117 +56,24 @@ class PendingRegistrationsController extends Controller
];
}
/**
* Render PendingRegistrations
*
* @param bool $export
* @param null $format
* @return string
*/
public function actionIndex($export = false, $format = null)
{
$searchModel = new PendingRegistrationSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$urlExportCsv = Url::to([
'export',
'format' => self::EXPORT_CSV,
'PendingRegistrationSearch' => Yii::$app->request->get('PendingRegistrationSearch')
]);
if($export) {
return $this->createCVS($dataProvider, $searchModel, $format);
}
$urlExportXlsx = Url::to([
'export',
'format' => self::EXPORT_XLSX,
'PendingRegistrationSearch' => Yii::$app->request->get('PendingRegistrationSearch')
]);
return $this->render('index', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
'urlExportCsv' => $urlExportCsv,
'urlExportXlsx' => $urlExportXlsx,
'types' => $this->typeMapping(),
'types' => $this->getTypeMapping()
]);
}
/**
* Export PendingRegistrations
*
* @param string $format
* @throws PHPExcel_Exception
*/
public function actionExport($format)
{
$searchModel = new PendingRegistrationSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
/** @var PHPExcel $file */
$file = $this->createCsvFile();
/** @var PHPExcel_Worksheet $worksheet */
$worksheet = $file->getActiveSheet();
// Row counter
$rowCount = 1;
// Build Header
$this->buildCsvHeaderRow($worksheet, $rowCount, $searchModel);
// Set format for Date fields
$formatDate = $format === self::EXPORT_CSV
? Yii::$app->formatter->getDateTimePattern()
: PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME;
// Build Rows
foreach ($dataProvider->query->all() as $record) {
$rowCount++;
$this->buildCsvRow($rowCount, $record, $worksheet, $formatDate);
}
if ($format === self::EXPORT_CSV) {
$this->exportAsCsv($file);
} else {
$this->exportAsXlsx($file);
}
}
/**
* Resend a invite
*
* @param integer $id
* @return string
* @throws HttpException
*/
public function actionResend($id)
{
$invite = Invite::findOne(['id' => $id]);
if ($invite === null) {
throw new HttpException(404, Yii::t(
'AdminModule.controllers_PendingRegistrationsController',
'Invite not found!'
));
}
if (Yii::$app->request->isPost) {
$invite->sendInviteMail();
$invite->save();
$invite->refresh();
$this->view->success(Yii::t(
'AdminModule.controllers_PendingRegistrationsController',
'Resend invitation email'
));
}
return $this->render('resend', ['model' => $invite]);
}
/**
* Return type mapping
*
* @return array
*/
private function typeMapping()
public function getTypeMapping()
{
return [
PendingRegistrationSearch::SOURCE_INVITE => Yii::t('AdminModule.base', 'Invite'),
@ -182,105 +81,78 @@ class PendingRegistrationsController extends Controller
];
}
/**
* Export the file as Csv
*
* @param PHPExcel $file
* @throws \PHPExcel_Reader_Exception
* @throws \PHPExcel_Writer_Exception
*/
private function exportAsCsv($file)
public function createCVS($dataProvider, ActiveRecord $model, $format = null)
{
header('Content-Type: application/csv');
header('Content-Disposition: attachment;filename="' . self::EXPORT_PREFIX . '_' . time() . '.csv"');
header('Cache-Control: max-age=0');
$columns = [
['email'],
['originator.username'],
['language'],
['source'],
['created_at', 'type' => 'datetime'],
];
/** @var \PHPExcel_Writer_CSV $writer */
$writer = PHPExcel_IOFactory::createWriter($file, 'CSV');
$writer->setDelimiter(';');
$writer->save('php://output');
}
/**
* Export the file as Xlsx
*
* @param PHPExcel $file
* @throws \PHPExcel_Reader_Exception
* @throws \PHPExcel_Writer_Exception
*/
private function exportAsXlsx($file)
{
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . self::EXPORT_PREFIX . '_' . time() . '.xlsx"');
header('Cache-Control: max-age=0');
/** @var \PHPExcel_Writer_Excel2007 $writer */
$writer = PHPExcel_IOFactory::createWriter($file, 'Excel2007');
$writer->save('php://output');
}
/**
* Build a row for csv document
*
* @param integer $row
* @param PendingRegistrationSearch $record
* @param PHPExcel_Worksheet $worksheet
* @param string $formatDate
*/
private function buildCsvRow($row, $record, $worksheet, $formatDate)
{
for ($i = 0; $i < count(self::EXPORT_COLUMNS); $i++) {
$name = self::EXPORT_COLUMNS[$i];
$value = $record->{$name};
if ($name === 'source') {
$typeMapping = $this->typeMapping();
$value = isset($typeMapping[$value]) ? $typeMapping[$value] : $value;
}
if ($name === 'created_at') {
$worksheet->getStyleByColumnAndRow($i, $row)->getNumberFormat()->setFormatCode($formatDate);
$value = PHPExcel_Shared_Date::PHPToExcel(new \DateTime($value));
}
$worksheet->setCellValueByColumnAndRow($i, $row, $value);
}
}
/**
* Build header row for csv document
*
* @param PHPExcel_Worksheet $worksheet
* @param integer $row
* @param PendingRegistrationSearch $searchModel
*/
private function buildCsvHeaderRow($worksheet, $row, $searchModel)
{
for ($i = 0; $i < count(self::EXPORT_COLUMNS); $i++) {
$worksheet->getColumnDimension(PHPExcel_Cell::stringFromColumnIndex($i))->setWidth(30);
$worksheet->setCellValueByColumnAndRow($i, $row, $searchModel->getAttributeLabel(self::EXPORT_COLUMNS[$i]));
}
}
/**
* Return new PHPExcel file
*
* @return PHPExcel
*/
private function createCsvFile()
{
$title = Yii::t(
'AdminModule.base',
'Pending user registrations'
);
/** @var PHPExcel $file */
$file = new PHPExcel();
$file->getProperties()
->setCreator('HumHub')
->setTitle($title)
->setSubject($title)
->setDescription($title);
return $file;
$file->getProperties()->setCreator('HumHub');
$file->getProperties()->setTitle(Yii::t('AdminModule.base', 'Pending user registrations'));
$file->getProperties()->setSubject(Yii::t('AdminModule.base', 'Pending user registrations'));
$file->getProperties()->setDescription(Yii::t('AdminModule.base', 'Pending user registrations'));
$file->setActiveSheetIndex(0);
$worksheet = $file->getActiveSheet();
$worksheet->setTitle(Yii::t('AdminModule.base', 'Pending user registrations'));
// Creat header
$row = 1;
$lastColumn = count($columns);
for ($column = 0; $column != $lastColumn; $column++) {
$columnKey = PHPExcel_Cell::stringFromColumnIndex($column);
$worksheet->getColumnDimension($columnKey)->setWidth(30);
$worksheet->setCellValueByColumnAndRow($column, $row, $model->getAttributeLabel($columns[$column][0]));
}
$row++;
// Fill content header
foreach($dataProvider->query->all() as $record) {
for ($column = 0; $column != $lastColumn; $column++) {
$attribute = $columns[$column][0];
$value = ArrayHelper::getValue($record,$attribute);
if(isset($columns[$column]['type']) && $columns[$column]['type'] === 'datetime') {
$value = PHPExcel_Shared_Date::PHPToExcel(new DateTime($value));
if($format === 'CSV') {
$worksheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(Yii::$app->formatter->getDateTimePattern());
} else {
$worksheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME);
}
}
if($attribute === 'source') {
$types = $this->getTypeMapping();
$value = isset($types[$value]) ? $types[$value] : $value;
}
$worksheet->setCellValueByColumnAndRow($column, $row, $value);
}
$row++;
}
$filePrefix = 'pur_export_'.time();
if($format === 'CSV') {
$writer = PHPExcel_IOFactory::createWriter($file, 'CSV');
$writer->setDelimiter(';');
header('Content-Type: application/csv');
header('Content-Disposition: attachment;filename="'.$filePrefix.'.csv"');
header('Cache-Control: max-age=0');
} else {
$writer = PHPExcel_IOFactory::createWriter($file, 'Excel2007');
header('Content-type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="'.$filePrefix.'.xlsx"');
header('Cache-Control: max-age=0');
}
$writer->save('php://output');
}
}
}

View File

@ -49,7 +49,10 @@ class SpaceController extends Controller
public function getAccessRules()
{
return [
['permissions' => [ManageSpaces::className(), ManageSettings::className()]],
['permissions' => [
ManageSpaces::className(),
ManageSettings::className()
]],
];
}
@ -58,42 +61,21 @@ class SpaceController extends Controller
*/
public function actionIndex()
{
if (!Yii::$app->user->can(new ManageSpaces())) {
return $this->redirect(['settings']);
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'
]);
}
$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());
}
throw new HttpException(403);
}
/**
@ -127,11 +109,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
]
);
}

View File

@ -12,16 +12,14 @@ 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\admin\models\forms\UserDeleteForm;
use humhub\modules\admin\models\UserSearch;
use humhub\modules\space\models\Membership;
/**
* User management
@ -36,15 +34,12 @@ 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();
}
/**
@ -53,37 +48,36 @@ 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 actionList()
public function actionIndex()
{
$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
]);
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();
}
}
/**
@ -154,6 +148,12 @@ 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,8 +172,15 @@ 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(['delete', 'id' => $user->id]);
return $this->redirect(['/admin/user/delete', 'id' => $user->id]);
}
return $this->render('edit', [
@ -182,6 +189,11 @@ 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();
@ -197,109 +209,33 @@ class UserController extends Controller
/**
* Deletes a user permanently
*/
public function actionDelete($id)
public function actionDelete()
{
$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!'));
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.user', 'You cannot delete yourself!'));
throw new HttpException(400, Yii::t('AdminModule.controllers_UserController', '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']);
if ($doit == 2) {
$this->forcePostRequest();
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->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);
}
$user->status = User::STATUS_ENABLED;
$user->save();
return $this->redirect(['list']);
}
public function actionDisable($id)
{
$this->forcePostRequest();
$user = User::findOne(['id' => $id]);
if ($user === null) {
throw new HttpException(404);
}
$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;
return $this->render('delete', ['model' => $user]);
}
}

View File

@ -1,43 +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\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);
}
}

View File

@ -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\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;
}
}

View File

@ -1,40 +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\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]);
}
}

View File

@ -1,56 +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\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 = '&nbsp;<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>';
}
}

View File

@ -1,55 +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\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);
}
}

View File

@ -9,7 +9,7 @@
namespace humhub\modules\admin\jobs;
use Yii;
use humhub\modules\queue\ActiveJob;
use humhub\components\queue\ActiveJob;
use humhub\modules\user\models\Group;
use humhub\modules\admin\libs\HumHubAPI;
use humhub\modules\admin\notifications\NewVersionAvailable;

View File

@ -8,7 +8,7 @@
namespace humhub\modules\admin\jobs;
use humhub\modules\queue\ActiveJob;
use humhub\components\queue\ActiveJob;
use humhub\modules\admin\models\Log;
/**

View File

@ -1,22 +0,0 @@
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message/extract-module' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
'Invite not found!' => '',
'Resend invitation email' => '',
];

View File

@ -8,32 +8,24 @@
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;
/**
* SpaceSearch for administration
* Description of UserSearch
*
* @author luke
*/
class SpaceSearch extends Space
{
public $freeText;
public $memberCount;
public $owner;
/**
* @inheritdoc
*/
public function rules()
{
return [
[['id', 'visibility', 'join_policy'], 'integer'],
[['freeText'], 'safe'],
[['name'], 'safe'],
];
}
@ -42,28 +34,10 @@ 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
*
@ -73,10 +47,7 @@ class SpaceSearch extends Space
*/
public function search($params)
{
$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]);
$query = Space::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
@ -89,60 +60,22 @@ 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],
];
// default visibility
$this->visibility = Space::VISIBILITY_ALL;
$this->load($params);
if (!$this->validate()) {
$query->emulateExecution();
$query->where('0=1');
return $dataProvider;
}
// 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]
]);
}
$query->andFilterWhere(['id' => $this->id]);
$query->andFilterWhere(['join_policy' => $this->join_policy]);
$query->andFilterWhere(['visibility' => $this->visibility]);
$query->andFilterWhere(['like', 'name', $this->name]);
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 . ')',
];
}
}

Some files were not shown because too many files have changed in this diff Show More