Passed
Push — master ( 235c52...927bab )
by Daniel
30:30 queued 10s
created

Version010000From000908   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 27
eloc 111
c 2
b 0
f 0
dl 0
loc 222
ccs 0
cts 142
cp 0
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A migrateCustomThemes() 0 17 3
B migrateSystemTemplates() 0 34 6
A postSchemaChange() 0 14 1
A migrateCustomTemplates() 0 17 3
B migrateSystemThemes() 0 34 6
A __construct() 0 9 1
B migratePrivateWebsites() 0 43 7
1
<?php
2
/**
3
 * CMS Pico - Create websites using Pico CMS for Nextcloud.
4
 *
5
 * @copyright Copyright (c) 2019, Daniel Rudolf (<[email protected]>)
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
declare(strict_types=1);
24
25
namespace OCA\CMSPico\Migration;
26
27
use OCA\CMSPico\Db\CoreRequestBuilder;
28
use OCA\CMSPico\Files\FolderInterface;
29
use OCA\CMSPico\Model\Template;
30
use OCA\CMSPico\Model\Theme;
31
use OCA\CMSPico\Model\WebsiteCore;
32
use OCA\CMSPico\Service\ConfigService;
33
use OCA\CMSPico\Service\FileService;
34
use OCA\CMSPico\Service\PicoService;
35
use OCA\CMSPico\Service\TemplatesService;
36
use OCA\CMSPico\Service\ThemesService;
37
use OCP\IDBConnection;
38
use OCP\Migration\IOutput;
39
use OCP\Migration\SimpleMigrationStep;
40
41
class Version010000From000908 extends SimpleMigrationStep
42
{
43
	use MigrationTrait;
44
45
	/** @var IDBConnection */
46
	private $databaseConnection;
47
48
	/** @var ConfigService */
49
	private $configService;
50
51
	/** @var TemplatesService */
52
	private $templatesService;
53
54
	/** @var ThemesService */
55
	private $themesService;
56
57
	/** @var FileService */
58
	private $fileService;
59
60
	/**
61
	 * Version010000 constructor.
62
	 */
63
	public function __construct()
64
	{
65
		$this->setLogger(\OC::$server->getLogger());
66
67
		$this->databaseConnection = \OC::$server->getDatabaseConnection();
68
		$this->configService = \OC::$server->query(ConfigService::class);
69
		$this->templatesService = \OC::$server->query(TemplatesService::class);
70
		$this->themesService = \OC::$server->query(ThemesService::class);
71
		$this->fileService = \OC::$server->query(FileService::class);
72
	}
73
74
	/**
75
	 * @param IOutput  $output
76
	 * @param \Closure $schemaClosure
77
	 * @param array    $options
78
	 */
79
	public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options)
80
	{
81
		$this->setOutput($output);
82
83
		// migrate the app config of custom templates and themes
84
		$this->migrateCustomTemplates();
85
		$this->migrateCustomThemes();
86
87
		// migrate old copies of system templates and themes in Nextcloud's data dir
88
		$this->migrateSystemTemplates();
89
		$themesMigrationMap = $this->migrateSystemThemes();
90
91
		// migrate cms_pico_websites database table
92
		$this->migratePrivateWebsites($themesMigrationMap);
93
	}
94
95
	/**
96
	 * @return void
97
	 */
98
	private function migrateCustomTemplates()
99
	{
100
		$customTemplatesJson = $this->configService->getAppValue(ConfigService::CUSTOM_TEMPLATES);
101
		$customTemplates = $customTemplatesJson ? json_decode($customTemplatesJson, true) : [];
102
103
		$newCustomTemplates = [];
104
		foreach ($customTemplates as $templateName) {
105
			$this->logInfo('Migrating Pico CMS custom template "%s"', $templateName);
106
107
			$newCustomTemplates[$templateName] = [
108
				'name' => $templateName,
109
				'type' => Template::TYPE_CUSTOM,
110
				'compat' => true
111
			];
112
		}
113
114
		$this->configService->setAppValue(ConfigService::CUSTOM_TEMPLATES, json_encode($newCustomTemplates));
115
	}
116
117
	/**
118
	 * @return void
119
	 */
120
	private function migrateCustomThemes()
121
	{
122
		$customThemesJson = $this->configService->getAppValue(ConfigService::CUSTOM_THEMES);
123
		$customThemes = $customThemesJson ? json_decode($customThemesJson, true) : [];
124
125
		$newCustomThemes = [];
126
		foreach ($customThemes as $themeName) {
127
			$this->logInfo('Migrating Pico CMS custom theme "%s"', $themeName);
128
129
			$newCustomThemes[$themeName] = [
130
				'name' => $themeName,
131
				'type' => Theme::TYPE_CUSTOM,
132
				'compat' => true
133
			];
134
		}
135
136
		$this->configService->setAppValue(ConfigService::CUSTOM_THEMES, json_encode($newCustomThemes));
137
	}
138
139
	/**
140
	 * @return array<string,string>
141
	 */
142
	private function migrateSystemTemplates()
143
	{
144
		$systemTemplatesFolder = $this->fileService->getSystemFolder(PicoService::DIR_TEMPLATES);
145
		$systemTemplatesFolder->sync(FolderInterface::SYNC_SHALLOW);
146
147
		$customTemplatesFolder = $this->fileService->getAppDataFolder(PicoService::DIR_TEMPLATES);
148
		$customTemplatesFolder->sync(FolderInterface::SYNC_SHALLOW);
149
150
		$templateExistsClosure = function ($templateName) use ($systemTemplatesFolder, $customTemplatesFolder) {
151
			return ($systemTemplatesFolder->exists($templateName) || $customTemplatesFolder->exists($templateName));
152
		};
153
154
		$templatesMigrationMap = [];
155
		foreach ($customTemplatesFolder as $templateFolder) {
156
			$templateName = $templateFolder->getName();
157
			if ($templateFolder->isFolder() && $systemTemplatesFolder->exists($templateName)) {
158
				$newTemplateName = $templateName . '-v0.9';
159
				for ($i = 1; $templateExistsClosure($newTemplateName); $i++) {
160
					$newTemplateName = $templateName . '-v0.9-dup' . $i;
161
				}
162
163
				$templateFolder->rename($newTemplateName);
164
				$this->templatesService->registerCustomTemplate($newTemplateName);
165
				$templatesMigrationMap[$templateName] = $newTemplateName;
166
167
				$this->logWarning(
168
					'Migrating Pico CMS system template "%s" to custom template "%s"',
169
					$templateName,
170
					$newTemplateName
171
				);
172
			}
173
		}
174
175
		return $templatesMigrationMap;
176
	}
177
178
	/**
179
	 * @return array<string,string>
180
	 */
181
	private function migrateSystemThemes()
182
	{
183
		$systemThemesFolder = $this->fileService->getSystemFolder(PicoService::DIR_THEMES);
184
		$systemThemesFolder->sync(FolderInterface::SYNC_SHALLOW);
185
186
		$customThemesFolder = $this->fileService->getAppDataFolder(PicoService::DIR_THEMES);
187
		$customThemesFolder->sync(FolderInterface::SYNC_SHALLOW);
188
189
		$themeExistsClosure = function ($themeName) use ($systemThemesFolder, $customThemesFolder) {
190
			return ($systemThemesFolder->exists($themeName) || $customThemesFolder->exists($themeName));
191
		};
192
193
		$themesMigrationMap = [];
194
		foreach ($customThemesFolder as $themeFolder) {
195
			$themeName = $themeFolder->getName();
196
			if ($themeFolder->isFolder() && $systemThemesFolder->exists($themeName)) {
197
				$newThemeName = $themeName . '-v0.9';
198
				for ($i = 1; $themeExistsClosure($newThemeName); $i++) {
199
					$newThemeName = $themeName . '-v0.9-dup' . $i;
200
				}
201
202
				$themeFolder->rename($newThemeName);
203
				$this->themesService->publishCustomTheme($newThemeName);
204
				$themesMigrationMap[$themeName] = $newThemeName;
205
206
				$this->logWarning(
207
					'Migrating Pico CMS system theme "%s" to custom theme "%s"',
208
					$themeName,
209
					$newThemeName
210
				);
211
			}
212
		}
213
214
		return $themesMigrationMap;
215
	}
216
217
	/**
218
	 * @param array $themesMigrationMap
219
	 */
220
	private function migratePrivateWebsites(array $themesMigrationMap)
221
	{
222
		$qbUpdate = $this->databaseConnection->getQueryBuilder();
223
		$qbUpdate
224
			->update(CoreRequestBuilder::TABLE_WEBSITES)
225
			->set('theme', $qbUpdate->createParameter('theme'))
226
			->set('type', $qbUpdate->createParameter('type'))
227
			->set('options', $qbUpdate->createParameter('options'))
228
			->where($qbUpdate->expr()->eq('id', $qbUpdate->createParameter('id')));
229
230
		$selectCursor = $this->databaseConnection->getQueryBuilder()
231
			->select('id', 'site', 'theme', 'type', 'options')
232
			->from(CoreRequestBuilder::TABLE_WEBSITES)
233
			->execute();
234
235
		while ($data = $selectCursor->fetch()) {
236
			$websiteTheme = $themesMigrationMap[$data['theme']] ?? $data['theme'];
237
238
			$websiteType = $data['type'] ?: WebsiteCore::TYPE_PUBLIC;
239
			$websiteOptions = $data['options'] ? json_decode($data['options'], true) : [];
240
			if (isset($websiteOptions['private'])) {
241
				$websiteType = $websiteOptions['private'] ? WebsiteCore::TYPE_PRIVATE : WebsiteCore::TYPE_PUBLIC;
242
				unset($websiteOptions['private']);
243
			}
244
245
			$qbUpdate->setParameters([
246
				'id' => $data['id'],
247
				'theme' => $websiteTheme,
248
				'type' => $websiteType,
249
				'options' => json_encode($websiteOptions),
250
			]);
251
252
			$this->logInfo(
253
				'Migrating Pico CMS website "%s" (private: %s, theme: "%s")',
254
				$data['site'],
255
				($websiteType === WebsiteCore::TYPE_PRIVATE) ? 'yes' : 'no',
256
				$websiteTheme
257
			);
258
259
			$qbUpdate->execute();
260
		}
261
262
		$selectCursor->closeCursor();
263
	}
264
}
265