Commit 349ab036 authored by Henning Leutz's avatar Henning Leutz 🥋

fix: Locale line break replacement at getByLang fixed; under certain...

fix: Locale line break replacement at getByLang fixed; under certain circumstances this was not done; conflict solved
parents 567a06e6 09800947
......@@ -14,23 +14,27 @@ QUI::$Ajax->registerFunction(
if ($server && is_array($server)) {
foreach ($server as $s) {
$Packages->addServer($s['server'], array(
$Packages->addServer($s['server'], [
'type' => $s['type']
));
]);
}
}
try {
$Packages->install($packageName, $packageVersion);
} catch (\QUI\Exception $Exception) {
QUI::getMessagesHandler()->addError($Exception->getMessage());
return false;
} catch (\Exception $Exception) {
return false;
}
return true;
},
array('packageName', 'packageVersion', 'server'),
array(
['packageName', 'packageVersion', 'server'],
[
'Permission::checkAdminUser',
'quiqqer.system.update'
)
]
);
......@@ -355,8 +355,19 @@ define('controls/projects/project/Panel', [
self.Loader.show();
Projects.getList(function (result) {
if (Object.getLength(result)) {
for (var key in result) {
var key;
if (Object.getLength(result) === 1) {
key = Object.keys(result)[0];
self.setAttribute('project', key);
self.setAttribute('lang', result[key].default_lang);
self.openProject();
self.Loader.hide();
return;
} else if (Object.getLength(result)) {
for (key in result) {
if (!result.hasOwnProperty(key)) {
continue;
}
......
/**
* Colors
*
* @module utils/color
*
* @author www.pcsg.de (Jan Wennrich)
* @author A lot of smart people from Stack Overflow
*/
define('utils/Color', [], function () {
"use strict";
return {
/**
* A custom web color pallet.
* Taken from clrs.cc (available under MIT license).
*
* @link https://clrs.cc/
* @link https://github.com/mrmrs/colors
*
* @licence MIT
*
* @typedef {Object} ColorPalette
* @property {string} aqua
* @property {string} black
* @property {string} blue
* @property {string} fuchsia
* @property {string} gray
* @property {string} green
* @property {string} lime
* @property {string} maroon
* @property {string} navy
* @property {string} olive
* @property {string} purple
* @property {string} red
* @property {string} silver
* @property {string} teal
* @property {string} white
* @property {string} yellow
*
* @type ColorPalette
*/
ColorPalette: {
aqua : "#7FDBFF",
black : "#111111",
blue : "#0074D9",
fuchsia: "#F012BE",
gray : "#AAAAAA",
green : "#2ECC40",
lime : "#01FF70",
maroon : "#85144b",
navy : "#001f3f",
olive : "#3D9970",
purple : "#B10DC9",
red : "#FF4136",
silver : "#DDDDDD",
teal : "#39CCCC",
white : "#FFFFFF",
yellow : "#FFDC00"
},
/**
* Generates a random color in hexadecimal format with a preceding "#"
*
* @see https://stackoverflow.com/questions/1484506/random-color-generator#comment6801353_5365036
*
* @returns {String}
*/
getRandomHexColor: function () {
return '#' + (Math.random() * 0xffffff).toString(16).slice(-6);
},
/**
* Returns an array with the given amount of random colors.
*
* @param {number} amount - How many colors to generate
* @return {Array}
*/
getRandomHexColors: function (amount) {
var result = [];
for (var i = 0; i < amount; i++) {
result.push(this.getRandomHexColor());
}
return result;
},
/**
* Returns a random color from the custom color pallet.
* Optionally an array of colors from the palette that should not be picked, can be passed.
*
* @param {array} [excludedColors] - Colors that should not be returned
*
* @return {String}
*/
getRandomHexColorFromPallet: function (excludedColors) {
var colors = Object.values(this.ColorPalette);
// Remove the excluded colors
if (excludedColors) {
excludedColors.forEach(function(excludedColor) {
colors.splice(colors.indexOf(excludedColor), 1);
});
}
return colors[Math.floor(Math.random() * colors.length)];
},
/**
* Returns an array with random colors from the color pallet.
* The amount of colors to return can be passed as an argument.
* If more colors are requested than there are in the pallet, some colors may appear multiple times.
*
* Optionally an array of colors from the palette that should not be picked, can be passed.
*
* Random picking taken from Bergi from {@link https://stackoverflow.com/a/19270021|Stack Overflow}
*
* @param {number} requestedColorsAmount
* @param {array} [excludedColors] - Colors that should not be returned
*
* @return {Array<String>}
*/
getRandomHexColorsFromPallet: function (requestedColorsAmount, excludedColors) {
var colors = Object.values(this.ColorPalette);
// Remove the excluded colors
if (excludedColors) {
excludedColors.forEach(function(excludedColor) {
colors.splice(colors.indexOf(excludedColor), 1);
});
}
var amountOfColors = colors.length,
result = [];
if (requestedColorsAmount > amountOfColors) {
result = result.concat(
this.getRandomHexColorsFromPallet(
requestedColorsAmount - amountOfColors,
excludedColors
)
);
requestedColorsAmount = amountOfColors;
}
while (requestedColorsAmount--) {
// Generate a random number to pick an element from the color array
var randomNumber = Math.floor(Math.random() * colors.length);
// Remove the color so we don't pick it twice
var pickedColor = colors.splice(randomNumber, 1)[0];
result.push(pickedColor);
}
return result;
},
/**
* Returns the hex code for a given color name from the custom color pallet
*
* @param {String} name
*
* @return {String}
*/
getHexColorFromPallet: function (name) {
return this.ColorPalette[name];
},
/**
* Converts a hex color (#0033FF, #03F, 03F, 0033FF) to an Object with RGB values.
*
* @note Taken from Tim Down from {@link https://stackoverflow.com/a/5624139|Stack Overflow}
*
* @param hex - Hex color format: '#0033FF', '#03F', '03F', or '0033FF'
*
* @return {Object} - RGB colors in object properties r, g, and b
*/
getRgbColorFromHex: function (hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function (m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
},
/**
* Converts an object with properties r, g, b to a hex string (e.g. "#0033FF")
*
* @note Taken from Tim Down from {@link https://stackoverflow.com/a/13070198|StackOverflow}
*
* @param {object} rgbObject - object with properties r, g, b
*
* @return {string} hex string (e.g. "#0033FF")
*/
getHexFromRgbObject: function (rgbObject) {
var rgbArray = [rgbObject.r, rgbObject.g, rgbObject.b];
var hexString = "#";
rgbArray.forEach(function (value) {
//Convert to a base16 string
var hexValue = parseInt(value).toString(16);
//Add zero if we get only one character
if (hexValue.length === 1) {
hexValue = "0" + hexValue;
}
hexString += hexValue;
});
return hexString;
},
/**
* Calculates whether the text color for the given background color should be black or white.
*
* @note Modified version of Marcus Mangelsdorf reply on {@link https://stackoverflow.com/a/36888120|StackOverflow}
*
* @param {Object} bgColor - Object with properties r, g and b
*
* @return {Object} - RGB colors in object properties r, g, and b
*/
getTextColorForRgbObject: function (bgColor) {
// Counting the perceptive luminance
var luminance = (((0.299 * bgColor.r) + ((0.587 * bgColor.g) + (0.114 * bgColor.b))) / 255);
// Return black for bright colors, white for dark colors
var r, g, b;
r = g = b = 0;
if (luminance < 0.5) {
r = g = b = 255;
}
return {r: r, g: g, b: b};
}
};
});
\ No newline at end of file
/**
* Date utils
*
* @module utils/Date
*
* @author www.pcsg.de (Jan Wennrich)
* @author Smart people from Stack Overflow
*
* @require Locale
*/
define('utils/Date', [
'Locale'
], function (QUILocale) {
"use strict";
return {
/**
* Returns the time since a given date as a readable string for the current language.
* Examples:
* - Date-object given dated to 3 days ago returns "3 days ago"
* - Date-object given dated to 51 seconds ago returns "51 seconds ago"
* - Currently german language; Date-object given dated to 51 seconds ago returns "vor 51 Sekunden"
*
* @param {TimeSinceObject} GivenDate
*
* @return {string}
*/
getTimeSinceAsString: function (GivenDate) {
var timeSince = this.getTimeSince(GivenDate);
return QUILocale.get(
'quiqqer/quiqqer',
'time.ago',
{
amount: timeSince.amount,
// get the time unit in dative form (necessary for languages like german)
unit : QUILocale.get('quiqqer/quiqqer', timeSince.unit + '.dative')
}
);
},
/**
* Returns the time since a given date in a appropriate size/format.
* The result is an object containing the time since the date and the calculated unit.
* This for example useful to format texts that tell the user how long ago something happened (e.g. for posts).
*
* If you don't want any fancy formatted text, then getTimeSinceAsString() can be used.
*
* Example:
* - A date 3 months ago would return {amount: 3, unit: 'months'}
* - A date 2 minutes ago would return {amount: 2, unit: 'minutes'}
*
* @author Inspired by a Stack Overflow answer from Sky Sander (https://stackoverflow.com/a/3177838)
*
* @param {Date} GivenDate
*
* @typedef {Object} TimeSinceObject
* @property {number} amount - The amount of time since a date
* @property {string} unit - The unit of time since a date. Can be either years, months, days, hours, minutes, or seconds
*
* @return {TimeSinceObject}
*/
getTimeSince: function (GivenDate) {
var seconds = Math.floor((new Date() - GivenDate) / 1000);
var interval = Math.floor(seconds / 31536000);
if (interval > 1) {
return {amount: interval, unit: "years"};
}
interval = Math.floor(seconds / 2592000);
if (interval > 1) {
return {amount: interval, unit: "months"};
}
interval = Math.floor(seconds / 86400);
if (interval > 1) {
return {amount: interval, unit: "days"};
}
interval = Math.floor(seconds / 3600);
if (interval > 1) {
return {amount: interval, unit: "hours"};
}
interval = Math.floor(seconds / 60);
if (interval > 1) {
return {amount: interval, unit: "minutes"};
}
return {amount: interval, unit: "seconds"};
}
};
});
{
"name": "quiqqer/quiqqer",
"name": "quiqqer\/quiqqer",
"type": "quiqqer-system",
"description": "A modular based management system written in JavaScript and PHP",
"version": "dev-master",
......@@ -8,70 +8,70 @@
{
"name": "Henning Leutz",
"email": "leutz@pcsg.de",
"homepage": "http://www.pcsg.de",
"homepage": "http:\/\/www.pcsg.de",
"role": "Developer"
},
{
"name": "Moritz Scholz",
"email": "scholz@pcsg.de",
"homepage": "http://www.pcsg.de",
"homepage": "http:\/\/www.pcsg.de",
"role": "Developer"
}
],
"support": {
"email": "support@pcsg.de",
"url": "http://www.quiqqer.com"
"url": "http:\/\/www.quiqqer.com"
},
"repositories": [
{
"type": "composer",
"url": "https://update.quiqqer.com"
"url": "https:\/\/update.quiqqer.com"
}
],
"require": {
"php": ">=5.3",
"composer/composer": "1.5.*",
"tedivm/stash": "0.14.*",
"robloach/component-installer": "0.0.12",
"phpmailer/phpmailer": "~6.0",
"symfony/http-foundation": ">=2.3|3.*|4.2.*",
"symfony/console": "~2.7",
"html2text/html2text": "1.0.1",
"intervention/image": "2.*",
"t7systems/blowfish": "1.0.0",
"pcsg/composer-assets": "^1.0.1",
"dusank/knapsack": "8.*",
"league/climate": "3.*",
"ramsey/uuid": "3.*",
"quiqqer/composer": ">=1.3|dev-master|dev-dev",
"quiqqer/controls": "1.*|dev-master|dev-dev",
"quiqqer/dashboard": "1.*|dev-master|dev-dev",
"quiqqer/qui": ">=1|dev-master|dev-dev",
"quiqqer/qui-php": ">=0.12|dev-master|dev-dev",
"quiqqer/smarty3": "1.*|dev-master|dev-dev",
"quiqqer/ckeditor4": "2.*|1.*|dev-master|dev-dev",
"quiqqer/calendar-controls": "1.*|dev-master|dev-dev",
"quiqqer/countries": "1.*|dev-master|dev-dev",
"quiqqer/colorpicker": ">=1.1|dev-master|dev-dev",
"quiqqer/translator": "1.*|dev-master|dev-dev",
"quiqqer/utils": ">=1.9|dev-master|dev-dev",
"quiqqer/cron": "1.*|dev-master|dev-dev",
"quiqqer/log": "1.*|dev-master|dev-dev",
"quiqqer/diashow": ">=0.9|dev-master|dev-dev",
"quiqqer/lockclient": "1.*|dev-master|dev-dev",
"quiqqer/messages": "1.*|dev-master|dev-dev",
"quiqqer/meta": "1.*|dev-master|dev-dev",
"quiqqer/fontawesome": "*",
"quiqqer/backendsearch": "1.*|dev-master|dev-dev",
"quiqqer/requirements": "2.*",
"npm-asset/intl": "1.*",
"npm-asset/nouislider": "*",
"npm-asset/mustache": "2.*",
"npm-asset/urijs": "1.*"
"composer\/composer": "1.5.*",
"tedivm\/stash": "0.14.*",
"robloach\/component-installer": "0.0.12",
"phpmailer\/phpmailer": "~6.0",
"symfony\/http-foundation": ">=2.3|3.*|4.2.*",
"symfony\/console": "~2.7",
"html2text\/html2text": "1.0.1",
"intervention\/image": "2.*",
"t7systems\/blowfish": "1.0.0",
"pcsg\/composer-assets": "^1.0.1",
"dusank\/knapsack": "8.*",
"league\/climate": "3.*",
"ramsey\/uuid": "3.*",
"quiqqer\/composer": ">=1.3|dev-master|dev-dev",
"quiqqer\/controls": "1.*|dev-master|dev-dev",
"quiqqer\/dashboard": "1.*|dev-master|dev-dev",
"quiqqer\/qui": ">=1|dev-master|dev-dev",
"quiqqer\/qui-php": ">=0.12|dev-master|dev-dev",
"quiqqer\/smarty3": "1.*|dev-master|dev-dev",
"quiqqer\/ckeditor4": "2.*|1.*|dev-master|dev-dev",
"quiqqer\/calendar-controls": "1.*|dev-master|dev-dev",
"quiqqer\/countries": "1.*|dev-master|dev-dev",
"quiqqer\/colorpicker": ">=1.1|dev-master|dev-dev",
"quiqqer\/translator": "1.*|dev-master|dev-dev",
"quiqqer\/utils": ">=1.9|dev-master|dev-dev",
"quiqqer\/cron": "1.*|dev-master|dev-dev",
"quiqqer\/log": "1.*|dev-master|dev-dev",
"quiqqer\/diashow": ">=0.9|dev-master|dev-dev",
"quiqqer\/lockclient": "1.*|dev-master|dev-dev",
"quiqqer\/messages": "1.*|dev-master|dev-dev",
"quiqqer\/meta": "1.*|dev-master|dev-dev",
"quiqqer\/fontawesome": "*",
"quiqqer\/backendsearch": "1.*|dev-master|dev-dev",
"quiqqer\/requirements": "2.*",
"npm-asset\/intl": "1.*",
"npm-asset\/nouislider": "*",
"npm-asset\/mustache": "2.*",
"npm-asset\/urijs": "1.*"
},
"require-dev": {
"mikey179/vfsStream": "1.*",
"phpstan/phpstan": ">=0.5"
"mikey179\/vfsStream": "1.*",
"phpstan\/phpstan": ">=0.5"
},
"scripts": {
"post-install-cmd": [
......@@ -83,12 +83,12 @@
},
"autoload": {
"psr-0": {
"QUI": "lib/"
"QUI": "lib\/"
}
},
"autoload-dev": {
"psr-4": {
"QUI\\Tests\\": "tests/QUI/"
"QUI\\Tests\\": "tests\/QUI\/"
}
}
}
......@@ -573,4 +573,33 @@ class Manager
QUI\System\Log::writeException($Exception);
}
}
/**
* Returns the size of the /var/cache/ folder in bytes.
* By default the value is returned from cache.
* If there is no value in cache, null is returned, unless you set the force parameter to true.
* Only if you really need to get a freshly calculated result, you may set the force parameter to true.
* When using the force parameter expect timeouts since the calculation could take a lot of time.
*
* @param boolean $force - Force a calculation of the cache folder's size. Values aren't returned from cache. Expect timeouts.
*
* @return int
*/
public static function getCacheFolderSize($force = false)
{
$cacheFolder = VAR_DIR . "cache/";
return QUI\Utils\System\Folder::getFolderSize($cacheFolder, $force);
}
/**
* Returns the timestamp when the cache folder's size was stored in cache.
* Returns null if there is no data in the cache.
*
* @return int|null
*/
public static function getCacheFolderSizeTimestamp()
{
$cacheFolder = VAR_DIR . "cache/";
return QUI\Utils\System\Folder::getFolderSizeTimestamp($cacheFolder);
}
}
......@@ -449,7 +449,10 @@ class Locale
public function getByLang($lang, $group, $value = false, $replace = false)
{
if ($replace === false || empty($replace)) {
return $this->getHelper($group, $value, $lang);
$str = $this->getHelper($group, $value, $lang);
$str = str_replace('{\n}', PHP_EOL, $str);
return $str;
}
$str = $this->getHelper($group, $value, $lang);
......
......@@ -22,14 +22,15 @@ class Template extends QUI\QDOM
*
* @param array $params
*/
public function __construct($params = array())
public function __construct($params = [])
{
$this->setAttributes(array(
$this->setAttributes([
'body' => '',
'Project' => false,
'TplHeader' => 'mails/header.html',
'TplBody' => 'mails/body.html',
'TplFooter' => 'mails/footer.html'
));
]);
$this->setAttributes($params);
}
......@@ -43,10 +44,11 @@ class Template extends QUI\QDOM
{
$Engine = QUI::getTemplateManager()->getEngine();
$Engine->assign($this->getAttributes());
$Engine->assign('mailBody', $this->getAttribute('body'));
$header = $Engine->fetch($this->getHeaderTemplate());
$body = $Engine->fetch($this->getBodyTemplate());
$footer = $Engine->fetch($this->getFooterTemplate());
$body = $this->getAttribute('body');
return $header . $body . $footer;
}
......@@ -149,6 +151,38 @@ class Template extends QUI\QDOM
return $standardTpl;
}
/**
* Return the body template path
*
* @return string
*/
public function getBodyTemplate()
{
$Project = $this->getProject();
$standardTpl = LIB_DIR . 'templates/mail/body.html';
if (!$Project) {
return $standardTpl;
}
// exit project template?
$template = $this->getAttribute('TplBody');
$projectDir = USR_DIR . $Project->getName() . '/lib/';
if (file_exists($projectDir . $template)) {
return $projectDir . $template;
}
$tplPath = OPT_DIR . $Project->getAttribute('template') . '/';
// exist template in opt?
if (file_exists($tplPath . $template)) {
return $tplPath . $template;
}
return $standardTpl;
}
/**
* Return the footer template path
*
......
This diff is collapsed.
......@@ -472,6 +472,16 @@ class Manager
continue;
}
switch ($area) {
case 'user':
case 'groups':
if ($params['area'] == 'global') {
$result[$key] = $params;
continue 2;
}
break;
}
if (empty($params['area'])
&& ($area == 'user' || $area == 'groups')
) {
......
......@@ -654,7 +654,7 @@ class Manager
"title" => "tinytext NULL",
"short" => "text NULL",
"content" => "longtext NULL",
"type" => "varchar(32) DEFAULT NULL",
"type" => "varchar(255) DEFAULT NULL",
"active" => "tinyint(1) NOT NULL DEFAULT 0",
"deleted" => "tinyint(1) NOT NULL DEFAULT 0",
"c_date" => "timestamp NULL DEFAULT NULL",
......
This diff is collapsed.
......@@ -2017,6 +2017,12 @@ class User implements QUI\Interfaces\Users\User
return;
}
if (QUI::getUserBySession()->getId() === $this->getId()) {
throw new QUI\Users\Exception(
QUI::getLocale()->get('quiqqer/quiqqer', 'exception.user_cannot_delete_himself')
);
}
if ($this->isSU()) {
$suUsers = QUI::getUsers()->getUserIds([
'where' => [
......
......@@ -597,15 +597,69 @@
<de><![CDATA[Einfacher Inhalt]]></de>
</locale>
<!-- region Time Units -->
<locale name="second">
<de><![CDATA[Sekunde]]></de>
</locale>
<locale name="seconds">
<de><![CDATA[Sekunden]]></de>
</locale>
<locale name="seconds.dative">
<de><![CDATA[Sekunden]]></de>