aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/composer/composer/InstalledVersions.php20
-rw-r--r--lib/composer/composer/autoload_classmap.php2
-rw-r--r--lib/composer/composer/autoload_static.php2
-rw-r--r--lib/composer/composer/installed.php4
-rw-r--r--lib/l10n/be.js44
-rw-r--r--lib/l10n/be.json44
-rw-r--r--lib/l10n/fr.js8
-rw-r--r--lib/l10n/fr.json8
-rw-r--r--lib/l10n/mk.js3
-rw-r--r--lib/l10n/mk.json3
-rw-r--r--lib/l10n/sw.js20
-rw-r--r--lib/l10n/sw.json20
-rw-r--r--lib/private/AppFramework/App.php15
-rw-r--r--lib/private/AppFramework/Http/Request.php47
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php4
-rw-r--r--lib/private/DB/QueryBuilder/QueryBuilder.php2
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php42
-rw-r--r--lib/private/Files/ObjectStore/S3ObjectTrait.php33
-rw-r--r--lib/private/Files/SetupManager.php12
-rw-r--r--lib/private/Files/Type/Detection.php33
-rw-r--r--lib/private/Files/Utils/Scanner.php8
-rw-r--r--lib/private/Notification/Manager.php12
-rw-r--r--lib/private/Security/IdentityProof/Manager.php26
-rw-r--r--lib/private/Setup/AbstractDatabase.php1
-rw-r--r--lib/private/Tags.php1
-rw-r--r--lib/private/TaskProcessing/Manager.php19
-rw-r--r--lib/public/Notification/IManager.php2
-rw-r--r--lib/public/Notification/INotifier.php5
-rw-r--r--lib/public/Notification/IPreloadableNotifier.php31
-rw-r--r--lib/public/TaskProcessing/IManager.php1
30 files changed, 362 insertions, 110 deletions
diff --git a/lib/composer/composer/InstalledVersions.php b/lib/composer/composer/InstalledVersions.php
index 6d29bff66aa..2052022fd8e 100644
--- a/lib/composer/composer/InstalledVersions.php
+++ b/lib/composer/composer/InstalledVersions.php
@@ -27,6 +27,12 @@ use Composer\Semver\VersionParser;
class InstalledVersions
{
/**
+ * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
+ * @internal
+ */
+ private static $selfDir = null;
+
+ /**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
@@ -323,6 +329,18 @@ class InstalledVersions
}
/**
+ * @return string
+ */
+ private static function getSelfDir()
+ {
+ if (self::$selfDir === null) {
+ self::$selfDir = strtr(__DIR__, '\\', '/');
+ }
+
+ return self::$selfDir;
+ }
+
+ /**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
@@ -336,7 +354,7 @@ class InstalledVersions
$copiedLocalDir = false;
if (self::$canGetVendors) {
- $selfDir = strtr(__DIR__, '\\', '/');
+ $selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 3f2dbe5edf9..fda8798fe43 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -696,6 +696,7 @@ return array(
'OCP\\Notification\\IManager' => $baseDir . '/lib/public/Notification/IManager.php',
'OCP\\Notification\\INotification' => $baseDir . '/lib/public/Notification/INotification.php',
'OCP\\Notification\\INotifier' => $baseDir . '/lib/public/Notification/INotifier.php',
+ 'OCP\\Notification\\IPreloadableNotifier' => $baseDir . '/lib/public/Notification/IPreloadableNotifier.php',
'OCP\\Notification\\IncompleteNotificationException' => $baseDir . '/lib/public/Notification/IncompleteNotificationException.php',
'OCP\\Notification\\IncompleteParsedNotificationException' => $baseDir . '/lib/public/Notification/IncompleteParsedNotificationException.php',
'OCP\\Notification\\InvalidValueException' => $baseDir . '/lib/public/Notification/InvalidValueException.php',
@@ -1510,6 +1511,7 @@ return array(
'OC\\Core\\Migrations\\Version31000Date20240814184402' => $baseDir . '/core/Migrations/Version31000Date20240814184402.php',
'OC\\Core\\Migrations\\Version31000Date20250213102442' => $baseDir . '/core/Migrations/Version31000Date20250213102442.php',
'OC\\Core\\Migrations\\Version32000Date20250620081925' => $baseDir . '/core/Migrations/Version32000Date20250620081925.php',
+ 'OC\\Core\\Migrations\\Version32000Date20250731062008' => $baseDir . '/core/Migrations/Version32000Date20250731062008.php',
'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php',
'OC\\Core\\ResponseDefinitions' => $baseDir . '/core/ResponseDefinitions.php',
'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 233b667add9..69e3c41284b 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -737,6 +737,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Notification\\IManager' => __DIR__ . '/../../..' . '/lib/public/Notification/IManager.php',
'OCP\\Notification\\INotification' => __DIR__ . '/../../..' . '/lib/public/Notification/INotification.php',
'OCP\\Notification\\INotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/INotifier.php',
+ 'OCP\\Notification\\IPreloadableNotifier' => __DIR__ . '/../../..' . '/lib/public/Notification/IPreloadableNotifier.php',
'OCP\\Notification\\IncompleteNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/IncompleteNotificationException.php',
'OCP\\Notification\\IncompleteParsedNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/IncompleteParsedNotificationException.php',
'OCP\\Notification\\InvalidValueException' => __DIR__ . '/../../..' . '/lib/public/Notification/InvalidValueException.php',
@@ -1551,6 +1552,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Migrations\\Version31000Date20240814184402' => __DIR__ . '/../../..' . '/core/Migrations/Version31000Date20240814184402.php',
'OC\\Core\\Migrations\\Version31000Date20250213102442' => __DIR__ . '/../../..' . '/core/Migrations/Version31000Date20250213102442.php',
'OC\\Core\\Migrations\\Version32000Date20250620081925' => __DIR__ . '/../../..' . '/core/Migrations/Version32000Date20250620081925.php',
+ 'OC\\Core\\Migrations\\Version32000Date20250731062008' => __DIR__ . '/../../..' . '/core/Migrations/Version32000Date20250731062008.php',
'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php',
'OC\\Core\\ResponseDefinitions' => __DIR__ . '/../../..' . '/core/ResponseDefinitions.php',
'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php',
diff --git a/lib/composer/composer/installed.php b/lib/composer/composer/installed.php
index 1cfe4bf1d74..cd89ef10785 100644
--- a/lib/composer/composer/installed.php
+++ b/lib/composer/composer/installed.php
@@ -3,7 +3,7 @@
'name' => '__root__',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => 'b7422ba97b7b42a9955a52031a32457ca521d740',
+ 'reference' => '3fce359f4c606737b21b1b4213efd5bc5536e867',
'type' => 'library',
'install_path' => __DIR__ . '/../../../',
'aliases' => array(),
@@ -13,7 +13,7 @@
'__root__' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => 'b7422ba97b7b42a9955a52031a32457ca521d740',
+ 'reference' => '3fce359f4c606737b21b1b4213efd5bc5536e867',
'type' => 'library',
'install_path' => __DIR__ . '/../../../',
'aliases' => array(),
diff --git a/lib/l10n/be.js b/lib/l10n/be.js
index eb38c0ed05e..4d73f079394 100644
--- a/lib/l10n/be.js
+++ b/lib/l10n/be.js
@@ -1,11 +1,39 @@
OC.L10N.register(
"lib",
{
+ "%1$s and %2$s" : "%1$s і %2$s",
+ "%1$s, %2$s and %3$s" : "%1$s, %2$s і %3$s",
+ "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s і %4$s",
+ "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s і %5$s",
"Authentication" : "Аўтэнтыфікацыя",
"Unknown filetype" : "Невядомы тып файла",
+ "Avatar image is not square" : "Відарыс аватара не квадратны",
"Files" : "Файлы",
+ "_%nh_::_%nh_" : ["%n г","%n г","%n г","%n г"],
+ "_%nm_::_%nm_" : ["%n хв","%n хв","%n хв","%n хв"],
+ "Local time: %s" : "Мясцовы час: %s",
+ "today" : "сёння",
+ "tomorrow" : "заўтра",
+ "yesterday" : "учора",
+ "_in %n day_::_in %n days_" : ["праз %n дзень","праз %n дні","праз %n дзён","праз %n дзён"],
+ "_%n day ago_::_%n days ago_" : ["%n дзень таму","%n дні таму","%n дзён таму","%n дзён таму"],
+ "next month" : "у наступным месяцы",
+ "last month" : "у мінулым месяцы",
+ "_in %n month_::_in %n months_" : ["праз %n месяц","праз %n месяцы","праз %n месяцаў","праз %n месяцаў"],
+ "_%n month ago_::_%n months ago_" : ["%n месяц таму","%n месяцы таму","%n месяцаў таму","%n месяцаў таму"],
+ "next year" : "у наступным годзе",
+ "last year" : "у мінулым годзе",
+ "_in %n year_::_in %n years_" : ["праз %n год","праз %n гады","праз %n гадоў","праз %n гадоў"],
"_%n year ago_::_%n years ago_" : ["%n год таму","%n гады таму","%n гадоў таму","%n гадоў таму"],
+ "_in %n hour_::_in %n hours_" : ["праз %n гадзіну","праз %n гадзіны","праз %n гадзін","праз %n гадзін"],
+ "_%n hour ago_::_%n hours ago_" : ["%n гадзіну таму","%n гадзіны таму","%n гадзін таму","%n гадзін таму"],
+ "_in %n minute_::_in %n minutes_" : ["праз %n хвіліну","праз %n хвіліны","праз %n хвілін","праз %n хвілін"],
+ "_%n minute ago_::_%n minutes ago_" : ["%n хвіліну таму","%n хвіліны таму","%n хвілін таму","%n хвілін таму"],
+ "in a few seconds" : "праз некалькі секунд",
"seconds ago" : "с таму",
+ "Empty file" : "Пусты файл",
+ "Could not convert file" : "Не атрымалася канвертаваць файл",
+ "%1$s (renamed)" : "%1$s (перайменаваны)",
"Templates" : "Шаблоны",
"__language_name__" : "Беларуская",
"Apps" : "Праграмы",
@@ -15,6 +43,7 @@ OC.L10N.register(
"Twitter" : "Twitter",
"Role" : "Роля",
"Pronouns" : "Займеннікі",
+ "Could not find category \"%s\"" : "Не ўдалося знайсці катэгорыю \"%s\"",
"Sunday" : "Нядзеля",
"Monday" : "Панядзелак",
"Tuesday" : "Аўторак",
@@ -41,7 +70,20 @@ OC.L10N.register(
"October" : "Кастрычнік",
"November" : "Лістапад",
"December" : "Снежань",
+ "Account disabled" : "Уліковы запіс адключаны",
+ "Application is not enabled" : "Праграма не ўключана",
+ "Authentication error" : "Памылка аўтэнтыфікацыі",
+ "Images" : "Відарысы",
+ "Question" : "Пытанне",
+ "Number of images" : "Колькасць відарысаў",
+ "Chat" : "Чат",
+ "Chat with the assistant" : "Чат з памочнікам",
"Text" : "Тэкст",
- "Translate" : "Перакласці"
+ "Translate" : "Перакласці",
+ "Result" : "Вынік",
+ "The translated text" : "Перакладзены тэкст",
+ "Organisation" : "Арганізацыя",
+ "Cannot download file" : "Немагчыма спампаваць файл",
+ "Login is too long" : "Лагін занадта доўгі"
},
"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);");
diff --git a/lib/l10n/be.json b/lib/l10n/be.json
index d944caed749..9a410c17f7d 100644
--- a/lib/l10n/be.json
+++ b/lib/l10n/be.json
@@ -1,9 +1,37 @@
{ "translations": {
+ "%1$s and %2$s" : "%1$s і %2$s",
+ "%1$s, %2$s and %3$s" : "%1$s, %2$s і %3$s",
+ "%1$s, %2$s, %3$s and %4$s" : "%1$s, %2$s, %3$s і %4$s",
+ "%1$s, %2$s, %3$s, %4$s and %5$s" : "%1$s, %2$s, %3$s, %4$s і %5$s",
"Authentication" : "Аўтэнтыфікацыя",
"Unknown filetype" : "Невядомы тып файла",
+ "Avatar image is not square" : "Відарыс аватара не квадратны",
"Files" : "Файлы",
+ "_%nh_::_%nh_" : ["%n г","%n г","%n г","%n г"],
+ "_%nm_::_%nm_" : ["%n хв","%n хв","%n хв","%n хв"],
+ "Local time: %s" : "Мясцовы час: %s",
+ "today" : "сёння",
+ "tomorrow" : "заўтра",
+ "yesterday" : "учора",
+ "_in %n day_::_in %n days_" : ["праз %n дзень","праз %n дні","праз %n дзён","праз %n дзён"],
+ "_%n day ago_::_%n days ago_" : ["%n дзень таму","%n дні таму","%n дзён таму","%n дзён таму"],
+ "next month" : "у наступным месяцы",
+ "last month" : "у мінулым месяцы",
+ "_in %n month_::_in %n months_" : ["праз %n месяц","праз %n месяцы","праз %n месяцаў","праз %n месяцаў"],
+ "_%n month ago_::_%n months ago_" : ["%n месяц таму","%n месяцы таму","%n месяцаў таму","%n месяцаў таму"],
+ "next year" : "у наступным годзе",
+ "last year" : "у мінулым годзе",
+ "_in %n year_::_in %n years_" : ["праз %n год","праз %n гады","праз %n гадоў","праз %n гадоў"],
"_%n year ago_::_%n years ago_" : ["%n год таму","%n гады таму","%n гадоў таму","%n гадоў таму"],
+ "_in %n hour_::_in %n hours_" : ["праз %n гадзіну","праз %n гадзіны","праз %n гадзін","праз %n гадзін"],
+ "_%n hour ago_::_%n hours ago_" : ["%n гадзіну таму","%n гадзіны таму","%n гадзін таму","%n гадзін таму"],
+ "_in %n minute_::_in %n minutes_" : ["праз %n хвіліну","праз %n хвіліны","праз %n хвілін","праз %n хвілін"],
+ "_%n minute ago_::_%n minutes ago_" : ["%n хвіліну таму","%n хвіліны таму","%n хвілін таму","%n хвілін таму"],
+ "in a few seconds" : "праз некалькі секунд",
"seconds ago" : "с таму",
+ "Empty file" : "Пусты файл",
+ "Could not convert file" : "Не атрымалася канвертаваць файл",
+ "%1$s (renamed)" : "%1$s (перайменаваны)",
"Templates" : "Шаблоны",
"__language_name__" : "Беларуская",
"Apps" : "Праграмы",
@@ -13,6 +41,7 @@
"Twitter" : "Twitter",
"Role" : "Роля",
"Pronouns" : "Займеннікі",
+ "Could not find category \"%s\"" : "Не ўдалося знайсці катэгорыю \"%s\"",
"Sunday" : "Нядзеля",
"Monday" : "Панядзелак",
"Tuesday" : "Аўторак",
@@ -39,7 +68,20 @@
"October" : "Кастрычнік",
"November" : "Лістапад",
"December" : "Снежань",
+ "Account disabled" : "Уліковы запіс адключаны",
+ "Application is not enabled" : "Праграма не ўключана",
+ "Authentication error" : "Памылка аўтэнтыфікацыі",
+ "Images" : "Відарысы",
+ "Question" : "Пытанне",
+ "Number of images" : "Колькасць відарысаў",
+ "Chat" : "Чат",
+ "Chat with the assistant" : "Чат з памочнікам",
"Text" : "Тэкст",
- "Translate" : "Перакласці"
+ "Translate" : "Перакласці",
+ "Result" : "Вынік",
+ "The translated text" : "Перакладзены тэкст",
+ "Organisation" : "Арганізацыя",
+ "Cannot download file" : "Немагчыма спампаваць файл",
+ "Login is too long" : "Лагін занадта доўгі"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
} \ No newline at end of file
diff --git a/lib/l10n/fr.js b/lib/l10n/fr.js
index edfe25a6362..3356ec5f0f2 100644
--- a/lib/l10n/fr.js
+++ b/lib/l10n/fr.js
@@ -371,10 +371,10 @@ OC.L10N.register(
"Output images" : "Images de sortie",
"The generated images" : "Les images générées",
"Generate speech" : "Générer une synthèse vocale",
- "Generate speech from a transcript" : "Générer la vocalisation à partir d'une transcription",
- "Write transcript that you want the assistant to generate speech from" : "Écrire la transcription à partir de laquelle vous voulez générer la vocalisation",
- "Output speech" : "Sortie de la vocalisation",
- "The generated speech" : "La vocalisation générée",
+ "Generate speech from a transcript" : "Générer synthèse vocale à partir d'une transcription",
+ "Write transcript that you want the assistant to generate speech from" : "Écrire la transcription à partir de laquelle vous voulez générer la synthèse vocale",
+ "Output speech" : "Synthèse vocale",
+ "The generated speech" : "La synthèse vocale générée",
"Free text to text prompt" : "Texte libre à texte libre",
"Runs an arbitrary prompt through a language model that returns a reply" : "Exécute une commande arbitraire à l'aide d'un modèle linguistique qui génère une réponse",
"Describe a task that you want the assistant to do or ask a question" : "Décrivez une tâche que vous voulez que l'assistant effectue ou posez une question",
diff --git a/lib/l10n/fr.json b/lib/l10n/fr.json
index 6f1edd70da2..4d7ac492a36 100644
--- a/lib/l10n/fr.json
+++ b/lib/l10n/fr.json
@@ -369,10 +369,10 @@
"Output images" : "Images de sortie",
"The generated images" : "Les images générées",
"Generate speech" : "Générer une synthèse vocale",
- "Generate speech from a transcript" : "Générer la vocalisation à partir d'une transcription",
- "Write transcript that you want the assistant to generate speech from" : "Écrire la transcription à partir de laquelle vous voulez générer la vocalisation",
- "Output speech" : "Sortie de la vocalisation",
- "The generated speech" : "La vocalisation générée",
+ "Generate speech from a transcript" : "Générer synthèse vocale à partir d'une transcription",
+ "Write transcript that you want the assistant to generate speech from" : "Écrire la transcription à partir de laquelle vous voulez générer la synthèse vocale",
+ "Output speech" : "Synthèse vocale",
+ "The generated speech" : "La synthèse vocale générée",
"Free text to text prompt" : "Texte libre à texte libre",
"Runs an arbitrary prompt through a language model that returns a reply" : "Exécute une commande arbitraire à l'aide d'un modèle linguistique qui génère une réponse",
"Describe a task that you want the assistant to do or ask a question" : "Décrivez une tâche que vous voulez que l'assistant effectue ou posez une question",
diff --git a/lib/l10n/mk.js b/lib/l10n/mk.js
index 8b49f0914e5..102926f9e1d 100644
--- a/lib/l10n/mk.js
+++ b/lib/l10n/mk.js
@@ -77,6 +77,9 @@ OC.L10N.register(
"Empty file" : "Празна датотека",
"Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Модул со ИД: %s не постои. Овозможете го во параметрите на апликациите или контактирајте администратор.",
"Dot files are not allowed" : "Датотеки само со точки не се дозволени",
+ "%1$s (renamed)" : "%1$s (преименувано)",
+ "renamed file" : "преименувана датотека",
+ "Filenames must not end with \"%1$s\"." : "Името неможе да завршува со \"%1$s\".",
"File already exists" : "Датотека веќе постои",
"Invalid path" : "Невалидна патека",
"Failed to create file from template" : "Неуспешно креирање на датотека од шаблон",
diff --git a/lib/l10n/mk.json b/lib/l10n/mk.json
index db83bccd774..d9de1976caf 100644
--- a/lib/l10n/mk.json
+++ b/lib/l10n/mk.json
@@ -75,6 +75,9 @@
"Empty file" : "Празна датотека",
"Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "Модул со ИД: %s не постои. Овозможете го во параметрите на апликациите или контактирајте администратор.",
"Dot files are not allowed" : "Датотеки само со точки не се дозволени",
+ "%1$s (renamed)" : "%1$s (преименувано)",
+ "renamed file" : "преименувана датотека",
+ "Filenames must not end with \"%1$s\"." : "Името неможе да завршува со \"%1$s\".",
"File already exists" : "Датотека веќе постои",
"Invalid path" : "Невалидна патека",
"Failed to create file from template" : "Неуспешно креирање на датотека од шаблон",
diff --git a/lib/l10n/sw.js b/lib/l10n/sw.js
index 9e10b43b403..0eca41da17e 100644
--- a/lib/l10n/sw.js
+++ b/lib/l10n/sw.js
@@ -45,9 +45,27 @@ OC.L10N.register(
"Storage is temporarily not available" : "Uhifadhi haupo kwa muda",
"Images" : "Picha",
"Question" : "Swali",
+ "Voice chat with the assistant" : "Voice chat with the assistant",
+ "System prompt" : "System prompt",
+ "Define rules and assumptions that the assistant should follow during the conversation." : "Define rules and assumptions that the assistant should follow during the conversation.",
+ "Chat voice message" : "Chat voice message",
+ "Chat history" : "Chat history",
+ "Input transcript" : "Input transcript",
+ "Transcription of the audio input" : "Transcription of the audio input",
+ "Response voice message" : "Response voice message",
+ "The generated voice response as part of the conversation" : "The generated voice response as part of the conversation",
+ "Output transcript" : "Output transcript",
+ "Transcription of the audio output" : "Transcription of the audio output",
+ "Transcribe audio" : "Transcribe audio",
+ "Audio input" : "Audio input",
"Confirmation" : "Uthibitisho",
+ "Prompt" : "Prompt",
+ "Describe a task that you want the assistant to do or ask a question" : "Describe a task that you want the assistant to do or ask a question",
+ "The history of chat messages before the current message, starting with a message by the user" : "The history of chat messages before the current message, starting with a message by the user",
"Text" : "Maandishi",
+ "Summarize" : "Summarize",
"Summary" : "Muhtasari",
- "Translate" : "Tafsiri"
+ "Translate" : "Tafsiri",
+ "Result" : "Result"
},
"nplurals=2; plural=(n != 1);");
diff --git a/lib/l10n/sw.json b/lib/l10n/sw.json
index a645af4e6a8..5759a8f07f4 100644
--- a/lib/l10n/sw.json
+++ b/lib/l10n/sw.json
@@ -43,9 +43,27 @@
"Storage is temporarily not available" : "Uhifadhi haupo kwa muda",
"Images" : "Picha",
"Question" : "Swali",
+ "Voice chat with the assistant" : "Voice chat with the assistant",
+ "System prompt" : "System prompt",
+ "Define rules and assumptions that the assistant should follow during the conversation." : "Define rules and assumptions that the assistant should follow during the conversation.",
+ "Chat voice message" : "Chat voice message",
+ "Chat history" : "Chat history",
+ "Input transcript" : "Input transcript",
+ "Transcription of the audio input" : "Transcription of the audio input",
+ "Response voice message" : "Response voice message",
+ "The generated voice response as part of the conversation" : "The generated voice response as part of the conversation",
+ "Output transcript" : "Output transcript",
+ "Transcription of the audio output" : "Transcription of the audio output",
+ "Transcribe audio" : "Transcribe audio",
+ "Audio input" : "Audio input",
"Confirmation" : "Uthibitisho",
+ "Prompt" : "Prompt",
+ "Describe a task that you want the assistant to do or ask a question" : "Describe a task that you want the assistant to do or ask a question",
+ "The history of chat messages before the current message, starting with a message by the user" : "The history of chat messages before the current message, starting with a message by the user",
"Text" : "Maandishi",
+ "Summarize" : "Summarize",
"Summary" : "Muhtasari",
- "Translate" : "Tafsiri"
+ "Translate" : "Tafsiri",
+ "Result" : "Result"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
} \ No newline at end of file
diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php
index e719ea19f90..77135986d5f 100644
--- a/lib/private/AppFramework/App.php
+++ b/lib/private/AppFramework/App.php
@@ -50,19 +50,8 @@ class App {
if (isset($appInfo['namespace'])) {
self::$nameSpaceCache[$appId] = trim($appInfo['namespace']);
} else {
- if ($appId !== 'spreed') {
- // if the tag is not found, fall back to uppercasing the first letter
- self::$nameSpaceCache[$appId] = ucfirst($appId);
- } else {
- // For the Talk app (appid spreed) the above fallback doesn't work.
- // This leads to a problem when trying to install it freshly,
- // because the apps namespace is already registered before the
- // app is downloaded from the appstore, because of the hackish
- // global route index.php/call/{token} which is registered via
- // the core/routes.php so it does not have the app namespace.
- // @ref https://github.com/nextcloud/server/pull/19433
- self::$nameSpaceCache[$appId] = 'Talk';
- }
+ // if the tag is not found, fall back to uppercasing the first letter
+ self::$nameSpaceCache[$appId] = ucfirst($appId);
}
return $topNamespace . self::$nameSpaceCache[$appId];
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php
index e662cb8679a..7cc7467675c 100644
--- a/lib/private/AppFramework/Http/Request.php
+++ b/lib/private/AppFramework/Http/Request.php
@@ -14,6 +14,7 @@ use OC\Security\TrustedDomainHelper;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IRequestId;
+use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\IpUtils;
/**
@@ -627,36 +628,46 @@ class Request implements \ArrayAccess, \Countable, IRequest {
/**
* Returns the server protocol. It respects one or more reverse proxies servers
- * and load balancers
+ * and load balancers. Precedence:
+ * 1. `overwriteprotocol` config value
+ * 2. `X-Forwarded-Proto` header value
+ * 3. $_SERVER['HTTPS'] value
+ * If an invalid protocol is provided, defaults to http, continues, but logs as an error.
+ *
* @return string Server protocol (http or https)
*/
public function getServerProtocol(): string {
- if ($this->config->getSystemValueString('overwriteprotocol') !== ''
- && $this->isOverwriteCondition()) {
- return $this->config->getSystemValueString('overwriteprotocol');
- }
+ $proto = 'http';
- if ($this->fromTrustedProxy() && isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
+ if ($this->config->getSystemValueString('overwriteprotocol') !== ''
+ && $this->isOverwriteCondition()
+ ) {
+ $proto = strtolower($this->config->getSystemValueString('overwriteprotocol'));
+ } elseif ($this->fromTrustedProxy()
+ && isset($this->server['HTTP_X_FORWARDED_PROTO'])
+ ) {
if (str_contains($this->server['HTTP_X_FORWARDED_PROTO'], ',')) {
$parts = explode(',', $this->server['HTTP_X_FORWARDED_PROTO']);
$proto = strtolower(trim($parts[0]));
} else {
$proto = strtolower($this->server['HTTP_X_FORWARDED_PROTO']);
}
-
- // Verify that the protocol is always HTTP or HTTPS
- // default to http if an invalid value is provided
- return $proto === 'https' ? 'https' : 'http';
+ } elseif (!empty($this->server['HTTPS'])
+ && $this->server['HTTPS'] !== 'off'
+ ) {
+ $proto = 'https';
}
- if (isset($this->server['HTTPS'])
- && $this->server['HTTPS'] !== null
- && $this->server['HTTPS'] !== 'off'
- && $this->server['HTTPS'] !== '') {
- return 'https';
+ if ($proto !== 'https' && $proto !== 'http') {
+ // log unrecognized value so admin has a chance to fix it
+ \OCP\Server::get(LoggerInterface::class)->critical(
+ 'Server protocol is malformed [falling back to http] (check overwriteprotocol and/or X-Forwarded-Proto to remedy): ' . $proto,
+ ['app' => 'core']
+ );
}
- return 'http';
+ // default to http if provided an invalid value
+ return $proto === 'https' ? 'https' : 'http';
}
/**
@@ -743,11 +754,11 @@ class Request implements \ArrayAccess, \Countable, IRequest {
}
/**
- * Get PathInfo from request
+ * Get PathInfo from request (rawurldecoded)
* @throws \Exception
* @return string|false Path info or false when not found
*/
- public function getPathInfo() {
+ public function getPathInfo(): string|false {
$pathInfo = $this->getRawPathInfo();
return \Sabre\HTTP\decodePath($pathInfo);
}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
index 8fae6275916..47a8eaa6fd0 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
@@ -81,12 +81,12 @@ class OCIFunctionBuilder extends FunctionBuilder {
public function octetLength($field, $alias = ''): IQueryFunction {
$alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
$quotedName = $this->helper->quoteColumnName($field);
- return new QueryFunction('LENGTHB(' . $quotedName . ')' . $alias);
+ return new QueryFunction('COALESCE(LENGTHB(' . $quotedName . '), 0)' . $alias);
}
public function charLength($field, $alias = ''): IQueryFunction {
$alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
$quotedName = $this->helper->quoteColumnName($field);
- return new QueryFunction('LENGTH(' . $quotedName . ')' . $alias);
+ return new QueryFunction('COALESCE(LENGTH(' . $quotedName . '), 0)' . $alias);
}
}
diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php
index 8b224c28dfe..1d1ccd29bf7 100644
--- a/lib/private/DB/QueryBuilder/QueryBuilder.php
+++ b/lib/private/DB/QueryBuilder/QueryBuilder.php
@@ -161,7 +161,7 @@ class QueryBuilder implements IQueryBuilder {
try {
$params = [];
foreach ($this->getParameters() as $placeholder => $value) {
- if ($value instanceof \DateTime) {
+ if ($value instanceof \DateTimeInterface) {
$params[] = $placeholder . ' => DateTime:\'' . $value->format('c') . '\'';
} elseif (is_array($value)) {
$params[] = $placeholder . ' => (\'' . implode('\', \'', $value) . '\')';
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
index 10ee6aec167..9ab11f8a3df 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -475,6 +475,9 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
'original-storage' => $this->getId(),
'original-path' => $path,
];
+ if ($size) {
+ $metadata['size'] = $size;
+ }
$stat['mimetype'] = $mimetype;
$stat['etag'] = $this->getETag($path);
@@ -496,32 +499,27 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$urn = $this->getURN($fileId);
try {
//upload to object storage
- if ($size === null) {
- $countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, &$size) {
+
+ $totalWritten = 0;
+ $countStream = CountWrapper::wrap($stream, function ($writtenSize) use ($fileId, $size, $exists, &$totalWritten) {
+ if (is_null($size) && !$exists) {
$this->getCache()->update($fileId, [
'size' => $writtenSize,
]);
- $size = $writtenSize;
- });
- if ($this->objectStore instanceof IObjectStoreMetaData) {
- $this->objectStore->writeObjectWithMetaData($urn, $countStream, $metadata);
- } else {
- $this->objectStore->writeObject($urn, $countStream, $metadata['mimetype']);
}
- if (is_resource($countStream)) {
- fclose($countStream);
- }
- $stat['size'] = $size;
+ $totalWritten = $writtenSize;
+ });
+
+ if ($this->objectStore instanceof IObjectStoreMetaData) {
+ $this->objectStore->writeObjectWithMetaData($urn, $countStream, $metadata);
} else {
- if ($this->objectStore instanceof IObjectStoreMetaData) {
- $this->objectStore->writeObjectWithMetaData($urn, $stream, $metadata);
- } else {
- $this->objectStore->writeObject($urn, $stream, $metadata['mimetype']);
- }
- if (is_resource($stream)) {
- fclose($stream);
- }
+ $this->objectStore->writeObject($urn, $countStream, $metadata['mimetype']);
}
+ if (is_resource($countStream)) {
+ fclose($countStream);
+ }
+
+ $stat['size'] = $totalWritten;
} catch (\Exception $ex) {
if (!$exists) {
/*
@@ -545,7 +543,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
]
);
}
- throw $ex; // make this bubble up
+ throw new GenericFileException('Error while writing stream to object store', 0, $ex);
}
if ($exists) {
@@ -561,7 +559,7 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
}
}
- return $size;
+ return $totalWritten;
}
public function getObjectStore(): IObjectStore {
diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php
index 5e6dcf88a42..89405de2e8e 100644
--- a/lib/private/Files/ObjectStore/S3ObjectTrait.php
+++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php
@@ -6,6 +6,8 @@
*/
namespace OC\Files\ObjectStore;
+use Aws\Command;
+use Aws\Exception\MultipartUploadException;
use Aws\S3\Exception\S3MultipartUploadException;
use Aws\S3\MultipartCopy;
use Aws\S3\MultipartUploader;
@@ -96,7 +98,9 @@ trait S3ObjectTrait {
protected function writeSingle(string $urn, StreamInterface $stream, array $metaData): void {
$mimetype = $metaData['mimetype'] ?? null;
unset($metaData['mimetype']);
- $this->getConnection()->putObject([
+ unset($metaData['size']);
+
+ $args = [
'Bucket' => $this->bucket,
'Key' => $urn,
'Body' => $stream,
@@ -104,7 +108,13 @@ trait S3ObjectTrait {
'ContentType' => $mimetype,
'Metadata' => $this->buildS3Metadata($metaData),
'StorageClass' => $this->storageClass,
- ] + $this->getSSECParameters());
+ ] + $this->getSSECParameters();
+
+ if ($size = $stream->getSize()) {
+ $args['ContentLength'] = $size;
+ }
+
+ $this->getConnection()->putObject($args);
}
@@ -119,12 +129,15 @@ trait S3ObjectTrait {
protected function writeMultiPart(string $urn, StreamInterface $stream, array $metaData): void {
$mimetype = $metaData['mimetype'] ?? null;
unset($metaData['mimetype']);
+ unset($metaData['size']);
$attempts = 0;
$uploaded = false;
$concurrency = $this->concurrency;
$exception = null;
$state = null;
+ $size = $stream->getSize();
+ $totalWritten = 0;
// retry multipart upload once with concurrency at half on failure
while (!$uploaded && $attempts <= 1) {
@@ -139,6 +152,15 @@ trait S3ObjectTrait {
'Metadata' => $this->buildS3Metadata($metaData),
'StorageClass' => $this->storageClass,
] + $this->getSSECParameters(),
+ 'before_upload' => function (Command $command) use (&$totalWritten) {
+ $totalWritten += $command['ContentLength'];
+ },
+ 'before_complete' => function ($_command) use (&$totalWritten, $size, &$uploader, &$attempts) {
+ if ($size !== null && $totalWritten != $size) {
+ $e = new \Exception('Incomplete multi part upload, expected ' . $size . ' bytes, wrote ' . $totalWritten);
+ throw new MultipartUploadException($uploader->getState(), $e);
+ }
+ },
]);
try {
@@ -155,6 +177,9 @@ trait S3ObjectTrait {
if ($stream->isSeekable()) {
$stream->rewind();
}
+ } catch (MultipartUploadException $e) {
+ $exception = $e;
+ break;
}
}
@@ -180,7 +205,9 @@ trait S3ObjectTrait {
public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void {
$canSeek = fseek($stream, 0, SEEK_CUR) === 0;
- $psrStream = Utils::streamFor($stream);
+ $psrStream = Utils::streamFor($stream, [
+ 'size' => $metaData['size'] ?? null,
+ ]);
$size = $psrStream->getSize();
diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php
index 37ecd5779e6..b92c608a81d 100644
--- a/lib/private/Files/SetupManager.php
+++ b/lib/private/Files/SetupManager.php
@@ -292,7 +292,7 @@ class SetupManager {
$mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
return !in_array($mount->getMountProvider(), $previouslySetupProviders);
});
- $this->userMountCache->registerMounts($user, $mounts, $newProviders);
+ $this->registerMounts($user, $mounts, $newProviders);
$cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
if ($cacheDuration > 0) {
@@ -457,7 +457,7 @@ class SetupManager {
}
if (count($mounts)) {
- $this->userMountCache->registerMounts($user, $mounts, $currentProviders);
+ $this->registerMounts($user, $mounts, $currentProviders);
$this->setupForUserWith($user, function () use ($mounts) {
array_walk($mounts, [$this->mountManager, 'addMount']);
});
@@ -528,7 +528,7 @@ class SetupManager {
$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, $providers);
}
- $this->userMountCache->registerMounts($user, $mounts, $providers);
+ $this->registerMounts($user, $mounts, $providers);
$this->setupForUserWith($user, function () use ($mounts) {
array_walk($mounts, [$this->mountManager, 'addMount']);
});
@@ -600,4 +600,10 @@ class SetupManager {
});
}
}
+
+ private function registerMounts(IUser $user, array $mounts, ?array $mountProviderClasses = null): void {
+ if ($this->lockdownManager->canAccessFilesystem()) {
+ $this->userMountCache->registerMounts($user, $mounts, $mountProviderClasses);
+ }
+ }
}
diff --git a/lib/private/Files/Type/Detection.php b/lib/private/Files/Type/Detection.php
index d5810a90868..6af6ce1a0b1 100644
--- a/lib/private/Files/Type/Detection.php
+++ b/lib/private/Files/Type/Detection.php
@@ -55,7 +55,8 @@ class Detection implements IMimeTypeDetector {
* @param string $mimeType
* @param string|null $secureMimeType
*/
- public function registerType(string $extension,
+ public function registerType(
+ string $extension,
string $mimeType,
?string $secureMimeType = null): void {
// Make sure the extension is a string
@@ -217,14 +218,10 @@ class Detection implements IMimeTypeDetector {
return 'httpd/unix-directory';
}
- if (function_exists('finfo_open')
- && function_exists('finfo_file')
- && $finfo = finfo_open(FILEINFO_MIME)) {
- $info = @finfo_file($finfo, $path);
- finfo_close($finfo);
- if ($info) {
- $info = strtolower($info);
- $mimeType = str_contains($info, ';') ? substr($info, 0, strpos($info, ';')) : $info;
+ if (class_exists(finfo::class)) {
+ $finfo = new finfo(FILEINFO_MIME_TYPE);
+ $mimeType = @$finfo->file($path);
+ if ($mimeType) {
$mimeType = $this->getSecureMimeType($mimeType);
if ($mimeType !== 'application/octet-stream') {
return $mimeType;
@@ -240,7 +237,7 @@ class Detection implements IMimeTypeDetector {
if (function_exists('mime_content_type')) {
// use mime magic extension if available
$mimeType = mime_content_type($path);
- if ($mimeType !== false) {
+ if ($mimeType) {
$mimeType = $this->getSecureMimeType($mimeType);
if ($mimeType !== 'application/octet-stream') {
return $mimeType;
@@ -258,7 +255,7 @@ class Detection implements IMimeTypeDetector {
if ($fp !== false) {
$mimeType = fgets($fp);
pclose($fp);
- if ($mimeType !== false) {
+ if ($mimeType) {
//trim the newline
$mimeType = trim($mimeType);
$mimeType = $this->getSecureMimeType($mimeType);
@@ -293,19 +290,21 @@ class Detection implements IMimeTypeDetector {
* @return string
*/
public function detectString($data): string {
- if (function_exists('finfo_open') && function_exists('finfo_file')) {
- $finfo = finfo_open(FILEINFO_MIME);
- $info = finfo_buffer($finfo, $data);
- return str_contains($info, ';') ? substr($info, 0, strpos($info, ';')) : $info;
+ if (class_exists(finfo::class)) {
+ $finfo = new finfo(FILEINFO_MIME_TYPE);
+ $mimeType = $finfo->buffer($data);
+ if ($mimeType) {
+ return $mimeType;
+ }
}
$tmpFile = \OCP\Server::get(ITempManager::class)->getTemporaryFile();
$fh = fopen($tmpFile, 'wb');
fwrite($fh, $data, 8024);
fclose($fh);
- $mime = $this->detect($tmpFile);
+ $mimeType = $this->detect($tmpFile);
unset($tmpFile);
- return $mime;
+ return $mimeType;
}
/**
diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php
index e9ed351b27b..576cb66b3cf 100644
--- a/lib/private/Files/Utils/Scanner.php
+++ b/lib/private/Files/Utils/Scanner.php
@@ -205,7 +205,10 @@ class Scanner extends PublicEmitter {
foreach (['', 'files'] as $path) {
if (!$storage->isCreatable($path)) {
$fullPath = $storage->getSourcePath($path);
- if (!$storage->is_dir($path) && $storage->getCache()->inCache($path)) {
+ if (isset($mounts[$mount->getMountPoint() . $path . '/'])) {
+ // /<user>/files is overwritten by a mountpoint, so this check is irrelevant
+ break;
+ } elseif (!$storage->is_dir($path) && $storage->getCache()->inCache($path)) {
throw new NotFoundException("User folder $fullPath exists in cache but not on disk");
} elseif ($storage->is_dir($path)) {
$ownerUid = fileowner($fullPath);
@@ -213,9 +216,6 @@ class Scanner extends PublicEmitter {
$owner = $owner['name'] ?? $ownerUid;
$permissions = decoct(fileperms($fullPath));
throw new ForbiddenException("User folder $fullPath is not writable, folders is owned by $owner and has mode $permissions");
- } elseif (isset($mounts[$mount->getMountPoint() . $path . '/'])) {
- // /<user>/files is overwritten by a mountpoint, so this check is irrelevant
- break;
} else {
// if the root exists in neither the cache nor the storage the user isn't setup yet
break 2;
diff --git a/lib/private/Notification/Manager.php b/lib/private/Notification/Manager.php
index 8c457db8beb..0cbda651a8b 100644
--- a/lib/private/Notification/Manager.php
+++ b/lib/private/Notification/Manager.php
@@ -21,6 +21,7 @@ use OCP\Notification\IncompleteNotificationException;
use OCP\Notification\IncompleteParsedNotificationException;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;
+use OCP\Notification\IPreloadableNotifier;
use OCP\Notification\UnknownNotificationException;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;
@@ -390,6 +391,17 @@ class Manager implements IManager {
return $notification;
}
+ public function preloadDataForParsing(array $notifications, string $languageCode): void {
+ $notifiers = $this->getNotifiers();
+ foreach ($notifiers as $notifier) {
+ if (!($notifier instanceof IPreloadableNotifier)) {
+ continue;
+ }
+
+ $notifier->preloadDataForParsing($notifications, $languageCode);
+ }
+ }
+
/**
* @param INotification $notification
*/
diff --git a/lib/private/Security/IdentityProof/Manager.php b/lib/private/Security/IdentityProof/Manager.php
index 935c18bb81d..c16b8314beb 100644
--- a/lib/private/Security/IdentityProof/Manager.php
+++ b/lib/private/Security/IdentityProof/Manager.php
@@ -11,6 +11,8 @@ namespace OC\Security\IdentityProof;
use OC\Files\AppData\Factory;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
+use OCP\ICache;
+use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IUser;
use OCP\Security\ICrypto;
@@ -19,13 +21,17 @@ use Psr\Log\LoggerInterface;
class Manager {
private IAppData $appData;
+ protected ICache $cache;
+
public function __construct(
Factory $appDataFactory,
private ICrypto $crypto,
private IConfig $config,
private LoggerInterface $logger,
+ private ICacheFactory $cacheFactory,
) {
$this->appData = $appDataFactory->get('identityproof');
+ $this->cache = $this->cacheFactory->createDistributed('identityproof::');
}
/**
@@ -96,12 +102,24 @@ class Manager {
*/
protected function retrieveKey(string $id): Key {
try {
+ $cachedPublicKey = $this->cache->get($id . '-public');
+ $cachedPrivateKey = $this->cache->get($id . '-private');
+
+ if ($cachedPublicKey !== null && $cachedPrivateKey !== null) {
+ $decryptedPrivateKey = $this->crypto->decrypt($cachedPrivateKey);
+
+ return new Key($cachedPublicKey, $decryptedPrivateKey);
+ }
+
$folder = $this->appData->getFolder($id);
- $privateKey = $this->crypto->decrypt(
- $folder->getFile('private')->getContent()
- );
+ $privateKey = $folder->getFile('private')->getContent();
$publicKey = $folder->getFile('public')->getContent();
- return new Key($publicKey, $privateKey);
+
+ $this->cache->set($id . '-public', $publicKey);
+ $this->cache->set($id . '-private', $privateKey);
+
+ $decryptedPrivateKey = $this->crypto->decrypt($privateKey);
+ return new Key($publicKey, $decryptedPrivateKey);
} catch (\Exception $e) {
return $this->generateKey($id);
}
diff --git a/lib/private/Setup/AbstractDatabase.php b/lib/private/Setup/AbstractDatabase.php
index ec4ce040090..8f6294faa66 100644
--- a/lib/private/Setup/AbstractDatabase.php
+++ b/lib/private/Setup/AbstractDatabase.php
@@ -77,7 +77,6 @@ abstract class AbstractDatabase {
$this->config->setValues([
'dbname' => $dbName,
'dbhost' => $dbHost,
- 'dbport' => $dbPort,
'dbtableprefix' => $dbTablePrefix,
]);
diff --git a/lib/private/Tags.php b/lib/private/Tags.php
index 0a37f4c9f4e..fe4a4137e10 100644
--- a/lib/private/Tags.php
+++ b/lib/private/Tags.php
@@ -273,7 +273,6 @@ class Tags implements ITags {
return false;
}
if ($this->userHasTag($name, $this->user)) {
- // TODO use unique db properties instead of an additional check
$this->logger->debug(__METHOD__ . ' Tag with name already exists', ['app' => 'core']);
return false;
}
diff --git a/lib/private/TaskProcessing/Manager.php b/lib/private/TaskProcessing/Manager.php
index a9c9f1e1ca2..11fb2bed559 100644
--- a/lib/private/TaskProcessing/Manager.php
+++ b/lib/private/TaskProcessing/Manager.php
@@ -31,9 +31,9 @@ use OCP\Files\Node;
use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Http\Client\IClientService;
+use OCP\IAppConfig;
use OCP\ICache;
use OCP\ICacheFactory;
-use OCP\IConfig;
use OCP\IL10N;
use OCP\IServerContainer;
use OCP\IUserManager;
@@ -73,6 +73,11 @@ class Manager implements IManager {
public const LEGACY_PREFIX_TEXTTOIMAGE = 'legacy:TextToImage:';
public const LEGACY_PREFIX_SPEECHTOTEXT = 'legacy:SpeechToText:';
+ public const LAZY_CONFIG_KEYS = [
+ 'ai.taskprocessing_type_preferences',
+ 'ai.taskprocessing_provider_preferences',
+ ];
+
/** @var list<IProvider>|null */
private ?array $providers = null;
@@ -92,7 +97,7 @@ class Manager implements IManager {
private ?GetTaskProcessingProvidersEvent $eventResult = null;
public function __construct(
- private IConfig $config,
+ private IAppConfig $appConfig,
private Coordinator $coordinator,
private IServerContainer $serverContainer,
private LoggerInterface $logger,
@@ -630,7 +635,7 @@ class Manager implements IManager {
*/
private function _getTaskTypeSettings(): array {
try {
- $json = $this->config->getAppValue('core', 'ai.taskprocessing_type_preferences', '');
+ $json = $this->appConfig->getValueString('core', 'ai.taskprocessing_type_preferences', '', lazy: true);
if ($json === '') {
return [];
}
@@ -788,7 +793,11 @@ class Manager implements IManager {
if ($this->preferences === null) {
$this->preferences = $this->distributedCache->get('ai.taskprocessing_provider_preferences');
if ($this->preferences === null) {
- $this->preferences = json_decode($this->config->getAppValue('core', 'ai.taskprocessing_provider_preferences', 'null'), associative: true, flags: JSON_THROW_ON_ERROR);
+ $this->preferences = json_decode(
+ $this->appConfig->getValueString('core', 'ai.taskprocessing_provider_preferences', 'null', lazy: true),
+ associative: true,
+ flags: JSON_THROW_ON_ERROR,
+ );
$this->distributedCache->set('ai.taskprocessing_provider_preferences', $this->preferences, 60 * 3);
}
}
@@ -889,7 +898,7 @@ class Manager implements IManager {
$user = $this->userManager->get($userId);
}
- $guestsAllowed = $this->config->getAppValue('core', 'ai.taskprocessing_guests', 'false');
+ $guestsAllowed = $this->appConfig->getValueString('core', 'ai.taskprocessing_guests', 'false');
if ($guestsAllowed == 'true' || !class_exists(\OCA\Guests\UserBackend::class) || !($user->getBackend() instanceof \OCA\Guests\UserBackend)) {
return true;
}
diff --git a/lib/public/Notification/IManager.php b/lib/public/Notification/IManager.php
index 23664af17cd..207a89344b0 100644
--- a/lib/public/Notification/IManager.php
+++ b/lib/public/Notification/IManager.php
@@ -11,7 +11,7 @@ namespace OCP\Notification;
use OCP\AppFramework\Attribute\Consumable;
#[Consumable(since: '9.0.0')]
-interface IManager extends IApp, INotifier {
+interface IManager extends IApp, IPreloadableNotifier {
/**
* @param string $appClass The service must implement IApp, otherwise a
* \InvalidArgumentException is thrown later
diff --git a/lib/public/Notification/INotifier.php b/lib/public/Notification/INotifier.php
index bdc7207216f..b6851e3dfb3 100644
--- a/lib/public/Notification/INotifier.php
+++ b/lib/public/Notification/INotifier.php
@@ -10,6 +10,11 @@ namespace OCP\Notification;
use OCP\AppFramework\Attribute\Implementable;
+/**
+ * Please consider implementing {@see IPreloadableNotifier} to improve performance. It allows to
+ * preload and cache data for many notifications at once instead of loading the data for each
+ * prepared notification separately.
+ */
#[Implementable(since: '9.0.0')]
interface INotifier {
/**
diff --git a/lib/public/Notification/IPreloadableNotifier.php b/lib/public/Notification/IPreloadableNotifier.php
new file mode 100644
index 00000000000..2bdcd84d254
--- /dev/null
+++ b/lib/public/Notification/IPreloadableNotifier.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Notification;
+
+use OCP\AppFramework\Attribute\Implementable;
+
+/**
+ * Allow notifier implementations to preload and cache data for many notifications at once to
+ * improve performance by, for example, bundling SQL queries.
+ */
+#[Implementable(since: '32.0.0')]
+interface IPreloadableNotifier extends INotifier {
+ /**
+ * This method provides a way for notifier implementations to preload and cache data for many
+ * notifications. The data is meant to be consumed later in the {@see INotifier::prepare()}
+ * method to improve performance.
+ *
+ * @since 32.0.0
+ *
+ * @param INotification[] $notifications The notifications which are about to be prepared in the next step.
+ * @param string $languageCode The code of the language that should be used to prepare the notification.
+ */
+ public function preloadDataForParsing(array $notifications, string $languageCode): void;
+}
diff --git a/lib/public/TaskProcessing/IManager.php b/lib/public/TaskProcessing/IManager.php
index f161030f5f4..723eca8f615 100644
--- a/lib/public/TaskProcessing/IManager.php
+++ b/lib/public/TaskProcessing/IManager.php
@@ -26,6 +26,7 @@ use OCP\TaskProcessing\Exception\ValidationException;
* @since 30.0.0
*/
interface IManager {
+
/**
* @since 30.0.0
*/