Passed
Pull Request — master (#77)
by Daniel
47:29
created

PluginsService::getPlugins()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
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\PluginNotFoundException;
29
use OCA\CMSPico\Files\FolderInterface;
30
use OCA\CMSPico\Files\LocalFolder;
31
use OCA\CMSPico\Model\Plugin;
32
use OCP\Files\AlreadyExistsException;
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 2
	public function getPlugins(): array
67
	{
68 2
		return $this->getSystemPlugins() + $this->getCustomPlugins();
69
	}
70
71
	/**
72
	 * @return array[]
73
	 */
74 2
	public function getSystemPlugins(): array
75
	{
76 2
		$json = $this->configService->getAppValue(ConfigService::SYSTEM_PLUGINS);
77 2
		return $json ? json_decode($json, true) : [];
78
	}
79
80
	/**
81
	 * @return array[]
82
	 */
83 2
	public function getCustomPlugins(): array
84
	{
85 2
		$json = $this->configService->getAppValue(ConfigService::CUSTOM_PLUGINS);
86 2
		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
	 */
116
	public function publishSystemPlugin(string $pluginName): Plugin
117
	{
118
		if (!$pluginName) {
119
			throw new PluginNotFoundException();
120
		}
121
122
		$systemPluginsFolder = $this->fileService->getSystemFolder(PicoService::DIR_PLUGINS);
123
		$systemPluginsFolder->sync(FolderInterface::SYNC_SHALLOW);
124
125
		try {
126
			$systemPluginFolder = $systemPluginsFolder->getFolder($pluginName);
127
		} catch (NotFoundException $e) {
128
			throw new PluginNotFoundException();
129
		}
130
131
		$plugins = $this->getSystemPlugins();
132
		$plugins[$pluginName] = $this->publishPlugin($systemPluginFolder, Plugin::PLUGIN_TYPE_SYSTEM);
133
		$this->configService->setAppValue(ConfigService::SYSTEM_PLUGINS, json_encode($plugins));
134
135
		return $plugins[$pluginName];
136
	}
137
138
	/**
139
	 * @param string $pluginName
140
	 *
141
	 * @return Plugin
142
	 * @throws PluginNotFoundException
143
	 */
144
	public function publishCustomPlugin(string $pluginName): Plugin
145
	{
146
		if (!$pluginName) {
147
			throw new PluginNotFoundException();
148
		}
149
150
		$appDataPluginsFolder = $this->fileService->getAppDataFolder(PicoService::DIR_PLUGINS);
151
		$appDataPluginsFolder->sync(FolderInterface::SYNC_SHALLOW);
152
153
		try {
154
			$appDataPluginFolder = $appDataPluginsFolder->getFolder($pluginName);
155
		} catch (NotFoundException $e) {
156
			throw new PluginNotFoundException();
157
		}
158
159
		$plugins = $this->getCustomPlugins();
160
		$plugins[$pluginName] = $this->publishPlugin($appDataPluginFolder, Plugin::PLUGIN_TYPE_CUSTOM);
161
		$this->configService->setAppValue(ConfigService::CUSTOM_PLUGINS, json_encode($plugins));
162
163
		return $plugins[$pluginName];
164
	}
165
166
	/**
167
	 * @param FolderInterface $pluginSourceFolder
168
	 * @param int             $pluginType
169
	 *
170
	 * @return Plugin
171
	 */
172
	private function publishPlugin(FolderInterface $pluginSourceFolder, int $pluginType): Plugin
173
	{
174
		$publicPluginsFolder = $this->getPluginsFolder(true);
175
176
		$pluginName = $pluginSourceFolder->getName();
177
		$pluginSourceFolder->sync();
178
179
		try {
180
			$publicPluginsFolder->getFolder($pluginName);
181
			throw new AlreadyExistsException();
182
		} catch (NotFoundException $e) {
183
			// in fact we want the plugin not to exist yet
184
		}
185
186
		/** @var LocalFolder $pluginFolder */
187
		$pluginFolder = $pluginSourceFolder->copy($publicPluginsFolder);
188
		return new Plugin($pluginFolder, $pluginType);
189
	}
190
191
	/**
192
	 * @param string $pluginName
193
	 */
194
	public function depublishCustomPlugin(string $pluginName)
195
	{
196
		if (!$pluginName) {
197
			throw new PluginNotFoundException();
198
		}
199
200
		$publicPluginsFolder = $this->getPluginsFolder();
201
202
		try {
203
			$publicPluginsFolder->getFolder($pluginName)->delete();
204
		} catch (NotFoundException $e) {
205
			throw new PluginNotFoundException();
206
		}
207
208
		$customPlugins = $this->getCustomPlugins();
209
		unset($customPlugins[$pluginName]);
210
		$this->configService->setAppValue(ConfigService::CUSTOM_PLUGINS, json_encode($customPlugins));
211
	}
212
213
	/**
214
	 * @param bool $renewETag
215
	 * @param bool $forceRenewETag
216
	 *
217
	 * @return LocalFolder
218
	 */
219 2
	public function getPluginsFolder(bool $renewETag = false, bool $forceRenewETag = false): LocalFolder
220
	{
221 2
		$pluginsBaseFolder = $this->fileService->getPublicFolder(PicoService::DIR_PLUGINS);
222
223
		/** @var LocalFolder $pluginsFolder */
224 2
		$pluginsFolder = null;
225
226 2
		$pluginsETag = $this->configService->getAppValue(ConfigService::PLUGINS_ETAG);
227 2
		if ($pluginsETag) {
228 1
			$pluginsFolder = $pluginsBaseFolder->getFolder($pluginsETag);
229
		}
230
231 2
		if (($renewETag && !$this->renewedETag) || $forceRenewETag || !$pluginsFolder) {
232 1
			$pluginsETag = $this->miscService->getRandom();
233
234 1
			if ($pluginsFolder) {
235
				$pluginsFolder = $pluginsFolder->rename($pluginsETag);
236
			} else {
237 1
				$pluginsFolder = $pluginsBaseFolder->newFolder($pluginsETag);
238
			}
239
240 1
			$this->configService->setAppValue(ConfigService::PLUGINS_ETAG, $pluginsETag);
241 1
			$this->renewedETag = true;
242
		}
243
244 2
		return $pluginsFolder->fakeRoot();
245
	}
246
247
	/**
248
	 * @return string
249
	 */
250 2
	public function getPluginsPath(): string
251
	{
252 2
		$appPath = Application::getAppPath() . '/';
253 2
		$pluginsPath = 'appdata_public/' . PicoService::DIR_PLUGINS . '/';
254 2
		$pluginsETag = $this->configService->getAppValue(ConfigService::PLUGINS_ETAG);
255 2
		return $appPath . $pluginsPath . ($pluginsETag ? $pluginsETag . '/' : '');
256
	}
257
258
	/**
259
	 * @return string
260
	 */
261 2
	public function getPluginsUrl(): string
262
	{
263 2
		$appWebPath = Application::getAppWebPath() . '/';
264 2
		$pluginsPath = 'appdata_public/' . PicoService::DIR_PLUGINS . '/';
265 2
		$pluginsETag = $this->configService->getAppValue(ConfigService::PLUGINS_ETAG);
266 2
		return $appWebPath . $pluginsPath . ($pluginsETag ? $pluginsETag . '/' : '');
267
	}
268
}
269