You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

316 lines
7.9 KiB

3 years ago
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de>
  4. *
  5. * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Joas Schilling <coding@schilljs.com>
  8. * @author Julius Härtl <jus@bitgrid.net>
  9. * @author Lukas Reschke <lukas@statuscode.ch>
  10. * @author Morris Jobke <hey@morrisjobke.de>
  11. * @author Robin Appelman <robin@icewind.nl>
  12. * @author Roeland Jago Douma <roeland@famdouma.nl>
  13. * @author sualko <klaus@jsxc.org>
  14. *
  15. * @license GNU AGPL version 3 or any later version
  16. *
  17. * This program is free software: you can redistribute it and/or modify
  18. * it under the terms of the GNU Affero General Public License as
  19. * published by the Free Software Foundation, either version 3 of the
  20. * License, or (at your option) any later version.
  21. *
  22. * This program is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU Affero General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU Affero General Public License
  28. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  29. *
  30. */
  31. namespace OC\Settings;
  32. use Closure;
  33. use OCP\AppFramework\QueryException;
  34. use OCP\IL10N;
  35. use OCP\ILogger;
  36. use OCP\IServerContainer;
  37. use OCP\IURLGenerator;
  38. use OCP\L10N\IFactory;
  39. use OCP\Settings\IManager;
  40. use OCP\Settings\ISection;
  41. use OCP\Settings\ISettings;
  42. use OCP\Settings\ISubAdminSettings;
  43. class Manager implements IManager {
  44. /** @var ILogger */
  45. private $log;
  46. /** @var IL10N */
  47. private $l;
  48. /** @var IFactory */
  49. private $l10nFactory;
  50. /** @var IURLGenerator */
  51. private $url;
  52. /** @var IServerContainer */
  53. private $container;
  54. public function __construct(
  55. ILogger $log,
  56. IFactory $l10nFactory,
  57. IURLGenerator $url,
  58. IServerContainer $container
  59. ) {
  60. $this->log = $log;
  61. $this->l10nFactory = $l10nFactory;
  62. $this->url = $url;
  63. $this->container = $container;
  64. }
  65. /** @var array */
  66. protected $sectionClasses = [];
  67. /** @var array */
  68. protected $sections = [];
  69. /**
  70. * @param string $type 'admin' or 'personal'
  71. * @param string $section Class must implement OCP\Settings\ISection
  72. *
  73. * @return void
  74. */
  75. public function registerSection(string $type, string $section) {
  76. if (!isset($this->sectionClasses[$type])) {
  77. $this->sectionClasses[$type] = [];
  78. }
  79. $this->sectionClasses[$type][] = $section;
  80. }
  81. /**
  82. * @param string $type 'admin' or 'personal'
  83. *
  84. * @return ISection[]
  85. */
  86. protected function getSections(string $type): array {
  87. if (!isset($this->sections[$type])) {
  88. $this->sections[$type] = [];
  89. }
  90. if (!isset($this->sectionClasses[$type])) {
  91. return $this->sections[$type];
  92. }
  93. foreach (array_unique($this->sectionClasses[$type]) as $index => $class) {
  94. try {
  95. /** @var ISection $section */
  96. $section = \OC::$server->query($class);
  97. } catch (QueryException $e) {
  98. $this->log->logException($e, ['level' => ILogger::INFO]);
  99. continue;
  100. }
  101. if (!$section instanceof ISection) {
  102. $this->log->logException(new \InvalidArgumentException('Invalid settings section registered'), ['level' => ILogger::INFO]);
  103. continue;
  104. }
  105. $sectionID = $section->getID();
  106. if ($sectionID !== 'connected-accounts' && isset($this->sections[$type][$sectionID])) {
  107. $this->log->logException(new \InvalidArgumentException('Section with the same ID already registered: ' . $sectionID . ', class: ' . $class), ['level' => ILogger::INFO]);
  108. continue;
  109. }
  110. $this->sections[$type][$sectionID] = $section;
  111. unset($this->sectionClasses[$type][$index]);
  112. }
  113. return $this->sections[$type];
  114. }
  115. /** @var array */
  116. protected $settingClasses = [];
  117. /** @var array */
  118. protected $settings = [];
  119. /**
  120. * @param string $type 'admin' or 'personal'
  121. * @param string $setting Class must implement OCP\Settings\ISetting
  122. *
  123. * @return void
  124. */
  125. public function registerSetting(string $type, string $setting) {
  126. $this->settingClasses[$setting] = $type;
  127. }
  128. /**
  129. * @param string $type 'admin' or 'personal'
  130. * @param string $section
  131. * @param Closure $filter optional filter to apply on all loaded ISettings
  132. *
  133. * @return ISettings[]
  134. */
  135. protected function getSettings(string $type, string $section, Closure $filter = null): array {
  136. if (!isset($this->settings[$type])) {
  137. $this->settings[$type] = [];
  138. }
  139. if (!isset($this->settings[$type][$section])) {
  140. $this->settings[$type][$section] = [];
  141. }
  142. foreach ($this->settingClasses as $class => $settingsType) {
  143. if ($type !== $settingsType) {
  144. continue;
  145. }
  146. try {
  147. /** @var ISettings $setting */
  148. $setting = $this->container->query($class);
  149. } catch (QueryException $e) {
  150. $this->log->logException($e, ['level' => ILogger::INFO]);
  151. continue;
  152. }
  153. if (!$setting instanceof ISettings) {
  154. $this->log->logException(new \InvalidArgumentException('Invalid settings setting registered (' . $class . ')'), ['level' => ILogger::INFO]);
  155. continue;
  156. }
  157. if ($filter !== null && !$filter($setting)) {
  158. continue;
  159. }
  160. if ($setting->getSection() === null) {
  161. continue;
  162. }
  163. if (!isset($this->settings[$settingsType][$setting->getSection()])) {
  164. $this->settings[$settingsType][$setting->getSection()] = [];
  165. }
  166. $this->settings[$settingsType][$setting->getSection()][] = $setting;
  167. unset($this->settingClasses[$class]);
  168. }
  169. return $this->settings[$type][$section];
  170. }
  171. /**
  172. * @inheritdoc
  173. */
  174. public function getAdminSections(): array {
  175. // built-in sections
  176. $sections = [];
  177. $appSections = $this->getSections('admin');
  178. foreach ($appSections as $section) {
  179. /** @var ISection $section */
  180. if (!isset($sections[$section->getPriority()])) {
  181. $sections[$section->getPriority()] = [];
  182. }
  183. $sections[$section->getPriority()][] = $section;
  184. }
  185. ksort($sections);
  186. return $sections;
  187. }
  188. /**
  189. * @inheritdoc
  190. */
  191. public function getAdminSettings($section, bool $subAdminOnly = false): array {
  192. if ($subAdminOnly) {
  193. $subAdminSettingsFilter = function (ISettings $settings) {
  194. return $settings instanceof ISubAdminSettings;
  195. };
  196. $appSettings = $this->getSettings('admin', $section, $subAdminSettingsFilter);
  197. } else {
  198. $appSettings = $this->getSettings('admin', $section);
  199. }
  200. $settings = [];
  201. foreach ($appSettings as $setting) {
  202. if (!isset($settings[$setting->getPriority()])) {
  203. $settings[$setting->getPriority()] = [];
  204. }
  205. $settings[$setting->getPriority()][] = $setting;
  206. }
  207. ksort($settings);
  208. return $settings;
  209. }
  210. /**
  211. * @inheritdoc
  212. */
  213. public function getPersonalSections(): array {
  214. if ($this->l === null) {
  215. $this->l = $this->l10nFactory->get('lib');
  216. }
  217. $sections = [];
  218. $legacyForms = \OC_App::getForms('personal');
  219. if ((!empty($legacyForms) && $this->hasLegacyPersonalSettingsToRender($legacyForms))
  220. || count($this->getPersonalSettings('additional')) > 1) {
  221. $sections[98] = [new Section('additional', $this->l->t('Additional settings'), 0, $this->url->imagePath('core', 'actions/settings-dark.svg'))];
  222. }
  223. $appSections = $this->getSections('personal');
  224. foreach ($appSections as $section) {
  225. /** @var ISection $section */
  226. if (!isset($sections[$section->getPriority()])) {
  227. $sections[$section->getPriority()] = [];
  228. }
  229. $sections[$section->getPriority()][] = $section;
  230. }
  231. ksort($sections);
  232. return $sections;
  233. }
  234. /**
  235. * @param string[] $forms
  236. *
  237. * @return bool
  238. */
  239. private function hasLegacyPersonalSettingsToRender(array $forms): bool {
  240. foreach ($forms as $form) {
  241. if (trim($form) !== '') {
  242. return true;
  243. }
  244. }
  245. return false;
  246. }
  247. /**
  248. * @inheritdoc
  249. */
  250. public function getPersonalSettings($section): array {
  251. $settings = [];
  252. $appSettings = $this->getSettings('personal', $section);
  253. foreach ($appSettings as $setting) {
  254. if (!isset($settings[$setting->getPriority()])) {
  255. $settings[$setting->getPriority()] = [];
  256. }
  257. $settings[$setting->getPriority()][] = $setting;
  258. }
  259. ksort($settings);
  260. return $settings;
  261. }
  262. }