mirror of
https://github.com/humhub/humhub.git
synced 2025-01-18 06:38:14 +01:00
Merge branch 'develop' of github.com:humhub/humhub into develop
# Conflicts: # protected/humhub/docs/CHANGELOG_DEV.md
This commit is contained in:
commit
c432cbc942
@ -15,7 +15,9 @@ HumHub Change Log (DEVELOP)
|
||||
- Enh #3697: Stay of module update page after updating a module
|
||||
- Fix #3692: Icon Upload Problems
|
||||
- Fix #3705: Don't render empty navigation/menu
|
||||
- Fix #3706: Space mentioning broken
|
||||
- Fix #3706: Space mentioning broken
|
||||
- Fix #3742: OAuth timeout doesn't respect configured timeout
|
||||
- Enh: Added `DateHelper:getUserTimeZone()`, `DateHelper:getSystemTimeZone()`, `DateHelper:isInDbFormat()`
|
||||
- Fix #3711: Fullscreen Richtext menu broken on ios safari
|
||||
|
||||
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
namespace humhub\libs;
|
||||
|
||||
use DateTimeZone;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Utility class for date issues
|
||||
*
|
||||
@ -16,12 +19,59 @@ namespace humhub\libs;
|
||||
*/
|
||||
class DateHelper
|
||||
{
|
||||
const DB_DATE_FORMAT = 'Y-m-d H:i:s';
|
||||
const DB_DATE_FORMAT_PHP = 'php:Y-m-d H:i:s';
|
||||
const REGEX_DBFORMAT_DATE = '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/';
|
||||
const REGEX_DBFORMAT_DATETIME = '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (\d{2}):(\d{2}):(\d{2})$/';
|
||||
|
||||
/**
|
||||
* Returns the user timeZone or app timezone as fallback.
|
||||
*
|
||||
* @return DateTimeZone|string
|
||||
* @since v1.4
|
||||
*/
|
||||
public static function getUserTimeZone($asString = false)
|
||||
{
|
||||
$tz = Yii::$app->user->isGuest
|
||||
? Yii::$app->timeZone
|
||||
: Yii::$app->user->getTimeZone();
|
||||
|
||||
if(!$tz) {
|
||||
$tz = Yii::$app->timeZone;
|
||||
}
|
||||
|
||||
return $asString ? $tz : new DateTimeZone($tz);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $asString
|
||||
* @return DateTimeZone|string
|
||||
* @since v1.4
|
||||
*/
|
||||
public static function getSystemTimeZone($asString = false)
|
||||
{
|
||||
return $asString ? Yii::$app->timeZone : new DateTimeZone(Yii::$app->timeZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given value is a db date format or not.
|
||||
*
|
||||
* @param string $value the date value
|
||||
* @return boolean
|
||||
* @since v1.4
|
||||
*/
|
||||
public static function isInDbFormat($value)
|
||||
{
|
||||
return (preg_match(self::REGEX_DBFORMAT_DATE, $value) || preg_match(self::REGEX_DBFORMAT_DATETIME, $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a date and optionally a time if timeAttribute is specified.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $timeValue optional time value
|
||||
* @return int timestamp in utc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function parseDateTimeToTimestamp($value, $timeValue = null)
|
||||
{
|
||||
@ -33,9 +83,10 @@ class DateHelper
|
||||
* an given pattern or the default pattern 'Y-m-d' if no pattern is provided.
|
||||
*
|
||||
* @param string $value date value
|
||||
* @param string $pattern pattern
|
||||
* @param string $pattern pattern
|
||||
* @param string $timeValue optional time value
|
||||
* @return int timestamp in utc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function parseDateTime($value, $pattern = 'Y-m-d', $timeValue = null)
|
||||
{
|
||||
|
@ -37,13 +37,7 @@ class DbDateValidator extends DateValidator
|
||||
public $timeAttribute = '';
|
||||
|
||||
/**
|
||||
* @var defines the source time zone which is by default the user time zone, this can be used if a form uses an own
|
||||
* timestamp setting.
|
||||
*/
|
||||
public $timeZone;
|
||||
|
||||
/**
|
||||
* @var string attribute name to save converted value to
|
||||
* @var string attribute name to save converted value to
|
||||
*/
|
||||
public $targetAttribute = null;
|
||||
|
||||
@ -52,10 +46,14 @@ class DbDateValidator extends DateValidator
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ($this->format === null) {
|
||||
if (!$this->format) {
|
||||
$this->format = Yii::$app->formatter->dateInputFormat;
|
||||
}
|
||||
|
||||
if(!$this->timeZone) {
|
||||
$this->timeZone = DateHelper::getUserTimeZone(true);
|
||||
}
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
@ -64,13 +62,14 @@ class DbDateValidator extends DateValidator
|
||||
*/
|
||||
public function validateAttribute($model, $attribute)
|
||||
{
|
||||
|
||||
// If no source timeZone
|
||||
if (empty($this->timeZone)) {
|
||||
$this->timeZone = (!\Yii::$app->formatter->timeZone) ? \Yii::$app->timeZone : \Yii::$app->formatter->timeZone;
|
||||
// If the date is already in system format, we do not need any further translation or parsing
|
||||
if(DateHelper::isInDbFormat($model->$attribute)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$timestamp = $this->parseDateTimeValue($model->$attribute, $this->getTimeValue($model));
|
||||
|
||||
$timeValue = $this->getTimeValue($model);
|
||||
$timestamp = $this->parseDateTimeValue($model->$attribute, $timeValue);
|
||||
|
||||
if ($timestamp === false) {
|
||||
$this->addError($model, $attribute, $this->message, []);
|
||||
@ -78,17 +77,14 @@ class DbDateValidator extends DateValidator
|
||||
$this->addError($model, $attribute, $this->tooSmall, ['min' => $this->minString]);
|
||||
} elseif ($this->max !== null && $timestamp > $this->max) {
|
||||
$this->addError($model, $attribute, $this->tooBig, ['max' => $this->maxString]);
|
||||
} elseif (!$this->isInDbFormat($model->$attribute)) {
|
||||
} else {
|
||||
// If there is no error, and attribute is not yet in DB Format - convert to DB
|
||||
$date = new \DateTime();
|
||||
$date = new \DateTime(null, new \DateTimeZone('UTC'));
|
||||
$date->setTimestamp($timestamp);
|
||||
if ($this->hasTime()) {
|
||||
|
||||
if ($timeValue) {
|
||||
// Convert timestamp to apps timeZone
|
||||
$date->setTimezone(new \DateTimeZone(\Yii::$app->timeZone));
|
||||
} else {
|
||||
// If we do not need to respect time, set timezone to utc
|
||||
// To ensure we're saving 00:00:00 time infos.
|
||||
$date->setTimezone(new \DateTimeZone('UTC'));
|
||||
$date->setTimezone(DateHelper::getSystemTimeZone());
|
||||
}
|
||||
|
||||
$targetAttribute = ($this->targetAttribute === null) ? $attribute : $this->targetAttribute;
|
||||
@ -99,6 +95,30 @@ class DbDateValidator extends DateValidator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a date and a time value if timeAttribute is specified.
|
||||
*
|
||||
* @param string $value
|
||||
* @return int timestamp in utc
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function parseDateTimeValue($value, $timeValue = null)
|
||||
{
|
||||
// It's already a database datetime / no conversion needed.
|
||||
if (DateHelper::isInDbFormat($value)) {
|
||||
return strtotime($value);
|
||||
}
|
||||
|
||||
$timestamp = $this->parseDateValue($value);
|
||||
|
||||
if ($this->hasTime() && !empty($timeValue)) {
|
||||
$timestamp += $this->parseTimeValue($timeValue);
|
||||
$timestamp = $this->fixTimestampTimeZone($timestamp, $this->timeZone);
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a time attribute name is given, if empty don't handle time
|
||||
*
|
||||
@ -110,18 +130,18 @@ class DbDateValidator extends DateValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time value
|
||||
* Returns time value if provided by the model
|
||||
*
|
||||
* @return string time value (e.g. 12:00)
|
||||
* @return string|null time value (e.g. 12:00)
|
||||
*/
|
||||
protected function getTimeValue($model)
|
||||
{
|
||||
if ($this->hasTime()) {
|
||||
$attributeName = $this->timeAttribute;
|
||||
return $model->$attributeName;
|
||||
return $model->$attributeName ?: null;
|
||||
}
|
||||
|
||||
return '';
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,54 +149,13 @@ class DbDateValidator extends DateValidator
|
||||
*
|
||||
* @param string $value
|
||||
* @return int timestamp in utc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function parseDateTime($value, $timeValue = null)
|
||||
{
|
||||
return (new self())->parseDateTimeValue($value, $timeValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a date and optionally a time if timeAttribute is specified.
|
||||
*
|
||||
* @param string $value
|
||||
* @return int timestamp in utc
|
||||
*/
|
||||
protected function parseDateTimeValue($value, $timeValue = "")
|
||||
{
|
||||
// It's already a database datetime / no conversion needed.
|
||||
if ($this->isInDbFormat($value)) {
|
||||
return strtotime($value);
|
||||
}
|
||||
|
||||
$timestamp = $this->parseDateValue($value);
|
||||
|
||||
if ($this->hasTime() && $timeValue != "") {
|
||||
$timestamp += $this->parseTimeValue($timeValue);
|
||||
$timestamp = $this->fixTimestampTimeZone($timestamp, $this->timeZone);
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given timestamp from user (or configured) timezone to a utc timestamp
|
||||
*
|
||||
* @param long $ts the timestamp
|
||||
* @param String $timeZone users timezone
|
||||
* @return long the timestamp in utc
|
||||
*/
|
||||
protected function fixTimestampTimeZone($ts, $timeZone)
|
||||
{
|
||||
// Create date string
|
||||
$fromDateTime = new \DateTime("@" . $ts);
|
||||
|
||||
// Create date object
|
||||
$toDateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $fromDateTime->format('Y-m-d H:i:s'), new \DateTimeZone($timeZone));
|
||||
$toDateTime->setTimezone(new \DateTimeZone('UTC'));
|
||||
|
||||
return $toDateTime->getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses given time value (hh:mm) to seconds
|
||||
*
|
||||
@ -190,13 +169,22 @@ class DbDateValidator extends DateValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given value is a db date format or not.
|
||||
* Converts the given timestamp from user (or configured) timezone to a utc timestamp
|
||||
*
|
||||
* @param string $value the date value
|
||||
* @return boolean
|
||||
* @param int $ts the timestamp
|
||||
* @param String $timeZone users timezone
|
||||
* @return int
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function isInDbFormat($value)
|
||||
protected function fixTimestampTimeZone($ts, $timeZone)
|
||||
{
|
||||
return (preg_match(self::REGEX_DBFORMAT_DATE, $value) || preg_match(self::REGEX_DBFORMAT_DATETIME, $value));
|
||||
// Create date string
|
||||
$fromDateTime = new \DateTime('@' . $ts);
|
||||
|
||||
// Create date object
|
||||
$toDateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $fromDateTime->format('Y-m-d H:i:s'), new \DateTimeZone($timeZone));
|
||||
$toDateTime->setTimezone(new \DateTimeZone('UTC'));
|
||||
|
||||
return $toDateTime->getTimestamp();
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\modules\user\authclient;
|
||||
|
||||
use humhub\modules\user\authclient\interfaces\StandaloneAuthClient;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Extended version of AuthAction with AuthClient support which are not handled
|
||||
@ -22,12 +23,14 @@ class AuthAction extends \yii\authclient\AuthAction
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
*
|
||||
* @param StandaloneAuthClient $client
|
||||
* @return \yii\web\Response response instance.
|
||||
*/
|
||||
public function auth($client, $authUrlParams = [])
|
||||
{
|
||||
Yii::$app->session->set('loginRememberMe', (boolean) Yii::$app->request->get('rememberMe'));
|
||||
|
||||
if ($client instanceof StandaloneAuthClient) {
|
||||
return $client->authAction($this);
|
||||
}
|
||||
|
@ -170,7 +170,9 @@ class AuthClientHelpers
|
||||
$registration->enableUserApproval = false;
|
||||
}
|
||||
|
||||
unset($attributes['id']);
|
||||
// remove potentially unsafe attributes
|
||||
unset($attributes['id'], $attributes['guid'], $attributes['contentcontainer_id'], $attributes['auth_mode'], $attributes['status']);
|
||||
|
||||
$registration->getUser()->setAttributes($attributes, false);
|
||||
$registration->getProfile()->setAttributes($attributes, false);
|
||||
$registration->getGroupUser()->setAttributes($attributes, false);
|
||||
|
@ -84,7 +84,7 @@ class AuthController extends Controller
|
||||
return $this->onAuthSuccess($login->authClient);
|
||||
}
|
||||
|
||||
// Self Invite
|
||||
// Self Invite
|
||||
$invite = new Invite();
|
||||
$invite->scenario = 'invite';
|
||||
if ($invite->load(Yii::$app->request->post()) && $invite->selfInvite()) {
|
||||
@ -119,7 +119,7 @@ class AuthController extends Controller
|
||||
return $this->redirect(['/user/account/connected-accounts']);
|
||||
}
|
||||
|
||||
// Login existing user
|
||||
// Login existing user
|
||||
$user = AuthClientHelpers::getUserByAuthClient($authClient);
|
||||
|
||||
if ($user !== null) {
|
||||
@ -177,12 +177,12 @@ class AuthController extends Controller
|
||||
$success = false;
|
||||
if ($user->status == User::STATUS_ENABLED) {
|
||||
$duration = 0;
|
||||
if ($authClient instanceof BaseFormAuth) {
|
||||
if ($authClient->login->rememberMe) {
|
||||
$duration = Yii::$app->getModule('user')->loginRememberMeDuration;
|
||||
}
|
||||
}
|
||||
if (
|
||||
($authClient instanceof BaseFormAuth && $authClient->login->rememberMe) ||
|
||||
!empty(Yii::$app->session->get('loginRememberMe'))) {
|
||||
|
||||
$duration = Yii::$app->getModule('user')->loginRememberMeDuration;
|
||||
}
|
||||
AuthClientHelpers::updateUser($authClient, $user);
|
||||
|
||||
if ($success = Yii::$app->user->login($user, $duration)) {
|
||||
|
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\tests\codeception\unit\libs;
|
||||
|
||||
|
||||
use Yii;
|
||||
use humhub\libs\DbDateValidator;
|
||||
use tests\codeception\_support\HumHubDbTestCase;
|
||||
|
||||
/**
|
||||
* Class MimeHelperTest
|
||||
*/
|
||||
class DBDateValidatorTest extends HumHubDbTestCase
|
||||
{
|
||||
public function _before()
|
||||
{
|
||||
parent::_before();
|
||||
Yii::$app->timeZone = 'Europe/Berlin';
|
||||
Yii::$app->language = 'en-US';
|
||||
$this->becomeUser('admin');
|
||||
Yii::$app->user->identity->time_zone = 'Europe/London';
|
||||
}
|
||||
|
||||
public function testInitValues()
|
||||
{
|
||||
$validator = new DbDateValidator();
|
||||
$this->assertEquals('Europe/London', $validator->timeZone);
|
||||
$this->assertEquals('short', $validator->format);
|
||||
$this->assertEquals('en-US', $validator->locale);
|
||||
}
|
||||
|
||||
public function testParseDateWithoutTimeValueFormatUS()
|
||||
{
|
||||
// No time translation, since no time value given
|
||||
$model = new DateValidatorTestModel(['date' => '12/1/19']);
|
||||
$validator = new DbDateValidator();
|
||||
$validator->validateAttribute($model, 'date');
|
||||
$this->assertEmpty($model->getErrors());
|
||||
$this->assertEquals('2019-12-01 00:00:00', $model->date);
|
||||
}
|
||||
|
||||
public function testParseDateWithoutTimeValueFormatDe()
|
||||
{
|
||||
// No time translation, since no time value given
|
||||
Yii::$app->language = 'de';
|
||||
$model = new DateValidatorTestModel(['date' => '01.12.19']);
|
||||
$validator = new DbDateValidator();
|
||||
$this->assertEquals('de', $validator->locale);
|
||||
$validator->validateAttribute($model, 'date');
|
||||
$this->assertEmpty($model->getErrors());
|
||||
$this->assertEquals('2019-12-01 00:00:00', $model->date);
|
||||
}
|
||||
|
||||
public function testParseDateWithTimeValueFormatUS()
|
||||
{
|
||||
// Translate from Cairo (UTC +2) to Berlin (UTC + 1)
|
||||
$model = new DateValidatorTestModel(['date' => '12/1/19', 'time' => '12 PM']);
|
||||
$validator = new DbDateValidator(['timeAttribute' => 'time', 'timeZone' => 'Africa/Cairo']);
|
||||
$validator->validateAttribute($model, 'date');
|
||||
$this->assertEmpty($model->getErrors());
|
||||
$this->assertEquals('2019-12-01 11:00:00', $model->date);
|
||||
}
|
||||
|
||||
public function testParseDateWithTimeValueFormatDE()
|
||||
{
|
||||
// Translate from Cairo (UTC +2) to Berlin (UTC + 1)
|
||||
Yii::$app->language = 'de';
|
||||
$model = new DateValidatorTestModel(['date' => '01.12.19', 'time' => '12:00']);
|
||||
$validator = new DbDateValidator(['timeAttribute' => 'time', 'timeZone' => 'Africa/Cairo']);
|
||||
$validator->validateAttribute($model, 'date');
|
||||
$this->assertEmpty($model->getErrors());
|
||||
$this->assertEquals('2019-12-01 11:00:00', $model->date);
|
||||
}
|
||||
|
||||
|
||||
public function testDoubleValidation()
|
||||
{
|
||||
// Ensure that double validation does not translate the value two times
|
||||
$model = new DateValidatorTestModel(['date' => '12/1/19', 'time' => '12 PM']);
|
||||
$validator = new DbDateValidator(['timeAttribute' => 'time', 'timeZone' => 'Africa/Cairo']);
|
||||
$validator->validateAttribute($model, 'date');
|
||||
$validator->validateAttribute($model, 'date');
|
||||
$this->assertEquals('2019-12-01 11:00:00', $model->date);
|
||||
}
|
||||
|
||||
public function testValidateWithUnsetTimeAttribute()
|
||||
{
|
||||
// No time given, so do not translate
|
||||
$model = new DateValidatorTestModel(['date' => '12/1/19']);
|
||||
$validator = new DbDateValidator(['timeAttribute' => 'time']);
|
||||
$validator->validateAttribute($model, 'date');
|
||||
$this->assertEquals('2019-12-01 00:00:00', $model->date);
|
||||
$this->assertEmpty($model->getErrors());
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2018 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\tests\codeception\unit\libs;
|
||||
|
||||
use Codeception\Test\Unit;
|
||||
use humhub\libs\DateHelper;
|
||||
use humhub\libs\DbDateValidator;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* Class MimeHelperTest
|
||||
*/
|
||||
class DateHelperTest extends Unit
|
||||
{
|
||||
public function _before()
|
||||
{
|
||||
parent::_before();
|
||||
Yii::$app->timeZone = 'Europe/Berlin';
|
||||
Yii::$app->formatter->timeZone = 'UTC';
|
||||
}
|
||||
|
||||
public function testIsInDBFormat()
|
||||
{
|
||||
$this->assertTrue(DateHelper::isInDbFormat('2019-12-01'));
|
||||
$this->assertTrue(DateHelper::isInDbFormat('2019-12-01 12:30:00'));
|
||||
|
||||
$this->assertFalse(DateHelper::isInDbFormat('2019-13-01'));
|
||||
$this->assertFalse(DateHelper::isInDbFormat('2019-13-01 12:30:00'));
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace humhub\tests\codeception\unit\libs;
|
||||
|
||||
|
||||
use yii\base\Model;
|
||||
|
||||
class DateValidatorTestModel extends Model
|
||||
{
|
||||
public $date;
|
||||
|
||||
public $time;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user