Completed
Push — master ( 33d925...cc7944 )
by Thomas
09:52
created

SettingsManager::getAdminSections()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Tom Needham <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2016, ownCloud GmbH.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace OC\Settings;
23
24
use OC\Security\CertificateManager;
25
use OC\Settings\Panels\Admin\Apps;
26
use OC\Settings\Panels\Helper;
27
use OCP\App\IAppManager;
28
use OCP\IDBConnection;
29
use OCP\L10N\IFactory;
30
use OCP\Lock\ILockingProvider;
31
use OCP\Settings\ISettingsManager;
32
use OCP\Settings\ISection;
33
use OCP\Settings\ISettings;
34
use OCP\ILogger;
35
use OCP\IL10N;
36
use OCP\IUserSession;
37
use OCP\AppFramework\QueryException;
38
use OCP\IConfig;
39
use OCP\IGroupManager;
40
use OCP\Defaults;
41
use OCP\IURLGenerator;
42
43
use OC\Settings\Panels\Personal\Profile;
44
use OC\Settings\Panels\Personal\Legacy as LegacyPersonal;
45
use OC\Settings\Panels\Admin\Legacy as LegacyAdmin;
46
use OC\Settings\Panels\Personal\Clients;
47
use OC\Settings\Panels\Personal\Version;
48
use OC\Settings\Panels\Personal\Tokens;
49
use OC\Settings\Panels\Personal\Quota;
50
use OC\Settings\Panels\Admin\BackgroundJobs;
51
use OC\Settings\Panels\Admin\Certificates;
52
use OC\Settings\Panels\Admin\Encryption;
53
use OC\Settings\Panels\Admin\FileSharing;
54
use OC\Settings\Panels\Admin\Mail;
55
use OC\Settings\Panels\Admin\Logging;
56
use OC\Settings\Panels\Admin\SecurityWarning;
57
use OC\Settings\Panels\Admin\Updater;
58
use OC\Settings\Panels\Admin\Tips;
59
60
/*
61
 * @since 10.0
62
 */
63
class SettingsManager implements ISettingsManager {
64
65
	/** @var IL10N */
66
	protected $l;
67
	/** @var IAppManager */
68
	protected $appManager;
69
	/** @var ILogger */
70
	protected $logger;
71
	/** @var IURLGenerator */
72
	protected $urlGenerator;
73
	/** @var Defaults  */
74
	protected $defaults;
75
	/** @var IUserSession  */
76
	protected $userSession;
77
	/** @var ILogger  */
78
	protected $log;
79
	/** @var IConfig  */
80
	protected $config;
81
	/** @var IGroupManager  */
82
	protected $groupManager;
83
	/** @var Helper */
84
	protected $helper;
85
	/** @var IFactory  */
86
	protected $lfactory;
87
	/** @var IDBConnection  */
88
	protected $dbconnection;
89
	/** @var ILockingProvider  */
90
	protected $lockingProvider;
91
	/** @var CertificateManager  */
92
	protected $certificateManager;
93
94
	/**
95
	 * Holds a cache of ISettings with keys for type
96
	 */
97
	protected $panels = [];
98
99
	/**
100
	 * Holds an array of sections
101
	 */
102
	protected $sections = [];
103
104
	/**
105
	 * @param IL10N $l
106
	 * @param IAppManager $appManager
107
	 * @param IUserSession $userSession
108
	 * @param ILogger $logger
109
	 * @param IGroupManager $groupManager
110
	 * @param IConfig $config
111
	 * @param Defaults $defaults
112
	 * @param IURLGenerator $urlGenerator
113
	 * @param Helper $helper
114
	 * @param ILockingProvider $lockingProvider
115
	 * @param IDBConnection $dbconnection
116
	 * @param CertificateManager $certificateManager
117
	 * @param IFactory $lfactory
118
	 */
119
	public function __construct(IL10N $l,
120
								IAppManager $appManager,
121
								IUserSession $userSession,
122
								ILogger $logger,
123
								IGroupManager $groupManager,
124
								IConfig $config,
125
								Defaults $defaults,
126
								IURLGenerator $urlGenerator,
127
								Helper $helper,
128
								ILockingProvider $lockingProvider,
129
								IDBConnection $dbconnection,
130
								CertificateManager $certificateManager,
131
								IFactory $lfactory) {
132
		$this->l = $l;
133
		$this->appManager = $appManager;
134
		$this->userSession = $userSession;
135
		$this->config = $config;
136
		$this->groupManager = $groupManager;
137
		$this->log = $logger;
138
		$this->defaults = $defaults;
139
		$this->urlGenerator = $urlGenerator;
140
		$this->helper = $helper;
141
		$this->lockingProvider = $lockingProvider;
142
		$this->dbconnection = $dbconnection;
143
		$this->certificateManager = $certificateManager;
144
		$this->lfactory = $lfactory;
145
	}
146
147
	public function getPersonalSections() {
148
		// Trigger a load of all personal panels to discover sections
149
		$this->loadPanels('personal');
150
		return $this->sections['personal'];
151
	}
152
153
	public function getAdminSections() {
154
		// Trigger a load of all admin panels to discover sections
155
		$this->loadPanels('admin');
156
		return $this->sections['admin'];
157
	}
158
159
	/**
160
	 * Returns ISettings for the personal settings in the given section
161
	 * @param string $sectionID
162
	 * @return array of ISection
163
	 */
164 View Code Duplication
	public function getPersonalPanels($sectionID) {
165
		// Trigger a load of all personal panels to discover sections
166
		$this->loadPanels('personal');
167
		if(isset($this->panels['personal'][$sectionID])) {
168
			return $this->panels['personal'][$sectionID];
169
		} else {
170
			return [];
171
		}
172
	}
173
174
	/**
175
	 * Returns ISettings for the admin settings in the given section
176
	 * @param string $sectionID
177
	 * @return array of ISection
178
	 */
179 View Code Duplication
	public function getAdminPanels($sectionID) {
180
		// Trigger a load of all admin panels to discover sections
181
		$this->loadPanels('admin');
182
		if(isset($this->panels['admin'][$sectionID])) {
183
			return $this->panels['admin'][$sectionID];
184
		} else {
185
			return [];
186
		}
187
	}
188
189
	/**
190
	 * Returns the default set of ISections used in core
191
	 * @param string $type the type of sections to return
192
	 * @return array of ISection
193
	 */
194
	private function getBuiltInSections($type) {
195
		if($type === 'admin') {
196
			return [
197
				new Section('general', $this->l->t('General'), 100),
198
				new Section('storage', $this->l->t('Storage'), 95),
199
				new Section('security', $this->l->t('Security'), 90),
200
				new Section('encryption', $this->l->t('Encryption'), 85),
201
				new Section('sharing', $this->l->t('Sharing'), 80),
202
				new Section('monitoring', $this->l->t('Monitoring'), 75),
203
				new Section('apps', $this->l->t('Apps'), 70),
204
				new Section('updates', $this->l->t('Updates'), 20),
205
				new Section('additional', $this->l->t('Additional'), -10),
206
			];
207
		} else if($type === 'personal') {
208
			return [
209
				new Section('general', $this->l->t('General'), 100),
210
				new Section('storage', $this->l->t('Storage'), 50),
211
				new Section('security', $this->l->t('Security'), 30),
212
				new Section('encryption', $this->l->t('Encryption'), 20),
213
				new Section('additional', $this->l->t('Additional'), 5),
214
			];
215
		}
216
	}
217
218
	/**
219
	 * Returns an array of classnames for built in settings panels
220
	 * @return array of strings
221
	 */
222
	private function getBuiltInPanels() {
223
		return [
224
			'personal' => [
225
				Profile::class,
226
				Clients::class,
227
				LegacyPersonal::class,
228
				Version::class,
229
				Tokens::class,
230
				Quota::class,
231
			],
232
			'admin' => [
233
				LegacyAdmin::class,
234
				BackgroundJobs::class,
235
				Logging::class,
236
				Tips::class,
237
				SecurityWarning::class,
238
				Mail::class,
239
				FileSharing::class,
240
				Encryption::class,
241
				Certificates::class,
242
				Apps::class
243
			]
244
		];
245
	}
246
247
	/**
248
	 * Gets panel objects with dependencies instantiated from the container
249
	 * @param string $className
250
	 * @return array|false
251
	 */
252
	public function getBuiltInPanel($className) {
253
		$panels = [
254
			// Personal
255
			Profile::class => new Profile(
256
				$this->config,
257
				$this->groupManager,
258
				$this->userSession,
259
				$this->helper,
260
				$this->lfactory),
261
			LegacyPersonal::class => new LegacyPersonal($this->helper),
262
			Clients::class => new Clients($this->config, $this->defaults),
263
			Version::class => new Version(),
264
			Tokens::class => new Tokens(),
265
			Quota::class => new Quota($this->helper),
266
			// Admin
267
			BackgroundJobs::class => new BackgroundJobs($this->config),
268
			Certificates::class => new Certificates(
269
				$this->config,
270
				$this->urlGenerator,
271
				$this->certificateManager),
272
			Encryption::class => new Encryption(),
273
			FileSharing::class => new FileSharing($this->config, $this->helper),
274
			Logging::class => new Logging($this->config, $this->urlGenerator, $this->helper),
275
			Mail::class => new Mail($this->config, $this->helper),
276
			SecurityWarning::class => new SecurityWarning(
277
				$this->l,
278
				$this->config,
279
				$this->dbconnection,
280
				$this->helper,
281
				$this->lockingProvider),
282
			Tips::class => new Tips(),
283
			LegacyAdmin::class => new LegacyAdmin($this->helper),
284
			Apps::class => new Apps($this->config)
285
		];
286
		if(isset($panels[$className])) {
287
			return $panels[$className];
288
		} else {
289
			return false;
290
		}
291
	}
292
293
	/**
294
	 * Gets all the panels for ownCloud
295
	 * @param string $type the type of sections to return
296
	 * @return array of strings
297
	 */
298
	public function getPanelsList($type) {
299
		$registered = isset($this->findRegisteredPanels()[$type]) ? $this->findRegisteredPanels()[$type] : [];
300
		$builtIn = isset($this->getBuiltInPanels()[$type]) ? $this->getBuiltInPanels()[$type] : [];
301
		return array_merge($registered, $builtIn);
302
	}
303
304
305
	/**
306
	 * Searches through the currently enabled apps and returns the panels registered
307
	 * @return array of strings
308
	 */
309
	protected function findRegisteredPanels() {
310
		$panels = [];
311
		foreach($this->appManager->getEnabledAppsForUser($this->userSession->getUser()) as $app) {
0 ignored issues
show
Bug introduced by
It seems like $this->userSession->getUser() can be null; however, getEnabledAppsForUser() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
312
			if(isset($this->appManager->getAppInfo($app)['settings'])) {
313
				foreach($this->appManager->getAppInfo($app)['settings'] as $type => $panel) {
314
					$panels[$type][] = (string) $panel;
315
				}
316
			}
317
		}
318
		return $panels;
319
	}
320
321
	/**
322
	 * Attempts to load a ISettings using the class name
323
	 * @param string $className
324
	 * @throws QueryException
325
	 * @return ISettings
326
	 */
327
	protected function loadPanel($className) {
328
		try {
329
			if(!$panel = $this->getBuiltInPanel($className)) {
330
				$panel = \OC::$server->query($className);
331
			}
332
			if(!$panel instanceof ISettings) {
333
				$this->log->error(
334
					'Class: {class} not an instance of OCP\Settings\ISettings',
335
					['class' => $className]);
336
			} else {
337
				return $panel;
338
			}
339
		} catch (QueryException $e) {
340
			$this->log->error(
341
				'Failed to load panel: {class} with error: {error}',
342
				[
343
					'class' => $className,
344
					'error' => $e->getMessage()
345
				]);
346
			throw $e;
347
		}
348
	}
349
350
	/**
351
	 * Find and return ISettings for the given type
352
	 * @param string $type of panels to load
353
	 * @return array of ISettings
354
	 */
355
	public function loadPanels($type) {
356
		// If already loaded just return
357
		if(!empty($this->panels[$type])) {
358
			return $this->panels[$type];
359
		}
360
		// Find the panels from info xml
361
		$panels = $this->getPanelsList($type);
362
		// Load the classes using the server container
363
		if(empty($panels)) {
364
			return [];
365
		}
366
		foreach($panels as $panelClassName) {
367
			// Attempt to load the panel
368
			try {
369
				$panel = $this->loadPanel($panelClassName);
370
				$section = $this->loadSection($type, $panel->getSectionID());
371
				$this->panels[$type][$section->getID()][] = $panel;
372
				$this->sections[$type][$section->getID()] = $section;
373
				// Now try and initialise the ISection from the panel
374
			} catch (QueryException $e) {
375
				// Just skip this panel, either its section of panel could not be loaded
376
			}
377
		}
378
		// Return the panel array sorted
379
		foreach($this->panels[$type] as $sectionID => $section) {
380
			$this->panels[$type][$sectionID] = $this->sortOrder($this->panels[$type][$sectionID]);
381
		}
382
		// sort section array
383
		$this->sections[$type] = $this->sortOrder($this->sections[$type]);
384
		return $this->panels[$type];
385
	}
386
387
	/**
388
	 * Return the section object for the corresponding type and sectionID
389
	 * @param string $type
390
	 * @param string $sectionID
391
	 * @throws QueryException
392
	 * @return ISection
393
	 */
394
	protected function loadSection($type, $sectionID) {
395
		// Load sections from default list
396
		foreach($this->getBuiltInSections($type) as $section) {
0 ignored issues
show
Bug introduced by
The expression $this->getBuiltInSections($type) of type array<integer,object<OC\...tings\\Section>"}>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
397
			if($section->getID() === $sectionID) {
398
				return $section;
399
			}
400
		}
401
		$this->log->error(
402
			'Failed to load section with id: {id}',
403
			['id' => $sectionID]);
404
		return new Section($sectionID, ucfirst($sectionID), -9);
405
	}
406
407
	/**
408
	 * Sort the array of ISettings or ISections by their priority attribute
409
	 * @param array $objects (ISections of ISettings)
410
	 * @return array
411
	 */
412
	protected function sortOrder($objects) {
413
		usort($objects, function($a, $b) {
414
			/** @var ISection | ISettings $a */
415
			/** @var ISection | ISettings $b */
416
			return $a->getPriority() < $b->getPriority();
417
		});
418
		return $objects;
419
	}
420
421
}
422