aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/composer/composer/autoload_classmap.php5
-rw-r--r--lib/composer/composer/autoload_static.php5
-rw-r--r--lib/l10n/de_DE.js2
-rw-r--r--lib/l10n/de_DE.json2
-rw-r--r--lib/l10n/en_GB.js7
-rw-r--r--lib/l10n/en_GB.json7
-rw-r--r--lib/l10n/es.js5
-rw-r--r--lib/l10n/es.json5
-rw-r--r--lib/l10n/et_EE.js14
-rw-r--r--lib/l10n/et_EE.json14
-rw-r--r--lib/l10n/lv.js12
-rw-r--r--lib/l10n/lv.json12
-rw-r--r--lib/l10n/pl.js1
-rw-r--r--lib/l10n/pl.json1
-rw-r--r--lib/l10n/zh_HK.js7
-rw-r--r--lib/l10n/zh_HK.json7
-rw-r--r--lib/private/AppConfig.php8
-rw-r--r--lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php2
-rw-r--r--lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php41
-rw-r--r--lib/private/Files/Cache/Scanner.php10
-rw-r--r--lib/private/Files/ObjectStore/ObjectStoreStorage.php18
-rw-r--r--lib/private/Files/ObjectStore/S3.php12
-rw-r--r--lib/private/Files/ObjectStore/S3ObjectTrait.php45
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php11
-rw-r--r--lib/private/Files/Utils/Scanner.php11
-rw-r--r--lib/private/Files/View.php3
-rw-r--r--lib/private/Preview/Generator.php63
-rw-r--r--lib/private/PreviewManager.php29
-rw-r--r--lib/private/Security/Bruteforce/Throttler.php29
-rw-r--r--lib/private/Setup.php2
-rw-r--r--lib/private/Share20/DefaultShareProvider.php42
-rw-r--r--lib/private/Share20/Manager.php13
-rw-r--r--lib/private/TaskProcessing/RemoveOldTasksBackgroundJob.php2
-rw-r--r--lib/public/Calendar/CalendarExportOptions.php68
-rw-r--r--lib/public/Calendar/ICalendarExport.php31
-rw-r--r--lib/public/Calendar/ICalendarIsEnabled.php24
-rw-r--r--lib/public/Encryption/Exceptions/InvalidHeaderException.php17
-rw-r--r--lib/public/Files/ObjectStore/IObjectStoreMetaData.php11
-rw-r--r--lib/public/IPreview.php4
-rw-r--r--lib/public/Lock/LockedException.php12
-rw-r--r--lib/public/Share/IShareProviderSupportsAllSharesInFolder.php24
41 files changed, 483 insertions, 155 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 6264126b028..f15d4e2d55f 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -191,6 +191,7 @@ return array(
'OCP\\Cache\\CappedMemoryCache' => $baseDir . '/lib/public/Cache/CappedMemoryCache.php',
'OCP\\Calendar\\BackendTemporarilyUnavailableException' => $baseDir . '/lib/public/Calendar/BackendTemporarilyUnavailableException.php',
'OCP\\Calendar\\CalendarEventStatus' => $baseDir . '/lib/public/Calendar/CalendarEventStatus.php',
+ 'OCP\\Calendar\\CalendarExportOptions' => $baseDir . '/lib/public/Calendar/CalendarExportOptions.php',
'OCP\\Calendar\\Events\\AbstractCalendarObjectEvent' => $baseDir . '/lib/public/Calendar/Events/AbstractCalendarObjectEvent.php',
'OCP\\Calendar\\Events\\CalendarObjectCreatedEvent' => $baseDir . '/lib/public/Calendar/Events/CalendarObjectCreatedEvent.php',
'OCP\\Calendar\\Events\\CalendarObjectDeletedEvent' => $baseDir . '/lib/public/Calendar/Events/CalendarObjectDeletedEvent.php',
@@ -202,6 +203,8 @@ return array(
'OCP\\Calendar\\IAvailabilityResult' => $baseDir . '/lib/public/Calendar/IAvailabilityResult.php',
'OCP\\Calendar\\ICalendar' => $baseDir . '/lib/public/Calendar/ICalendar.php',
'OCP\\Calendar\\ICalendarEventBuilder' => $baseDir . '/lib/public/Calendar/ICalendarEventBuilder.php',
+ 'OCP\\Calendar\\ICalendarExport' => $baseDir . '/lib/public/Calendar/ICalendarExport.php',
+ 'OCP\\Calendar\\ICalendarIsEnabled' => $baseDir . '/lib/public/Calendar/ICalendarIsEnabled.php',
'OCP\\Calendar\\ICalendarIsShared' => $baseDir . '/lib/public/Calendar/ICalendarIsShared.php',
'OCP\\Calendar\\ICalendarIsWritable' => $baseDir . '/lib/public/Calendar/ICalendarIsWritable.php',
'OCP\\Calendar\\ICalendarProvider' => $baseDir . '/lib/public/Calendar/ICalendarProvider.php',
@@ -318,6 +321,7 @@ return array(
'OCP\\DirectEditing\\IToken' => $baseDir . '/lib/public/DirectEditing/IToken.php',
'OCP\\DirectEditing\\RegisterDirectEditorEvent' => $baseDir . '/lib/public/DirectEditing/RegisterDirectEditorEvent.php',
'OCP\\Encryption\\Exceptions\\GenericEncryptionException' => $baseDir . '/lib/public/Encryption/Exceptions/GenericEncryptionException.php',
+ 'OCP\\Encryption\\Exceptions\\InvalidHeaderException' => $baseDir . '/lib/public/Encryption/Exceptions/InvalidHeaderException.php',
'OCP\\Encryption\\IEncryptionModule' => $baseDir . '/lib/public/Encryption/IEncryptionModule.php',
'OCP\\Encryption\\IFile' => $baseDir . '/lib/public/Encryption/IFile.php',
'OCP\\Encryption\\IManager' => $baseDir . '/lib/public/Encryption/IManager.php',
@@ -778,6 +782,7 @@ return array(
'OCP\\Share\\IShareHelper' => $baseDir . '/lib/public/Share/IShareHelper.php',
'OCP\\Share\\IShareProvider' => $baseDir . '/lib/public/Share/IShareProvider.php',
'OCP\\Share\\IShareProviderSupportsAccept' => $baseDir . '/lib/public/Share/IShareProviderSupportsAccept.php',
+ 'OCP\\Share\\IShareProviderSupportsAllSharesInFolder' => $baseDir . '/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php',
'OCP\\Share\\IShareProviderWithNotification' => $baseDir . '/lib/public/Share/IShareProviderWithNotification.php',
'OCP\\Share_Backend' => $baseDir . '/lib/public/Share_Backend.php',
'OCP\\Share_Backend_Collection' => $baseDir . '/lib/public/Share_Backend_Collection.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 5771a621afe..dfb238acbf3 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -232,6 +232,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Cache\\CappedMemoryCache' => __DIR__ . '/../../..' . '/lib/public/Cache/CappedMemoryCache.php',
'OCP\\Calendar\\BackendTemporarilyUnavailableException' => __DIR__ . '/../../..' . '/lib/public/Calendar/BackendTemporarilyUnavailableException.php',
'OCP\\Calendar\\CalendarEventStatus' => __DIR__ . '/../../..' . '/lib/public/Calendar/CalendarEventStatus.php',
+ 'OCP\\Calendar\\CalendarExportOptions' => __DIR__ . '/../../..' . '/lib/public/Calendar/CalendarExportOptions.php',
'OCP\\Calendar\\Events\\AbstractCalendarObjectEvent' => __DIR__ . '/../../..' . '/lib/public/Calendar/Events/AbstractCalendarObjectEvent.php',
'OCP\\Calendar\\Events\\CalendarObjectCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Calendar/Events/CalendarObjectCreatedEvent.php',
'OCP\\Calendar\\Events\\CalendarObjectDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Calendar/Events/CalendarObjectDeletedEvent.php',
@@ -243,6 +244,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Calendar\\IAvailabilityResult' => __DIR__ . '/../../..' . '/lib/public/Calendar/IAvailabilityResult.php',
'OCP\\Calendar\\ICalendar' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendar.php',
'OCP\\Calendar\\ICalendarEventBuilder' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarEventBuilder.php',
+ 'OCP\\Calendar\\ICalendarExport' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarExport.php',
+ 'OCP\\Calendar\\ICalendarIsEnabled' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarIsEnabled.php',
'OCP\\Calendar\\ICalendarIsShared' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarIsShared.php',
'OCP\\Calendar\\ICalendarIsWritable' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarIsWritable.php',
'OCP\\Calendar\\ICalendarProvider' => __DIR__ . '/../../..' . '/lib/public/Calendar/ICalendarProvider.php',
@@ -359,6 +362,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\DirectEditing\\IToken' => __DIR__ . '/../../..' . '/lib/public/DirectEditing/IToken.php',
'OCP\\DirectEditing\\RegisterDirectEditorEvent' => __DIR__ . '/../../..' . '/lib/public/DirectEditing/RegisterDirectEditorEvent.php',
'OCP\\Encryption\\Exceptions\\GenericEncryptionException' => __DIR__ . '/../../..' . '/lib/public/Encryption/Exceptions/GenericEncryptionException.php',
+ 'OCP\\Encryption\\Exceptions\\InvalidHeaderException' => __DIR__ . '/../../..' . '/lib/public/Encryption/Exceptions/InvalidHeaderException.php',
'OCP\\Encryption\\IEncryptionModule' => __DIR__ . '/../../..' . '/lib/public/Encryption/IEncryptionModule.php',
'OCP\\Encryption\\IFile' => __DIR__ . '/../../..' . '/lib/public/Encryption/IFile.php',
'OCP\\Encryption\\IManager' => __DIR__ . '/../../..' . '/lib/public/Encryption/IManager.php',
@@ -819,6 +823,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Share\\IShareHelper' => __DIR__ . '/../../..' . '/lib/public/Share/IShareHelper.php',
'OCP\\Share\\IShareProvider' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProvider.php',
'OCP\\Share\\IShareProviderSupportsAccept' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProviderSupportsAccept.php',
+ 'OCP\\Share\\IShareProviderSupportsAllSharesInFolder' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php',
'OCP\\Share\\IShareProviderWithNotification' => __DIR__ . '/../../..' . '/lib/public/Share/IShareProviderWithNotification.php',
'OCP\\Share_Backend' => __DIR__ . '/../../..' . '/lib/public/Share_Backend.php',
'OCP\\Share_Backend_Collection' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_Collection.php',
diff --git a/lib/l10n/de_DE.js b/lib/l10n/de_DE.js
index 2d101052cf5..8b00460854c 100644
--- a/lib/l10n/de_DE.js
+++ b/lib/l10n/de_DE.js
@@ -133,7 +133,7 @@ OC.L10N.register(
"View %s on the fediverse" : "Zeige %s auf dem Fediverse",
"Phone" : "Telefon",
"Call %s" : "%s anrufen",
- "Twitter" : "Twitter",
+ "Twitter" : "X",
"View %s on Twitter" : "%s auf Twitter anzeigen",
"Website" : "Webseite",
"Visit %s" : "%s besuchen",
diff --git a/lib/l10n/de_DE.json b/lib/l10n/de_DE.json
index ea316cb1060..602206cda8d 100644
--- a/lib/l10n/de_DE.json
+++ b/lib/l10n/de_DE.json
@@ -131,7 +131,7 @@
"View %s on the fediverse" : "Zeige %s auf dem Fediverse",
"Phone" : "Telefon",
"Call %s" : "%s anrufen",
- "Twitter" : "Twitter",
+ "Twitter" : "X",
"View %s on Twitter" : "%s auf Twitter anzeigen",
"Website" : "Webseite",
"Visit %s" : "%s besuchen",
diff --git a/lib/l10n/en_GB.js b/lib/l10n/en_GB.js
index 93782960c94..2494ab4aca4 100644
--- a/lib/l10n/en_GB.js
+++ b/lib/l10n/en_GB.js
@@ -201,6 +201,7 @@ OC.L10N.register(
"Path is already shared with this group" : "Path is already shared with this group",
"Link sharing is not allowed" : "Link sharing is not allowed",
"Public upload is not allowed" : "Public upload is not allowed",
+ "You cannot share a folder that contains other shares" : "You cannot share a folder that contains other shares",
"Sharing is disabled" : "Sharing is disabled",
"Sharing is disabled for you" : "Sharing is disabled for you",
"Cannot share with the share owner" : "Cannot share with the share owner",
@@ -272,6 +273,7 @@ OC.L10N.register(
"A valid Login must be provided" : "A valid Login must be provided",
"Login contains whitespace at the beginning or at the end" : "Login contains whitespace at the beginning or at the end",
"Login must not consist of dots only" : "Login must not consist of dots only",
+ "Login is too long" : "Login is too long",
"Login is invalid because files already exist for this user" : "Login is invalid because files already exist for this user",
"Account disabled" : "Account disabled",
"Login canceled by app" : "Login cancelled by app",
@@ -362,6 +364,11 @@ OC.L10N.register(
"How many images to generate" : "How many images to generate",
"Output images" : "Output images",
"The generated images" : "The generated images",
+ "Generate speech" : "Generate speech",
+ "Generate speech from a transcript" : "Generate speech from a transcript",
+ "Write transcript that you want the assistant to generate speech from" : "Write transcript that you want the assistant to generate speech from",
+ "Output speech" : "Output speech",
+ "The generated speech" : "The generated speech",
"Free text to text prompt" : "Free text to text prompt",
"Runs an arbitrary prompt through a language model that returns a reply" : "Runs an arbitrary prompt through a language model that returns a reply",
"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",
diff --git a/lib/l10n/en_GB.json b/lib/l10n/en_GB.json
index 40402118ddf..08e84f39af1 100644
--- a/lib/l10n/en_GB.json
+++ b/lib/l10n/en_GB.json
@@ -199,6 +199,7 @@
"Path is already shared with this group" : "Path is already shared with this group",
"Link sharing is not allowed" : "Link sharing is not allowed",
"Public upload is not allowed" : "Public upload is not allowed",
+ "You cannot share a folder that contains other shares" : "You cannot share a folder that contains other shares",
"Sharing is disabled" : "Sharing is disabled",
"Sharing is disabled for you" : "Sharing is disabled for you",
"Cannot share with the share owner" : "Cannot share with the share owner",
@@ -270,6 +271,7 @@
"A valid Login must be provided" : "A valid Login must be provided",
"Login contains whitespace at the beginning or at the end" : "Login contains whitespace at the beginning or at the end",
"Login must not consist of dots only" : "Login must not consist of dots only",
+ "Login is too long" : "Login is too long",
"Login is invalid because files already exist for this user" : "Login is invalid because files already exist for this user",
"Account disabled" : "Account disabled",
"Login canceled by app" : "Login cancelled by app",
@@ -360,6 +362,11 @@
"How many images to generate" : "How many images to generate",
"Output images" : "Output images",
"The generated images" : "The generated images",
+ "Generate speech" : "Generate speech",
+ "Generate speech from a transcript" : "Generate speech from a transcript",
+ "Write transcript that you want the assistant to generate speech from" : "Write transcript that you want the assistant to generate speech from",
+ "Output speech" : "Output speech",
+ "The generated speech" : "The generated speech",
"Free text to text prompt" : "Free text to text prompt",
"Runs an arbitrary prompt through a language model that returns a reply" : "Runs an arbitrary prompt through a language model that returns a reply",
"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",
diff --git a/lib/l10n/es.js b/lib/l10n/es.js
index 94e52dbc724..a3cf61509ec 100644
--- a/lib/l10n/es.js
+++ b/lib/l10n/es.js
@@ -364,6 +364,11 @@ OC.L10N.register(
"How many images to generate" : "Cuántas imágenes se generarán",
"Output images" : "Imágenes de salida",
"The generated images" : "Las imágenes generadas",
+ "Generate speech" : "Generar dictado",
+ "Generate speech from a transcript" : "Generar dictado desde una transcripción",
+ "Write transcript that you want the assistant to generate speech from" : "Escriba la transcripción desde la que desea que el asistente genere un dictado",
+ "Output speech" : "Dictado de salida",
+ "The generated speech" : "El dictado generado",
"Free text to text prompt" : "Texto libre a prompt de texto",
"Runs an arbitrary prompt through a language model that returns a reply" : "Ejecuta un prompt arbitrario a través de un modelo de lenguaje que retorna una respuesta",
"Describe a task that you want the assistant to do or ask a question" : "Describa una tarea que quiere que el asistente realice, o, haga una pregunta",
diff --git a/lib/l10n/es.json b/lib/l10n/es.json
index 61f519db2a7..34d4db2eec4 100644
--- a/lib/l10n/es.json
+++ b/lib/l10n/es.json
@@ -362,6 +362,11 @@
"How many images to generate" : "Cuántas imágenes se generarán",
"Output images" : "Imágenes de salida",
"The generated images" : "Las imágenes generadas",
+ "Generate speech" : "Generar dictado",
+ "Generate speech from a transcript" : "Generar dictado desde una transcripción",
+ "Write transcript that you want the assistant to generate speech from" : "Escriba la transcripción desde la que desea que el asistente genere un dictado",
+ "Output speech" : "Dictado de salida",
+ "The generated speech" : "El dictado generado",
"Free text to text prompt" : "Texto libre a prompt de texto",
"Runs an arbitrary prompt through a language model that returns a reply" : "Ejecuta un prompt arbitrario a través de un modelo de lenguaje que retorna una respuesta",
"Describe a task that you want the assistant to do or ask a question" : "Describa una tarea que quiere que el asistente realice, o, haga una pregunta",
diff --git a/lib/l10n/et_EE.js b/lib/l10n/et_EE.js
index d882e0ee79e..e14744dc6ee 100644
--- a/lib/l10n/et_EE.js
+++ b/lib/l10n/et_EE.js
@@ -279,6 +279,7 @@ OC.L10N.register(
"Ensure there is a file called \"%1$s\" in the root of the data directory. It should have the content: \"%2$s\"" : "Palun taga, et andmete juurkaustas leidub fail „%1$s“, mille sisuks on „%2$s“",
"Action \"%s\" not supported or implemented." : "„%s“ tegevus pole toetatud või implementeeritud.",
"Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Päringu lõpetamiseks on puudu järgmised parameetrid; „%s“",
+ "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "„%1$s“ tunnus on juba kasutusel liitpilve serveris „%2$s“",
"Cloud Federation Provider with ID: \"%s\" does not exist." : "Liitpilve teenusepakkujat tunnusega „%s“ pole olemas.",
"Could not obtain lock type %d on \"%s\"." : "Ei suutnud hankida %d tüüpi lukustust asukohas „%s“.",
"Storage unauthorized. %s" : "Andmeruum on autoriseerimata. %s",
@@ -286,6 +287,16 @@ OC.L10N.register(
"Storage connection error. %s" : "Viga andmeruumi ühenduse loomisel. %s",
"Storage is temporarily not available" : "Salvestusruum pole ajutiselt kättesaadav",
"Storage connection timeout. %s" : "Aegumine andmeruumi ühenduse loomisel. %s",
+ "Transcribe audio" : "Kirjuta heli üles",
+ "Transcribe the things said in an audio" : "Kirjuta üles helifailis kuuldav jutt",
+ "Audio input" : "Helisisend",
+ "The audio to transcribe" : "Üleskirjutatav helifail",
+ "Transcription" : "Üleskirjutus",
+ "The transcribed text" : "Üleskirjutatud tekst",
+ "Context write" : "Kontekstuaalne kirjutamine",
+ "Writes text in a given style based on the provided source material." : "Kirjutab etteantud lähtematerjali lausel teksti üles.",
+ "Writing style" : "Kirjutamisstiil",
+ "Source material" : "Lähtematerjal",
"Generate image" : "Piltide loomine",
"Generate an image from a text prompt" : "Loo tekstisisendist pilt",
"Prompt" : "Sisendvorm",
@@ -299,6 +310,9 @@ OC.L10N.register(
"Write transcript that you want the assistant to generate speech from" : "Kirjuta üles see, mille alusel tahad Abilisel lasta koostada kõne",
"Output speech" : "Kõneväljund",
"The generated speech" : "Koostatud kõne",
+ "Chat" : "Vestle",
+ "Chat with the assistant" : "Vestle Abilisega",
+ "System prompt" : "Süsteemi viip",
"Generate a headline" : "Alapealkirja loomine",
"Generates a possible headline for a text." : "Võimaldab luua teksti põhjal kokkuvõtliku alapealkirja.",
"Original text" : "Lähtetekst",
diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json
index 295c4b77855..f6c46ab05cb 100644
--- a/lib/l10n/et_EE.json
+++ b/lib/l10n/et_EE.json
@@ -277,6 +277,7 @@
"Ensure there is a file called \"%1$s\" in the root of the data directory. It should have the content: \"%2$s\"" : "Palun taga, et andmete juurkaustas leidub fail „%1$s“, mille sisuks on „%2$s“",
"Action \"%s\" not supported or implemented." : "„%s“ tegevus pole toetatud või implementeeritud.",
"Parameters missing in order to complete the request. Missing Parameters: \"%s\"" : "Päringu lõpetamiseks on puudu järgmised parameetrid; „%s“",
+ "ID \"%1$s\" already used by cloud federation provider \"%2$s\"" : "„%1$s“ tunnus on juba kasutusel liitpilve serveris „%2$s“",
"Cloud Federation Provider with ID: \"%s\" does not exist." : "Liitpilve teenusepakkujat tunnusega „%s“ pole olemas.",
"Could not obtain lock type %d on \"%s\"." : "Ei suutnud hankida %d tüüpi lukustust asukohas „%s“.",
"Storage unauthorized. %s" : "Andmeruum on autoriseerimata. %s",
@@ -284,6 +285,16 @@
"Storage connection error. %s" : "Viga andmeruumi ühenduse loomisel. %s",
"Storage is temporarily not available" : "Salvestusruum pole ajutiselt kättesaadav",
"Storage connection timeout. %s" : "Aegumine andmeruumi ühenduse loomisel. %s",
+ "Transcribe audio" : "Kirjuta heli üles",
+ "Transcribe the things said in an audio" : "Kirjuta üles helifailis kuuldav jutt",
+ "Audio input" : "Helisisend",
+ "The audio to transcribe" : "Üleskirjutatav helifail",
+ "Transcription" : "Üleskirjutus",
+ "The transcribed text" : "Üleskirjutatud tekst",
+ "Context write" : "Kontekstuaalne kirjutamine",
+ "Writes text in a given style based on the provided source material." : "Kirjutab etteantud lähtematerjali lausel teksti üles.",
+ "Writing style" : "Kirjutamisstiil",
+ "Source material" : "Lähtematerjal",
"Generate image" : "Piltide loomine",
"Generate an image from a text prompt" : "Loo tekstisisendist pilt",
"Prompt" : "Sisendvorm",
@@ -297,6 +308,9 @@
"Write transcript that you want the assistant to generate speech from" : "Kirjuta üles see, mille alusel tahad Abilisel lasta koostada kõne",
"Output speech" : "Kõneväljund",
"The generated speech" : "Koostatud kõne",
+ "Chat" : "Vestle",
+ "Chat with the assistant" : "Vestle Abilisega",
+ "System prompt" : "Süsteemi viip",
"Generate a headline" : "Alapealkirja loomine",
"Generates a possible headline for a text." : "Võimaldab luua teksti põhjal kokkuvõtliku alapealkirja.",
"Original text" : "Lähtetekst",
diff --git a/lib/l10n/lv.js b/lib/l10n/lv.js
index e5b635a2bd3..c6eeeaa756c 100644
--- a/lib/l10n/lv.js
+++ b/lib/l10n/lv.js
@@ -31,14 +31,14 @@ OC.L10N.register(
"View profile" : "Skatīt profilu",
"today" : "šodien",
"yesterday" : "vakar",
- "_%n day ago_::_%n days ago_" : ["%n dienas atpakaļ","%n dienas atpakaļ","%n dienām"],
+ "_%n day ago_::_%n days ago_" : ["pirms %n dienām","pirms %n dienas","pirms %n dienām"],
"last month" : "pagājušajā mēnesī",
- "_%n month ago_::_%n months ago_" : ["%n mēneši atpakaļ","%n mēneši atpakaļ","%n mēnešiem"],
+ "_%n month ago_::_%n months ago_" : ["pirms %n mēnešiem","pirms %n mēneša","pirms %n mēnešiem"],
"last year" : "gājušajā gadā",
- "_%n year ago_::_%n years ago_" : ["%n gadiem","%n gadiem","%n gadiem"],
- "_%n hour ago_::_%n hours ago_" : ["%n stundas atpakaļ","%n stundas atpakaļ","%n stundām"],
- "_%n minute ago_::_%n minutes ago_" : ["%n minūtes atpakaļ","%n minūtes atpakaļ","%n minūtēm"],
- "seconds ago" : "sekundēm",
+ "_%n year ago_::_%n years ago_" : ["pirms %n gadiem","pirms %n gada","pirms %n gadiem"],
+ "_%n hour ago_::_%n hours ago_" : ["pirms %n stundām","pirms %n stundas","pirms %n stundām"],
+ "_%n minute ago_::_%n minutes ago_" : ["pirms %n minūtēm","pirms %n minūtes","pirms %n minūtēm"],
+ "seconds ago" : "pirms vairākām sekundēm",
"Empty file" : "Tukša datne",
"File already exists" : "Datne jau pastāv",
"Filename contains at least one invalid character" : "Datnes nosaukums satur vismaz vienu nederīgu rakstzīmi",
diff --git a/lib/l10n/lv.json b/lib/l10n/lv.json
index f71090c5fd4..865458737df 100644
--- a/lib/l10n/lv.json
+++ b/lib/l10n/lv.json
@@ -29,14 +29,14 @@
"View profile" : "Skatīt profilu",
"today" : "šodien",
"yesterday" : "vakar",
- "_%n day ago_::_%n days ago_" : ["%n dienas atpakaļ","%n dienas atpakaļ","%n dienām"],
+ "_%n day ago_::_%n days ago_" : ["pirms %n dienām","pirms %n dienas","pirms %n dienām"],
"last month" : "pagājušajā mēnesī",
- "_%n month ago_::_%n months ago_" : ["%n mēneši atpakaļ","%n mēneši atpakaļ","%n mēnešiem"],
+ "_%n month ago_::_%n months ago_" : ["pirms %n mēnešiem","pirms %n mēneša","pirms %n mēnešiem"],
"last year" : "gājušajā gadā",
- "_%n year ago_::_%n years ago_" : ["%n gadiem","%n gadiem","%n gadiem"],
- "_%n hour ago_::_%n hours ago_" : ["%n stundas atpakaļ","%n stundas atpakaļ","%n stundām"],
- "_%n minute ago_::_%n minutes ago_" : ["%n minūtes atpakaļ","%n minūtes atpakaļ","%n minūtēm"],
- "seconds ago" : "sekundēm",
+ "_%n year ago_::_%n years ago_" : ["pirms %n gadiem","pirms %n gada","pirms %n gadiem"],
+ "_%n hour ago_::_%n hours ago_" : ["pirms %n stundām","pirms %n stundas","pirms %n stundām"],
+ "_%n minute ago_::_%n minutes ago_" : ["pirms %n minūtēm","pirms %n minūtes","pirms %n minūtēm"],
+ "seconds ago" : "pirms vairākām sekundēm",
"Empty file" : "Tukša datne",
"File already exists" : "Datne jau pastāv",
"Filename contains at least one invalid character" : "Datnes nosaukums satur vismaz vienu nederīgu rakstzīmi",
diff --git a/lib/l10n/pl.js b/lib/l10n/pl.js
index 213b78d5c28..0d9fd0cb98a 100644
--- a/lib/l10n/pl.js
+++ b/lib/l10n/pl.js
@@ -307,6 +307,7 @@ OC.L10N.register(
"Chat" : "Rozmowa",
"Chat history" : "Historia rozmów",
"Generates a possible headline for a text." : "Generuje możliwy nagłówek tekstu.",
+ "Original text" : "Tekst oryginalny",
"Text" : "Tekst",
"Summarize" : "Podsumuj",
"Summary" : "Podsumowanie",
diff --git a/lib/l10n/pl.json b/lib/l10n/pl.json
index 6837f941bb7..c97634e8eff 100644
--- a/lib/l10n/pl.json
+++ b/lib/l10n/pl.json
@@ -305,6 +305,7 @@
"Chat" : "Rozmowa",
"Chat history" : "Historia rozmów",
"Generates a possible headline for a text." : "Generuje możliwy nagłówek tekstu.",
+ "Original text" : "Tekst oryginalny",
"Text" : "Tekst",
"Summarize" : "Podsumuj",
"Summary" : "Podsumowanie",
diff --git a/lib/l10n/zh_HK.js b/lib/l10n/zh_HK.js
index 7a98e4b4905..a85c29e400c 100644
--- a/lib/l10n/zh_HK.js
+++ b/lib/l10n/zh_HK.js
@@ -201,6 +201,7 @@ OC.L10N.register(
"Path is already shared with this group" : "已與此群組分享了路徑",
"Link sharing is not allowed" : "不允許連結分享",
"Public upload is not allowed" : "不允許公開上傳",
+ "You cannot share a folder that contains other shares" : "您無法分享包含其他分享的資料夾",
"Sharing is disabled" : "已停用分享",
"Sharing is disabled for you" : "您已停用分享",
"Cannot share with the share owner" : "無法與分享擁有者分享",
@@ -272,6 +273,7 @@ OC.L10N.register(
"A valid Login must be provided" : "必須提供有效帳戶",
"Login contains whitespace at the beginning or at the end" : "帳戶的開頭或結尾有空白",
"Login must not consist of dots only" : "帳戶不能只包含小數點",
+ "Login is too long" : "帳號太長了",
"Login is invalid because files already exist for this user" : "帳戶無效,因為此用戶的檔案已經存在",
"Account disabled" : "帳戶已停用",
"Login canceled by app" : "登入已被應用程式取消",
@@ -362,6 +364,11 @@ OC.L10N.register(
"How many images to generate" : "要產生多少圖像",
"Output images" : "輸出圖像",
"The generated images" : "產生的圖像",
+ "Generate speech" : "產生語音",
+ "Generate speech from a transcript" : "從文字稿産生語音",
+ "Write transcript that you want the assistant to generate speech from" : "寫下您想要小幫手產生語音的文字稿",
+ "Output speech" : "輸出語音",
+ "The generated speech" : "產生的語音",
"Free text to text prompt" : "文字提示的自由文字",
"Runs an arbitrary prompt through a language model that returns a reply" : "透過回傳回覆的語言模型執行任意提示",
"Describe a task that you want the assistant to do or ask a question" : "描述您希望助理執行的任務或提出問題",
diff --git a/lib/l10n/zh_HK.json b/lib/l10n/zh_HK.json
index 94658c90974..b58db1e510c 100644
--- a/lib/l10n/zh_HK.json
+++ b/lib/l10n/zh_HK.json
@@ -199,6 +199,7 @@
"Path is already shared with this group" : "已與此群組分享了路徑",
"Link sharing is not allowed" : "不允許連結分享",
"Public upload is not allowed" : "不允許公開上傳",
+ "You cannot share a folder that contains other shares" : "您無法分享包含其他分享的資料夾",
"Sharing is disabled" : "已停用分享",
"Sharing is disabled for you" : "您已停用分享",
"Cannot share with the share owner" : "無法與分享擁有者分享",
@@ -270,6 +271,7 @@
"A valid Login must be provided" : "必須提供有效帳戶",
"Login contains whitespace at the beginning or at the end" : "帳戶的開頭或結尾有空白",
"Login must not consist of dots only" : "帳戶不能只包含小數點",
+ "Login is too long" : "帳號太長了",
"Login is invalid because files already exist for this user" : "帳戶無效,因為此用戶的檔案已經存在",
"Account disabled" : "帳戶已停用",
"Login canceled by app" : "登入已被應用程式取消",
@@ -360,6 +362,11 @@
"How many images to generate" : "要產生多少圖像",
"Output images" : "輸出圖像",
"The generated images" : "產生的圖像",
+ "Generate speech" : "產生語音",
+ "Generate speech from a transcript" : "從文字稿産生語音",
+ "Write transcript that you want the assistant to generate speech from" : "寫下您想要小幫手產生語音的文字稿",
+ "Output speech" : "輸出語音",
+ "The generated speech" : "產生的語音",
"Free text to text prompt" : "文字提示的自由文字",
"Runs an arbitrary prompt through a language model that returns a reply" : "透過回傳回覆的語言模型執行任意提示",
"Describe a task that you want the assistant to do or ask a question" : "描述您希望助理執行的任務或提出問題",
diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php
index 092d37c3338..a8a6f689ffa 100644
--- a/lib/private/AppConfig.php
+++ b/lib/private/AppConfig.php
@@ -488,6 +488,14 @@ class AppConfig implements IAppConfig {
* @see VALUE_ARRAY
*/
public function getValueType(string $app, string $key, ?bool $lazy = null): int {
+ $type = self::VALUE_MIXED;
+ $ignorable = $lazy ?? false;
+ $this->matchAndApplyLexiconDefinition($app, $key, $ignorable, $type);
+ if ($type !== self::VALUE_MIXED) {
+ // a modified $type means config key is set in Lexicon
+ return $type;
+ }
+
$this->assertParams($app, $key);
$this->loadConfig($app, $lazy);
diff --git a/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php b/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php
index 2b3025fccff..b3040673d0f 100644
--- a/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php
+++ b/lib/private/AppFramework/Middleware/PublicShare/PublicShareMiddleware.php
@@ -120,7 +120,7 @@ class PublicShareMiddleware extends Middleware {
private function throttle($bruteforceProtectionAction, $token): void {
$ip = $this->request->getRemoteAddress();
- $this->throttler->sleepDelay($ip, $bruteforceProtectionAction);
+ $this->throttler->sleepDelayOrThrowOnMax($ip, $bruteforceProtectionAction);
$this->throttler->registerAttempt($bruteforceProtectionAction, $ip, ['token' => $token]);
}
}
diff --git a/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php
index 16f63594f19..982693bcfe8 100644
--- a/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php
+++ b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php
@@ -19,6 +19,7 @@ use OCP\Files\NotPermittedException;
use OCP\FilesMetadata\AMetadataEvent;
use OCP\FilesMetadata\Event\MetadataBackgroundEvent;
use OCP\FilesMetadata\Event\MetadataLiveEvent;
+use OCP\IPreview;
use OCP\Lock\LockedException;
/**
@@ -27,11 +28,14 @@ use OCP\Lock\LockedException;
* @template-implements IEventListener<AMetadataEvent>
*/
class GenerateBlurhashMetadata implements IEventListener {
- private const RESIZE_BOXSIZE = 30;
-
private const COMPONENTS_X = 4;
private const COMPONENTS_Y = 3;
+ public function __construct(
+ private IPreview $preview,
+ ) {
+ }
+
/**
* @throws NotPermittedException
* @throws GenericFileException
@@ -64,7 +68,9 @@ class GenerateBlurhashMetadata implements IEventListener {
return;
}
- $image = $this->resizedImageFromFile($file);
+ $preview = $this->preview->getPreview($file, 64, 64, cacheResult: false);
+ $image = @imagecreatefromstring($preview->getContent());
+
if (!$image) {
return;
}
@@ -74,35 +80,6 @@ class GenerateBlurhashMetadata implements IEventListener {
}
/**
- * @param File $file
- *
- * @return GdImage|false
- * @throws GenericFileException
- * @throws NotPermittedException
- * @throws LockedException
- */
- private function resizedImageFromFile(File $file): GdImage|false {
- $image = @imagecreatefromstring($file->getContent());
- if ($image === false) {
- return false;
- }
-
- $currX = imagesx($image);
- $currY = imagesy($image);
-
- if ($currX > $currY) {
- $newX = self::RESIZE_BOXSIZE;
- $newY = intval($currY * $newX / $currX);
- } else {
- $newY = self::RESIZE_BOXSIZE;
- $newX = intval($currX * $newY / $currY);
- }
-
- $newImage = @imagescale($image, $newX, $newY);
- return ($newImage !== false) ? $newImage : $image;
- }
-
- /**
* @param GdImage $image
*
* @return string
diff --git a/lib/private/Files/Cache/Scanner.php b/lib/private/Files/Cache/Scanner.php
index 1fb408a0655..b067f70b8cb 100644
--- a/lib/private/Files/Cache/Scanner.php
+++ b/lib/private/Files/Cache/Scanner.php
@@ -210,7 +210,7 @@ class Scanner extends BasicEmitter implements IScanner {
* @var \OC\Files\Cache\CacheEntry $cacheData
*/
$newData = $this->array_diff_assoc_multi($data, $cacheData->getData());
-
+
// make it known to the caller that etag has been changed and needs propagation
if (isset($newData['etag'])) {
$data['etag_changed'] = true;
@@ -351,23 +351,23 @@ class Scanner extends BasicEmitter implements IScanner {
*
*/
protected function array_diff_assoc_multi(array $array1, array $array2) {
-
+
$result = [];
foreach ($array1 as $key => $value) {
-
+
// if $array2 doesn't have the same key, that's a result
if (!array_key_exists($key, $array2)) {
$result[$key] = $value;
continue;
}
-
+
// if $array2's value for the same key is different, that's a result
if ($array2[$key] !== $value && !is_array($value)) {
$result[$key] = $value;
continue;
}
-
+
if (is_array($value)) {
$nestedDiff = $this->array_diff_assoc_multi($value, $array2[$key]);
if (!empty($nestedDiff)) {
diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
index 16ef4e7de63..ebe87399ab4 100644
--- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php
+++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php
@@ -22,6 +22,7 @@ use OCP\Files\FileInfo;
use OCP\Files\GenericFileException;
use OCP\Files\NotFoundException;
use OCP\Files\ObjectStore\IObjectStore;
+use OCP\Files\ObjectStore\IObjectStoreMetaData;
use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload;
use OCP\Files\Storage\IChunkedFileWrite;
use OCP\Files\Storage\IStorage;
@@ -479,6 +480,11 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
$mimetypeDetector = \OC::$server->getMimeTypeDetector();
$mimetype = $mimetypeDetector->detectPath($path);
+ $metadata = [
+ 'mimetype' => $mimetype,
+ 'original-storage' => $this->getId(),
+ 'original-path' => $path,
+ ];
$stat['mimetype'] = $mimetype;
$stat['etag'] = $this->getETag($path);
@@ -507,13 +513,21 @@ class ObjectStoreStorage extends \OC\Files\Storage\Common implements IChunkedFil
]);
$size = $writtenSize;
});
- $this->objectStore->writeObject($urn, $countStream, $mimetype);
+ 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;
} else {
- $this->objectStore->writeObject($urn, $stream, $mimetype);
+ 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);
}
diff --git a/lib/private/Files/ObjectStore/S3.php b/lib/private/Files/ObjectStore/S3.php
index e970fb6ac14..23c061db174 100644
--- a/lib/private/Files/ObjectStore/S3.php
+++ b/lib/private/Files/ObjectStore/S3.php
@@ -95,6 +95,16 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload, IObjectStoreMetaD
]);
}
+ private function parseS3Metadata(array $metadata): array {
+ $result = [];
+ foreach ($metadata as $key => $value) {
+ if (str_starts_with($key, 'x-amz-meta-')) {
+ $result[substr($key, strlen('x-amz-meta-'))] = $value;
+ }
+ }
+ return $result;
+ }
+
public function getObjectMetaData(string $urn): array {
$object = $this->getConnection()->headObject([
'Bucket' => $this->bucket,
@@ -104,7 +114,7 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload, IObjectStoreMetaD
'mtime' => $object['LastModified'],
'etag' => trim($object['ETag'], '"'),
'size' => (int)($object['Size'] ?? $object['ContentLength']),
- ];
+ ] + $this->parseS3Metadata($object['Metadata'] ?? []);
}
public function listObjects(string $prefix = ''): \Iterator {
diff --git a/lib/private/Files/ObjectStore/S3ObjectTrait.php b/lib/private/Files/ObjectStore/S3ObjectTrait.php
index 9d7cfa644e6..61e8158b863 100644
--- a/lib/private/Files/ObjectStore/S3ObjectTrait.php
+++ b/lib/private/Files/ObjectStore/S3ObjectTrait.php
@@ -77,22 +77,32 @@ trait S3ObjectTrait {
return $fh;
}
+ private function buildS3Metadata(array $metadata): array {
+ $result = [];
+ foreach ($metadata as $key => $value) {
+ $result['x-amz-meta-' . $key] = $value;
+ }
+ return $result;
+ }
/**
* Single object put helper
*
* @param string $urn the unified resource name used to identify the object
* @param StreamInterface $stream stream with the data to write
- * @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0
+ * @param array $metaData the metadata to set for the object
* @throws \Exception when something goes wrong, message will be logged
*/
- protected function writeSingle(string $urn, StreamInterface $stream, ?string $mimetype = null): void {
+ protected function writeSingle(string $urn, StreamInterface $stream, array $metaData): void {
+ $mimetype = $metaData['mimetype'] ?? null;
+ unset($metaData['mimetype']);
$this->getConnection()->putObject([
'Bucket' => $this->bucket,
'Key' => $urn,
'Body' => $stream,
'ACL' => 'private',
'ContentType' => $mimetype,
+ 'Metadata' => $this->buildS3Metadata($metaData),
'StorageClass' => $this->storageClass,
] + $this->getSSECParameters());
}
@@ -103,10 +113,12 @@ trait S3ObjectTrait {
*
* @param string $urn the unified resource name used to identify the object
* @param StreamInterface $stream stream with the data to write
- * @param string|null $mimetype the mimetype to set for the remove object
+ * @param array $metaData the metadata to set for the object
* @throws \Exception when something goes wrong, message will be logged
*/
- protected function writeMultiPart(string $urn, StreamInterface $stream, ?string $mimetype = null): void {
+ protected function writeMultiPart(string $urn, StreamInterface $stream, array $metaData): void {
+ $mimetype = $metaData['mimetype'] ?? null;
+ unset($metaData['mimetype']);
$uploader = new MultipartUploader($this->getConnection(), $stream, [
'bucket' => $this->bucket,
'concurrency' => $this->concurrency,
@@ -114,6 +126,7 @@ trait S3ObjectTrait {
'part_size' => $this->uploadPartSize,
'params' => [
'ContentType' => $mimetype,
+ 'Metadata' => $this->buildS3Metadata($metaData),
'StorageClass' => $this->storageClass,
] + $this->getSSECParameters(),
]);
@@ -131,15 +144,15 @@ trait S3ObjectTrait {
}
}
-
- /**
- * @param string $urn the unified resource name used to identify the object
- * @param resource $stream stream with the data to write
- * @param string|null $mimetype the mimetype to set for the remove object @since 22.0.0
- * @throws \Exception when something goes wrong, message will be logged
- * @since 7.0.0
- */
public function writeObject($urn, $stream, ?string $mimetype = null) {
+ $metaData = [];
+ if ($mimetype) {
+ $metaData['mimetype'] = $mimetype;
+ }
+ $this->writeObjectWithMetaData($urn, $stream, $metaData);
+ }
+
+ public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void {
$canSeek = fseek($stream, 0, SEEK_CUR) === 0;
$psrStream = Utils::streamFor($stream);
@@ -154,16 +167,16 @@ trait S3ObjectTrait {
$buffer->seek(0);
if ($buffer->getSize() < $this->putSizeLimit) {
// buffer is fully seekable, so use it directly for the small upload
- $this->writeSingle($urn, $buffer, $mimetype);
+ $this->writeSingle($urn, $buffer, $metaData);
} else {
$loadStream = new Psr7\AppendStream([$buffer, $psrStream]);
- $this->writeMultiPart($urn, $loadStream, $mimetype);
+ $this->writeMultiPart($urn, $loadStream, $metaData);
}
} else {
if ($size < $this->putSizeLimit) {
- $this->writeSingle($urn, $psrStream, $mimetype);
+ $this->writeSingle($urn, $psrStream, $metaData);
} else {
- $this->writeMultiPart($urn, $psrStream, $mimetype);
+ $this->writeMultiPart($urn, $psrStream, $metaData);
}
}
$psrStream->close();
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index ba23f3c43ec..0de009f0894 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -18,6 +18,7 @@ use OC\Files\Storage\Common;
use OC\Files\Storage\LocalTempFileTrait;
use OC\Memcache\ArrayCache;
use OCP\Cache\CappedMemoryCache;
+use OCP\Encryption\Exceptions\InvalidHeaderException;
use OCP\Encryption\IFile;
use OCP\Encryption\IManager;
use OCP\Encryption\Keys\IStorage;
@@ -344,6 +345,16 @@ class Encryption extends Wrapper {
if ($shouldEncrypt === true && $encryptionModule !== null) {
$this->encryptedPaths->set($this->util->stripPartialFileExtension($path), true);
$headerSize = $this->getHeaderSize($path);
+ if ($mode === 'r' && $headerSize === 0) {
+ $firstBlock = $this->readFirstBlock($path);
+ if (!$firstBlock) {
+ throw new InvalidHeaderException("Unable to get header block for $path");
+ } elseif (!str_starts_with($firstBlock, Util::HEADER_START)) {
+ throw new InvalidHeaderException("Unable to get header size for $path, file doesn't start with encryption header");
+ } else {
+ throw new InvalidHeaderException("Unable to get header size for $path, even though file does start with encryption header");
+ }
+ }
$source = $this->storage->fopen($path, $mode);
if (!is_resource($source)) {
return false;
diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php
index 4d94629443f..e9ed351b27b 100644
--- a/lib/private/Files/Utils/Scanner.php
+++ b/lib/private/Files/Utils/Scanner.php
@@ -29,6 +29,7 @@ use OCP\Files\Storage\IStorage;
use OCP\Files\StorageNotAvailableException;
use OCP\IDBConnection;
use OCP\Lock\ILockingProvider;
+use OCP\Lock\LockedException;
use Psr\Log\LoggerInterface;
/**
@@ -260,7 +261,15 @@ class Scanner extends PublicEmitter {
try {
$propagator = $storage->getPropagator();
$propagator->beginBatch();
- $scanner->scan($relativePath, $recursive, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE);
+ try {
+ $scanner->scan($relativePath, $recursive, \OC\Files\Cache\Scanner::REUSE_ETAG | \OC\Files\Cache\Scanner::REUSE_SIZE);
+ } catch (LockedException $e) {
+ if (is_string($e->getReadablePath()) && str_starts_with($e->getReadablePath(), 'scanner::')) {
+ throw new LockedException("scanner::$dir", $e, $e->getExistingLock());
+ } else {
+ throw $e;
+ }
+ }
$cache = $storage->getCache();
if ($cache instanceof Cache) {
// only re-calculate for the root folder we scanned, anything below that is taken care of by the scanner
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index bbad24d3e43..f17ced1611b 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -1466,8 +1466,7 @@ class View {
public function addSubMounts(FileInfo $info, $extOnly = false): void {
$mounts = Filesystem::getMountManager()->findIn($info->getPath());
$info->setSubMounts(array_filter($mounts, function (IMountPoint $mount) use ($extOnly) {
- $subStorage = $mount->getStorage();
- return !($extOnly && $subStorage instanceof \OCA\Files_Sharing\SharedStorage);
+ return !($extOnly && $mount instanceof SharedMount);
}));
}
diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php
index b95971d0085..00fc3b43d61 100644
--- a/lib/private/Preview/Generator.php
+++ b/lib/private/Preview/Generator.php
@@ -12,6 +12,7 @@ use OCP\Files\IAppData;
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
+use OCP\Files\SimpleFS\InMemoryFile;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IConfig;
@@ -43,17 +44,19 @@ class Generator {
* The cache is searched first and if nothing usable was found then a preview is
* generated by one of the providers
*
- * @param File $file
- * @param int $width
- * @param int $height
- * @param bool $crop
- * @param string $mode
- * @param string|null $mimeType
* @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
*/
- public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
+ public function getPreview(
+ File $file,
+ int $width = -1,
+ int $height = -1,
+ bool $crop = false,
+ string $mode = IPreview::MODE_FILL,
+ ?string $mimeType = null,
+ bool $cacheResult = true,
+ ): ISimpleFile {
$specification = [
'width' => $width,
'height' => $height,
@@ -78,23 +81,19 @@ class Generator {
'mode' => $mode,
'mimeType' => $mimeType,
]);
-
+
// since we only ask for one preview, and the generate method return the last one it created, it returns the one we want
- return $this->generatePreviews($file, [$specification], $mimeType);
+ return $this->generatePreviews($file, [$specification], $mimeType, $cacheResult);
}
/**
* Generates previews of a file
*
- * @param File $file
- * @param non-empty-array $specifications
- * @param string $mimeType
- * @return ISimpleFile the last preview that was generated
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
*/
- public function generatePreviews(File $file, array $specifications, $mimeType = null) {
+ public function generatePreviews(File $file, array $specifications, ?string $mimeType = null, bool $cacheResult = true): ISimpleFile {
//Make sure that we can read the file
if (!$file->isReadable()) {
$this->logger->warning('Cannot read file: {path}, skipping preview generation.', ['path' => $file->getPath()]);
@@ -167,7 +166,7 @@ class Generator {
}
$this->logger->warning('Cached preview not found for file {path}, generating a new preview.', ['path' => $file->getPath()]);
- $preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion);
+ $preview = $this->generatePreview($previewFolder, $maxPreviewImage, $width, $height, $crop, $maxWidth, $maxHeight, $previewVersion, $cacheResult);
// New file, augment our array
$previewFiles[] = $preview;
}
@@ -351,11 +350,10 @@ class Generator {
$path = $this->generatePath($preview->width(), $preview->height(), $crop, $max, $preview->dataMimeType(), $prefix);
try {
- $file = $previewFolder->newFile($path);
if ($preview instanceof IStreamImage) {
- $file->putContent($preview->resource());
+ return $previewFolder->newFile($path, $preview->resource());
} else {
- $file->putContent($preview->data());
+ return $previewFolder->newFile($path, $preview->data());
}
} catch (NotPermittedException $e) {
throw new NotFoundException();
@@ -490,19 +488,20 @@ class Generator {
}
/**
- * @param ISimpleFolder $previewFolder
- * @param ISimpleFile $maxPreview
- * @param int $width
- * @param int $height
- * @param bool $crop
- * @param int $maxWidth
- * @param int $maxHeight
- * @param string $prefix
- * @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
*/
- private function generatePreview(ISimpleFolder $previewFolder, IImage $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight, $prefix) {
+ private function generatePreview(
+ ISimpleFolder $previewFolder,
+ IImage $maxPreview,
+ int $width,
+ int $height,
+ bool $crop,
+ int $maxWidth,
+ int $maxHeight,
+ string $prefix,
+ bool $cacheResult,
+ ): ISimpleFile {
$preview = $maxPreview;
if (!$preview->valid()) {
throw new \InvalidArgumentException('Failed to generate preview, failed to load image');
@@ -539,12 +538,14 @@ class Generator {
$path = $this->generatePath($width, $height, $crop, false, $preview->dataMimeType(), $prefix);
try {
- $file = $previewFolder->newFile($path);
- $file->putContent($preview->data());
+ if ($cacheResult) {
+ return $previewFolder->newFile($path, $preview->data());
+ } else {
+ return new InMemoryFile($path, $preview->data());
+ }
} catch (NotPermittedException $e) {
throw new NotFoundException();
}
-
return $file;
}
diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php
index bc77dcfe483..1f618dab22d 100644
--- a/lib/private/PreviewManager.php
+++ b/lib/private/PreviewManager.php
@@ -145,29 +145,20 @@ class PreviewManager implements IPreview {
return $this->generator;
}
- /**
- * Returns a preview of a file
- *
- * The cache is searched first and if nothing usable was found then a preview is
- * generated by one of the providers
- *
- * @param File $file
- * @param int $width
- * @param int $height
- * @param bool $crop
- * @param string $mode
- * @param string $mimeType
- * @return ISimpleFile
- * @throws NotFoundException
- * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
- * @since 11.0.0 - \InvalidArgumentException was added in 12.0.0
- */
- public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
+ public function getPreview(
+ File $file,
+ $width = -1,
+ $height = -1,
+ $crop = false,
+ $mode = IPreview::MODE_FILL,
+ $mimeType = null,
+ bool $cacheResult = true,
+ ): ISimpleFile {
$this->throwIfPreviewsDisabled();
$previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
$sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
try {
- $preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType);
+ $preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType, $cacheResult);
} finally {
Generator::unguardWithSemaphore($sem);
}
diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php
index 21d50848641..065f720ba72 100644
--- a/lib/private/Security/Bruteforce/Throttler.php
+++ b/lib/private/Security/Bruteforce/Throttler.php
@@ -127,6 +127,13 @@ class Throttler implements IThrottler {
*/
public function getDelay(string $ip, string $action = ''): int {
$attempts = $this->getAttempts($ip, $action);
+ return $this->calculateDelay($attempts);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function calculateDelay(int $attempts): int {
if ($attempts === 0) {
return 0;
}
@@ -199,25 +206,29 @@ class Throttler implements IThrottler {
* {@inheritDoc}
*/
public function sleepDelayOrThrowOnMax(string $ip, string $action = ''): int {
- $delay = $this->getDelay($ip, $action);
- if (($delay === self::MAX_DELAY_MS) && $this->getAttempts($ip, $action, 0.5) > $this->config->getSystemValueInt('auth.bruteforce.max-attempts', self::MAX_ATTEMPTS)) {
- $this->logger->info('IP address blocked because it reached the maximum failed attempts in the last 30 minutes [action: {action}, ip: {ip}]', [
+ $attempts = $this->getAttempts($ip, $action, 0.5);
+ if ($attempts > $this->config->getSystemValueInt('auth.bruteforce.max-attempts', self::MAX_ATTEMPTS)) {
+ $this->logger->info('IP address blocked because it reached the maximum failed attempts in the last 30 minutes [action: {action}, attempts: {attempts}, ip: {ip}]', [
'action' => $action,
'ip' => $ip,
+ 'attempts' => $attempts,
]);
// If the ip made too many attempts within the last 30 mins we don't execute anymore
throw new MaxDelayReached('Reached maximum delay');
}
- if ($delay > 100) {
- $this->logger->info('IP address throttled because it reached the attempts limit in the last 30 minutes [action: {action}, delay: {delay}, ip: {ip}]', [
+
+ $attempts = $this->getAttempts($ip, $action);
+ if ($attempts > 10) {
+ $this->logger->info('IP address throttled because it reached the attempts limit in the last 12 hours [action: {action}, attempts: {attempts}, ip: {ip}]', [
'action' => $action,
'ip' => $ip,
- 'delay' => $delay,
+ 'attempts' => $attempts,
]);
}
- if (!$this->config->getSystemValueBool('auth.bruteforce.protection.testing')) {
- usleep($delay * 1000);
+ if ($attempts > 0) {
+ return $this->calculateDelay($attempts);
}
- return $delay;
+
+ return 0;
}
}
diff --git a/lib/private/Setup.php b/lib/private/Setup.php
index 6d3021aff71..959797fb962 100644
--- a/lib/private/Setup.php
+++ b/lib/private/Setup.php
@@ -14,6 +14,7 @@ use Exception;
use InvalidArgumentException;
use OC\Authentication\Token\PublicKeyTokenProvider;
use OC\Authentication\Token\TokenCleanupJob;
+use OC\Core\BackgroundJobs\GenerateMetadataJob;
use OC\Log\Rotate;
use OC\Preview\BackgroundCleanupJob;
use OC\TextProcessing\RemoveOldTasksBackgroundJob;
@@ -495,6 +496,7 @@ class Setup {
$jobList->add(BackgroundCleanupJob::class);
$jobList->add(RemoveOldTasksBackgroundJob::class);
$jobList->add(CleanupDeletedUsers::class);
+ $jobList->add(GenerateMetadataJob::class);
}
/**
diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php
index a257bc4f7b5..e1eebe1e450 100644
--- a/lib/private/Share20/DefaultShareProvider.php
+++ b/lib/private/Share20/DefaultShareProvider.php
@@ -5,6 +5,7 @@
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
* SPDX-License-Identifier: AGPL-3.0-only
*/
+
namespace OC\Share20;
use OC\Files\Cache\Cache;
@@ -31,6 +32,7 @@ use OCP\Share\IAttributes;
use OCP\Share\IManager;
use OCP\Share\IShare;
use OCP\Share\IShareProviderSupportsAccept;
+use OCP\Share\IShareProviderSupportsAllSharesInFolder;
use OCP\Share\IShareProviderWithNotification;
use Psr\Log\LoggerInterface;
use function str_starts_with;
@@ -40,7 +42,7 @@ use function str_starts_with;
*
* @package OC\Share20
*/
-class DefaultShareProvider implements IShareProviderWithNotification, IShareProviderSupportsAccept {
+class DefaultShareProvider implements IShareProviderWithNotification, IShareProviderSupportsAccept, IShareProviderSupportsAllSharesInFolder {
// Special share type for user modified group shares
public const SHARE_TYPE_USERGROUP = 2;
@@ -603,6 +605,17 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv
throw new \Exception('non-shallow getSharesInFolder is no longer supported');
}
+ return $this->getSharesInFolderInternal($userId, $node, $reshares);
+ }
+
+ public function getAllSharesInFolder(Folder $node): array {
+ return $this->getSharesInFolderInternal(null, $node, null);
+ }
+
+ /**
+ * @return array<int, list<IShare>>
+ */
+ private function getSharesInFolderInternal(?string $userId, Folder $node, ?bool $reshares): array {
$qb = $this->dbConn->getQueryBuilder();
$qb->select('s.*',
'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
@@ -613,18 +626,20 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv
$qb->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter([IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK], IQueryBuilder::PARAM_INT_ARRAY)));
- /**
- * Reshares for this user are shares where they are the owner.
- */
- if ($reshares === false) {
- $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
- } else {
- $qb->andWhere(
- $qb->expr()->orX(
- $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
- $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
- )
- );
+ if ($userId !== null) {
+ /**
+ * Reshares for this user are shares where they are the owner.
+ */
+ if ($reshares !== true) {
+ $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
+ } else {
+ $qb->andWhere(
+ $qb->expr()->orX(
+ $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
+ $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
+ )
+ );
+ }
}
// todo? maybe get these from the oc_mounts table
@@ -656,7 +671,6 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv
foreach ($chunks as $chunk) {
$qb->setParameter('chunk', $chunk, IQueryBuilder::PARAM_INT_ARRAY);
- $a = $qb->getSQL();
$cursor = $qb->executeQuery();
while ($data = $cursor->fetch()) {
$shares[$data['fileid']][] = $this->createShare($data);
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index 3b247475afa..2104c07593a 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -51,6 +51,7 @@ use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
use OCP\Share\IShareProviderSupportsAccept;
+use OCP\Share\IShareProviderSupportsAllSharesInFolder;
use OCP\Share\IShareProviderWithNotification;
use Psr\Log\LoggerInterface;
@@ -1213,11 +1214,13 @@ class Manager implements IManager {
$shares = [];
foreach ($providers as $provider) {
if ($isOwnerless) {
- foreach ($node->getDirectoryListing() as $childNode) {
- $data = $provider->getSharesByPath($childNode);
- $fid = $childNode->getId();
- $shares[$fid] ??= [];
- $shares[$fid] = array_merge($shares[$fid], $data);
+ // If the provider does not implement the additional interface,
+ // we lack a performant way of querying all shares and therefore ignore the provider.
+ if ($provider instanceof IShareProviderSupportsAllSharesInFolder) {
+ foreach ($provider->getAllSharesInFolder($node) as $fid => $data) {
+ $shares[$fid] ??= [];
+ $shares[$fid] = array_merge($shares[$fid], $data);
+ }
}
} else {
foreach ($provider->getSharesInFolder($userId, $node, $reshares) as $fid => $data) {
diff --git a/lib/private/TaskProcessing/RemoveOldTasksBackgroundJob.php b/lib/private/TaskProcessing/RemoveOldTasksBackgroundJob.php
index c6f26e3aa8b..42d073a024d 100644
--- a/lib/private/TaskProcessing/RemoveOldTasksBackgroundJob.php
+++ b/lib/private/TaskProcessing/RemoveOldTasksBackgroundJob.php
@@ -16,7 +16,7 @@ use OCP\Files\SimpleFS\ISimpleFolder;
use Psr\Log\LoggerInterface;
class RemoveOldTasksBackgroundJob extends TimedJob {
- public const MAX_TASK_AGE_SECONDS = 60 * 60 * 24 * 7 * 4; // 4 weeks
+ public const MAX_TASK_AGE_SECONDS = 60 * 60 * 24 * 30 * 4; // 4 months
private \OCP\Files\IAppData $appData;
public function __construct(
diff --git a/lib/public/Calendar/CalendarExportOptions.php b/lib/public/Calendar/CalendarExportOptions.php
new file mode 100644
index 00000000000..bf21dd85ae4
--- /dev/null
+++ b/lib/public/Calendar/CalendarExportOptions.php
@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * Calendar Export Options
+ *
+ * @since 32.0.0
+ */
+final class CalendarExportOptions {
+
+ /** @var 'ical'|'jcal'|'xcal' */
+ private string $format = 'ical';
+ private ?string $rangeStart = null;
+ private ?int $rangeCount = null;
+
+ /**
+ * Gets the export format
+ *
+ * @return 'ical'|'jcal'|'xcal' (defaults to ical)
+ */
+ public function getFormat(): string {
+ return $this->format;
+ }
+
+ /**
+ * Sets the export format
+ *
+ * @param 'ical'|'jcal'|'xcal' $format
+ */
+ public function setFormat(string $format): void {
+ $this->format = $format;
+ }
+
+ /**
+ * Gets the start of the range to export
+ */
+ public function getRangeStart(): ?string {
+ return $this->rangeStart;
+ }
+
+ /**
+ * Sets the start of the range to export
+ */
+ public function setRangeStart(?string $rangeStart): void {
+ $this->rangeStart = $rangeStart;
+ }
+
+ /**
+ * Gets the number of objects to export
+ */
+ public function getRangeCount(): ?int {
+ return $this->rangeCount;
+ }
+
+ /**
+ * Sets the number of objects to export
+ */
+ public function setRangeCount(?int $rangeCount): void {
+ $this->rangeCount = $rangeCount;
+ }
+}
diff --git a/lib/public/Calendar/ICalendarExport.php b/lib/public/Calendar/ICalendarExport.php
new file mode 100644
index 00000000000..61b286e1668
--- /dev/null
+++ b/lib/public/Calendar/ICalendarExport.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\Calendar;
+
+use Generator;
+
+/**
+ * ICalendar Interface Extension to export data
+ *
+ * @since 32.0.0
+ */
+interface ICalendarExport {
+
+ /**
+ * Export objects
+ *
+ * @since 32.0.0
+ *
+ * @param CalendarExportOptions|null $options
+ *
+ * @return Generator<\Sabre\VObject\Component\VCalendar>
+ */
+ public function export(?CalendarExportOptions $options): Generator;
+
+}
diff --git a/lib/public/Calendar/ICalendarIsEnabled.php b/lib/public/Calendar/ICalendarIsEnabled.php
new file mode 100644
index 00000000000..868159d208f
--- /dev/null
+++ b/lib/public/Calendar/ICalendarIsEnabled.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Calendar;
+
+/**
+ * ICalendar Interface Extension
+ *
+ * @since 32.0.0
+ */
+interface ICalendarIsEnabled {
+
+ /**
+ * Indicates whether the calendar is enabled
+ *
+ * @since 32.0.0
+ */
+ public function isEnabled(): bool;
+
+}
diff --git a/lib/public/Encryption/Exceptions/InvalidHeaderException.php b/lib/public/Encryption/Exceptions/InvalidHeaderException.php
new file mode 100644
index 00000000000..f7213577fb6
--- /dev/null
+++ b/lib/public/Encryption/Exceptions/InvalidHeaderException.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OCP\Encryption\Exceptions;
+
+use OCP\HintException;
+
+/**
+ * Class InvalidHeaderException
+ *
+ * @since 32.0.0
+ */
+class InvalidHeaderException extends HintException {
+}
diff --git a/lib/public/Files/ObjectStore/IObjectStoreMetaData.php b/lib/public/Files/ObjectStore/IObjectStoreMetaData.php
index 8359e83f573..9683873be36 100644
--- a/lib/public/Files/ObjectStore/IObjectStoreMetaData.php
+++ b/lib/public/Files/ObjectStore/IObjectStoreMetaData.php
@@ -9,7 +9,7 @@ namespace OCP\Files\ObjectStore;
/**
* Interface IObjectStoreMetaData
*
- * @psalm-type ObjectMetaData = array{mtime?: \DateTime, etag?: string, size?: int, mimetype?: string, filename?: string}
+ * @psalm-type ObjectMetaData = array{mtime?: \DateTime, etag?: string, size?: int, mimetype?: string, filename?: string, original-path?: string, original-storage?: string}
*
* @since 32.0.0
*/
@@ -35,4 +35,13 @@ interface IObjectStoreMetaData {
* @since 32.0.0
*/
public function listObjects(string $prefix = ''): \Iterator;
+
+ /**
+ * @param string $urn the unified resource name used to identify the object
+ * @param resource $stream stream with the data to write
+ * @param ObjectMetaData $metaData the metadata to set for the object
+ * @throws \Exception when something goes wrong, message will be logged
+ * @since 32.0.0
+ */
+ public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void;
}
diff --git a/lib/public/IPreview.php b/lib/public/IPreview.php
index 6ab4af1b7ca..5a2bcde69f1 100644
--- a/lib/public/IPreview.php
+++ b/lib/public/IPreview.php
@@ -71,12 +71,14 @@ interface IPreview {
* @param bool $crop
* @param string $mode
* @param string $mimeType To force a given mimetype for the file (files_versions needs this)
+ * @param bool $cacheResult Whether or not to cache the preview on the filesystem. Default to true. Can be useful to set to false to limit the amount of stored previews.
* @return ISimpleFile
* @throws NotFoundException
* @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
* @since 11.0.0 - \InvalidArgumentException was added in 12.0.0
+ * @since 32.0.0 - getPreview($cacheResult) added the $cacheResult argument to the signature
*/
- public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null);
+ public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null, bool $cacheResult = true);
/**
* Returns true if the passed mime type is supported
diff --git a/lib/public/Lock/LockedException.php b/lib/public/Lock/LockedException.php
index ce41d2d7242..799886a2dbb 100644
--- a/lib/public/Lock/LockedException.php
+++ b/lib/public/Lock/LockedException.php
@@ -24,6 +24,8 @@ class LockedException extends \Exception {
/** @var string|null */
private $existingLock;
+ private ?string $readablePath;
+
/**
* LockedException constructor.
*
@@ -34,6 +36,7 @@ class LockedException extends \Exception {
* @since 8.1.0
*/
public function __construct(string $path, ?\Exception $previous = null, ?string $existingLock = null, ?string $readablePath = null) {
+ $this->readablePath = $readablePath;
if ($readablePath) {
$message = "\"$path\"(\"$readablePath\") is locked";
} else {
@@ -62,4 +65,13 @@ class LockedException extends \Exception {
public function getExistingLock(): ?string {
return $this->existingLock;
}
+
+ /**
+ * @return ?string
+ * @since 32.0.0
+ */
+ public function getReadablePath(): ?string {
+ return $this->readablePath;
+ }
+
}
diff --git a/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php b/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php
new file mode 100644
index 00000000000..e27da7682ce
--- /dev/null
+++ b/lib/public/Share/IShareProviderSupportsAllSharesInFolder.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+namespace OCP\Share;
+
+use OCP\Files\Folder;
+
+/**
+ * Allows defining a IShareProvider with support for the getAllSharesInFolder method.
+ *
+ * @since 32.0.0
+ */
+interface IShareProviderSupportsAllSharesInFolder extends IShareProvider {
+ /**
+ * Get all shares in a folder.
+ *
+ * @return array<int, list<IShare>>
+ * @since 32.0.0
+ */
+ public function getAllSharesInFolder(Folder $node): array;
+}