Completed
Push — master ( 4c54ca...8e9505 )
by Joas
34:55
created

Manager::onAppDisabled()   D

Complexity

Conditions 9
Paths 24

Size

Total Lines 25
Code Lines 14

Duplication

Lines 20
Ratio 80 %

Importance

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