aboutsummaryrefslogtreecommitdiffstats
path: root/apps/theming/lib/Jobs
diff options
context:
space:
mode:
Diffstat (limited to 'apps/theming/lib/Jobs')
-rw-r--r--apps/theming/lib/Jobs/MigrateBackgroundImages.php44
-rw-r--r--apps/theming/lib/Jobs/RestoreBackgroundImageColor.php205
2 files changed, 213 insertions, 36 deletions
diff --git a/apps/theming/lib/Jobs/MigrateBackgroundImages.php b/apps/theming/lib/Jobs/MigrateBackgroundImages.php
index 62179e46a4b..62e58f5e722 100644
--- a/apps/theming/lib/Jobs/MigrateBackgroundImages.php
+++ b/apps/theming/lib/Jobs/MigrateBackgroundImages.php
@@ -3,25 +3,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2022 Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Theming\Jobs;
@@ -47,31 +30,20 @@ class MigrateBackgroundImages extends QueuedJob {
// will be saved in appdata/theming/global/
protected const STATE_FILE_NAME = '25_dashboard_to_theming_migration_users.json';
- private IAppDataFactory $appDataFactory;
- private IJobList $jobList;
- private IDBConnection $dbc;
- private IAppData $appData;
- private LoggerInterface $logger;
-
public function __construct(
ITimeFactory $time,
- IAppDataFactory $appDataFactory,
- IJobList $jobList,
- IDBConnection $dbc,
- IAppData $appData,
- LoggerInterface $logger
+ private IAppDataFactory $appDataFactory,
+ private IJobList $jobList,
+ private IDBConnection $dbc,
+ private IAppData $appData,
+ private LoggerInterface $logger,
) {
parent::__construct($time);
- $this->appDataFactory = $appDataFactory;
- $this->jobList = $jobList;
- $this->dbc = $dbc;
- $this->appData = $appData;
- $this->logger = $logger;
}
protected function run(mixed $argument): void {
if (!is_array($argument) || !isset($argument['stage'])) {
- throw new \Exception('Job '.self::class.' called with wrong argument');
+ throw new \Exception('Job ' . self::class . ' called with wrong argument');
}
switch ($argument['stage']) {
diff --git a/apps/theming/lib/Jobs/RestoreBackgroundImageColor.php b/apps/theming/lib/Jobs/RestoreBackgroundImageColor.php
new file mode 100644
index 00000000000..42662dacef2
--- /dev/null
+++ b/apps/theming/lib/Jobs/RestoreBackgroundImageColor.php
@@ -0,0 +1,205 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Theming\Jobs;
+
+use OCA\Theming\AppInfo\Application;
+use OCA\Theming\Service\BackgroundService;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\IJobList;
+use OCP\BackgroundJob\QueuedJob;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Files\NotPermittedException;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use Psr\Log\LoggerInterface;
+
+class RestoreBackgroundImageColor extends QueuedJob {
+
+ public const STAGE_PREPARE = 'prepare';
+ public const STAGE_EXECUTE = 'execute';
+ // will be saved in appdata/theming/global/
+ protected const STATE_FILE_NAME = '30_background_image_color_restoration.json';
+
+ public function __construct(
+ ITimeFactory $time,
+ private IConfig $config,
+ private IAppData $appData,
+ private IJobList $jobList,
+ private IDBConnection $dbc,
+ private LoggerInterface $logger,
+ private BackgroundService $service,
+ ) {
+ parent::__construct($time);
+ }
+
+ protected function run(mixed $argument): void {
+ if (!is_array($argument) || !isset($argument['stage'])) {
+ throw new \Exception('Job ' . self::class . ' called with wrong argument');
+ }
+
+ switch ($argument['stage']) {
+ case self::STAGE_PREPARE:
+ $this->runPreparation();
+ break;
+ case self::STAGE_EXECUTE:
+ $this->runMigration();
+ break;
+ default:
+ break;
+ }
+ }
+
+ protected function runPreparation(): void {
+ try {
+ $qb = $this->dbc->getQueryBuilder();
+ $qb2 = $this->dbc->getQueryBuilder();
+
+ $innerSQL = $qb2->select('userid')
+ ->from('preferences')
+ ->where($qb2->expr()->eq('configkey', $qb->createNamedParameter('background_color')));
+
+ // Get those users, that have a background_image set - not the default, but no background_color.
+ $result = $qb->selectDistinct('a.userid')
+ ->from('preferences', 'a')
+ ->leftJoin('a', $qb->createFunction('(' . $innerSQL->getSQL() . ')'), 'b', 'a.userid = b.userid')
+ ->where($qb2->expr()->eq('a.configkey', $qb->createNamedParameter('background_image')))
+ ->andWhere($qb2->expr()->neq('a.configvalue', $qb->createNamedParameter(BackgroundService::BACKGROUND_DEFAULT)))
+ ->andWhere($qb2->expr()->isNull('b.userid'))
+ ->executeQuery();
+
+ $userIds = $result->fetchAll(\PDO::FETCH_COLUMN);
+ $this->logger->info('Prepare to restore background information for {users} users', ['users' => count($userIds)]);
+ $this->storeUserIdsToProcess($userIds);
+ } catch (\Throwable $t) {
+ $this->jobList->add(self::class, ['stage' => self::STAGE_PREPARE]);
+ throw $t;
+ }
+ $this->jobList->add(self::class, ['stage' => self::STAGE_EXECUTE]);
+ }
+
+ /**
+ * @throws NotPermittedException
+ * @throws NotFoundException
+ */
+ protected function runMigration(): void {
+ $allUserIds = $this->readUserIdsToProcess();
+ $notSoFastMode = count($allUserIds) > 1000;
+
+ $userIds = array_slice($allUserIds, 0, 1000);
+ foreach ($userIds as $userId) {
+ $backgroundColor = $this->config->getUserValue($userId, Application::APP_ID, 'background_color');
+ if ($backgroundColor !== '') {
+ continue;
+ }
+
+ $background = $this->config->getUserValue($userId, Application::APP_ID, 'background_image');
+ switch ($background) {
+ case BackgroundService::BACKGROUND_DEFAULT:
+ $this->service->setDefaultBackground($userId);
+ break;
+ case BackgroundService::BACKGROUND_COLOR:
+ break;
+ case BackgroundService::BACKGROUND_CUSTOM:
+ $this->service->recalculateMeanColor($userId);
+ break;
+ default:
+ // shipped backgrounds
+ // do not alter primary color
+ $primary = $this->config->getUserValue($userId, Application::APP_ID, 'primary_color');
+ if (isset(BackgroundService::SHIPPED_BACKGROUNDS[$background])) {
+ $this->service->setShippedBackground($background, $userId);
+ } else {
+ $this->service->setDefaultBackground($userId);
+ }
+ // Restore primary
+ if ($primary !== '') {
+ $this->config->setUserValue($userId, Application::APP_ID, 'primary_color', $primary);
+ }
+ }
+ }
+
+ if ($notSoFastMode) {
+ $remainingUserIds = array_slice($allUserIds, 1000);
+ $this->storeUserIdsToProcess($remainingUserIds);
+ $this->jobList->add(self::class, ['stage' => self::STAGE_EXECUTE]);
+ } else {
+ $this->deleteStateFile();
+ }
+ }
+
+ /**
+ * @throws NotPermittedException
+ * @throws NotFoundException
+ */
+ protected function readUserIdsToProcess(): array {
+ $globalFolder = $this->appData->getFolder('global');
+ if ($globalFolder->fileExists(self::STATE_FILE_NAME)) {
+ $file = $globalFolder->getFile(self::STATE_FILE_NAME);
+ try {
+ $userIds = \json_decode($file->getContent(), true);
+ } catch (NotFoundException $e) {
+ $userIds = [];
+ }
+ if ($userIds === null) {
+ $userIds = [];
+ }
+ } else {
+ $userIds = [];
+ }
+ return $userIds;
+ }
+
+ /**
+ * @throws NotFoundException
+ */
+ protected function storeUserIdsToProcess(array $userIds): void {
+ $storableUserIds = \json_encode($userIds);
+ $globalFolder = $this->appData->getFolder('global');
+ try {
+ if ($globalFolder->fileExists(self::STATE_FILE_NAME)) {
+ $file = $globalFolder->getFile(self::STATE_FILE_NAME);
+ } else {
+ $file = $globalFolder->newFile(self::STATE_FILE_NAME);
+ }
+ $file->putContent($storableUserIds);
+ } catch (NotFoundException $e) {
+ } catch (NotPermittedException $e) {
+ $this->logger->warning('Lacking permissions to create {file}',
+ [
+ 'app' => 'theming',
+ 'file' => self::STATE_FILE_NAME,
+ 'exception' => $e,
+ ]
+ );
+ }
+ }
+
+ /**
+ * @throws NotFoundException
+ */
+ protected function deleteStateFile(): void {
+ $globalFolder = $this->appData->getFolder('global');
+ if ($globalFolder->fileExists(self::STATE_FILE_NAME)) {
+ $file = $globalFolder->getFile(self::STATE_FILE_NAME);
+ try {
+ $file->delete();
+ } catch (NotPermittedException $e) {
+ $this->logger->info('Could not delete {file} due to permissions. It is safe to delete manually inside data -> appdata -> theming -> global.',
+ [
+ 'app' => 'theming',
+ 'file' => $file->getName(),
+ 'exception' => $e,
+ ]
+ );
+ }
+ }
+ }
+}