Completed
Pull Request — master (#7230)
by Morris
13:01
created

Manager::hasLegacyPersonalSettingsToRender()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 3
nop 1
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016 Arthur Schiwon <[email protected]>
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Joas Schilling <[email protected]>
7
 * @author Lukas Reschke <[email protected]>
8
 * @author Marius Blüm <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 *
13
 * @license GNU AGPL version 3 or any later version
14
 *
15
 * This program is free software: you can redistribute it and/or modify
16
 * it under the terms of the GNU Affero General Public License as
17
 * published by the Free Software Foundation, either version 3 of the
18
 * License, or (at your option) any later version.
19
 *
20
 * This program is distributed in the hope that it will be useful,
21
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
 * GNU Affero General Public License for more details.
24
 *
25
 * You should have received a copy of the GNU Affero General Public License
26
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
 *
28
 */
29
30
namespace OC\Settings;
31
32
use OC\Accounts\AccountManager;
33
use OCP\App\IAppManager;
34
use OCP\AppFramework\QueryException;
35
use OCP\AutoloadNotAllowedException;
36
use OCP\Encryption\IManager as EncryptionManager;
37
use OCP\IConfig;
38
use OCP\IDBConnection;
39
use OCP\IGroupManager;
40
use OCP\IL10N;
41
use OCP\ILogger;
42
use OCP\IRequest;
43
use OCP\IURLGenerator;
44
use OCP\IUserManager;
45
use OCP\L10N\IFactory;
46
use OCP\Lock\ILockingProvider;
47
use OCP\Settings\ISettings;
48
use OCP\Settings\IManager;
49
use OCP\Settings\ISection;
50
51
class Manager implements IManager {
52
	/** @var ILogger */
53
	private $log;
54
	/** @var IDBConnection */
55
	private $dbc;
56
	/** @var Mapper */
57
	private $mapper;
58
	/** @var IL10N */
59
	private $l;
60
	/** @var IConfig */
61
	private $config;
62
	/** @var EncryptionManager */
63
	private $encryptionManager;
64
	/** @var IUserManager */
65
	private $userManager;
66
	/** @var ILockingProvider */
67
	private $lockingProvider;
68
	/** @var IRequest */
69
	private $request;
70
	/** @var IURLGenerator */
71
	private $url;
72
	/** @var AccountManager */
73
	private $accountManager;
74
	/** @var IGroupManager */
75
	private $groupManager;
76
	/** @var IFactory */
77
	private $l10nFactory;
78
	/** @var \OC_Defaults */
79
	private $defaults;
80
	/** @var IAppManager */
81
	private $appManager;
82
83
	/**
84
	 * @param ILogger $log
85
	 * @param IDBConnection $dbc
86
	 * @param IL10N $l
87
	 * @param IConfig $config
88
	 * @param EncryptionManager $encryptionManager
89
	 * @param IUserManager $userManager
90
	 * @param ILockingProvider $lockingProvider
91
	 * @param IRequest $request
92
	 * @param Mapper $mapper
93
	 * @param IURLGenerator $url
94
	 * @param AccountManager $accountManager
95
	 * @param IGroupManager $groupManager
96
	 * @param IFactory $l10nFactory
97
	 * @param \OC_Defaults $defaults
98
	 */
99
	public function __construct(
100
		ILogger $log,
101
		IDBConnection $dbc,
102
		IL10N $l,
103
		IConfig $config,
104
		EncryptionManager $encryptionManager,
105
		IUserManager $userManager,
106
		ILockingProvider $lockingProvider,
107
		IRequest $request,
108
		Mapper $mapper,
109
		IURLGenerator $url,
110
		AccountManager $accountManager,
111
		IGroupManager $groupManager,
112
		IFactory $l10nFactory,
113
		\OC_Defaults $defaults,
114
		IAppManager $appManager
115
	) {
116
		$this->log = $log;
117
		$this->dbc = $dbc;
118
		$this->mapper = $mapper;
119
		$this->l = $l;
120
		$this->config = $config;
121
		$this->encryptionManager = $encryptionManager;
122
		$this->userManager = $userManager;
123
		$this->lockingProvider = $lockingProvider;
124
		$this->request = $request;
125
		$this->url = $url;
126
		$this->accountManager = $accountManager;
127
		$this->groupManager = $groupManager;
128
		$this->l10nFactory = $l10nFactory;
129
		$this->defaults = $defaults;
130
		$this->appManager = $appManager;
131
	}
132
133
	/**
134
	 * @inheritdoc
135
	 */
136
	public function setupSettings(array $settings) {
137
		if (!empty($settings[IManager::KEY_ADMIN_SECTION])) {
138
			foreach ($settings[IManager::KEY_ADMIN_SECTION] as $className) {
139
				$this->setupSectionEntry($className, 'admin');
140
			}
141
		}
142 View Code Duplication
		if (!empty($settings[IManager::KEY_ADMIN_SETTINGS])) {
143
			foreach ($settings[IManager::KEY_ADMIN_SETTINGS] as $className) {
144
				$this->setupSettingsEntry($className, 'admin');
145
			}
146
		}
147
148 View Code Duplication
		if (!empty($settings[IManager::KEY_PERSONAL_SECTION])) {
149
			foreach ($settings[IManager::KEY_PERSONAL_SECTION] as $className) {
150
				$this->setupSectionEntry($className, 'personal');
151
			}
152
		}
153 View Code Duplication
		if (!empty($settings[IManager::KEY_PERSONAL_SETTINGS])) {
154
			foreach ($settings[IManager::KEY_PERSONAL_SETTINGS] as $className) {
155
				$this->setupSettingsEntry($className, 'personal');
156
			}
157
		}
158
	}
159
160
	/**
161
	 * attempts to remove an apps section and/or settings entry. A listener is
162
	 * added centrally making sure that this method is called ones an app was
163
	 * disabled.
164
	 *
165
	 * @param string $appId
166
	 * @since 9.1.0
167
	 */
168
	public function onAppDisabled($appId) {
169
		$appInfo = \OC_App::getAppInfo($appId); // hello static legacy
170
171 View Code Duplication
		if (!empty($appInfo['settings'][IManager::KEY_ADMIN_SECTION])) {
172
			foreach ($appInfo['settings'][IManager::KEY_ADMIN_SECTION] as $className) {
173
				$this->mapper->remove(Mapper::TABLE_ADMIN_SECTIONS, trim($className, '\\'));
174
			}
175
		}
176 View Code Duplication
		if (!empty($appInfo['settings'][IManager::KEY_ADMIN_SETTINGS])) {
177
			foreach ($appInfo['settings'][IManager::KEY_ADMIN_SETTINGS] as $className) {
178
				$this->mapper->remove(Mapper::TABLE_ADMIN_SETTINGS, trim($className, '\\'));
179
			}
180
		}
181
182 View Code Duplication
		if (!empty($appInfo['settings'][IManager::KEY_PERSONAL_SECTION])) {
183
			foreach ($appInfo['settings'][IManager::KEY_PERSONAL_SECTION] as $className) {
184
				$this->mapper->remove(Mapper::TABLE_PERSONAL_SECTIONS, trim($className, '\\'));
185
			}
186
		}
187 View Code Duplication
		if (!empty($appInfo['settings'][IManager::KEY_PERSONAL_SETTINGS])) {
188
			foreach ($appInfo['settings'][IManager::KEY_PERSONAL_SETTINGS] as $className) {
189
				$this->mapper->remove(Mapper::TABLE_PERSONAL_SETTINGS, trim($className, '\\'));
190
			}
191
		}
192
	}
193
194
	public function checkForOrphanedClassNames() {
195
		$tables = [Mapper::TABLE_ADMIN_SECTIONS, Mapper::TABLE_ADMIN_SETTINGS, Mapper::TABLE_PERSONAL_SECTIONS, Mapper::TABLE_PERSONAL_SETTINGS];
196
		foreach ($tables as $table) {
197
			$classes = $this->mapper->getClasses($table);
198
			foreach ($classes as $className) {
199
				try {
200
					\OC::$server->query($className);
201
				} catch (QueryException $e) {
202
					$this->mapper->remove($table, $className);
203
				}
204
			}
205
		}
206
	}
207
208
	/**
209
	 * @param string $sectionClassName
210
	 * @param string $type either 'admin' or 'personal'
211
	 */
212 View Code Duplication
	private function setupSectionEntry($sectionClassName, $type) {
213
		if (!class_exists($sectionClassName)) {
214
			$this->log->debug('Could not find ' . ucfirst($type) . ' section class ' . $sectionClassName);
215
			return;
216
		}
217
		try {
218
			$section = $this->query($sectionClassName);
219
		} catch (QueryException $e) {
220
			// cancel
221
			return;
222
		}
223
224
		if (!$section instanceof ISection) {
225
			$this->log->error(
226
				ucfirst($type) .' section instance must implement \OCP\ISection. Invalid class: {class}',
227
				['class' => $sectionClassName]
228
			);
229
			return;
230
		}
231
		$table = $this->getSectionTableForType($type);
232
		if(!$this->hasSection(get_class($section), $table)) {
233
			$this->addSection($section, $table);
234
		} else {
235
			$this->updateSection($section, $table);
236
		}
237
	}
238
239 View Code Duplication
	private function addSection(ISection $section, $table) {
240
		$this->mapper->add($table, [
241
			'id' => $section->getID(),
242
			'class' => get_class($section),
243
			'priority' => $section->getPriority(),
244
		]);
245
	}
246
247 View Code Duplication
	private function addSettings(ISettings $settings, $table) {
248
		$this->mapper->add($table, [
249
			'class' => get_class($settings),
250
			'section' => $settings->getSection(),
251
			'priority' => $settings->getPriority(),
252
		]);
253
	}
254
255 View Code Duplication
	private function updateSettings(ISettings $settings, $table) {
256
		$this->mapper->update(
257
			$table,
258
			'class',
259
			get_class($settings),
260
			[
261
				'section' => $settings->getSection(),
262
				'priority' => $settings->getPriority(),
263
			]
264
		);
265
	}
266
267 View Code Duplication
	private function updateSection(ISection $section, $table) {
268
		$this->mapper->update(
269
			$table,
270
			'class',
271
			get_class($section),
272
			[
273
				'id' => $section->getID(),
274
				'priority' => $section->getPriority(),
275
			]
276
		);
277
	}
278
279
	/**
280
	 * @param string $className
281
	 * @param string $table
282
	 * @return bool
283
	 */
284
	private function hasSection($className, $table) {
285
		return $this->mapper->has($table, $className);
286
	}
287
288
	/**
289
	 * @param string $className
290
	 * @return bool
291
	 */
292
	private function hasSettings($className, $table) {
293
		return $this->mapper->has($table, $className);
294
	}
295
296 View Code Duplication
	private function setupSettingsEntry($settingsClassName, $type) {
297
		if (!class_exists($settingsClassName)) {
298
			$this->log->debug('Could not find ' . $type . ' section class ' . $settingsClassName);
299
			return;
300
		}
301
302
		try {
303
			/** @var ISettings $settings */
304
			$settings = $this->query($settingsClassName);
305
		} catch (QueryException $e) {
306
			// cancel
307
			return;
308
		}
309
310
		if (!$settings instanceof ISettings) {
311
			$this->log->error(
312
				ucfirst($type) . ' section instance must implement \OCP\Settings\ISettings. Invalid class: {class}',
313
				['class' => $settingsClassName]
314
			);
315
			return;
316
		}
317
		$table = $this->getSettingsTableForType($type);
318
		if (!$this->hasSettings(get_class($settings), $table)) {
319
			$this->addSettings($settings, $table);
320
		} else {
321
			$this->updateSettings($settings, $table);
322
		}
323
	}
324
325 View Code Duplication
	private function getSectionTableForType($type) {
326
		if($type === 'admin') {
327
			return Mapper::TABLE_ADMIN_SECTIONS;
328
		} else if($type === 'personal') {
329
			return Mapper::TABLE_PERSONAL_SECTIONS;
330
		}
331
		throw new \InvalidArgumentException('"admin" or "personal" expected');
332
	}
333
334 View Code Duplication
	private function getSettingsTableForType($type) {
335
		if($type === 'admin') {
336
			return Mapper::TABLE_ADMIN_SETTINGS;
337
		} else if($type === 'personal') {
338
			return Mapper::TABLE_PERSONAL_SETTINGS;
339
		}
340
		throw new \InvalidArgumentException('"admin" or "personal" expected');
341
	}
342
343
	private function query($className) {
344
		try {
345
			return \OC::$server->query($className);
346
		} catch (QueryException $e) {
347
			$this->log->logException($e);
348
			throw $e;
349
		}
350
	}
351
352
	/**
353
	 * @inheritdoc
354
	 */
355
	public function getAdminSections() {
356
		// built-in sections
357
		$sections = [
358
			0 => [new Section('server', $this->l->t('Basic settings'), 0, $this->url->imagePath('settings', 'admin.svg'))],
359
			5 => [new Section('sharing', $this->l->t('Sharing'), 0, $this->url->imagePath('core', 'actions/share.svg'))],
360
			10 => [new Section('security', $this->l->t('Security'), 0, $this->url->imagePath('core', 'actions/password.svg'))],
361
			45 => [new Section('encryption', $this->l->t('Encryption'), 0, $this->url->imagePath('core', 'actions/password.svg'))],
362
			98 => [new Section('additional', $this->l->t('Additional settings'), 0, $this->url->imagePath('core', 'actions/settings-dark.svg'))],
363
			99 => [new Section('tips-tricks', $this->l->t('Tips & tricks'), 0, $this->url->imagePath('settings', 'help.svg'))],
364
		];
365
366
		$rows = $this->mapper->getAdminSectionsFromDB();
367
368
		foreach ($rows as $row) {
369
			if (!isset($sections[$row['priority']])) {
370
				$sections[$row['priority']] = [];
371
			}
372
			try {
373
				$sections[$row['priority']][] = $this->query($row['class']);
374
			} catch (QueryException $e) {
375
				// skip
376
			}
377
		}
378
379
		ksort($sections);
380
381
		return $sections;
382
	}
383
384
	/**
385
	 * @param string $section
386
	 * @return ISection[]
387
	 */
388
	private function getBuiltInAdminSettings($section) {
389
		$forms = [];
390
		try {
391
			if ($section === 'server') {
392
				/** @var ISettings $form */
393
				$form = new Admin\Server($this->dbc, $this->request, $this->config, $this->lockingProvider, $this->l);
394
				$forms[$form->getPriority()] = [$form];
395
				$form = new Admin\ServerDevNotice();
396
				$forms[$form->getPriority()] = [$form];
397
			}
398
			if ($section === 'encryption') {
399
				/** @var ISettings $form */
400
				$form = new Admin\Encryption($this->encryptionManager, $this->userManager);
401
				$forms[$form->getPriority()] = [$form];
402
			}
403
			if ($section === 'sharing') {
404
				/** @var ISettings $form */
405
				$form = new Admin\Sharing($this->config);
406
				$forms[$form->getPriority()] = [$form];
407
			}
408 View Code Duplication
			if ($section === 'additional') {
409
				/** @var ISettings $form */
410
				$form = new Admin\Additional($this->config);
411
				$forms[$form->getPriority()] = [$form];
412
			}
413
			if ($section === 'tips-tricks') {
414
				/** @var ISettings $form */
415
				$form = new Admin\TipsTricks($this->config);
416
				$forms[$form->getPriority()] = [$form];
417
			}
418
		} catch (QueryException $e) {
419
			// skip
420
		}
421
		return $forms;
422
	}
423
424
	/**
425
	 * @param string $section
426
	 * @return ISection[]
427
	 */
428
	private function getBuiltInPersonalSettings($section) {
429
		$forms = [];
430
		try {
431
			if ($section === 'personal-info') {
432
				/** @var ISettings $form */
433
				$form = new Personal\PersonalInfo(
434
					$this->config,
435
					$this->userManager,
436
					$this->groupManager,
437
					$this->accountManager,
438
					$this->appManager,
439
					$this->l10nFactory,
440
					$this->l
441
				);
442
				$forms[$form->getPriority()] = [$form];
443
			}
444
			if($section === 'security') {
445
				/** @var ISettings $form */
446
				$form = new Personal\Security();
447
				$forms[$form->getPriority()] = [$form];
448
			}
449 View Code Duplication
			if ($section === 'additional') {
450
				/** @var ISettings $form */
451
				$form = new Personal\Additional($this->config);
452
				$forms[$form->getPriority()] = [$form];
453
			}
454
		} catch (QueryException $e) {
455
			// skip
456
		}
457
		return $forms;
458
	}
459
460
	/**
461
	 * @inheritdoc
462
	 */
463
	public function getAdminSettings($section) {
464
		$settings = $this->getBuiltInAdminSettings($section);
465
		$dbRows = $this->mapper->getAdminSettingsFromDB($section);
466
467
		foreach ($dbRows as $row) {
468
			if (!isset($settings[$row['priority']])) {
469
				$settings[$row['priority']] = [];
470
			}
471
			try {
472
				$settings[$row['priority']][] = $this->query($row['class']);
473
			} catch (QueryException $e) {
474
				// skip
475
			} catch (AutoloadNotAllowedException $e) {
476
				// skip error and remove remnant of disabled app
477
				$this->log->warning('Orphan setting entry will be removed from admin_settings: ' . json_encode($row));
478
				$this->mapper->remove(Mapper::TABLE_ADMIN_SETTINGS, $row['class']);
479
			}
480
		}
481
482
		ksort($settings);
483
		return $settings;
484
	}
485
486
	/**
487
	 * @inheritdoc
488
	 */
489
	public function getPersonalSections() {
490
		$sections = [
491
			0 => [new Section('personal-info', $this->l->t('Personal info'), 0, $this->url->imagePath('core', 'actions/info.svg'))],
492
			5 => [new Section('security', $this->l->t('Security'), 0, $this->url->imagePath('settings', 'password.svg'))],
493
			15 => [new Section('sync-clients', $this->l->t('Sync clients'), 0, $this->url->imagePath('settings', 'change.svg'))],
494
		];
495
496
		$legacyForms = \OC_App::getForms('personal');
497
		if(count($legacyForms) > 0 && $this->hasLegacyPersonalSettingsToRender($legacyForms)) {
498
			$sections[98] = [new Section('additional', $this->l->t('Additional settings'), 0, $this->url->imagePath('core', 'actions/settings-dark.svg'))];
499
		}
500
501
		$rows = $this->mapper->getPersonalSectionsFromDB();
502
503
		foreach ($rows as $row) {
504
			if (!isset($sections[$row['priority']])) {
505
				$sections[$row['priority']] = [];
506
			}
507
			try {
508
				$sections[$row['priority']][] = $this->query($row['class']);
509
			} catch (QueryException $e) {
510
				// skip
511
			}
512
		}
513
514
		ksort($sections);
515
516
		return $sections;
517
	}
518
519
	/**
520
	 * @param $forms
521
	 * @return bool
522
	 */
523
	private function hasLegacyPersonalSettingsToRender($forms) {
524
		foreach ($forms as $form) {
525
			if(trim($form) !== '') {
526
				return true;
527
			}
528
		}
529
		return false;
530
	}
531
532
	/**
533
	 * @inheritdoc
534
	 */
535
	public function getPersonalSettings($section) {
536
		$settings = $this->getBuiltInPersonalSettings($section);
537
		$dbRows = $this->mapper->getPersonalSettingsFromDB($section);
538
539
		foreach ($dbRows as $row) {
540
			if (!isset($settings[$row['priority']])) {
541
				$settings[$row['priority']] = [];
542
			}
543
			try {
544
				$settings[$row['priority']][] = $this->query($row['class']);
545
			} catch (QueryException $e) {
546
				// skip
547
			}
548
		}
549
550
		ksort($settings);
551
		return $settings;
552
	}
553
}
554