Passed
Push — master ( fa41e0...4bd63f )
by Daniel
07:07 queued 12s
created

PluginsService::copyDummyPlugin()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
eloc 21
c 0
b 0
f 0
dl 0
loc 33
ccs 0
cts 20
cp 0
rs 8.6506
cc 7
nc 10
nop 1
crap 56
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\Service;
26
27
use OCA\CMSPico\AppInfo\Application;
28
use OCA\CMSPico\Exceptions\PluginAlreadyExistsException;
29
use OCA\CMSPico\Exceptions\PluginNotFoundException;
30
use OCA\CMSPico\Files\FolderInterface;
31
use OCA\CMSPico\Files\LocalFolder;
32
use OCA\CMSPico\Model\DummyPluginFile;
33
use OCA\CMSPico\Model\Plugin;
34
use OCP\Files\AlreadyExistsException;
35
use OCP\Files\InvalidPathException;
36
use OCP\Files\NotFoundException;
37
38
class PluginsService
39
{
40
	/** @var ConfigService */
41
	private $configService;
42
43
	/** @var FileService */
44
	private $fileService;
45
46
	/** @var MiscService */
47
	private $miscService;
48
49
	/** @var bool */
50
	private $renewedETag = false;
51
52
	/**
53
	 * PluginsService constructor.
54
	 *
55
	 * @param ConfigService $configService
56
	 * @param FileService   $fileService
57
	 * @param MiscService   $miscService
58
	 */
59
	public function __construct(ConfigService $configService, FileService $fileService, MiscService $miscService)
60
	{
61
		$this->configService = $configService;
62
		$this->fileService = $fileService;
63
		$this->miscService = $miscService;
64
	}
65
66
	/**
67
	 * @return array[]
68
	 */
69 11
	public function getPlugins(): array
70
	{
71 11
		return $this->getSystemPlugins() + $this->getCustomPlugins();
72
	}
73
74
	/**
75
	 * @return array[]
76
	 */
77 11
	public function getSystemPlugins(): array
78
	{
79 11
		$json = $this->configService->getAppValue(ConfigService::SYSTEM_PLUGINS);
80 11
		return $json ? json_decode($json, true) : [];
81
	}
82
83
	/**
84
	 * @return array[]
85
	 */
86 11
	public function getCustomPlugins(): array
87
	{
88 11
		$json = $this->configService->getAppValue(ConfigService::CUSTOM_PLUGINS);
89 11
		return $json ? json_decode($json, true) : [];
90
	}
91
92
	/**
93
	 * @return string[]
94
	 */
95 6
	public function getNewCustomPlugins(): array
96
	{
97 6
		$appDataPluginsFolder = $this->fileService->getAppDataFolder(PicoService::DIR_PLUGINS);
98 6
		$appDataPluginsFolder->sync(FolderInterface::SYNC_SHALLOW);
99
100 6
		$currentPlugins = $this->getPlugins();
101
102 6
		$newCustomPlugins = [];
103 6
		foreach ($appDataPluginsFolder as $pluginFolder) {
104 5
			$pluginName = $pluginFolder->getName();
105 5
			if ($pluginFolder->isFolder() && !isset($currentPlugins[$pluginName])) {
106 2
				$newCustomPlugins[] = $pluginName;
107
			}
108
		}
109
110 6
		return $newCustomPlugins;
111
	}
112
113
	/**
114
	 * @param string $pluginName
115
	 *
116
	 * @return Plugin
117
	 * @throws PluginNotFoundException
118
	 * @throws PluginAlreadyExistsException
119
	 */
120
	public function publishSystemPlugin(string $pluginName): Plugin
121
	{
122
		if (!$pluginName) {
123
			throw new PluginNotFoundException();
124
		}
125
126
		$systemPluginsFolder = $this->fileService->getSystemFolder(PicoService::DIR_PLUGINS);
127
		$systemPluginsFolder->sync(FolderInterface::SYNC_SHALLOW);
128
129
		try {
130
			$systemPluginFolder = $systemPluginsFolder->getFolder($pluginName);
131
		} catch (NotFoundException $e) {
132
			throw new PluginNotFoundException();
133
		}
134
135
		$plugins = $this->getSystemPlugins();
136
		$plugins[$pluginName] = $this->publishPlugin($systemPluginFolder, Plugin::TYPE_SYSTEM);
137
		$this->configService->setAppValue(ConfigService::SYSTEM_PLUGINS, json_encode($plugins));
138
139
		return $plugins[$pluginName];
140
	}
141
142
	/**
143
	 * @param string $pluginName
144
	 *
145
	 * @return Plugin
146
	 * @throws PluginNotFoundException
147
	 * @throws PluginAlreadyExistsException
148
	 */
149 3
	public function publishCustomPlugin(string $pluginName): Plugin
150
	{
151 3
		if (!$pluginName) {
152
			throw new PluginNotFoundException();
153
		}
154
155 3
		$systemPlugins = $this->getSystemPlugins();
156 3
		if (isset($systemPlugins[$pluginName])) {
157
			throw new PluginAlreadyExistsException();
158
		}
159
160 3
		$appDataPluginsFolder = $this->fileService->getAppDataFolder(PicoService::DIR_PLUGINS);
161 3
		$appDataPluginsFolder->sync(FolderInterface::SYNC_SHALLOW);
162
163
		try {
164 3
			$appDataPluginFolder = $appDataPluginsFolder->getFolder($pluginName);
165
		} catch (NotFoundException $e) {
166
			throw new PluginNotFoundException();
167
		}
168
169 3
		$plugins = $this->getCustomPlugins();
170 3
		$plugins[$pluginName] = $this->publishPlugin($appDataPluginFolder, Plugin::TYPE_CUSTOM);
171 3
		$this->configService->setAppValue(ConfigService::CUSTOM_PLUGINS, json_encode($plugins));
172
173 3
		return $plugins[$pluginName];
174
	}
175
176
	/**
177
	 * @param FolderInterface $pluginSourceFolder
178
	 * @param int             $pluginType
179
	 *
180
	 * @return Plugin
181
	 * @throws PluginAlreadyExistsException
182
	 */
183 3
	private function publishPlugin(FolderInterface $pluginSourceFolder, int $pluginType): Plugin
184
	{
185 3
		$publicPluginsFolder = $this->getPluginsFolder(true);
186
187 3
		$pluginName = $pluginSourceFolder->getName();
188 3
		$pluginSourceFolder->sync();
189
190
		try {
191 3
			$publicPluginsFolder->getFolder($pluginName);
192
			throw new PluginAlreadyExistsException();
193 3
		} catch (NotFoundException $e) {
194
			// in fact we want the plugin not to exist yet
195
		}
196
197
		/** @var LocalFolder $pluginFolder */
198 3
		$pluginFolder = $pluginSourceFolder->copy($publicPluginsFolder);
199 3
		return new Plugin($pluginFolder, $pluginType);
200
	}
201
202
	/**
203
	 * @param string $pluginName
204
	 *
205
	 * @throws PluginNotFoundException
206
	 */
207 2
	public function depublishCustomPlugin(string $pluginName): void
208
	{
209 2
		if (!$pluginName) {
210
			throw new PluginNotFoundException();
211
		}
212
213 2
		$publicPluginsFolder = $this->getPluginsFolder();
214
215
		try {
216 2
			$publicPluginsFolder->getFolder($pluginName)->delete();
217
		} catch (NotFoundException $e) {
218
			throw new PluginNotFoundException();
219
		}
220
221 2
		$customPlugins = $this->getCustomPlugins();
222 2
		unset($customPlugins[$pluginName]);
223 2
		$this->configService->setAppValue(ConfigService::CUSTOM_PLUGINS, json_encode($customPlugins));
224 2
	}
225
226
	/**
227
	 * @param string $pluginName
228
	 *
229
	 * @return Plugin
230
	 * @throws PluginNotFoundException
231
	 * @throws PluginAlreadyExistsException
232
	 */
233
	public function copyDummyPlugin(string $pluginName): Plugin
234
	{
235
		if (!$pluginName) {
236
			throw new PluginNotFoundException();
237
		}
238
239
		$systemPlugins = $this->getSystemPlugins();
240
		$customPlugins = $this->getCustomPlugins();
241
242
		if (isset($systemPlugins[$pluginName]) || isset($customPlugins[$pluginName])) {
243
			throw new PluginAlreadyExistsException();
244
		}
245
246
		$systemPluginsFolder = $this->fileService->getSystemFolder(PicoService::DIR_PLUGINS);
247
		$appDataPluginsFolder = $this->fileService->getAppDataFolder(PicoService::DIR_PLUGINS);
248
249
		try {
250
			$basePluginFile = $systemPluginsFolder->getFile('DummyPlugin.php');
251
		} catch (NotFoundException $e) {
252
			throw new PluginNotFoundException();
253
		}
254
255
		try {
256
			$pluginFile = new DummyPluginFile($pluginName, $basePluginFile);
257
			$pluginFolder = $appDataPluginsFolder->newFolder($pluginName);
258
			$pluginFile->copy($pluginFolder);
259
		} catch (InvalidPathException $e) {
260
			throw new PluginNotFoundException();
261
		} catch (AlreadyExistsException $e) {
262
			throw new PluginAlreadyExistsException();
263
		}
264
265
		return $this->publishCustomPlugin($pluginName);
266
	}
267
268
	/**
269
	 * @param bool $renewETag
270
	 * @param bool $forceRenewETag
271
	 *
272
	 * @return LocalFolder
273
	 */
274 9
	public function getPluginsFolder(bool $renewETag = false, bool $forceRenewETag = false): LocalFolder
275
	{
276 9
		$pluginsBaseFolder = $this->fileService->getPublicFolder(PicoService::DIR_PLUGINS);
277
278
		/** @var LocalFolder $pluginsFolder */
279 9
		$pluginsFolder = null;
280
281 9
		$pluginsETag = $this->configService->getAppValue(ConfigService::PLUGINS_ETAG);
282 9
		if ($pluginsETag) {
283 9
			$pluginsFolder = $pluginsBaseFolder->getFolder($pluginsETag);
284
		}
285
286 9
		if (($renewETag && !$this->renewedETag) || $forceRenewETag || !$pluginsFolder) {
287
			$pluginsETag = $this->miscService->getRandom();
288
289
			if ($pluginsFolder) {
290
				$pluginsFolder = $pluginsFolder->rename($pluginsETag);
291
			} else {
292
				$pluginsFolder = $pluginsBaseFolder->newFolder($pluginsETag);
293
			}
294
295
			$this->configService->setAppValue(ConfigService::PLUGINS_ETAG, $pluginsETag);
296
			$this->renewedETag = true;
297
		}
298
299 9
		return $pluginsFolder->fakeRoot();
300
	}
301
302
	/**
303
	 * @return string
304
	 */
305 5
	public function getPluginsPath(): string
306
	{
307 5
		$appPath = Application::getAppPath() . '/';
308 5
		$pluginsPath = 'appdata_public/' . PicoService::DIR_PLUGINS . '/';
309 5
		$pluginsETag = $this->configService->getAppValue(ConfigService::PLUGINS_ETAG);
310 5
		return $appPath . $pluginsPath . ($pluginsETag ? $pluginsETag . '/' : '');
311
	}
312
313
	/**
314
	 * @return string
315
	 */
316 5
	public function getPluginsUrl(): string
317
	{
318 5
		$appWebPath = Application::getAppWebPath() . '/';
319 5
		$pluginsPath = 'appdata_public/' . PicoService::DIR_PLUGINS . '/';
320 5
		$pluginsETag = $this->configService->getAppValue(ConfigService::PLUGINS_ETAG);
321 5
		return $appWebPath . $pluginsPath . ($pluginsETag ? $pluginsETag . '/' : '');
322
	}
323
}
324