aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/l10n/bg.js1
-rw-r--r--lib/l10n/bg.json1
-rw-r--r--lib/l10n/lt_LT.js1
-rw-r--r--lib/l10n/lt_LT.json1
-rw-r--r--lib/l10n/uk.js9
-rw-r--r--lib/l10n/uk.json9
-rw-r--r--lib/l10n/uz.js33
-rw-r--r--lib/l10n/uz.json33
-rw-r--r--lib/private/Avatar/Avatar.php37
-rw-r--r--lib/private/Avatar/GuestAvatar.php4
-rw-r--r--lib/private/Avatar/PlaceholderAvatar.php10
-rw-r--r--lib/private/Avatar/UserAvatar.php46
-rw-r--r--lib/private/Calendar/Manager.php17
-rw-r--r--lib/private/Files/Node/Folder.php82
-rw-r--r--lib/private/Files/SetupManager.php8
-rw-r--r--lib/private/Files/Storage/Wrapper/Quota.php71
-rw-r--r--lib/private/Repair/ClearGeneratedAvatarCache.php20
-rw-r--r--lib/private/Settings/Manager.php7
-rw-r--r--lib/private/User/User.php2
-rw-r--r--lib/public/Color.php14
-rw-r--r--lib/public/IAvatar.php6
-rw-r--r--lib/public/Settings/IIconSection.php4
-rw-r--r--lib/public/Settings/IManager.php6
23 files changed, 289 insertions, 133 deletions
diff --git a/lib/l10n/bg.js b/lib/l10n/bg.js
index a0be77e48fa..4081facf7e8 100644
--- a/lib/l10n/bg.js
+++ b/lib/l10n/bg.js
@@ -92,6 +92,7 @@ OC.L10N.register(
"Help" : "Помощ",
"Apps" : "Приложения",
"Personal settings" : "Лични настройки",
+ "Administration settings" : "Административни настройки",
"Settings" : "Настройки",
"Log out" : "Отписване",
"Users" : "Потребители",
diff --git a/lib/l10n/bg.json b/lib/l10n/bg.json
index 52faf059f8c..35a4bf1a7a9 100644
--- a/lib/l10n/bg.json
+++ b/lib/l10n/bg.json
@@ -90,6 +90,7 @@
"Help" : "Помощ",
"Apps" : "Приложения",
"Personal settings" : "Лични настройки",
+ "Administration settings" : "Административни настройки",
"Settings" : "Настройки",
"Log out" : "Отписване",
"Users" : "Потребители",
diff --git a/lib/l10n/lt_LT.js b/lib/l10n/lt_LT.js
index c029d11b399..93707397511 100644
--- a/lib/l10n/lt_LT.js
+++ b/lib/l10n/lt_LT.js
@@ -68,6 +68,7 @@ OC.L10N.register(
"This is an automatically sent email, please do not reply." : "Tai yra automatinis pranešimas, prašome neatsakyti.",
"Help" : "Pagalba",
"Apps" : "Programėlės",
+ "Personal settings" : "Asmeniniai nustatymai",
"Settings" : "Nustatymai",
"Log out" : "Atsijungti",
"Users" : "Naudotojai",
diff --git a/lib/l10n/lt_LT.json b/lib/l10n/lt_LT.json
index e4be438cd11..783eac7f717 100644
--- a/lib/l10n/lt_LT.json
+++ b/lib/l10n/lt_LT.json
@@ -66,6 +66,7 @@
"This is an automatically sent email, please do not reply." : "Tai yra automatinis pranešimas, prašome neatsakyti.",
"Help" : "Pagalba",
"Apps" : "Programėlės",
+ "Personal settings" : "Asmeniniai nustatymai",
"Settings" : "Nustatymai",
"Log out" : "Atsijungti",
"Users" : "Naudotojai",
diff --git a/lib/l10n/uk.js b/lib/l10n/uk.js
index 8f204020c65..9705debbece 100644
--- a/lib/l10n/uk.js
+++ b/lib/l10n/uk.js
@@ -16,6 +16,7 @@ OC.L10N.register(
"The command line tool %s could not be found" : "Утиліту командного рядка %s не знайдено",
"The library %s is not available." : "Бібліотека %s недоступна.",
"Server version %s or higher is required." : "Потрібна версія сервера %s або вище.",
+ "Server version %s or lower is required." : "Потрібна версія сервера %s або нижча.",
"Remote wipe started" : "Розпочато віддалене стирання",
"Remote wipe finished" : "Віддалене стирання завершено",
"Authentication" : "Автентифікація",
@@ -34,19 +35,24 @@ OC.L10N.register(
"last year" : "минулого року",
"_%n year ago_::_%n years ago_" : ["%n рік тому","%n років тому","%n років тому","%n років тому"],
"_%n hour ago_::_%n hours ago_" : ["%nгодину тому","%n годин тому","%n годин тому","%n годин тому"],
+ "_%n minute ago_::_%n minutes ago_" : ["%n хвилину тому","%n хвилин тому","%n хвилин тому","%n хвилин тому"],
"in a few seconds" : "через кілька секунд",
"seconds ago" : "секунди тому",
"Empty file" : "Порожній файл",
"File already exists" : "Файл вже існує",
+ "Templates" : "Шаблони",
"File name is a reserved word" : "Ім’я файлу є зарезервованим словом",
"File name contains at least one invalid character" : "Ім’я файлу містить принаймні один некоректний символ",
"File name is too long" : "Ім’я файлу занадто довге",
"Dot files are not allowed" : "Файли які починаються з крапки не допустимі",
"Empty filename is not allowed" : "Порожні імена файлів не допускаються",
"App \"%s\" cannot be installed because appinfo file cannot be read." : "Застосунок \"%s\" не може бути встановлений через те, що файл appinfo не може бути прочитано.",
+ "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Програму \"%s\" неможливо встановити, оскільки вона не сумісна з цією версією сервера.",
"__language_name__" : "Українська",
"Help" : "Допомога",
"Apps" : "Застосунки",
+ "Personal settings" : "Персональні налаштування",
+ "Administration settings" : "Налаштування адміністрування",
"Settings" : "Налаштування",
"Log out" : "Вихід",
"Users" : "Користувачі",
@@ -58,6 +64,9 @@ OC.L10N.register(
"Profile picture" : "Зображення облікового запису",
"About" : "Про систему",
"Full name" : "Повна назва",
+ "Headline" : "Заголовок",
+ "Organisation" : "Організація",
+ "Role" : "Роль",
"Unknown user" : "Невідомий користувач",
"Additional settings" : "Додаткові налаштування",
"%s enter the database username and name." : "%s введіть назву бази даних та ім'я користувача.",
diff --git a/lib/l10n/uk.json b/lib/l10n/uk.json
index 24ae8d496ba..3d478f62337 100644
--- a/lib/l10n/uk.json
+++ b/lib/l10n/uk.json
@@ -14,6 +14,7 @@
"The command line tool %s could not be found" : "Утиліту командного рядка %s не знайдено",
"The library %s is not available." : "Бібліотека %s недоступна.",
"Server version %s or higher is required." : "Потрібна версія сервера %s або вище.",
+ "Server version %s or lower is required." : "Потрібна версія сервера %s або нижча.",
"Remote wipe started" : "Розпочато віддалене стирання",
"Remote wipe finished" : "Віддалене стирання завершено",
"Authentication" : "Автентифікація",
@@ -32,19 +33,24 @@
"last year" : "минулого року",
"_%n year ago_::_%n years ago_" : ["%n рік тому","%n років тому","%n років тому","%n років тому"],
"_%n hour ago_::_%n hours ago_" : ["%nгодину тому","%n годин тому","%n годин тому","%n годин тому"],
+ "_%n minute ago_::_%n minutes ago_" : ["%n хвилину тому","%n хвилин тому","%n хвилин тому","%n хвилин тому"],
"in a few seconds" : "через кілька секунд",
"seconds ago" : "секунди тому",
"Empty file" : "Порожній файл",
"File already exists" : "Файл вже існує",
+ "Templates" : "Шаблони",
"File name is a reserved word" : "Ім’я файлу є зарезервованим словом",
"File name contains at least one invalid character" : "Ім’я файлу містить принаймні один некоректний символ",
"File name is too long" : "Ім’я файлу занадто довге",
"Dot files are not allowed" : "Файли які починаються з крапки не допустимі",
"Empty filename is not allowed" : "Порожні імена файлів не допускаються",
"App \"%s\" cannot be installed because appinfo file cannot be read." : "Застосунок \"%s\" не може бути встановлений через те, що файл appinfo не може бути прочитано.",
+ "App \"%s\" cannot be installed because it is not compatible with this version of the server." : "Програму \"%s\" неможливо встановити, оскільки вона не сумісна з цією версією сервера.",
"__language_name__" : "Українська",
"Help" : "Допомога",
"Apps" : "Застосунки",
+ "Personal settings" : "Персональні налаштування",
+ "Administration settings" : "Налаштування адміністрування",
"Settings" : "Налаштування",
"Log out" : "Вихід",
"Users" : "Користувачі",
@@ -56,6 +62,9 @@
"Profile picture" : "Зображення облікового запису",
"About" : "Про систему",
"Full name" : "Повна назва",
+ "Headline" : "Заголовок",
+ "Organisation" : "Організація",
+ "Role" : "Роль",
"Unknown user" : "Невідомий користувач",
"Additional settings" : "Додаткові налаштування",
"%s enter the database username and name." : "%s введіть назву бази даних та ім'я користувача.",
diff --git a/lib/l10n/uz.js b/lib/l10n/uz.js
index cea4453992f..41cb4509e83 100644
--- a/lib/l10n/uz.js
+++ b/lib/l10n/uz.js
@@ -1,18 +1,25 @@
OC.L10N.register(
"lib",
{
- "Cannot write into \"config\" directory!" : "\"Config\" katalogiga yozish mumkin emas!",
- "Unknown filetype" : "Noma'lum filetype",
- "Invalid image" : "Tasdiqlanmagan tasvir",
- "seconds ago" : "soniya oldin",
- "Help" : "Yordam",
- "Apps" : "Ilovalar",
- "Settings" : "Sozlamalar",
- "Users" : "Foydalanuvchilar",
- "Address" : "manzil",
- "About" : "Biz haqimizda",
- "Unknown user" : "Noma'lum foydalanuvchi",
- "January" : "Yanvar",
- "Storage is temporarily not available" : "Saqlash vaqti-vaqti bilan mavjud emas"
+ "Cannot write into \"config\" directory!" : "Cannot write into \"config\" directory!",
+ "Unknown filetype" : "Unknown filetype",
+ "Invalid image" : "Invalid image",
+ "View profile" : "View profile",
+ "last month" : "last month",
+ "seconds ago" : "seconds ago",
+ "File name is too long" : "File name is too long",
+ "Help" : "Help",
+ "Apps" : "Apps",
+ "Settings" : "Settings",
+ "Users" : "Users",
+ "Address" : "Address",
+ "Profile picture" : "Profil rasmi",
+ "About" : "About",
+ "Full name" : "Full name",
+ "Unknown user" : "Unknown user",
+ "Set an admin password." : "Set an admin password.",
+ "January" : "January",
+ "Authentication error" : "Authentication error",
+ "Storage is temporarily not available" : "Storage is temporarily not available"
},
"nplurals=1; plural=0;");
diff --git a/lib/l10n/uz.json b/lib/l10n/uz.json
index 3ad6192351f..bbddc8953c7 100644
--- a/lib/l10n/uz.json
+++ b/lib/l10n/uz.json
@@ -1,16 +1,23 @@
{ "translations": {
- "Cannot write into \"config\" directory!" : "\"Config\" katalogiga yozish mumkin emas!",
- "Unknown filetype" : "Noma'lum filetype",
- "Invalid image" : "Tasdiqlanmagan tasvir",
- "seconds ago" : "soniya oldin",
- "Help" : "Yordam",
- "Apps" : "Ilovalar",
- "Settings" : "Sozlamalar",
- "Users" : "Foydalanuvchilar",
- "Address" : "manzil",
- "About" : "Biz haqimizda",
- "Unknown user" : "Noma'lum foydalanuvchi",
- "January" : "Yanvar",
- "Storage is temporarily not available" : "Saqlash vaqti-vaqti bilan mavjud emas"
+ "Cannot write into \"config\" directory!" : "Cannot write into \"config\" directory!",
+ "Unknown filetype" : "Unknown filetype",
+ "Invalid image" : "Invalid image",
+ "View profile" : "View profile",
+ "last month" : "last month",
+ "seconds ago" : "seconds ago",
+ "File name is too long" : "File name is too long",
+ "Help" : "Help",
+ "Apps" : "Apps",
+ "Settings" : "Settings",
+ "Users" : "Users",
+ "Address" : "Address",
+ "Profile picture" : "Profil rasmi",
+ "About" : "About",
+ "Full name" : "Full name",
+ "Unknown user" : "Unknown user",
+ "Set an admin password." : "Set an admin password.",
+ "January" : "January",
+ "Authentication error" : "Authentication error",
+ "Storage is temporarily not available" : "Storage is temporarily not available"
},"pluralForm" :"nplurals=1; plural=0;"
} \ No newline at end of file
diff --git a/lib/private/Avatar/Avatar.php b/lib/private/Avatar/Avatar.php
index 0eb8f8816d8..9b9220936eb 100644
--- a/lib/private/Avatar/Avatar.php
+++ b/lib/private/Avatar/Avatar.php
@@ -59,7 +59,7 @@ abstract class Avatar implements IAvatar {
private string $svgTemplate = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="{size}" height="{size}" version="1.1" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="#{fill}"></rect>
- <text x="50%" y="350" style="font-weight:normal;font-size:280px;font-family:\'Noto Sans\';text-anchor:middle;fill:#fff">{letter}</text>
+ <text x="50%" y="350" style="font-weight:normal;font-size:280px;font-family:\'Noto Sans\';text-anchor:middle;fill:#{fgFill}">{letter}</text>
</svg>';
public function __construct(LoggerInterface $logger) {
@@ -88,9 +88,9 @@ abstract class Avatar implements IAvatar {
/**
* @inheritdoc
*/
- public function get(int $size = 64) {
+ public function get(int $size = 64, bool $darkTheme = false) {
try {
- $file = $this->getFile($size);
+ $file = $this->getFile($size, $darkTheme);
} catch (NotFoundException $e) {
return false;
}
@@ -111,25 +111,27 @@ abstract class Avatar implements IAvatar {
* @return string
*
*/
- protected function getAvatarVector(int $size): string {
+ protected function getAvatarVector(int $size, bool $darkTheme): string {
$userDisplayName = $this->getDisplayName();
- $bgRGB = $this->avatarBackgroundColor($userDisplayName);
- $bgHEX = sprintf("%02x%02x%02x", $bgRGB->red(), $bgRGB->green(), $bgRGB->blue());
+ $fgRGB = $this->avatarBackgroundColor($userDisplayName);
+ $bgRGB = $fgRGB->alphaBlending(0.1, $darkTheme ? new Color(0, 0, 0) : new Color(255, 255, 255));
+ $fill = sprintf("%02x%02x%02x", $bgRGB->red(), $bgRGB->green(), $bgRGB->blue());
+ $fgFill = sprintf("%02x%02x%02x", $fgRGB->red(), $fgRGB->green(), $fgRGB->blue());
$text = $this->getAvatarText();
- $toReplace = ['{size}', '{fill}', '{letter}'];
- return str_replace($toReplace, [$size, $bgHEX, $text], $this->svgTemplate);
+ $toReplace = ['{size}', '{fill}', '{fgFill}', '{letter}'];
+ return str_replace($toReplace, [$size, $fill, $fgFill, $text], $this->svgTemplate);
}
/**
* Generate png avatar from svg with Imagick
*/
- protected function generateAvatarFromSvg(int $size): ?string {
+ protected function generateAvatarFromSvg(int $size, bool $darkTheme): ?string {
if (!extension_loaded('imagick')) {
return null;
}
try {
- $font = __DIR__ . '/../../core/fonts/NotoSans-Regular.ttf';
- $svg = $this->getAvatarVector($size);
+ $font = __DIR__ . '/../../../core/fonts/NotoSans-Regular.ttf';
+ $svg = $this->getAvatarVector($size, $darkTheme);
$avatar = new Imagick();
$avatar->setFont($font);
$avatar->readImageBlob($svg);
@@ -145,9 +147,10 @@ abstract class Avatar implements IAvatar {
/**
* Generate png avatar with GD
*/
- protected function generateAvatar(string $userDisplayName, int $size): string {
+ protected function generateAvatar(string $userDisplayName, int $size, bool $darkTheme): string {
$text = $this->getAvatarText();
- $backgroundColor = $this->avatarBackgroundColor($userDisplayName);
+ $textColor = $this->avatarBackgroundColor($userDisplayName);
+ $backgroundColor = $textColor->alphaBlending(0.1, $darkTheme ? new Color(0, 0, 0) : new Color(255, 255, 255));
$im = imagecreatetruecolor($size, $size);
$background = imagecolorallocate(
@@ -156,7 +159,11 @@ abstract class Avatar implements IAvatar {
$backgroundColor->green(),
$backgroundColor->blue()
);
- $white = imagecolorallocate($im, 255, 255, 255);
+ $textColor = imagecolorallocate($im,
+ $textColor->red(),
+ $textColor->green(),
+ $textColor->blue()
+ );
imagefilledrectangle($im, 0, 0, $size, $size, $background);
$font = __DIR__ . '/../../../core/fonts/NotoSans-Regular.ttf';
@@ -166,7 +173,7 @@ abstract class Avatar implements IAvatar {
$im, $text, $font, (int)$fontSize
);
- imagettftext($im, $fontSize, 0, $x, $y, $white, $font, $text);
+ imagettftext($im, $fontSize, 0, $x, $y, $textColor, $font, $text);
ob_start();
imagepng($im);
diff --git a/lib/private/Avatar/GuestAvatar.php b/lib/private/Avatar/GuestAvatar.php
index 79d7e6ee094..083deb4108f 100644
--- a/lib/private/Avatar/GuestAvatar.php
+++ b/lib/private/Avatar/GuestAvatar.php
@@ -84,8 +84,8 @@ class GuestAvatar extends Avatar {
/**
* Generates an avatar for the guest.
*/
- public function getFile(int $size): ISimpleFile {
- $avatar = $this->generateAvatar($this->userDisplayName, $size);
+ public function getFile(int $size, bool $darkTheme = false): ISimpleFile {
+ $avatar = $this->generateAvatar($this->userDisplayName, $size, $darkTheme);
return new InMemoryFile('avatar.png', $avatar);
}
diff --git a/lib/private/Avatar/PlaceholderAvatar.php b/lib/private/Avatar/PlaceholderAvatar.php
index 504e5c1457d..e7ca89f4d30 100644
--- a/lib/private/Avatar/PlaceholderAvatar.php
+++ b/lib/private/Avatar/PlaceholderAvatar.php
@@ -108,13 +108,13 @@ class PlaceholderAvatar extends Avatar {
* @throws \OCP\Files\NotPermittedException
* @throws \OCP\PreConditionNotMetException
*/
- public function getFile(int $size): ISimpleFile {
+ public function getFile(int $size, bool $darkTheme = false): ISimpleFile {
$ext = 'png';
if ($size === -1) {
- $path = 'avatar-placeholder.' . $ext;
+ $path = 'avatar-placeholder' . ($darkTheme ? '-dark' : '') . '.' . $ext;
} else {
- $path = 'avatar-placeholder.' . $size . '.' . $ext;
+ $path = 'avatar-placeholder' . ($darkTheme ? '-dark' : '') . '.' . $size . '.' . $ext;
}
try {
@@ -124,8 +124,8 @@ class PlaceholderAvatar extends Avatar {
throw new NotFoundException;
}
- if (!$data = $this->generateAvatarFromSvg($size)) {
- $data = $this->generateAvatar($this->getDisplayName(), $size);
+ if (!$data = $this->generateAvatarFromSvg($size, $darkTheme)) {
+ $data = $this->generateAvatar($this->getDisplayName(), $size, $darkTheme);
}
try {
diff --git a/lib/private/Avatar/UserAvatar.php b/lib/private/Avatar/UserAvatar.php
index f5a1d7e77b1..02fcfcb0fc8 100644
--- a/lib/private/Avatar/UserAvatar.php
+++ b/lib/private/Avatar/UserAvatar.php
@@ -208,7 +208,14 @@ class UserAvatar extends Avatar {
*
* @throws NotFoundException
*/
- private function getExtension(): string {
+ private function getExtension(bool $generated, bool $darkTheme): string {
+ if ($darkTheme && !$generated) {
+ if ($this->folder->fileExists('avatar-dark.jpg')) {
+ return 'jpg';
+ } elseif ($this->folder->fileExists('avatar-dark.png')) {
+ return 'png';
+ }
+ }
if ($this->folder->fileExists('avatar.jpg')) {
return 'jpg';
} elseif ($this->folder->fileExists('avatar.png')) {
@@ -228,25 +235,36 @@ class UserAvatar extends Avatar {
* @throws \OCP\Files\NotPermittedException
* @throws \OCP\PreConditionNotMetException
*/
- public function getFile(int $size): ISimpleFile {
+ public function getFile(int $size, bool $darkTheme = false): ISimpleFile {
+ $generated = $this->folder->fileExists('generated');
+
try {
- $ext = $this->getExtension();
+ $ext = $this->getExtension($generated, $darkTheme);
} catch (NotFoundException $e) {
- if (!$data = $this->generateAvatarFromSvg(1024)) {
- $data = $this->generateAvatar($this->getDisplayName(), 1024);
+ if (!$data = $this->generateAvatarFromSvg(1024, $darkTheme)) {
+ $data = $this->generateAvatar($this->getDisplayName(), 1024, $darkTheme);
}
- $avatar = $this->folder->newFile('avatar.png');
+ $avatar = $this->folder->newFile($darkTheme ? 'avatar-dark.png' : 'avatar.png');
$avatar->putContent($data);
$ext = 'png';
$this->folder->newFile('generated', '');
$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', 'true');
+ $generated = true;
}
- if ($size === -1) {
- $path = 'avatar.' . $ext;
+ if ($generated) {
+ if ($size === -1) {
+ $path = 'avatar' . ($darkTheme ? '-dark' : '') . '.' . $ext;
+ } else {
+ $path = 'avatar' . ($darkTheme ? '-dark' : '') . '.' . $size . '.' . $ext;
+ }
} else {
- $path = 'avatar.' . $size . '.' . $ext;
+ if ($size === -1) {
+ $path = 'avatar.' . $ext;
+ } else {
+ $path = 'avatar.' . $size . '.' . $ext;
+ }
}
try {
@@ -255,11 +273,9 @@ class UserAvatar extends Avatar {
if ($size <= 0) {
throw new NotFoundException;
}
-
- // TODO: rework to integrate with the PlaceholderAvatar in a compatible way
- if ($this->folder->fileExists('generated')) {
- if (!$data = $this->generateAvatarFromSvg($size)) {
- $data = $this->generateAvatar($this->getDisplayName(), $size);
+ if ($generated) {
+ if (!$data = $this->generateAvatarFromSvg($size, $darkTheme)) {
+ $data = $this->generateAvatar($this->getDisplayName(), $size, $darkTheme);
}
} else {
$avatar = new \OCP\Image();
@@ -279,7 +295,7 @@ class UserAvatar extends Avatar {
}
if ($this->config->getUserValue($this->user->getUID(), 'avatar', 'generated', null) === null) {
- $generated = $this->folder->fileExists('generated') ? 'true' : 'false';
+ $generated = $generated ? 'true' : 'false';
$this->config->setUserValue($this->user->getUID(), 'avatar', 'generated', $generated);
}
diff --git a/lib/private/Calendar/Manager.php b/lib/private/Calendar/Manager.php
index f0b8e9fd50d..550ba36dd6b 100644
--- a/lib/private/Calendar/Manager.php
+++ b/lib/private/Calendar/Manager.php
@@ -330,12 +330,27 @@ class Manager implements IManager {
// to the email address in the ORGANIZER.
// We don't want to accept a CANCEL request from just anyone
$organizer = substr($vEvent->{'ORGANIZER'}->getValue(), 7);
- if (strcasecmp($sender, $organizer) !== 0 && strcasecmp($replyTo, $organizer) !== 0) {
+ $isNotOrganizer = ($replyTo !== null) ? (strcasecmp($sender, $organizer) !== 0 && strcasecmp($replyTo, $organizer) !== 0) : (strcasecmp($sender, $organizer) !== 0);
+ if ($isNotOrganizer) {
$this->logger->warning('Sender must be the ORGANIZER of this event');
return false;
}
+ //check if the event is in the future
+ /** @var DateTime $eventTime */
+ $eventTime = $vEvent->{'DTSTART'};
+ if ($eventTime->getDateTime()->getTimeStamp() < $this->timeFactory->getTime()) { // this might cause issues with recurrences
+ $this->logger->warning('Only events in the future are processed');
+ return false;
+ }
+
+ // Check if we have a calendar to work with
$calendars = $this->getCalendarsForPrincipal($principalUri);
+ if (empty($calendars)) {
+ $this->logger->warning('Could not find any calendars for principal ' . $principalUri);
+ return false;
+ }
+
$found = null;
// if the attendee has been found in at least one calendar event with the UID of the iMIP event
// we process it.
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index fb3c78bb801..268c1d8dd06 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -413,37 +413,65 @@ class Folder extends Node implements \OCP\Files\Folder {
* @return \OCP\Files\Node[]
*/
public function getRecent($limit, $offset = 0) {
- $query = new SearchQuery(
- new SearchBinaryOperator(
- // filter out non empty folders
- ISearchBinaryOperator::OPERATOR_OR,
- [
- new SearchBinaryOperator(
- ISearchBinaryOperator::OPERATOR_NOT,
- [
- new SearchComparison(
- ISearchComparison::COMPARE_EQUAL,
- 'mimetype',
- FileInfo::MIMETYPE_FOLDER
- ),
- ]
- ),
- new SearchComparison(
- ISearchComparison::COMPARE_EQUAL,
- 'size',
- 0
- ),
- ]
- ),
- $limit,
- $offset,
+ $filterOutNonEmptyFolder = new SearchBinaryOperator(
+ // filter out non empty folders
+ ISearchBinaryOperator::OPERATOR_OR,
[
- new SearchOrder(
- ISearchOrder::DIRECTION_DESCENDING,
- 'mtime'
+ new SearchBinaryOperator(
+ ISearchBinaryOperator::OPERATOR_NOT,
+ [
+ new SearchComparison(
+ ISearchComparison::COMPARE_EQUAL,
+ 'mimetype',
+ FileInfo::MIMETYPE_FOLDER
+ ),
+ ]
+ ),
+ new SearchComparison(
+ ISearchComparison::COMPARE_EQUAL,
+ 'size',
+ 0
),
]
);
+
+ $filterNonRecentFiles = new SearchComparison(
+ ISearchComparison::COMPARE_GREATER_THAN,
+ 'mtime',
+ strtotime("-2 week")
+ );
+ if ($offset === 0 && $limit <= 100) {
+ $query = new SearchQuery(
+ new SearchBinaryOperator(
+ ISearchBinaryOperator::OPERATOR_AND,
+ [
+ $filterOutNonEmptyFolder,
+ $filterNonRecentFiles,
+ ],
+ ),
+ $limit,
+ $offset,
+ [
+ new SearchOrder(
+ ISearchOrder::DIRECTION_DESCENDING,
+ 'mtime'
+ ),
+ ]
+ );
+ } else {
+ $query = new SearchQuery(
+ $filterOutNonEmptyFolder,
+ $limit,
+ $offset,
+ [
+ new SearchOrder(
+ ISearchOrder::DIRECTION_DESCENDING,
+ 'mtime'
+ ),
+ ]
+ );
+ }
+
return $this->search($query);
}
}
diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php
index 5782a5a72a6..d52a291cd99 100644
--- a/lib/private/Files/SetupManager.php
+++ b/lib/private/Files/SetupManager.php
@@ -172,10 +172,10 @@ class SetupManager {
*/
if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) {
if (is_object($storage->getUser())) {
- $quota = OC_Util::getUserQuota($storage->getUser());
- if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
- return new Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']);
- }
+ $user = $storage->getUser();
+ return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
+ return OC_Util::getUserQuota($user);
+ }, 'root' => 'files']);
}
}
diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php
index 4cd0a5e0b4a..8b129472eb0 100644
--- a/lib/private/Files/Storage/Wrapper/Quota.php
+++ b/lib/private/Files/Storage/Wrapper/Quota.php
@@ -33,40 +33,47 @@
namespace OC\Files\Storage\Wrapper;
use OC\Files\Filesystem;
+use OC\SystemConfig;
use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\FileInfo;
use OCP\Files\Storage\IStorage;
class Quota extends Wrapper {
-
- /**
- * @var int $quota
- */
- protected $quota;
-
- /**
- * @var string $sizeRoot
- */
- protected $sizeRoot;
-
- private $config;
+ /** @var callable|null */
+ protected $quotaCallback;
+ protected ?int $quota;
+ protected string $sizeRoot;
+ private SystemConfig $config;
/**
* @param array $parameters
*/
public function __construct($parameters) {
parent::__construct($parameters);
- $this->quota = $parameters['quota'];
- $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : '';
- $this->config = \OC::$server->getSystemConfig();
+ $this->quota = $parameters['quota'] ?? null;
+ $this->quotaCallback = $parameters['quotaCallback'] ?? null;
+ $this->sizeRoot = $parameters['root'] ?? '';
+ $this->config = \OC::$server->get(SystemConfig::class);
}
/**
* @return int quota value
*/
- public function getQuota() {
+ public function getQuota(): int {
+ if ($this->quota === null) {
+ $quotaCallback = $this->quotaCallback;
+ if ($quotaCallback === null) {
+ throw new \Exception("No quota or quota callback provider");
+ }
+ $this->quota = $quotaCallback();
+ }
return $this->quota;
}
+ private function hasQuota(): bool {
+ return $this->getQuota() !== FileInfo::SPACE_UNLIMITED;
+ }
+
/**
* @param string $path
* @param \OC\Files\Storage\Storage $storage
@@ -100,7 +107,10 @@ class Quota extends Wrapper {
* @return int|bool
*/
public function free_space($path) {
- if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
+ if (!$this->hasQuota()) {
+ return $this->storage->free_space($path);
+ }
+ if ($this->getQuota() < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
return $this->storage->free_space($path);
} else {
$used = $this->getSize($this->sizeRoot);
@@ -108,7 +118,7 @@ class Quota extends Wrapper {
return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
} else {
$free = $this->storage->free_space($path);
- $quotaFree = max($this->quota - $used, 0);
+ $quotaFree = max($this->getQuota() - $used, 0);
// if free space is known
if ($free >= 0) {
$free = min($free, $quotaFree);
@@ -128,6 +138,9 @@ class Quota extends Wrapper {
* @return int|false
*/
public function file_put_contents($path, $data) {
+ if (!$this->hasQuota()) {
+ return $this->storage->file_put_contents($path, $data);
+ }
$free = $this->free_space($path);
if ($free < 0 or strlen($data) < $free) {
return $this->storage->file_put_contents($path, $data);
@@ -144,6 +157,9 @@ class Quota extends Wrapper {
* @return bool
*/
public function copy($source, $target) {
+ if (!$this->hasQuota()) {
+ return $this->storage->copy($source, $target);
+ }
$free = $this->free_space($target);
if ($free < 0 or $this->getSize($source) < $free) {
return $this->storage->copy($source, $target);
@@ -160,6 +176,9 @@ class Quota extends Wrapper {
* @return resource|bool
*/
public function fopen($path, $mode) {
+ if (!$this->hasQuota()) {
+ return $this->storage->fopen($path, $mode);
+ }
$source = $this->storage->fopen($path, $mode);
// don't apply quota for part files
@@ -202,6 +221,9 @@ class Quota extends Wrapper {
* @return bool
*/
public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ if (!$this->hasQuota()) {
+ return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ }
$free = $this->free_space($targetInternalPath);
if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
@@ -217,6 +239,9 @@ class Quota extends Wrapper {
* @return bool
*/
public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
+ if (!$this->hasQuota()) {
+ return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
+ }
$free = $this->free_space($targetInternalPath);
if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
@@ -226,8 +251,11 @@ class Quota extends Wrapper {
}
public function mkdir($path) {
+ if (!$this->hasQuota()) {
+ return $this->storage->mkdir($path);
+ }
$free = $this->free_space($path);
- if ($this->shouldApplyQuota($path) && $free === 0.0) {
+ if ($this->shouldApplyQuota($path) && $free == 0) {
return false;
}
@@ -235,8 +263,11 @@ class Quota extends Wrapper {
}
public function touch($path, $mtime = null) {
+ if (!$this->hasQuota()) {
+ return $this->storage->touch($path, $mtime);
+ }
$free = $this->free_space($path);
- if ($free === 0.0) {
+ if ($free == 0) {
return false;
}
diff --git a/lib/private/Repair/ClearGeneratedAvatarCache.php b/lib/private/Repair/ClearGeneratedAvatarCache.php
index 314299a0528..1c1be4f7893 100644
--- a/lib/private/Repair/ClearGeneratedAvatarCache.php
+++ b/lib/private/Repair/ClearGeneratedAvatarCache.php
@@ -30,35 +30,29 @@ use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
class ClearGeneratedAvatarCache implements IRepairStep {
-
- /** @var AvatarManager */
- protected $avatarManager;
-
- /** @var IConfig */
- private $config;
+ protected AvatarManager $avatarManager;
+ private IConfig $config;
public function __construct(IConfig $config, AvatarManager $avatarManager) {
$this->config = $config;
$this->avatarManager = $avatarManager;
}
- public function getName() {
+ public function getName(): string {
return 'Clear every generated avatar on major updates';
}
/**
* Check if this repair step should run
- *
- * @return boolean
*/
- private function shouldRun() {
+ private function shouldRun(): bool {
$versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0.0');
- // was added to 15.0.0.4
- return version_compare($versionFromBeforeUpdate, '15.0.0.4', '<=');
+ // was added to 25.0.0.10
+ return version_compare($versionFromBeforeUpdate, '25.0.0.10', '<=');
}
- public function run(IOutput $output) {
+ public function run(IOutput $output): void {
if ($this->shouldRun()) {
try {
$this->avatarManager->clearCachedAvatars();
diff --git a/lib/private/Settings/Manager.php b/lib/private/Settings/Manager.php
index 05a286e4758..44f1df09c15 100644
--- a/lib/private/Settings/Manager.php
+++ b/lib/private/Settings/Manager.php
@@ -150,6 +150,13 @@ class Manager implements IManager {
return $this->sections[$type];
}
+ public function getSection(string $type, string $sectionId): ?IIconSection {
+ if (isset($this->sections[$type]) && isset($this->sections[$type][$sectionId])) {
+ return $this->sections[$type][$sectionId];
+ }
+ return null;
+ }
+
protected function isKnownDuplicateSectionId(string $sectionID): bool {
return in_array($sectionID, [
'connected-accounts',
diff --git a/lib/private/User/User.php b/lib/private/User/User.php
index 72c0d5c1a88..f5d93dcd680 100644
--- a/lib/private/User/User.php
+++ b/lib/private/User/User.php
@@ -199,7 +199,7 @@ class User implements IUser {
$this->setPrimaryEMailAddress('');
}
- if ($oldMailAddress !== $mailAddress) {
+ if ($oldMailAddress !== strtolower($mailAddress)) {
$this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
}
}
diff --git a/lib/public/Color.php b/lib/public/Color.php
index e2cabd9c2fc..d5b2a92a6ac 100644
--- a/lib/public/Color.php
+++ b/lib/public/Color.php
@@ -126,6 +126,20 @@ class Color {
}
/**
+ * Alpha blend another color with a given opacity to this color
+ *
+ * @return Color The new color
+ * @since 25.0.0
+ */
+ public function alphaBlending(float $opacity, Color $source): Color {
+ return new Color(
+ (int)((1 - $opacity) * $source->red() + $opacity * $this->red()),
+ (int)((1 - $opacity) * $source->green() + $opacity * $this->green()),
+ (int)((1 - $opacity) * $source->blue() + $opacity * $this->blue())
+ );
+ }
+
+ /**
* Calculate steps between two Colors
* @param int $steps start color
* @param Color[] $ends end color
diff --git a/lib/public/IAvatar.php b/lib/public/IAvatar.php
index d05a12e1dbf..f9fe9a645e6 100644
--- a/lib/public/IAvatar.php
+++ b/lib/public/IAvatar.php
@@ -39,10 +39,11 @@ interface IAvatar {
* Get the users avatar
*
* @param int $size size in px of the avatar, avatars are square, defaults to 64, -1 can be used to not scale the image
+ * @param bool $darkTheme Should the generated avatar be dark themed
* @return false|\OCP\IImage containing the avatar or false if there's no image
* @since 6.0.0 - size of -1 was added in 9.0.0
*/
- public function get(int $size = 64);
+ public function get(int $size = 64, bool $darkTheme = false);
/**
* Check if an avatar exists for the user
@@ -81,10 +82,11 @@ interface IAvatar {
* Get the file of the avatar
*
* @param int $size The desired image size. -1 can be used to not scale the image
+ * @param bool $darkTheme Should the generated avatar be dark themed
* @throws NotFoundException
* @since 9.0.0
*/
- public function getFile(int $size): ISimpleFile;
+ public function getFile(int $size, bool $darkTheme = false): ISimpleFile;
/**
* Get the avatar background color
diff --git a/lib/public/Settings/IIconSection.php b/lib/public/Settings/IIconSection.php
index c56565fbf85..bb9b2e94b0d 100644
--- a/lib/public/Settings/IIconSection.php
+++ b/lib/public/Settings/IIconSection.php
@@ -31,7 +31,7 @@ interface IIconSection {
* returns the ID of the section. It is supposed to be a lower case string,
* e.g. 'ldap'
*
- * @returns string
+ * @return string
* @since 9.1
*/
public function getID();
@@ -59,7 +59,7 @@ interface IIconSection {
* returns the relative path to an 16*16 icon describing the section.
* e.g. '/core/img/places/files.svg'
*
- * @returns string
+ * @return string
* @since 12
*/
public function getIcon();
diff --git a/lib/public/Settings/IManager.php b/lib/public/Settings/IManager.php
index 2ec3fb0fd21..10de596dbea 100644
--- a/lib/public/Settings/IManager.php
+++ b/lib/public/Settings/IManager.php
@@ -116,4 +116,10 @@ interface IManager {
* @since 13.0.0
*/
public function getPersonalSettings($section): array;
+
+ /**
+ * Get a specific section by type and id
+ * @since 25.0.0
+ */
+ public function getSection(string $type, string $sectionId): ?IIconSection;
}