diff options
Diffstat (limited to 'lib')
55 files changed, 391 insertions, 158 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index abeaf0d513a..52e3075e413 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -190,6 +190,7 @@ return array( 'OCP\\Broadcast\\Events\\IBroadcastEvent' => $baseDir . '/lib/public/Broadcast/Events/IBroadcastEvent.php', '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\\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', @@ -455,6 +456,7 @@ return array( 'OCP\\Files\\Notify\\INotifyHandler' => $baseDir . '/lib/public/Files/Notify/INotifyHandler.php', 'OCP\\Files\\Notify\\IRenameChange' => $baseDir . '/lib/public/Files/Notify/IRenameChange.php', 'OCP\\Files\\ObjectStore\\IObjectStore' => $baseDir . '/lib/public/Files/ObjectStore/IObjectStore.php', + 'OCP\\Files\\ObjectStore\\IObjectStoreMetaData' => $baseDir . '/lib/public/Files/ObjectStore/IObjectStoreMetaData.php', 'OCP\\Files\\ObjectStore\\IObjectStoreMultiPartUpload' => $baseDir . '/lib/public/Files/ObjectStore/IObjectStoreMultiPartUpload.php', 'OCP\\Files\\ReservedWordException' => $baseDir . '/lib/public/Files/ReservedWordException.php', 'OCP\\Files\\Search\\ISearchBinaryOperator' => $baseDir . '/lib/public/Files/Search/ISearchBinaryOperator.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 956fa820ac5..e98bc3e1aaa 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -239,6 +239,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Broadcast\\Events\\IBroadcastEvent' => __DIR__ . '/../../..' . '/lib/public/Broadcast/Events/IBroadcastEvent.php', '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\\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', @@ -504,6 +505,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Files\\Notify\\INotifyHandler' => __DIR__ . '/../../..' . '/lib/public/Files/Notify/INotifyHandler.php', 'OCP\\Files\\Notify\\IRenameChange' => __DIR__ . '/../../..' . '/lib/public/Files/Notify/IRenameChange.php', 'OCP\\Files\\ObjectStore\\IObjectStore' => __DIR__ . '/../../..' . '/lib/public/Files/ObjectStore/IObjectStore.php', + 'OCP\\Files\\ObjectStore\\IObjectStoreMetaData' => __DIR__ . '/../../..' . '/lib/public/Files/ObjectStore/IObjectStoreMetaData.php', 'OCP\\Files\\ObjectStore\\IObjectStoreMultiPartUpload' => __DIR__ . '/../../..' . '/lib/public/Files/ObjectStore/IObjectStoreMultiPartUpload.php', 'OCP\\Files\\ReservedWordException' => __DIR__ . '/../../..' . '/lib/public/Files/ReservedWordException.php', 'OCP\\Files\\Search\\ISearchBinaryOperator' => __DIR__ . '/../../..' . '/lib/public/Files/Search/ISearchBinaryOperator.php', diff --git a/lib/l10n/et_EE.js b/lib/l10n/et_EE.js index adefc8ed808..b1807c1fcad 100644 --- a/lib/l10n/et_EE.js +++ b/lib/l10n/et_EE.js @@ -49,6 +49,7 @@ OC.L10N.register( "Administration settings" : "Administreerimise seaded", "Settings" : "Seaded", "Log out" : "Logi välja", + "Accounts" : "Kasutajakontod", "Email" : "Epost", "Phone" : "Telefon", "Twitter" : "Twitter", @@ -124,7 +125,7 @@ OC.L10N.register( "a safe home for all your data" : "turvaline koht sinu andmetele", "Application is not enabled" : "Rakendus pole sisse lülitatud", "Authentication error" : "Autentimise viga", - "Token expired. Please reload page." : "Kontrollkood aegus. Paelun lae leht uuesti.", + "Token expired. Please reload page." : "Kontrollkood aegus. Paelun laadi leht uuesti.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Ühtegi andmebaasi (sqlite, mysql või postgresql) draiverit pole paigaldatud.", "PHP module %s not installed." : "PHP moodulit %s pole paigaldatud.", "Please ask your server administrator to install the module." : "Palu oma serveri haldajal moodul paigadalda.", @@ -138,9 +139,10 @@ OC.L10N.register( "Text" : "Tekst", "Summary" : "Kokkuvõte", "Translate" : "Tõlgi", + "The translated text" : "Tõlgitud tekst", "File name is a reserved word" : "Failinimi sisaldab keelatud sõna", - "File name contains at least one invalid character" : "Faili nimesonvähemalt üks keelatud märk", - "File name is too long" : "Faili nimi on liiga pikk", + "File name contains at least one invalid character" : "Failinimes on vähemalt üks keelatud tähemärk", + "File name is too long" : "Failinimi on liiga pikk", "Users" : "Kasutajad", "Open »%s«" : "Ava »%s«", "Click the button below to open it." : "Vajuta allolevat nuppu, et see avada.", diff --git a/lib/l10n/et_EE.json b/lib/l10n/et_EE.json index 51d86cc0e29..53b0fb7a9b8 100644 --- a/lib/l10n/et_EE.json +++ b/lib/l10n/et_EE.json @@ -47,6 +47,7 @@ "Administration settings" : "Administreerimise seaded", "Settings" : "Seaded", "Log out" : "Logi välja", + "Accounts" : "Kasutajakontod", "Email" : "Epost", "Phone" : "Telefon", "Twitter" : "Twitter", @@ -122,7 +123,7 @@ "a safe home for all your data" : "turvaline koht sinu andmetele", "Application is not enabled" : "Rakendus pole sisse lülitatud", "Authentication error" : "Autentimise viga", - "Token expired. Please reload page." : "Kontrollkood aegus. Paelun lae leht uuesti.", + "Token expired. Please reload page." : "Kontrollkood aegus. Paelun laadi leht uuesti.", "No database drivers (sqlite, mysql, or postgresql) installed." : "Ühtegi andmebaasi (sqlite, mysql või postgresql) draiverit pole paigaldatud.", "PHP module %s not installed." : "PHP moodulit %s pole paigaldatud.", "Please ask your server administrator to install the module." : "Palu oma serveri haldajal moodul paigadalda.", @@ -136,9 +137,10 @@ "Text" : "Tekst", "Summary" : "Kokkuvõte", "Translate" : "Tõlgi", + "The translated text" : "Tõlgitud tekst", "File name is a reserved word" : "Failinimi sisaldab keelatud sõna", - "File name contains at least one invalid character" : "Faili nimesonvähemalt üks keelatud märk", - "File name is too long" : "Faili nimi on liiga pikk", + "File name contains at least one invalid character" : "Failinimes on vähemalt üks keelatud tähemärk", + "File name is too long" : "Failinimi on liiga pikk", "Users" : "Kasutajad", "Open »%s«" : "Ava »%s«", "Click the button below to open it." : "Vajuta allolevat nuppu, et see avada.", diff --git a/lib/l10n/pt_BR.js b/lib/l10n/pt_BR.js index b4d737d7b95..92b55232bea 100644 --- a/lib/l10n/pt_BR.js +++ b/lib/l10n/pt_BR.js @@ -88,6 +88,7 @@ OC.L10N.register( "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "O módulo com a ID: %s não existe. Por favor, habilite-o nas configurações de seu aplicativo ou contacte o administrador.", "No file conversion providers available" : "Não há provedores de conversão de arquivos disponíveis", "File is too large to convert" : "O arquivo é muito grande para converter", + "Destination does not match conversion extension" : "O destino não corresponde à extensão de conversão", "Could not convert file" : "Não foi possível converter o arquivo", "Destination does not exist" : "Destino não existe", "Destination is not creatable" : "Destino não pode ser criado", @@ -103,6 +104,8 @@ OC.L10N.register( "Failed to create file from template" : "Falha ao criar arquivo do modelo ", "Templates" : "Modelos ", "Storage %s cannot be moved" : "O armazenamento %s não pode ser movido", + "Moving a share (%s) into a shared folder is not allowed" : "Não é permitido mover um compartilhamento (%s) para uma pasta compartilhada", + "Moving a storage (%s) into a shared folder is not allowed" : "Não é permitido mover um armazenamento (%s) para uma pasta compartilhada", "Moving a share (%s) into another share (%s) is not allowed" : "Não é permitido mover um compartilhamento (%s) para outro compartilhamento (%s)", "Moving a share (%s) into another storage (%s) is not allowed" : "Não é permitido mover um compartilhamento (%s) para outro armazenamento (%s)", "Moving a storage (%s) into a share (%s) is not allowed" : "Não é permitido mover um armazenamento (%s) para compartilhamento (%s)", diff --git a/lib/l10n/pt_BR.json b/lib/l10n/pt_BR.json index 1203a493d97..1d0a4d2e40e 100644 --- a/lib/l10n/pt_BR.json +++ b/lib/l10n/pt_BR.json @@ -86,6 +86,7 @@ "Module with ID: %s does not exist. Please enable it in your apps settings or contact your administrator." : "O módulo com a ID: %s não existe. Por favor, habilite-o nas configurações de seu aplicativo ou contacte o administrador.", "No file conversion providers available" : "Não há provedores de conversão de arquivos disponíveis", "File is too large to convert" : "O arquivo é muito grande para converter", + "Destination does not match conversion extension" : "O destino não corresponde à extensão de conversão", "Could not convert file" : "Não foi possível converter o arquivo", "Destination does not exist" : "Destino não existe", "Destination is not creatable" : "Destino não pode ser criado", @@ -101,6 +102,8 @@ "Failed to create file from template" : "Falha ao criar arquivo do modelo ", "Templates" : "Modelos ", "Storage %s cannot be moved" : "O armazenamento %s não pode ser movido", + "Moving a share (%s) into a shared folder is not allowed" : "Não é permitido mover um compartilhamento (%s) para uma pasta compartilhada", + "Moving a storage (%s) into a shared folder is not allowed" : "Não é permitido mover um armazenamento (%s) para uma pasta compartilhada", "Moving a share (%s) into another share (%s) is not allowed" : "Não é permitido mover um compartilhamento (%s) para outro compartilhamento (%s)", "Moving a share (%s) into another storage (%s) is not allowed" : "Não é permitido mover um compartilhamento (%s) para outro armazenamento (%s)", "Moving a storage (%s) into a share (%s) is not allowed" : "Não é permitido mover um armazenamento (%s) para compartilhamento (%s)", diff --git a/lib/l10n/sk.js b/lib/l10n/sk.js index ddd31dde93a..4415a806550 100644 --- a/lib/l10n/sk.js +++ b/lib/l10n/sk.js @@ -38,6 +38,7 @@ OC.L10N.register( "Server version %s or higher is required." : "Je vyžadovaná verzia servera %s alebo vyššia.", "Server version %s or lower is required." : "Je vyžadovaná verzia servera %s alebo nižšia.", "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený účet musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu.", + "Your current IP address doesn't allow you to perform admin actions" : "Vaša aktuálna adresa IP vám neumožňuje vykonávať akcie správcu", "Logged in account must be an admin or sub admin" : "Prihlásený účet musí byť správcom alebo sub správcom.", "Logged in account must be an admin" : "Prihlásený účet musí byť správcom", "Wiping of device %s has started" : "Začalo sa mazanie zariadenia %s", @@ -155,6 +156,7 @@ OC.L10N.register( "Oracle connection could not be established" : "Nie je možné pripojiť sa k Oracle", "Oracle Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre Oracle databázu je neplatné", "PostgreSQL Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre PostgreSQL databázu je neplatné", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X nie je podporovaný a %s nebude správne fungovať na tejto platforme. Použitie na vlastné riziko!", "For the best results, please consider using a GNU/Linux server instead." : "Pre dosiahnutie najlepších výsledkov, prosím zvážte použitie GNU/Linux servera.", "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Zdá sa, že táto inštancia %s beží v 32-bitovom prostredí PHP a v php.ini bola nastavená voľba open_basedir. To bude zdrojom problémov so súbormi väčšími ako 4GB a dôrazne sa neodporúča.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Prosím, odstráňte nastavenie open_basedir vo vašom php.ini alebo prejdite na 64-bit PHP.", diff --git a/lib/l10n/sk.json b/lib/l10n/sk.json index 626188a2538..057936c2a89 100644 --- a/lib/l10n/sk.json +++ b/lib/l10n/sk.json @@ -36,6 +36,7 @@ "Server version %s or higher is required." : "Je vyžadovaná verzia servera %s alebo vyššia.", "Server version %s or lower is required." : "Je vyžadovaná verzia servera %s alebo nižšia.", "Logged in account must be an admin, a sub admin or gotten special right to access this setting" : "Prihlásený účet musí byť správcom, podadministrátorom alebo musí mať špeciálne právo na prístup k tomuto nastaveniu.", + "Your current IP address doesn't allow you to perform admin actions" : "Vaša aktuálna adresa IP vám neumožňuje vykonávať akcie správcu", "Logged in account must be an admin or sub admin" : "Prihlásený účet musí byť správcom alebo sub správcom.", "Logged in account must be an admin" : "Prihlásený účet musí byť správcom", "Wiping of device %s has started" : "Začalo sa mazanie zariadenia %s", @@ -153,6 +154,7 @@ "Oracle connection could not be established" : "Nie je možné pripojiť sa k Oracle", "Oracle Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre Oracle databázu je neplatné", "PostgreSQL Login and/or password not valid" : "Prihlasovacie meno a/alebo heslo pre PostgreSQL databázu je neplatné", + "Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk!" : "Mac OS X nie je podporovaný a %s nebude správne fungovať na tejto platforme. Použitie na vlastné riziko!", "For the best results, please consider using a GNU/Linux server instead." : "Pre dosiahnutie najlepších výsledkov, prosím zvážte použitie GNU/Linux servera.", "It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Zdá sa, že táto inštancia %s beží v 32-bitovom prostredí PHP a v php.ini bola nastavená voľba open_basedir. To bude zdrojom problémov so súbormi väčšími ako 4GB a dôrazne sa neodporúča.", "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Prosím, odstráňte nastavenie open_basedir vo vašom php.ini alebo prejdite na 64-bit PHP.", diff --git a/lib/l10n/sr@latin.js b/lib/l10n/sr@latin.js index 3b65c71f694..0042ab270b7 100644 --- a/lib/l10n/sr@latin.js +++ b/lib/l10n/sr@latin.js @@ -8,6 +8,7 @@ OC.L10N.register( "seconds ago" : "pre par sekundi", "Filename contains at least one invalid character" : "Naziv fajla sadrži bar jedan nedozvoljen znak", "__language_name__" : "Srpski", + "Apps" : "Aplikacije", "Settings" : "Postavke", "Log out" : "Odjava", "Email" : "email", diff --git a/lib/l10n/sr@latin.json b/lib/l10n/sr@latin.json index c31a77690d0..857f80a066d 100644 --- a/lib/l10n/sr@latin.json +++ b/lib/l10n/sr@latin.json @@ -6,6 +6,7 @@ "seconds ago" : "pre par sekundi", "Filename contains at least one invalid character" : "Naziv fajla sadrži bar jedan nedozvoljen znak", "__language_name__" : "Srpski", + "Apps" : "Aplikacije", "Settings" : "Postavke", "Log out" : "Odjava", "Email" : "email", diff --git a/lib/private/App/AppManager.php b/lib/private/App/AppManager.php index 067cc89d674..740da31770d 100644 --- a/lib/private/App/AppManager.php +++ b/lib/private/App/AppManager.php @@ -812,6 +812,15 @@ class AppManager implements IAppManager { } /** + * Returns the installed versions of all apps + * + * @return array<string, string> + */ + public function getAppInstalledVersions(): array { + return $this->getAppConfig()->getAppInstalledVersions(); + } + + /** * Returns a list of apps incompatible with the given version * * @param string $version Nextcloud version as array of version components diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php index ad9299f01fd..1228b9c20e3 100644 --- a/lib/private/AppConfig.php +++ b/lib/private/AppConfig.php @@ -62,6 +62,9 @@ class AppConfig implements IAppConfig { /** @var array<array-key, array{entries: array<array-key, ConfigLexiconEntry>, strictness: ConfigLexiconStrictness}> ['app_id' => ['strictness' => ConfigLexiconStrictness, 'entries' => ['config_key' => ConfigLexiconEntry[]]] */ private array $configLexiconDetails = []; + /** @var ?array<string, string> */ + private ?array $appVersionsCache = null; + public function __construct( protected IDBConnection $connection, protected LoggerInterface $logger, @@ -1647,4 +1650,17 @@ class AppConfig implements IAppConfig { return $this->configLexiconDetails[$appId]; } + + /** + * Returns the installed versions of all apps + * + * @return array<string, string> + */ + public function getAppInstalledVersions(): array { + if ($this->appVersionsCache === null) { + /** @var array<string, string> */ + $this->appVersionsCache = $this->searchValues('installed_version', false, IAppConfig::VALUE_STRING); + } + return $this->appVersionsCache; + } } diff --git a/lib/private/AppFramework/Services/AppConfig.php b/lib/private/AppFramework/Services/AppConfig.php index 423a9eb5814..77c5ea4de0c 100644 --- a/lib/private/AppFramework/Services/AppConfig.php +++ b/lib/private/AppFramework/Services/AppConfig.php @@ -337,4 +337,13 @@ class AppConfig implements IAppConfig { public function deleteUserValue(string $userId, string $key): void { $this->config->deleteUserValue($userId, $this->appName, $key); } + + /** + * Returns the installed versions of all apps + * + * @return array<string, string> + */ + public function getAppInstalledVersions(): array { + return $this->appConfig->getAppInstalledVersions(); + } } diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php index 98d037e4dec..0d88200cff7 100644 --- a/lib/private/BackgroundJob/JobList.php +++ b/lib/private/BackgroundJob/JobList.php @@ -20,6 +20,7 @@ use OCP\IDBConnection; use Psr\Log\LoggerInterface; use function get_class; use function json_encode; +use function min; use function strlen; class JobList implements IJobList { @@ -209,6 +210,26 @@ class JobList implements IJobList { return $this->getNext($onlyTimeSensitive, $jobClasses); } + if ($job instanceof \OCP\BackgroundJob\TimedJob) { + $now = $this->timeFactory->getTime(); + $nextPossibleRun = $job->getLastRun() + $job->getInterval(); + if ($now < $nextPossibleRun) { + // This job is not ready for execution yet. Set timestamps to the future to avoid + // re-checking with every cron run. + // To avoid bugs that lead to jobs never executing again, the future timestamp is + // capped at two days. + $nextCheck = min($nextPossibleRun, $now + 48 * 3600); + $updateTimedJob = $this->connection->getQueryBuilder(); + $updateTimedJob->update('jobs') + ->set('last_checked', $updateTimedJob->createNamedParameter($nextCheck, IQueryBuilder::PARAM_INT)) + ->where($updateTimedJob->expr()->eq('id', $updateTimedJob->createParameter('jobid'))); + $updateTimedJob->setParameter('jobid', $row['id']); + $updateTimedJob->executeStatement(); + + return $this->getNext($onlyTimeSensitive, $jobClasses); + } + } + $update = $this->connection->getQueryBuilder(); $update->update('jobs') ->set('reserved_at', $update->createNamedParameter($this->timeFactory->getTime())) diff --git a/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php index b84dd61fc5f..16f63594f19 100644 --- a/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php +++ b/lib/private/Blurhash/Listener/GenerateBlurhashMetadata.php @@ -98,7 +98,7 @@ class GenerateBlurhashMetadata implements IEventListener { $newX = intval($currX * $newY / $currY); } - $newImage = imagescale($image, $newX, $newY); + $newImage = @imagescale($image, $newX, $newY); return ($newImage !== false) ? $newImage : $image; } diff --git a/lib/private/Calendar/CalendarEventBuilder.php b/lib/private/Calendar/CalendarEventBuilder.php index 9198d383ef9..1aa11c2436d 100644 --- a/lib/private/Calendar/CalendarEventBuilder.php +++ b/lib/private/Calendar/CalendarEventBuilder.php @@ -12,6 +12,7 @@ namespace OC\Calendar; use DateTimeInterface; use InvalidArgumentException; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Calendar\CalendarEventStatus; use OCP\Calendar\ICalendarEventBuilder; use OCP\Calendar\ICreateFromString; use Sabre\VObject\Component\VCalendar; @@ -23,6 +24,7 @@ class CalendarEventBuilder implements ICalendarEventBuilder { private ?string $summary = null; private ?string $description = null; private ?string $location = null; + private ?CalendarEventStatus $status = null; private ?array $organizer = null; private array $attendees = []; @@ -57,6 +59,11 @@ class CalendarEventBuilder implements ICalendarEventBuilder { return $this; } + public function setStatus(CalendarEventStatus $status): static { + $this->status = $status; + return $this; + } + public function setOrganizer(string $email, ?string $commonName = null): ICalendarEventBuilder { $this->organizer = [$email, $commonName]; return $this; @@ -91,6 +98,7 @@ class CalendarEventBuilder implements ICalendarEventBuilder { 'SUMMARY' => $this->summary, 'DTSTART' => $this->startDate, 'DTEND' => $this->endDate, + 'STATUS' => $this->status->value, ]; if ($this->description !== null) { $props['DESCRIPTION'] = $this->description; @@ -126,6 +134,13 @@ class CalendarEventBuilder implements ICalendarEventBuilder { $params = []; if ($cn !== null) { $params['CN'] = $cn; + if ($name === 'ORGANIZER') { + $params['ROLE'] = 'CHAIR'; + $params['PARTSTAT'] = 'ACCEPTED'; + } else { + $params['ROLE'] = 'REQ-PARTICIPANT'; + $params['PARTSTAT'] = 'NEEDS-ACTION'; + } } $vevent->add($name, $email, $params); } diff --git a/lib/private/Collaboration/Collaborators/MailPlugin.php b/lib/private/Collaboration/Collaborators/MailPlugin.php index 134970518bc..278ba19aa5a 100644 --- a/lib/private/Collaboration/Collaborators/MailPlugin.php +++ b/lib/private/Collaboration/Collaborators/MailPlugin.php @@ -100,6 +100,11 @@ class MailPlugin implements ISearchPlugin { $emailAddress = $emailAddressData['value']; $emailAddressType = $emailAddressData['type']; } + + if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) { + continue; + } + if (isset($contact['FN'])) { $displayName = $contact['FN'] . ' (' . $emailAddress . ')'; } diff --git a/lib/private/Files/Cache/CacheEntry.php b/lib/private/Files/Cache/CacheEntry.php index e9417c8012a..ab5bae316f4 100644 --- a/lib/private/Files/Cache/CacheEntry.php +++ b/lib/private/Files/Cache/CacheEntry.php @@ -110,6 +110,10 @@ class CacheEntry implements ICacheEntry { return $this->data['upload_time'] ?? null; } + public function getParentId(): int { + return $this->data['parent']; + } + public function getData() { return $this->data; } diff --git a/lib/private/Files/FilenameValidator.php b/lib/private/Files/FilenameValidator.php index fde45068df7..b1979789ec8 100644 --- a/lib/private/Files/FilenameValidator.php +++ b/lib/private/Files/FilenameValidator.php @@ -127,9 +127,6 @@ class FilenameValidator implements IFilenameValidator { if (empty($this->forbiddenCharacters)) { // Get always forbidden characters $forbiddenCharacters = str_split(\OCP\Constants::FILENAME_INVALID_CHARS); - if ($forbiddenCharacters === false) { - $forbiddenCharacters = []; - } // Get admin defined invalid characters $additionalChars = $this->config->getSystemValue('forbidden_filename_characters', []); @@ -231,7 +228,8 @@ class FilenameValidator implements IFilenameValidator { return false; } - protected function checkForbiddenName($filename): void { + protected function checkForbiddenName(string $filename): void { + $filename = mb_strtolower($filename); if ($this->isForbidden($filename)) { throw new ReservedWordException($this->l10n->t('"%1$s" is a forbidden file or folder name.', [$filename])); } @@ -295,6 +293,6 @@ class FilenameValidator implements IFilenameValidator { $values = $fallback; } - return array_map('mb_strtolower', $values); + return array_map(mb_strtolower(...), $values); } }; diff --git a/lib/private/Files/ObjectStore/S3.php b/lib/private/Files/ObjectStore/S3.php index 41ab75caf45..e970fb6ac14 100644 --- a/lib/private/Files/ObjectStore/S3.php +++ b/lib/private/Files/ObjectStore/S3.php @@ -3,14 +3,16 @@ * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OC\Files\ObjectStore; use Aws\Result; use Exception; use OCP\Files\ObjectStore\IObjectStore; +use OCP\Files\ObjectStore\IObjectStoreMetaData; use OCP\Files\ObjectStore\IObjectStoreMultiPartUpload; -class S3 implements IObjectStore, IObjectStoreMultiPartUpload { +class S3 implements IObjectStore, IObjectStoreMultiPartUpload, IObjectStoreMetaData { use S3ConnectionTrait; use S3ObjectTrait; @@ -61,7 +63,7 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload { 'Key' => $urn, 'UploadId' => $uploadId, 'MaxParts' => 1000, - 'PartNumberMarker' => $partNumberMarker + 'PartNumberMarker' => $partNumberMarker, ] + $this->getSSECParameters()); $parts = array_merge($parts, $result->get('Parts') ?? []); $isTruncated = $result->get('IsTruncated'); @@ -89,7 +91,41 @@ class S3 implements IObjectStore, IObjectStoreMultiPartUpload { $this->getConnection()->abortMultipartUpload([ 'Bucket' => $this->bucket, 'Key' => $urn, - 'UploadId' => $uploadId + 'UploadId' => $uploadId, ]); } + + public function getObjectMetaData(string $urn): array { + $object = $this->getConnection()->headObject([ + 'Bucket' => $this->bucket, + 'Key' => $urn + ] + $this->getSSECParameters())->toArray(); + return [ + 'mtime' => $object['LastModified'], + 'etag' => trim($object['ETag'], '"'), + 'size' => (int)($object['Size'] ?? $object['ContentLength']), + ]; + } + + public function listObjects(string $prefix = ''): \Iterator { + $results = $this->getConnection()->getPaginator('ListObjectsV2', [ + 'Bucket' => $this->bucket, + 'Prefix' => $prefix, + ] + $this->getSSECParameters()); + + foreach ($results as $result) { + if (is_array($result['Contents'])) { + foreach ($result['Contents'] as $object) { + yield [ + 'urn' => basename($object['Key']), + 'metadata' => [ + 'mtime' => $object['LastModified'], + 'etag' => trim($object['ETag'], '"'), + 'size' => (int)($object['Size'] ?? $object['ContentLength']), + ], + ]; + } + } + } + } } diff --git a/lib/private/Repair/RepairMimeTypes.php b/lib/private/Repair/RepairMimeTypes.php index 715f7623440..28b22ec3f20 100644 --- a/lib/private/Repair/RepairMimeTypes.php +++ b/lib/private/Repair/RepairMimeTypes.php @@ -338,6 +338,21 @@ class RepairMimeTypes implements IRepairStep { } /** + * @throws Exception + * @since 32.0.0 + */ + private function introduceMusicxmlType(): IResult|int|null { + $updatedMimetypes = [ + 'mxl' => 'application/vnd.recordare.musicxml', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + ]; + + return $this->updateMimetypes($updatedMimetypes); + } + + + + /** * Check if there are any migrations available * * @throws Exception @@ -447,6 +462,10 @@ class RepairMimeTypes implements IRepairStep { $out->info('Fixed zst mime type'); } + if (version_compare($mimeTypeVersion, '32.0.0.0', '<') && $this->introduceMusicxmlType()) { + $out->info('Fixed musicxml mime type'); + } + if (!$this->dryRun) { $this->appConfig->setValueString('files', 'mimetype_version', $serverVersion); } diff --git a/lib/private/Server.php b/lib/private/Server.php index 523fc7b9914..4d79fefd261 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -607,10 +607,10 @@ class Server extends ServerContainer implements IServerContainer { if ($config->getValue('installed', false) && !(defined('PHPUNIT_RUN') && PHPUNIT_RUN)) { $logQuery = $config->getValue('log_query'); - $prefixClosure = function () use ($logQuery, $serverVersion) { + $prefixClosure = function () use ($logQuery, $serverVersion): ?string { if (!$logQuery) { try { - $v = \OC_App::getAppVersions(); + $v = \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions(); } catch (\Doctrine\DBAL\Exception $e) { // Database service probably unavailable // Probably related to https://github.com/nextcloud/server/issues/37424 @@ -867,15 +867,15 @@ class Server extends ServerContainer implements IServerContainer { $this->registerDeprecatedAlias('IntegrityCodeChecker', Checker::class); $this->registerService(Checker::class, function (ContainerInterface $c) { - // IConfig and IAppManager requires a working database. This code - // might however be called when ownCloud is not yet setup. + // IConfig requires a working database. This code + // might however be called when Nextcloud is not yet setup. if (\OC::$server->get(SystemConfig::class)->getValue('installed', false)) { $config = $c->get(\OCP\IConfig::class); $appConfig = $c->get(\OCP\IAppConfig::class); } else { - $config = $appConfig = $appManager = null; + $config = null; + $appConfig = null; } - $appManager = $c->get(IAppManager::class); return new Checker( $c->get(ServerVersion::class), @@ -885,7 +885,7 @@ class Server extends ServerContainer implements IServerContainer { $config, $appConfig, $c->get(ICacheFactory::class), - $appManager, + $c->get(IAppManager::class), $c->get(IMimeTypeDetector::class) ); }); diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index c9e5bf96cb7..a257bc4f7b5 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -322,10 +322,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USERGROUP))) ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient))) ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )) + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))) ->executeQuery(); $data = $stmt->fetch(); @@ -383,10 +380,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv ], IQueryBuilder::PARAM_INT_ARRAY) ) ) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )) + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))) ->orderBy('id'); $cursor = $qb->executeQuery(); @@ -449,10 +443,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USERGROUP))) ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient))) ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )) + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))) ->executeQuery(); $data = $stmt->fetch(); @@ -565,10 +556,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USERGROUP))) ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient))) ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId()))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )) + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))) ->setMaxResults(1) ->executeQuery(); @@ -621,16 +609,9 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv 'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime', 'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum') ->from('share', 's') - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )); + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); - $qb->andWhere($qb->expr()->orX( - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USER)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_LINK)) - )); + $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. @@ -693,10 +674,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv $qb = $this->dbConn->getQueryBuilder(); $qb->select('*') ->from('share') - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )); + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType))); @@ -756,10 +734,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv ], IQueryBuilder::PARAM_INT_ARRAY) ) ) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )); + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); $cursor = $qb->executeQuery(); $data = $cursor->fetch(); @@ -795,17 +770,8 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv $cursor = $qb->select('*') ->from('share') ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) - ->andWhere( - $qb->expr()->orX( - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USER)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_LINK)), - ) - ) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )) + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter([IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK], IQueryBuilder::PARAM_INT_ARRAY))) + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))) ->orderBy('id', 'ASC') ->executeQuery(); @@ -874,10 +840,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USER))) ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )); + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); // Filter by node if provided if ($node !== null) { @@ -942,10 +905,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv $groups, IQueryBuilder::PARAM_STR_ARRAY ))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )); + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); $cursor = $qb->executeQuery(); while ($data = $cursor->fetch()) { @@ -988,10 +948,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv ->from('share') ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_LINK))) ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )) + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))) ->executeQuery(); $data = $cursor->fetch(); @@ -1090,7 +1047,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv ->from('share') ->where($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))) ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USERGROUP))) - ->andWhere($qb->expr()->in('item_type', [$qb->createNamedParameter('file'), $qb->createNamedParameter('folder')])); + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); // this is called with either all group shares or one group share. // for all shares it's easier to just only search by share_with, @@ -1147,10 +1104,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv */ $qb->where( $qb->expr()->andX( - $qb->expr()->orX( - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USERGROUP)) - ), + $qb->expr()->in('share_type', $qb->createNamedParameter([IShare::TYPE_GROUP, IShare::TYPE_USERGROUP], IQueryBuilder::PARAM_INT_ARRAY)), $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)) ) ); @@ -1323,26 +1277,19 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv $qb = $this->dbConn->getQueryBuilder(); - $or = $qb->expr()->orX( - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USER)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_LINK)) - ); + $shareTypes = [IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK]; if ($currentAccess) { - $or->add($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_USERGROUP))); + $shareTypes[] = IShare::TYPE_USERGROUP; } $qb->select('id', 'parent', 'share_type', 'share_with', 'file_source', 'file_target', 'permissions') ->from('share') ->where( - $or + $qb->expr()->in('share_type', $qb->createNamedParameter($shareTypes, IQueryBuilder::PARAM_INT_ARRAY)) ) ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) - ->andWhere($qb->expr()->orX( - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) - )); + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); // Ensure accepted is true for user and usergroup type $qb->andWhere( @@ -1659,13 +1606,7 @@ class DefaultShareProvider implements IShareProviderWithNotification, IShareProv $qb->select('*') ->from('share') - ->where( - $qb->expr()->orX( - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_USER)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_GROUP)), - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share\IShare::TYPE_LINK)) - ) - ); + ->where($qb->expr()->in('share_type', $qb->createNamedParameter([IShare::TYPE_USER, IShare::TYPE_GROUP, IShare::TYPE_LINK], IQueryBuilder::PARAM_INT_ARRAY))); $cursor = $qb->executeQuery(); while ($data = $cursor->fetch()) { diff --git a/lib/private/SystemTag/SystemTagObjectMapper.php b/lib/private/SystemTag/SystemTagObjectMapper.php index 09a7ce1a6ed..3881336bf37 100644 --- a/lib/private/SystemTag/SystemTagObjectMapper.php +++ b/lib/private/SystemTag/SystemTagObjectMapper.php @@ -284,6 +284,9 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { * {@inheritdoc} */ public function setObjectIdsForTag(string $tagId, string $objectType, array $objectIds): void { + $currentObjectIds = $this->getObjectIdsForTags($tagId, $objectType); + $removedObjectIds = array_diff($currentObjectIds, $objectIds); + $addedObjectIds = array_diff($objectIds, $currentObjectIds); $this->connection->beginTransaction(); $query = $this->connection->getQueryBuilder(); $query->delete(self::RELATION_TABLE) @@ -292,6 +295,15 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { ->executeStatement(); $this->connection->commit(); + foreach ($removedObjectIds as $objectId) { + $this->dispatcher->dispatch(MapperEvent::EVENT_UNASSIGN, new MapperEvent( + MapperEvent::EVENT_UNASSIGN, + $objectType, + (string)$objectId, + [(int)$tagId] + )); + } + if (empty($objectIds)) { return; } @@ -312,6 +324,14 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { $this->updateEtagForTags([$tagId]); $this->connection->commit(); + foreach ($addedObjectIds as $objectId) { + $this->dispatcher->dispatch(MapperEvent::EVENT_ASSIGN, new MapperEvent( + MapperEvent::EVENT_ASSIGN, + $objectType, + (string)$objectId, + [(int)$tagId] + )); + } } /** diff --git a/lib/private/Template/functions.php b/lib/private/Template/functions.php index 4354d0d8fce..957aaee2237 100644 --- a/lib/private/Template/functions.php +++ b/lib/private/Template/functions.php @@ -13,7 +13,10 @@ use OCP\IURLGenerator; use OCP\Server; use OCP\Util; -function p(string $string): void { +/** + * @param string $string + */ +function p($string): void { print(Util::sanitizeHTML($string)); } diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php index 9c1d7ca1d2c..01d22edc0fb 100644 --- a/lib/private/TemplateLayout.php +++ b/lib/private/TemplateLayout.php @@ -48,6 +48,7 @@ class TemplateLayout { private InitialStateService $initialState, private INavigationManager $navigationManager, private ITemplateManager $templateManager, + private ServerVersion $serverVersion, ) { } @@ -204,8 +205,8 @@ class TemplateLayout { if ($this->config->getSystemValueBool('installed', false)) { if (empty(self::$versionHash)) { - $v = \OC_App::getAppVersions(); - $v['core'] = implode('.', \OCP\Util::getVersion()); + $v = $this->appManager->getAppInstalledVersions(); + $v['core'] = implode('.', $this->serverVersion->getVersion()); self::$versionHash = substr(md5(implode(',', $v)), 0, 8); } } else { @@ -220,7 +221,7 @@ class TemplateLayout { // this is on purpose outside of the if statement below so that the initial state is prefilled (done in the getConfig() call) // see https://github.com/nextcloud/server/pull/22636 for details $jsConfigHelper = new JSConfigHelper( - \OCP\Server::get(ServerVersion::class), + $this->serverVersion, \OCP\Util::getL10N('lib'), \OCP\Server::get(Defaults::class), $this->appManager, diff --git a/lib/private/User/Database.php b/lib/private/User/Database.php index 4252f57ba36..31488247939 100644 --- a/lib/private/User/Database.php +++ b/lib/private/User/Database.php @@ -487,9 +487,12 @@ class Database extends ABackend implements $query = $dbConn->getQueryBuilder(); $query->select($query->func()->count('uid')) ->from($this->table); - $result = $query->executeQuery(); + $result = $query->executeQuery()->fetchOne(); + if ($result === false) { + return false; + } - return $result->fetchOne(); + return (int)$result; } /** diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php index 62a7b39be16..152fb08eeeb 100644 --- a/lib/private/User/Manager.php +++ b/lib/private/User/Manager.php @@ -628,30 +628,14 @@ class Manager extends PublicEmitter implements IUserManager { return $result; } - /** - * @param \Closure $callback - * @psalm-param \Closure(\OCP\IUser):?bool $callback - * @since 11.0.0 - */ public function callForSeenUsers(\Closure $callback) { - $limit = 1000; - $offset = 0; - do { - $userIds = $this->getSeenUserIds($limit, $offset); - $offset += $limit; - foreach ($userIds as $userId) { - foreach ($this->backends as $backend) { - if ($backend->userExists($userId)) { - $user = $this->getUserObject($userId, $backend, false); - $return = $callback($user); - if ($return === false) { - return; - } - break; - } - } + $users = $this->getSeenUsers(); + foreach ($users as $user) { + $return = $callback($user); + if ($return === false) { + return; } - } while (count($userIds) >= $limit); + } } /** @@ -827,4 +811,30 @@ class Manager extends PublicEmitter implements IUserManager { public function getDisplayNameCache(): DisplayNameCache { return $this->displayNameCache; } + + /** + * Gets the list of users sorted by lastLogin, from most recent to least recent + * + * @param int $offset from which offset to fetch + * @return \Iterator<IUser> list of user IDs + * @since 30.0.0 + */ + public function getSeenUsers(int $offset = 0): \Iterator { + $limit = 1000; + + do { + $userIds = $this->getSeenUserIds($limit, $offset); + $offset += $limit; + + foreach ($userIds as $userId) { + foreach ($this->backends as $backend) { + if ($backend->userExists($userId)) { + $user = $this->getUserObject($userId, $backend, false); + yield $user; + break; + } + } + } + } while (count($userIds) === $limit); + } } diff --git a/lib/private/legacy/OC_App.php b/lib/private/legacy/OC_App.php index 7fee946b776..ecceafa65b3 100644 --- a/lib/private/legacy/OC_App.php +++ b/lib/private/legacy/OC_App.php @@ -456,10 +456,9 @@ class OC_App { /** * List all supported apps * - * @return array + * @deprecated 32.0.0 Use \OCP\Support\Subscription\IRegistry::delegateGetSupportedApps instead */ public function getSupportedApps(): array { - /** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */ $subscriptionRegistry = \OCP\Server::get(\OCP\Support\Subscription\IRegistry::class); $supportedApps = $subscriptionRegistry->delegateGetSupportedApps(); return $supportedApps; @@ -643,16 +642,10 @@ class OC_App { /** * get the installed version of all apps + * @deprecated 32.0.0 Use IAppManager::getAppInstalledVersions or IAppConfig::getAppInstalledVersions instead */ - public static function getAppVersions() { - static $versions; - - if (!$versions) { - /** @var IAppConfig $appConfig */ - $appConfig = \OCP\Server::get(IAppConfig::class); - $versions = $appConfig->searchValues('installed_version'); - } - return $versions; + public static function getAppVersions(): array { + return \OCP\Server::get(IAppConfig::class)->getAppInstalledVersions(); } /** diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index fa35819b779..67ef2d796be 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -52,6 +52,14 @@ interface IAppManager { public function getAppVersion(string $appId, bool $useCache = true): string; /** + * Returns the installed version of all apps + * + * @return array<string, string> + * @since 32.0.0 + */ + public function getAppInstalledVersions(): array; + + /** * Returns the app icon or null if none is found * * @param string $appId diff --git a/lib/public/BackgroundJob/TimedJob.php b/lib/public/BackgroundJob/TimedJob.php index 85ca34665b4..296bd9e4e32 100644 --- a/lib/public/BackgroundJob/TimedJob.php +++ b/lib/public/BackgroundJob/TimedJob.php @@ -33,6 +33,15 @@ abstract class TimedJob extends Job { } /** + * Get the interval [seconds] for the job + * + * @since 32.0.0 + */ + public function getInterval(): int { + return $this->interval; + } + + /** * Whether the background job is time sensitive and needs to run soon after * the scheduled interval, of if it is okay to be delayed until a later time. * diff --git a/lib/public/Calendar/CalendarEventStatus.php b/lib/public/Calendar/CalendarEventStatus.php new file mode 100644 index 00000000000..5e070545758 --- /dev/null +++ b/lib/public/Calendar/CalendarEventStatus.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCP\Calendar; + +/** + * The status of a calendar event. + * + * @since 32.0.0 + */ +enum CalendarEventStatus: string { + case TENTATIVE = 'TENTATIVE'; + case CONFIRMED = 'CONFIRMED'; + case CANCELLED = 'CANCELLED'; +}; diff --git a/lib/public/Calendar/ICalendarEventBuilder.php b/lib/public/Calendar/ICalendarEventBuilder.php index 8afc817a61e..c99dc60cc8c 100644 --- a/lib/public/Calendar/ICalendarEventBuilder.php +++ b/lib/public/Calendar/ICalendarEventBuilder.php @@ -66,6 +66,13 @@ interface ICalendarEventBuilder { public function setLocation(string $location): self; /** + * Set the event status. + * + * @since 32.0.0 + */ + public function setStatus(CalendarEventStatus $status): static; + + /** * Set the event organizer. * This property is required if attendees are added! * diff --git a/lib/public/Files/Cache/ICacheEntry.php b/lib/public/Files/Cache/ICacheEntry.php index 11d91e74105..28e673071fd 100644 --- a/lib/public/Files/Cache/ICacheEntry.php +++ b/lib/public/Files/Cache/ICacheEntry.php @@ -161,4 +161,12 @@ interface ICacheEntry extends ArrayAccess { * @since 25.0.0 */ public function getUnencryptedSize(): int; + + /** + * Get the file id of the parent folder + * + * @return int + * @since 32.0.0 + */ + public function getParentId(): int; } diff --git a/lib/public/Files/ObjectStore/IObjectStoreMetaData.php b/lib/public/Files/ObjectStore/IObjectStoreMetaData.php new file mode 100644 index 00000000000..8359e83f573 --- /dev/null +++ b/lib/public/Files/ObjectStore/IObjectStoreMetaData.php @@ -0,0 +1,38 @@ +<?php + +/** + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ +namespace OCP\Files\ObjectStore; + +/** + * Interface IObjectStoreMetaData + * + * @psalm-type ObjectMetaData = array{mtime?: \DateTime, etag?: string, size?: int, mimetype?: string, filename?: string} + * + * @since 32.0.0 + */ +interface IObjectStoreMetaData { + /** + * Get metadata for an object. + * + * @param string $urn + * @return ObjectMetaData + * + * @since 32.0.0 + */ + public function getObjectMetaData(string $urn): array; + + /** + * List all objects in the object store. + * + * If the object store implementation can do it efficiently, the metadata for each object is also included. + * + * @param string $prefix + * @return \Iterator<array{urn: string, metadata: ?ObjectMetaData}> + * + * @since 32.0.0 + */ + public function listObjects(string $prefix = ''): \Iterator; +} diff --git a/lib/public/IAppConfig.php b/lib/public/IAppConfig.php index d4d5c1c09c7..f4210793476 100644 --- a/lib/public/IAppConfig.php +++ b/lib/public/IAppConfig.php @@ -507,4 +507,12 @@ interface IAppConfig { * @deprecated 29.0.0 Use {@see getAllValues()} or {@see searchValues()} */ public function getFilteredValues($app); + + /** + * Returns the installed version of all apps + * + * @return array<string, string> + * @since 32.0.0 + */ + public function getAppInstalledVersions(): array; } diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php index 50eaa9c98b7..3fd3234818e 100644 --- a/lib/public/IUserManager.php +++ b/lib/public/IUserManager.php @@ -231,4 +231,15 @@ interface IUserManager { * @since 30.0.0 */ public function getLastLoggedInUsers(?int $limit = null, int $offset = 0, string $search = ''): array; + + /** + * Gets the list of users. + * An iterator is returned allowing the caller to stop the iteration at any time. + * The offset argument allows the caller to continue the iteration at a specific offset. + * + * @param int $offset from which offset to fetch + * @return \Iterator<IUser> list of IUser object + * @since 32.0.0 + */ + public function getSeenUsers(int $offset = 0): \Iterator; } diff --git a/lib/public/TaskProcessing/TaskTypes/AudioToText.php b/lib/public/TaskProcessing/TaskTypes/AudioToText.php index 3f23d00d41b..1982d4c9d28 100644 --- a/lib/public/TaskProcessing/TaskTypes/AudioToText.php +++ b/lib/public/TaskProcessing/TaskTypes/AudioToText.php @@ -34,7 +34,7 @@ class AudioToText implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/ContextAgentInteraction.php b/lib/public/TaskProcessing/TaskTypes/ContextAgentInteraction.php index f5bef6b48e3..937c13bbba5 100644 --- a/lib/public/TaskProcessing/TaskTypes/ContextAgentInteraction.php +++ b/lib/public/TaskProcessing/TaskTypes/ContextAgentInteraction.php @@ -31,7 +31,7 @@ class ContextAgentInteraction implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } /** diff --git a/lib/public/TaskProcessing/TaskTypes/ContextWrite.php b/lib/public/TaskProcessing/TaskTypes/ContextWrite.php index 36ee8f24d3f..fd5c6a8f58b 100644 --- a/lib/public/TaskProcessing/TaskTypes/ContextWrite.php +++ b/lib/public/TaskProcessing/TaskTypes/ContextWrite.php @@ -34,7 +34,7 @@ class ContextWrite implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/GenerateEmoji.php b/lib/public/TaskProcessing/TaskTypes/GenerateEmoji.php index 89ddfa58072..2cb22b3b455 100644 --- a/lib/public/TaskProcessing/TaskTypes/GenerateEmoji.php +++ b/lib/public/TaskProcessing/TaskTypes/GenerateEmoji.php @@ -34,7 +34,7 @@ class GenerateEmoji implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToImage.php b/lib/public/TaskProcessing/TaskTypes/TextToImage.php index a4b8070e8bb..ed956d244a1 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToImage.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToImage.php @@ -34,7 +34,7 @@ class TextToImage implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToText.php b/lib/public/TaskProcessing/TaskTypes/TextToText.php index 92eaf5629e8..c39d435688a 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToText.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToText.php @@ -34,7 +34,7 @@ class TextToText implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextChangeTone.php b/lib/public/TaskProcessing/TaskTypes/TextToTextChangeTone.php index bab60976454..0ea4575a187 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextChangeTone.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextChangeTone.php @@ -31,7 +31,7 @@ class TextToTextChangeTone implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } /** diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextChat.php b/lib/public/TaskProcessing/TaskTypes/TextToTextChat.php index e9169f64837..9cf1e7ef3ce 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextChat.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextChat.php @@ -34,7 +34,7 @@ class TextToTextChat implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextChatWithTools.php b/lib/public/TaskProcessing/TaskTypes/TextToTextChatWithTools.php index e09211e940b..ebc660a3af9 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextChatWithTools.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextChatWithTools.php @@ -31,7 +31,7 @@ class TextToTextChatWithTools implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } /** diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextFormalization.php b/lib/public/TaskProcessing/TaskTypes/TextToTextFormalization.php index 81eff28f3e9..70e38f78c0b 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextFormalization.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextFormalization.php @@ -34,7 +34,7 @@ class TextToTextFormalization implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php b/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php index 9907a3605b2..dde4ea03042 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextHeadline.php @@ -34,7 +34,7 @@ class TextToTextHeadline implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextProofread.php b/lib/public/TaskProcessing/TaskTypes/TextToTextProofread.php index 09f2111e22e..508794490be 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextProofread.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextProofread.php @@ -33,7 +33,7 @@ class TextToTextProofread implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextReformulation.php b/lib/public/TaskProcessing/TaskTypes/TextToTextReformulation.php index 44c1fddc73c..120f5316aee 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextReformulation.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextReformulation.php @@ -34,7 +34,7 @@ class TextToTextReformulation implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextSimplification.php b/lib/public/TaskProcessing/TaskTypes/TextToTextSimplification.php index 580b9d92755..d107e584e3a 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextSimplification.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextSimplification.php @@ -34,7 +34,7 @@ class TextToTextSimplification implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php b/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php index 8b00c64f915..601b478c0bd 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextSummary.php @@ -33,7 +33,7 @@ class TextToTextSummary implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php b/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php index a08ec6d2c0f..943cc2e2fd4 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextTopics.php @@ -34,7 +34,7 @@ class TextToTextTopics implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php b/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php index 11b71ec3eb2..a02550226ee 100644 --- a/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php +++ b/lib/public/TaskProcessing/TaskTypes/TextToTextTranslate.php @@ -34,7 +34,7 @@ class TextToTextTranslate implements ITaskType { public function __construct( IFactory $l10nFactory, ) { - $this->l = $l10nFactory->get('core'); + $this->l = $l10nFactory->get('lib'); } diff --git a/lib/public/Template.php b/lib/public/Template.php index 20783d31cb6..3b31ee10a54 100644 --- a/lib/public/Template.php +++ b/lib/public/Template.php @@ -7,6 +7,8 @@ */ namespace OCP; +use OCP\Template\ITemplate; + /* * We have to require the functions file because this class contains aliases to the functions */ @@ -19,7 +21,7 @@ require_once __DIR__ . '/../private/Template/functions.php'; * @since 8.0.0 * @deprecated 32.0.0 Use \OCP\Template\ITemplateManager instead */ -class Template extends \OC_Template { +class Template extends \OC_Template implements ITemplate { /** * Make OC_Helper::imagePath available as a simple function * |