aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/admin_audit/l10n/eo.js7
-rw-r--r--apps/admin_audit/l10n/eo.json5
-rw-r--r--apps/cloud_federation_api/l10n/eo.js8
-rw-r--r--apps/cloud_federation_api/l10n/eo.json6
-rw-r--r--apps/dav/l10n/pl.js3
-rw-r--r--apps/dav/l10n/pl.json3
-rw-r--r--apps/dav/lib/CardDAV/Converter.php11
-rw-r--r--apps/federation/lib/SyncFederationAddressBooks.php8
-rw-r--r--apps/files/l10n/en_GB.js2
-rw-r--r--apps/files/l10n/en_GB.json2
-rw-r--r--apps/files/l10n/es.js2
-rw-r--r--apps/files/l10n/es.json2
-rw-r--r--apps/files/l10n/fr.js4
-rw-r--r--apps/files/l10n/fr.json4
-rw-r--r--apps/files/l10n/zh_HK.js2
-rw-r--r--apps/files/l10n/zh_HK.json2
-rw-r--r--apps/files_versions/l10n/pl.js3
-rw-r--r--apps/files_versions/l10n/pl.json3
-rw-r--r--apps/theming/l10n/eo.js4
-rw-r--r--apps/theming/l10n/eo.json4
-rw-r--r--build/psalm-baseline.xml5
-rw-r--r--core/Command/Info/File.php138
-rw-r--r--core/Command/Info/FileUtils.php254
-rw-r--r--core/Command/Info/Space.php67
-rw-r--r--core/register_command.php1
-rw-r--r--lib/composer/composer/autoload_classmap.php2
-rw-r--r--lib/composer/composer/autoload_static.php2
-rw-r--r--lib/private/Security/CertificateManager.php17
-rw-r--r--version.php4
29 files changed, 429 insertions, 146 deletions
diff --git a/apps/admin_audit/l10n/eo.js b/apps/admin_audit/l10n/eo.js
new file mode 100644
index 00000000000..3ab916b0b54
--- /dev/null
+++ b/apps/admin_audit/l10n/eo.js
@@ -0,0 +1,7 @@
+OC.L10N.register(
+ "admin_audit",
+ {
+ "Auditing / Logging" : "Ekzamenado / Protokolado",
+ "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Provizi protokolado-kapablojn por Nextcloud, kiel ekzemple protokolado de aliroj al dosieroj aŭ aliaj delikataj agoj."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/admin_audit/l10n/eo.json b/apps/admin_audit/l10n/eo.json
new file mode 100644
index 00000000000..eef1c6821c5
--- /dev/null
+++ b/apps/admin_audit/l10n/eo.json
@@ -0,0 +1,5 @@
+{ "translations": {
+ "Auditing / Logging" : "Ekzamenado / Protokolado",
+ "Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions." : "Provizi protokolado-kapablojn por Nextcloud, kiel ekzemple protokolado de aliroj al dosieroj aŭ aliaj delikataj agoj."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/cloud_federation_api/l10n/eo.js b/apps/cloud_federation_api/l10n/eo.js
new file mode 100644
index 00000000000..d01810bba74
--- /dev/null
+++ b/apps/cloud_federation_api/l10n/eo.js
@@ -0,0 +1,8 @@
+OC.L10N.register(
+ "cloud_federation_api",
+ {
+ "Cloud Federation API" : "API de Nuba Federacio",
+ "Enable clouds to communicate with each other and exchange data" : "Ebligi interkomunikadon inter diversaj nuboj kaj la interŝanĝon de datumoj",
+ "The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de Nuba Federacio ebligas diversajn instancojn de Nextcloud interkomuniki kaj interŝanĝi datumojn inter si."
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/cloud_federation_api/l10n/eo.json b/apps/cloud_federation_api/l10n/eo.json
new file mode 100644
index 00000000000..17dd80538d8
--- /dev/null
+++ b/apps/cloud_federation_api/l10n/eo.json
@@ -0,0 +1,6 @@
+{ "translations": {
+ "Cloud Federation API" : "API de Nuba Federacio",
+ "Enable clouds to communicate with each other and exchange data" : "Ebligi interkomunikadon inter diversaj nuboj kaj la interŝanĝon de datumoj",
+ "The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data." : "La API de Nuba Federacio ebligas diversajn instancojn de Nextcloud interkomuniki kaj interŝanĝi datumojn inter si."
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/dav/l10n/pl.js b/apps/dav/l10n/pl.js
index d0454c424da..af760bd33d1 100644
--- a/apps/dav/l10n/pl.js
+++ b/apps/dav/l10n/pl.js
@@ -75,6 +75,9 @@ OC.L10N.register(
"Cancelled: %1$s" : "Anulowane: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" zostało anulowane",
"Re: %1$s" : "Odp: %1$s",
+ "%1$s has accepted your invitation" : "Twoje zaproszenie zostało zaakceptowane przez %1$s",
+ "%1$s has tentatively accepted your invitation" : "Twoje zaproszenie zostało wstępnie zaakceptowane przez %1$s",
+ "%1$s has declined your invitation" : "Twoje zaproszenie zostało odrzucone przez %1$s",
"%1$s has responded to your invitation" : "%1$s odpowiedział/a na Twoje zaproszenie",
"Invitation updated: %1$s" : "Zaktualizowano zaproszenie: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s zaktualizował/a wydarzenie \"%2$s\"",
diff --git a/apps/dav/l10n/pl.json b/apps/dav/l10n/pl.json
index 2560da78ef1..5332f810cac 100644
--- a/apps/dav/l10n/pl.json
+++ b/apps/dav/l10n/pl.json
@@ -73,6 +73,9 @@
"Cancelled: %1$s" : "Anulowane: %1$s",
"\"%1$s\" has been canceled" : "\"%1$s\" zostało anulowane",
"Re: %1$s" : "Odp: %1$s",
+ "%1$s has accepted your invitation" : "Twoje zaproszenie zostało zaakceptowane przez %1$s",
+ "%1$s has tentatively accepted your invitation" : "Twoje zaproszenie zostało wstępnie zaakceptowane przez %1$s",
+ "%1$s has declined your invitation" : "Twoje zaproszenie zostało odrzucone przez %1$s",
"%1$s has responded to your invitation" : "%1$s odpowiedział/a na Twoje zaproszenie",
"Invitation updated: %1$s" : "Zaktualizowano zaproszenie: %1$s",
"%1$s updated the event \"%2$s\"" : "%1$s zaktualizował/a wydarzenie \"%2$s\"",
diff --git a/apps/dav/lib/CardDAV/Converter.php b/apps/dav/lib/CardDAV/Converter.php
index 4c7d6f9075f..409fce62105 100644
--- a/apps/dav/lib/CardDAV/Converter.php
+++ b/apps/dav/lib/CardDAV/Converter.php
@@ -29,10 +29,12 @@ namespace OCA\DAV\CardDAV;
use Exception;
use OCP\Accounts\IAccountManager;
+use OCP\Accounts\PropertyDoesNotExistException;
use OCP\IImage;
use OCP\IUser;
use Sabre\VObject\Component\VCard;
use Sabre\VObject\Property\Text;
+use function array_merge;
class Converter {
@@ -44,7 +46,13 @@ class Converter {
}
public function createCardFromUser(IUser $user): ?VCard {
- $userProperties = $this->accountManager->getAccount($user)->getProperties();
+ $account = $this->accountManager->getAccount($user);
+ $userProperties = $account->getProperties();
+ try {
+ $additionalEmailsCollection = $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
+ $userProperties = array_merge($userProperties, $additionalEmailsCollection->getProperties());
+ } catch (PropertyDoesNotExistException $e) {
+ }
$uid = $user->getUID();
$cloudId = $user->getCloudId();
@@ -75,6 +83,7 @@ class Converter {
$vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType()]);
}
break;
+ case IAccountManager::COLLECTION_EMAIL:
case IAccountManager::PROPERTY_EMAIL:
$vCard->add(new Text($vCard, 'EMAIL', $property->getValue(), ['TYPE' => 'OTHER']));
break;
diff --git a/apps/federation/lib/SyncFederationAddressBooks.php b/apps/federation/lib/SyncFederationAddressBooks.php
index 401fd19bd75..3c3c8c872c7 100644
--- a/apps/federation/lib/SyncFederationAddressBooks.php
+++ b/apps/federation/lib/SyncFederationAddressBooks.php
@@ -82,10 +82,14 @@ class SyncFederationAddressBooks {
} catch (\Exception $ex) {
if ($ex->getCode() === Http::STATUS_UNAUTHORIZED) {
$this->dbHandler->setServerStatus($url, TrustedServers::STATUS_ACCESS_REVOKED);
- $this->logger->error("Server sync for $url failed because of revoked access.");
+ $this->logger->error("Server sync for $url failed because of revoked access.", [
+ 'exception' => $ex,
+ ]);
} else {
$this->dbHandler->setServerStatus($url, TrustedServers::STATUS_FAILURE);
- $this->logger->error("Server sync for $url failed.");
+ $this->logger->error("Server sync for $url failed.", [
+ 'exception' => $ex,
+ ]);
}
$callback($url, $ex);
}
diff --git a/apps/files/l10n/en_GB.js b/apps/files/l10n/en_GB.js
index c73292f069f..e0708ccdd23 100644
--- a/apps/files/l10n/en_GB.js
+++ b/apps/files/l10n/en_GB.js
@@ -109,6 +109,8 @@ OC.L10N.register(
"Create new folder" : "Create new folder",
"Upload file" : "Upload file",
"Recent" : "Recent",
+ "This file has the tag {tag}" : "This file has the tag {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "This file has the tags {firstTags} and {lastTag}",
"Not favorited" : "Not favourited",
"Remove from favorites" : "Remove from favourites",
"Add to favorites" : "Add to favourites",
diff --git a/apps/files/l10n/en_GB.json b/apps/files/l10n/en_GB.json
index c74a72b87db..ea827a9f8a1 100644
--- a/apps/files/l10n/en_GB.json
+++ b/apps/files/l10n/en_GB.json
@@ -107,6 +107,8 @@
"Create new folder" : "Create new folder",
"Upload file" : "Upload file",
"Recent" : "Recent",
+ "This file has the tag {tag}" : "This file has the tag {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "This file has the tags {firstTags} and {lastTag}",
"Not favorited" : "Not favourited",
"Remove from favorites" : "Remove from favourites",
"Add to favorites" : "Add to favourites",
diff --git a/apps/files/l10n/es.js b/apps/files/l10n/es.js
index 61432fe570e..5893b81ab5d 100644
--- a/apps/files/l10n/es.js
+++ b/apps/files/l10n/es.js
@@ -109,6 +109,8 @@ OC.L10N.register(
"Create new folder" : "Crear nueva carpeta",
"Upload file" : "Subir archivo",
"Recent" : "Reciente",
+ "This file has the tag {tag}" : "Este archivo tiene la etiqueta {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "Este archivo tiene las etiquetas {firstTags} y {lastTag}",
"Not favorited" : "Quitado como favorito",
"Remove from favorites" : "Quitar de favoritos",
"Add to favorites" : "Añadir a favoritos",
diff --git a/apps/files/l10n/es.json b/apps/files/l10n/es.json
index cabb9dca6c3..58c2d1a304e 100644
--- a/apps/files/l10n/es.json
+++ b/apps/files/l10n/es.json
@@ -107,6 +107,8 @@
"Create new folder" : "Crear nueva carpeta",
"Upload file" : "Subir archivo",
"Recent" : "Reciente",
+ "This file has the tag {tag}" : "Este archivo tiene la etiqueta {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "Este archivo tiene las etiquetas {firstTags} y {lastTag}",
"Not favorited" : "Quitado como favorito",
"Remove from favorites" : "Quitar de favoritos",
"Add to favorites" : "Añadir a favoritos",
diff --git a/apps/files/l10n/fr.js b/apps/files/l10n/fr.js
index fafff6d98e6..bbda95dafb5 100644
--- a/apps/files/l10n/fr.js
+++ b/apps/files/l10n/fr.js
@@ -109,6 +109,8 @@ OC.L10N.register(
"Create new folder" : "Créer un nouveau dossier",
"Upload file" : "Téléverser un fichier",
"Recent" : "Récent",
+ "This file has the tag {tag}" : "Ce fichier a l'étiquette {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "Ce fichier a les étiquettes {firstTags} et {lastTag}",
"Not favorited" : "Non marqué comme favori",
"Remove from favorites" : "Retirer des favoris",
"Add to favorites" : "Ajouter aux favoris",
@@ -174,6 +176,7 @@ OC.L10N.register(
"Download file {name}" : "Télécharger le fichier {name}",
"\"{displayName}\" action executed successfully" : "Action \"{displayName}\" exécutée avec succès",
"\"{displayName}\" action failed" : "Échec de l'action \"{displayName}\"",
+ "Total rows summary" : "Récapitulatif du nombre total de lignes",
"Select all" : "Tout sélectionner",
"Unselect all" : "Tout désélectionner",
"\"{displayName}\" failed on some elements " : "\"{displayName}\" a échoué pour avec certains éléments",
@@ -229,6 +232,7 @@ OC.L10N.register(
"Delete permanently" : "Supprimer définitivement",
"Set up templates folder" : "Configurer le dossier des modèles",
"Templates" : "Modèles",
+ "Create new templates folder" : "Créer un nouveau dossier de modèles",
"Unable to initialize the templates directory" : "Impossible d'initialiser le dossier des modèles",
"Toggle %1$s sublist" : "Basculer %1$s sous-liste",
"Toggle grid view" : "Activer/Désactiver l'affichage mosaïque",
diff --git a/apps/files/l10n/fr.json b/apps/files/l10n/fr.json
index 6486b97d32e..19a6da272a7 100644
--- a/apps/files/l10n/fr.json
+++ b/apps/files/l10n/fr.json
@@ -107,6 +107,8 @@
"Create new folder" : "Créer un nouveau dossier",
"Upload file" : "Téléverser un fichier",
"Recent" : "Récent",
+ "This file has the tag {tag}" : "Ce fichier a l'étiquette {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "Ce fichier a les étiquettes {firstTags} et {lastTag}",
"Not favorited" : "Non marqué comme favori",
"Remove from favorites" : "Retirer des favoris",
"Add to favorites" : "Ajouter aux favoris",
@@ -172,6 +174,7 @@
"Download file {name}" : "Télécharger le fichier {name}",
"\"{displayName}\" action executed successfully" : "Action \"{displayName}\" exécutée avec succès",
"\"{displayName}\" action failed" : "Échec de l'action \"{displayName}\"",
+ "Total rows summary" : "Récapitulatif du nombre total de lignes",
"Select all" : "Tout sélectionner",
"Unselect all" : "Tout désélectionner",
"\"{displayName}\" failed on some elements " : "\"{displayName}\" a échoué pour avec certains éléments",
@@ -227,6 +230,7 @@
"Delete permanently" : "Supprimer définitivement",
"Set up templates folder" : "Configurer le dossier des modèles",
"Templates" : "Modèles",
+ "Create new templates folder" : "Créer un nouveau dossier de modèles",
"Unable to initialize the templates directory" : "Impossible d'initialiser le dossier des modèles",
"Toggle %1$s sublist" : "Basculer %1$s sous-liste",
"Toggle grid view" : "Activer/Désactiver l'affichage mosaïque",
diff --git a/apps/files/l10n/zh_HK.js b/apps/files/l10n/zh_HK.js
index 61c7b00c1c2..c51b90cebe2 100644
--- a/apps/files/l10n/zh_HK.js
+++ b/apps/files/l10n/zh_HK.js
@@ -109,6 +109,8 @@ OC.L10N.register(
"Create new folder" : "新增資料夾",
"Upload file" : "上傳檔案",
"Recent" : "最新",
+ "This file has the tag {tag}" : "此檔案有標籤 {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "此檔案有標籤 {firstTags} 與 {lastTag}",
"Not favorited" : "未加入至最愛",
"Remove from favorites" : "從最愛中移除",
"Add to favorites" : "加到我的最愛",
diff --git a/apps/files/l10n/zh_HK.json b/apps/files/l10n/zh_HK.json
index c9dbf1a731a..33e803bfdd6 100644
--- a/apps/files/l10n/zh_HK.json
+++ b/apps/files/l10n/zh_HK.json
@@ -107,6 +107,8 @@
"Create new folder" : "新增資料夾",
"Upload file" : "上傳檔案",
"Recent" : "最新",
+ "This file has the tag {tag}" : "此檔案有標籤 {tag}",
+ "This file has the tags {firstTags} and {lastTag}" : "此檔案有標籤 {firstTags} 與 {lastTag}",
"Not favorited" : "未加入至最愛",
"Remove from favorites" : "從最愛中移除",
"Add to favorites" : "加到我的最愛",
diff --git a/apps/files_versions/l10n/pl.js b/apps/files_versions/l10n/pl.js
index b9d8dd4687a..e55af7f1c3d 100644
--- a/apps/files_versions/l10n/pl.js
+++ b/apps/files_versions/l10n/pl.js
@@ -4,13 +4,16 @@ OC.L10N.register(
"Versions" : "Wersje",
"This application automatically maintains older versions of files that are changed." : "Aplikacja przechowuje starsze wersje plików poddanych modyfikacji.",
"This application automatically maintains older versions of files that are changed. When enabled, a hidden versions folder is provisioned in every user's directory and is used to store old file versions. A user can revert to an older version through the web interface at any time, with the replaced file becoming a version. The app automatically manages the versions folder to ensure the user does not run out of Quota because of versions.\n\t\tIn addition to the expiry of versions, the versions app makes certain never to use more than 50% of the user's currently available free space. If stored versions exceed this limit, the app will delete the oldest versions first until it meets this limit. More information is available in the Versions documentation." : "Aplikacja automatycznie utrzymuje starsze wersje zmienionych plików. Po włączeniu, ukryty katalog versions jest udostępniany w każdym katalogu użytkownika i służy do przechowywania starych wersji plików. Użytkownik może w dowolnym momencie powrócić do starszej wersji za pośrednictwem strony internetowej, a zastąpiony plik staje się jego wersją. Aplikacja automatycznie zarządza katalogiem versions, aby zapewnić użytkownikowi ciągłość wersji.\n\t\tOprócz wygaśnięcia wersji, aplikacja Versions zapewnia, że nigdy nie będzie wykorzystywać więcej niż 50% dostępnej przestrzeni użytkownika. Jeśli przechowywane wersje przekroczą ten limit, aplikacja usunie najpierw najstarsze wersje, aż do osiągnięcia tego limitu. Więcej informacji można znaleźć w dokumentacji Versions.",
+ "Name this version" : "Nazwij tę wersję",
"Edit version name" : "Edytuj nazwę wersji",
"Restore version" : "Przywróć wersję",
"Download version" : "Pobierz wersję",
"Delete version" : "Usuń wersję",
"Version name" : "Nazwa wersji",
+ "Named versions are persisted, and excluded from automatic cleanups when your storage quota is full." : "Nazwane wersje są utrwalane i wykluczane z automatycznego czyszczenia, gdy limit przechowywania zostanie przekroczony.",
"Remove version name" : "Usuń nazwę wersji",
"Save version name" : "Zapis nazwę wersji",
+ "Initial version restored" : "Przywrócono wersję początkową",
"Version restored" : "Wersja przywrócona",
"Could not restore version" : "Nie można przywrócić wersji",
"Could not set version name" : "Nie można ustawić nazwy wersji",
diff --git a/apps/files_versions/l10n/pl.json b/apps/files_versions/l10n/pl.json
index a9cd03e6fee..93ccd7b4ad4 100644
--- a/apps/files_versions/l10n/pl.json
+++ b/apps/files_versions/l10n/pl.json
@@ -2,13 +2,16 @@
"Versions" : "Wersje",
"This application automatically maintains older versions of files that are changed." : "Aplikacja przechowuje starsze wersje plików poddanych modyfikacji.",
"This application automatically maintains older versions of files that are changed. When enabled, a hidden versions folder is provisioned in every user's directory and is used to store old file versions. A user can revert to an older version through the web interface at any time, with the replaced file becoming a version. The app automatically manages the versions folder to ensure the user does not run out of Quota because of versions.\n\t\tIn addition to the expiry of versions, the versions app makes certain never to use more than 50% of the user's currently available free space. If stored versions exceed this limit, the app will delete the oldest versions first until it meets this limit. More information is available in the Versions documentation." : "Aplikacja automatycznie utrzymuje starsze wersje zmienionych plików. Po włączeniu, ukryty katalog versions jest udostępniany w każdym katalogu użytkownika i służy do przechowywania starych wersji plików. Użytkownik może w dowolnym momencie powrócić do starszej wersji za pośrednictwem strony internetowej, a zastąpiony plik staje się jego wersją. Aplikacja automatycznie zarządza katalogiem versions, aby zapewnić użytkownikowi ciągłość wersji.\n\t\tOprócz wygaśnięcia wersji, aplikacja Versions zapewnia, że nigdy nie będzie wykorzystywać więcej niż 50% dostępnej przestrzeni użytkownika. Jeśli przechowywane wersje przekroczą ten limit, aplikacja usunie najpierw najstarsze wersje, aż do osiągnięcia tego limitu. Więcej informacji można znaleźć w dokumentacji Versions.",
+ "Name this version" : "Nazwij tę wersję",
"Edit version name" : "Edytuj nazwę wersji",
"Restore version" : "Przywróć wersję",
"Download version" : "Pobierz wersję",
"Delete version" : "Usuń wersję",
"Version name" : "Nazwa wersji",
+ "Named versions are persisted, and excluded from automatic cleanups when your storage quota is full." : "Nazwane wersje są utrwalane i wykluczane z automatycznego czyszczenia, gdy limit przechowywania zostanie przekroczony.",
"Remove version name" : "Usuń nazwę wersji",
"Save version name" : "Zapis nazwę wersji",
+ "Initial version restored" : "Przywrócono wersję początkową",
"Version restored" : "Wersja przywrócona",
"Could not restore version" : "Nie można przywrócić wersji",
"Could not set version name" : "Nie można ustawić nazwy wersji",
diff --git a/apps/theming/l10n/eo.js b/apps/theming/l10n/eo.js
index d07abe4e8e6..f73e7fc8f6c 100644
--- a/apps/theming/l10n/eo.js
+++ b/apps/theming/l10n/eo.js
@@ -23,9 +23,12 @@ OC.L10N.register(
"You are already using a custom theme. Theming app settings might be overwritten by that." : "Vi jam uzas propran etoson. Agordoj de la aplikaĵo „Etosoj“ povus esti anstataŭigitaj de ĝi.",
"Theming" : "Etosoj",
"Dark theme" : "Malhela etoso",
+ "Enable dark theme" : "Ŝaltu malhelan etoson",
"Dyslexia font" : "Tiparo por limigi vortblindecon",
+ "Enable dyslexia font" : "Ŝaltu disleksian tiparon",
"OpenDyslexic is a free typeface/font designed to mitigate some of the common reading errors caused by dyslexia." : "OpenDyslexic estas tiparo kreita por malpliigi legajn erarojn kaŭzitajn de vortblindeco (medicine „disleksio“).",
"High contrast mode" : "Altkontrasta reĝimo",
+ "Enable high contrast mode" : "Ŝaltu altkontrastan reĝimon",
"A high contrast mode to ease your navigation. Visual quality will be reduced but clarity will be increased." : "Altkontrasta reĝimo, kiu faciligas vian navigadon. Vida kvalito malpliiĝos, sed klareco pliiĝos.",
"Legal notice" : "Leĝa regularo",
"Privacy policy" : "Privateca regularo",
@@ -46,6 +49,7 @@ OC.L10N.register(
"Favicon" : "Retpaĝsimbolo",
"Upload new favicon" : "Alŝuti novan retpaĝsimbolon",
"Keyboard shortcuts" : "Fulmoklavoj",
+ "Universal access is very important to us. We follow web standards and check to make everything usable also without mouse, and assistive software such as screenreaders. We aim to be compliant with the {guidelines}Web Content Accessibility Guidelines{linkend} 2.1 on AA level, with the high contrast theme even on AAA level." : "Universala aliro estas tre grava por ni. Ni sekvas la retejo-standardojn kaj kontrolas, ĉu ĉio estas uzebla eĉ sen muso, kaj per helpa programaro, kiel ekzemple ekranlegiloj. Ni celas esti kongruaj kun la {guidelines}Reteja alireblecaj reguloj{linkend} 2.1 je la AA nivelo, kun alta kontrasta temo eĉ ĉe la AAA nivelo.",
"Reset to default" : "Restarigi al defaŭltaj agordoj",
"Upload" : "Alŝuti",
"Remove background image" : "Forigi fonan bildon",
diff --git a/apps/theming/l10n/eo.json b/apps/theming/l10n/eo.json
index 03b3b9d4693..fcdfaeadad1 100644
--- a/apps/theming/l10n/eo.json
+++ b/apps/theming/l10n/eo.json
@@ -21,9 +21,12 @@
"You are already using a custom theme. Theming app settings might be overwritten by that." : "Vi jam uzas propran etoson. Agordoj de la aplikaĵo „Etosoj“ povus esti anstataŭigitaj de ĝi.",
"Theming" : "Etosoj",
"Dark theme" : "Malhela etoso",
+ "Enable dark theme" : "Ŝaltu malhelan etoson",
"Dyslexia font" : "Tiparo por limigi vortblindecon",
+ "Enable dyslexia font" : "Ŝaltu disleksian tiparon",
"OpenDyslexic is a free typeface/font designed to mitigate some of the common reading errors caused by dyslexia." : "OpenDyslexic estas tiparo kreita por malpliigi legajn erarojn kaŭzitajn de vortblindeco (medicine „disleksio“).",
"High contrast mode" : "Altkontrasta reĝimo",
+ "Enable high contrast mode" : "Ŝaltu altkontrastan reĝimon",
"A high contrast mode to ease your navigation. Visual quality will be reduced but clarity will be increased." : "Altkontrasta reĝimo, kiu faciligas vian navigadon. Vida kvalito malpliiĝos, sed klareco pliiĝos.",
"Legal notice" : "Leĝa regularo",
"Privacy policy" : "Privateca regularo",
@@ -44,6 +47,7 @@
"Favicon" : "Retpaĝsimbolo",
"Upload new favicon" : "Alŝuti novan retpaĝsimbolon",
"Keyboard shortcuts" : "Fulmoklavoj",
+ "Universal access is very important to us. We follow web standards and check to make everything usable also without mouse, and assistive software such as screenreaders. We aim to be compliant with the {guidelines}Web Content Accessibility Guidelines{linkend} 2.1 on AA level, with the high contrast theme even on AAA level." : "Universala aliro estas tre grava por ni. Ni sekvas la retejo-standardojn kaj kontrolas, ĉu ĉio estas uzebla eĉ sen muso, kaj per helpa programaro, kiel ekzemple ekranlegiloj. Ni celas esti kongruaj kun la {guidelines}Reteja alireblecaj reguloj{linkend} 2.1 je la AA nivelo, kun alta kontrasta temo eĉ ĉe la AAA nivelo.",
"Reset to default" : "Restarigi al defaŭltaj agordoj",
"Upload" : "Alŝuti",
"Remove background image" : "Forigi fonan bildon",
diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index e7359123151..08062266683 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -2875,9 +2875,6 @@
</UndefinedInterfaceMethod>
</file>
<file src="lib/private/Files/Storage/Wrapper/Encryption.php">
- <FalsableReturnStatement>
- <code>false</code>
- </FalsableReturnStatement>
<InvalidOperand>
<code>$result</code>
<code>$result</code>
@@ -2886,12 +2883,10 @@
<InvalidReturnStatement>
<code>$newUnencryptedSize</code>
<code>$result</code>
- <code><![CDATA[$this->storage->file_get_contents($path)]]></code>
</InvalidReturnStatement>
<InvalidReturnType>
<code>bool</code>
<code>int</code>
- <code>string</code>
</InvalidReturnType>
<InvalidScalarArgument>
<code>$lastChunkPos</code>
diff --git a/core/Command/Info/File.php b/core/Command/Info/File.php
index bf7b9ae4e0a..20d8cbffc94 100644
--- a/core/Command/Info/File.php
+++ b/core/Command/Info/File.php
@@ -5,22 +5,15 @@ declare(strict_types=1);
namespace OC\Core\Command\Info;
use OC\Files\ObjectStore\ObjectStoreStorage;
-use OCA\Circles\MountManager\CircleMount;
use OCA\Files_External\Config\ExternalMountPoint;
-use OCA\Files_Sharing\SharedMount;
use OCA\GroupFolders\Mount\GroupMountPoint;
-use OCP\Constants;
-use OCP\Files\Config\IUserMountCache;
-use OCP\Files\FileInfo;
use OCP\Files\Folder;
use OCP\Files\IHomeStorage;
-use OCP\Files\IRootFolder;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\IL10N;
use OCP\L10N\IFactory;
-use OCP\Share\IShare;
use OCP\Util;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
@@ -29,14 +22,12 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class File extends Command {
- private IRootFolder $rootFolder;
- private IUserMountCache $userMountCache;
private IL10N $l10n;
+ private FileUtils $fileUtils;
- public function __construct(IRootFolder $rootFolder, IUserMountCache $userMountCache, IFactory $l10nFactory) {
- $this->rootFolder = $rootFolder;
- $this->userMountCache = $userMountCache;
+ public function __construct(IFactory $l10nFactory, FileUtils $fileUtils) {
$this->l10n = $l10nFactory->get("core");
+ $this->fileUtils = $fileUtils;
parent::__construct();
}
@@ -51,7 +42,7 @@ class File extends Command {
public function execute(InputInterface $input, OutputInterface $output): int {
$fileInput = $input->getArgument('file');
$showChildren = $input->getOption('children');
- $node = $this->getNode($fileInput);
+ $node = $this->fileUtils->getNode($fileInput);
if (!$node) {
$output->writeln("<error>file $fileInput not found</error>");
return 1;
@@ -83,137 +74,22 @@ class File extends Command {
}
$this->outputStorageDetails($node->getMountPoint(), $node, $output);
- $filesPerUser = $this->getFilesByUser($node);
+ $filesPerUser = $this->fileUtils->getFilesByUser($node);
$output->writeln("");
$output->writeln("The following users have access to the file");
$output->writeln("");
foreach ($filesPerUser as $user => $files) {
$output->writeln("$user:");
foreach ($files as $userFile) {
- $output->writeln(" " . $userFile->getPath() . ": " . $this->formatPermissions($userFile->getType(), $userFile->getPermissions()));
+ $output->writeln(" " . $userFile->getPath() . ": " . $this->fileUtils->formatPermissions($userFile->getType(), $userFile->getPermissions()));
$mount = $userFile->getMountPoint();
- $output->writeln(" " . $this->formatMountType($mount));
+ $output->writeln(" " . $this->fileUtils->formatMountType($mount));
}
}
return 0;
}
- private function getNode(string $fileInput): ?Node {
- if (is_numeric($fileInput)) {
- $mounts = $this->userMountCache->getMountsForFileId((int)$fileInput);
- if (!$mounts) {
- return null;
- }
- $mount = $mounts[0];
- $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
- $nodes = $userFolder->getById((int)$fileInput);
- if (!$nodes) {
- return null;
- }
- return $nodes[0];
- } else {
- try {
- return $this->rootFolder->get($fileInput);
- } catch (NotFoundException $e) {
- return null;
- }
- }
- }
-
- /**
- * @param FileInfo $file
- * @return array<string, Node[]>
- * @throws \OCP\Files\NotPermittedException
- * @throws \OC\User\NoUserException
- */
- private function getFilesByUser(FileInfo $file): array {
- $id = $file->getId();
- if (!$id) {
- return [];
- }
-
- $mounts = $this->userMountCache->getMountsForFileId($id);
- $result = [];
- foreach ($mounts as $mount) {
- if (isset($result[$mount->getUser()->getUID()])) {
- continue;
- }
-
- $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
- $result[$mount->getUser()->getUID()] = $userFolder->getById($id);
- }
-
- return $result;
- }
-
- private function formatPermissions(string $type, int $permissions): string {
- if ($permissions == Constants::PERMISSION_ALL || ($type === 'file' && $permissions == (Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE))) {
- return "full permissions";
- }
-
- $perms = [];
- $allPerms = [Constants::PERMISSION_READ => "read", Constants::PERMISSION_UPDATE => "update", Constants::PERMISSION_CREATE => "create", Constants::PERMISSION_DELETE => "delete", Constants::PERMISSION_SHARE => "share"];
- foreach ($allPerms as $perm => $name) {
- if (($permissions & $perm) === $perm) {
- $perms[] = $name;
- }
- }
-
- return implode(", ", $perms);
- }
-
- /**
- * @psalm-suppress UndefinedClass
- * @psalm-suppress UndefinedInterfaceMethod
- */
- private function formatMountType(IMountPoint $mountPoint): string {
- $storage = $mountPoint->getStorage();
- if ($storage && $storage->instanceOfStorage(IHomeStorage::class)) {
- return "home storage";
- } elseif ($mountPoint instanceof SharedMount) {
- $share = $mountPoint->getShare();
- $shares = $mountPoint->getGroupedShares();
- $sharedBy = array_map(function (IShare $share) {
- $shareType = $this->formatShareType($share);
- if ($shareType) {
- return $share->getSharedBy() . " (via " . $shareType . " " . $share->getSharedWith() . ")";
- } else {
- return $share->getSharedBy();
- }
- }, $shares);
- $description = "shared by " . implode(', ', $sharedBy);
- if ($share->getSharedBy() !== $share->getShareOwner()) {
- $description .= " owned by " . $share->getShareOwner();
- }
- return $description;
- } elseif ($mountPoint instanceof GroupMountPoint) {
- return "groupfolder " . $mountPoint->getFolderId();
- } elseif ($mountPoint instanceof ExternalMountPoint) {
- return "external storage " . $mountPoint->getStorageConfig()->getId();
- } elseif ($mountPoint instanceof CircleMount) {
- return "circle";
- }
- return get_class($mountPoint);
- }
-
- private function formatShareType(IShare $share): ?string {
- switch ($share->getShareType()) {
- case IShare::TYPE_GROUP:
- return "group";
- case IShare::TYPE_CIRCLE:
- return "circle";
- case IShare::TYPE_DECK:
- return "deck";
- case IShare::TYPE_ROOM:
- return "room";
- case IShare::TYPE_USER:
- return null;
- default:
- return "Unknown (".$share->getShareType().")";
- }
- }
-
/**
* @psalm-suppress UndefinedClass
* @psalm-suppress UndefinedInterfaceMethod
diff --git a/core/Command/Info/FileUtils.php b/core/Command/Info/FileUtils.php
new file mode 100644
index 00000000000..1264dee5de2
--- /dev/null
+++ b/core/Command/Info/FileUtils.php
@@ -0,0 +1,254 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Core\Command\Info;
+
+use OC\Files\SetupManager;
+use OCA\Circles\MountManager\CircleMount;
+use OCA\Files_External\Config\ExternalMountPoint;
+use OCA\Files_Sharing\SharedMount;
+use OCA\GroupFolders\Mount\GroupMountPoint;
+use OCP\Constants;
+use OCP\Files\Config\IUserMountCache;
+use OCP\Files\FileInfo;
+use OCP\Files\IHomeStorage;
+use OCP\Files\IRootFolder;
+use OCP\Files\Mount\IMountManager;
+use OCP\Files\Mount\IMountPoint;
+use OCP\Files\Node;
+use OCP\Files\NotFoundException;
+use OCP\Share\IShare;
+use OCP\Util;
+use Symfony\Component\Console\Output\OutputInterface;
+use OCP\Files\Folder;
+
+class FileUtils {
+ private IRootFolder $rootFolder;
+ private IUserMountCache $userMountCache;
+ private IMountManager $mountManager;
+ private SetupManager $setupManager;
+
+ public function __construct(
+ IRootFolder $rootFolder,
+ IUserMountCache $userMountCache,
+ IMountManager $mountManager,
+ SetupManager $setupManager
+ ) {
+ $this->rootFolder = $rootFolder;
+ $this->userMountCache = $userMountCache;
+ $this->mountManager = $mountManager;
+ $this->setupManager = $setupManager;
+ }
+
+ /**
+ * @param FileInfo $file
+ * @return array<string, Node[]>
+ * @throws \OCP\Files\NotPermittedException
+ * @throws \OC\User\NoUserException
+ */
+ public function getFilesByUser(FileInfo $file): array {
+ $id = $file->getId();
+ if (!$id) {
+ return [];
+ }
+
+ $mounts = $this->userMountCache->getMountsForFileId($id);
+ $result = [];
+ foreach ($mounts as $mount) {
+ if (isset($result[$mount->getUser()->getUID()])) {
+ continue;
+ }
+
+ $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
+ $result[$mount->getUser()->getUID()] = $userFolder->getById($id);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Get file by either id of path
+ *
+ * @param string $fileInput
+ * @return Node|null
+ */
+ public function getNode(string $fileInput): ?Node {
+ if (is_numeric($fileInput)) {
+ $mounts = $this->userMountCache->getMountsForFileId((int)$fileInput);
+ if (!$mounts) {
+ return null;
+ }
+ $mount = $mounts[0];
+ $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
+ $nodes = $userFolder->getById((int)$fileInput);
+ if (!$nodes) {
+ return null;
+ }
+ return $nodes[0];
+ } else {
+ try {
+ return $this->rootFolder->get($fileInput);
+ } catch (NotFoundException $e) {
+ return null;
+ }
+ }
+ }
+
+ public function formatPermissions(string $type, int $permissions): string {
+ if ($permissions == Constants::PERMISSION_ALL || ($type === 'file' && $permissions == (Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE))) {
+ return "full permissions";
+ }
+
+ $perms = [];
+ $allPerms = [Constants::PERMISSION_READ => "read", Constants::PERMISSION_UPDATE => "update", Constants::PERMISSION_CREATE => "create", Constants::PERMISSION_DELETE => "delete", Constants::PERMISSION_SHARE => "share"];
+ foreach ($allPerms as $perm => $name) {
+ if (($permissions & $perm) === $perm) {
+ $perms[] = $name;
+ }
+ }
+
+ return implode(", ", $perms);
+ }
+
+ /**
+ * @psalm-suppress UndefinedClass
+ * @psalm-suppress UndefinedInterfaceMethod
+ */
+ public function formatMountType(IMountPoint $mountPoint): string {
+ $storage = $mountPoint->getStorage();
+ if ($storage && $storage->instanceOfStorage(IHomeStorage::class)) {
+ return "home storage";
+ } elseif ($mountPoint instanceof SharedMount) {
+ $share = $mountPoint->getShare();
+ $shares = $mountPoint->getGroupedShares();
+ $sharedBy = array_map(function (IShare $share) {
+ $shareType = $this->formatShareType($share);
+ if ($shareType) {
+ return $share->getSharedBy() . " (via " . $shareType . " " . $share->getSharedWith() . ")";
+ } else {
+ return $share->getSharedBy();
+ }
+ }, $shares);
+ $description = "shared by " . implode(', ', $sharedBy);
+ if ($share->getSharedBy() !== $share->getShareOwner()) {
+ $description .= " owned by " . $share->getShareOwner();
+ }
+ return $description;
+ } elseif ($mountPoint instanceof GroupMountPoint) {
+ return "groupfolder " . $mountPoint->getFolderId();
+ } elseif ($mountPoint instanceof ExternalMountPoint) {
+ return "external storage " . $mountPoint->getStorageConfig()->getId();
+ } elseif ($mountPoint instanceof CircleMount) {
+ return "circle";
+ }
+ return get_class($mountPoint);
+ }
+
+ public function formatShareType(IShare $share): ?string {
+ switch ($share->getShareType()) {
+ case IShare::TYPE_GROUP:
+ return "group";
+ case IShare::TYPE_CIRCLE:
+ return "circle";
+ case IShare::TYPE_DECK:
+ return "deck";
+ case IShare::TYPE_ROOM:
+ return "room";
+ case IShare::TYPE_USER:
+ return null;
+ default:
+ return "Unknown (" . $share->getShareType() . ")";
+ }
+ }
+
+ /**
+ * Print out the largest count($sizeLimits) files in the directory tree
+ *
+ * @param OutputInterface $output
+ * @param Folder $node
+ * @param string $prefix
+ * @param array $sizeLimits largest items that are still in the queue to be printed, ordered ascending
+ * @return int how many items we've printed
+ */
+ public function outputLargeFilesTree(
+ OutputInterface $output,
+ Folder $node,
+ string $prefix,
+ array &$sizeLimits,
+ bool $all,
+ ): int {
+ /**
+ * Algorithm to print the N largest items in a folder without requiring to query or sort the entire three
+ *
+ * This is done by keeping a list ($sizeLimits) of size N that contain the largest items outside of this
+ * folders that are could be printed if there aren't enough items in this folder that are larger.
+ *
+ * We loop over the items in this folder by size descending until the size of the item falls before the smallest
+ * size in $sizeLimits (at that point there are enough items outside this folder to complete the N items).
+ *
+ * When encountering a folder, we create an updated $sizeLimits with the largest items in the current folder still
+ * remaining which we pass into the recursion. (We don't update the current $sizeLimits because that should only
+ * hold items *outside* of the current folder.)
+ *
+ * For every item printed we remove the first item of $sizeLimits are there is no longer room in the output to print
+ * items that small.
+ */
+
+ $count = 0;
+ $children = $node->getDirectoryListing();
+ usort($children, function (Node $a, Node $b) {
+ return $b->getSize() <=> $a->getSize();
+ });
+ foreach ($children as $i => $child) {
+ if (!$all) {
+ if (count($sizeLimits) === 0 || $child->getSize() < $sizeLimits[0]) {
+ return $count;
+ }
+ array_shift($sizeLimits);
+ }
+ $count += 1;
+
+ /** @var Node $child */
+ $output->writeln("$prefix- " . $child->getName() . ": <info>" . Util::humanFileSize($child->getSize()) . "</info>");
+ if ($child instanceof Folder) {
+ $recurseSizeLimits = $sizeLimits;
+ if (!$all) {
+ for ($j = 0; $j < count($recurseSizeLimits); $j++) {
+ if (isset($children[$i + $j + 1])) {
+ $nextChildSize = $children[$i + $j + 1]->getSize();
+ if ($nextChildSize > $recurseSizeLimits[0]) {
+ array_shift($recurseSizeLimits);
+ $recurseSizeLimits[] = $nextChildSize;
+ }
+ }
+ }
+ sort($recurseSizeLimits);
+ }
+ $recurseCount = $this->outputLargeFilesTree($output, $child, $prefix . " ", $recurseSizeLimits, $all);
+ $sizeLimits = array_slice($sizeLimits, $recurseCount);
+ $count += $recurseCount;
+ }
+ }
+ return $count;
+ }
+}
diff --git a/core/Command/Info/Space.php b/core/Command/Info/Space.php
new file mode 100644
index 00000000000..7f901ee729b
--- /dev/null
+++ b/core/Command/Info/Space.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2023 Robin Appelman <robin@icewind.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Core\Command\Info;
+
+use OCP\Files\Folder;
+use OCP\Util;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Space extends Command {
+ private FileUtils $fileUtils;
+
+ public function __construct(FileUtils $fileUtils) {
+ $this->fileUtils = $fileUtils;
+ parent::__construct();
+ }
+
+ protected function configure(): void {
+ $this
+ ->setName('info:file:space')
+ ->setDescription('Summarize space usage of specified folder')
+ ->addArgument('file', InputArgument::REQUIRED, "File id or path")
+ ->addOption('count', 'c', InputOption::VALUE_REQUIRED, "Number of items to display", 25)
+ ->addOption('all', 'a', InputOption::VALUE_NONE, "Display all items");
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output): int {
+ $fileInput = $input->getArgument('file');
+ $count = (int)$input->getOption('count');
+ $all = $input->getOption('all');
+ $node = $this->fileUtils->getNode($fileInput);
+ if (!$node) {
+ $output->writeln("<error>file $fileInput not found</error>");
+ return 1;
+ }
+ $output->writeln($node->getName() . ": <info>" . Util::humanFileSize($node->getSize()) . "</info>");
+ if ($node instanceof Folder) {
+ $limits = $all ? [] : array_fill(0, $count - 1, 0);
+ $this->fileUtils->outputLargeFilesTree($output, $node, '', $limits, $all);
+ }
+ return 0;
+ }
+}
diff --git a/core/register_command.php b/core/register_command.php
index 4aac7fbf8ce..8f600d7b894 100644
--- a/core/register_command.php
+++ b/core/register_command.php
@@ -104,6 +104,7 @@ if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
$application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
$application->add(\OC::$server->get(OC\Core\Command\Info\File::class));
+ $application->add(\OC::$server->get(OC\Core\Command\Info\Space::class));
$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
$application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->get(LoggerInterface::class)));
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 316b21e8122..ec11cda456d 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -961,6 +961,8 @@ return array(
'OC\\Core\\Command\\Group\\ListCommand' => $baseDir . '/core/Command/Group/ListCommand.php',
'OC\\Core\\Command\\Group\\RemoveUser' => $baseDir . '/core/Command/Group/RemoveUser.php',
'OC\\Core\\Command\\Info\\File' => $baseDir . '/core/Command/Info/File.php',
+ 'OC\\Core\\Command\\Info\\FileUtils' => $baseDir . '/core/Command/Info/FileUtils.php',
+ 'OC\\Core\\Command\\Info\\Space' => $baseDir . '/core/Command/Info/Space.php',
'OC\\Core\\Command\\Integrity\\CheckApp' => $baseDir . '/core/Command/Integrity/CheckApp.php',
'OC\\Core\\Command\\Integrity\\CheckCore' => $baseDir . '/core/Command/Integrity/CheckCore.php',
'OC\\Core\\Command\\Integrity\\SignApp' => $baseDir . '/core/Command/Integrity/SignApp.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 656f8196320..308290b95bc 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -994,6 +994,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Command\\Group\\ListCommand' => __DIR__ . '/../../..' . '/core/Command/Group/ListCommand.php',
'OC\\Core\\Command\\Group\\RemoveUser' => __DIR__ . '/../../..' . '/core/Command/Group/RemoveUser.php',
'OC\\Core\\Command\\Info\\File' => __DIR__ . '/../../..' . '/core/Command/Info/File.php',
+ 'OC\\Core\\Command\\Info\\FileUtils' => __DIR__ . '/../../..' . '/core/Command/Info/FileUtils.php',
+ 'OC\\Core\\Command\\Info\\Space' => __DIR__ . '/../../..' . '/core/Command/Info/Space.php',
'OC\\Core\\Command\\Integrity\\CheckApp' => __DIR__ . '/../../..' . '/core/Command/Integrity/CheckApp.php',
'OC\\Core\\Command\\Integrity\\CheckCore' => __DIR__ . '/../../..' . '/core/Command/Integrity/CheckCore.php',
'OC\\Core\\Command\\Integrity\\SignApp' => __DIR__ . '/../../..' . '/core/Command/Integrity/SignApp.php',
diff --git a/lib/private/Security/CertificateManager.php b/lib/private/Security/CertificateManager.php
index ee68f602bd1..b9fbdcc9f02 100644
--- a/lib/private/Security/CertificateManager.php
+++ b/lib/private/Security/CertificateManager.php
@@ -138,6 +138,10 @@ class CertificateManager implements ICertificateManager {
$tmpPath = $certPath . '.tmp' . $this->random->generate(10, ISecureRandom::CHAR_DIGITS);
$fhCerts = $this->view->fopen($tmpPath, 'w');
+ if (!is_resource($fhCerts)) {
+ throw new \RuntimeException('Unable to open file handler to create certificate bundle "' . $tmpPath . '".');
+ }
+
// Write user certificates
foreach ($certs as $cert) {
$file = $path . '/uploads/' . $cert->getName();
@@ -228,7 +232,7 @@ class CertificateManager implements ICertificateManager {
*/
public function getAbsoluteBundlePath(): string {
try {
- if (!$this->bundlePath) {
+ if ($this->bundlePath === null) {
if (!$this->hasCertificates()) {
$this->bundlePath = \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
}
@@ -237,13 +241,16 @@ class CertificateManager implements ICertificateManager {
$this->createCertificateBundle();
}
- $this->bundlePath = $this->view->getLocalFile($this->getCertificateBundle()) ?: null;
- }
- if ($this->bundlePath === null) {
- throw new \Exception('Failed to get absolute bundle path');
+ $certificateBundle = $this->getCertificateBundle();
+ $this->bundlePath = $this->view->getLocalFile($certificateBundle) ?: null;
+
+ if ($this->bundlePath === null) {
+ throw new \RuntimeException('Unable to get certificate bundle "' . $certificateBundle . '".');
+ }
}
return $this->bundlePath;
} catch (\Exception $e) {
+ $this->logger->error('Failed to get absolute bundle path. Fallback to default ca-bundle.crt', ['exception' => $e]);
return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
}
}
diff --git a/version.php b/version.php
index 44889f77860..d56a5d3cd6e 100644
--- a/version.php
+++ b/version.php
@@ -30,10 +30,10 @@
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patch level
// when updating major/minor version number.
-$OC_Version = [27, 0, 0, 1];
+$OC_Version = [27, 0, 0, 2];
// The human-readable string
-$OC_VersionString = '27.0.0 dev';
+$OC_VersionString = '27.0.0 beta 1';
$OC_VersionCanBeUpgradedFrom = [
'nextcloud' => [