Test Failed
Push — master ( dc798f...d76e2d )
by Daniel
48:22
created

PluginsService::getPlugins()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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