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.
 
 
 
 
 

293 lines
9.7 KiB

  1. <?php
  2. /**
  3. * Configuration Manager admin plugin
  4. *
  5. * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
  6. * @author Christopher Smith <chris@jalakai.co.uk>
  7. * @author Ben Coburn <btcoburn@silicodon.net>
  8. */
  9. use dokuwiki\Extension\AdminPlugin;
  10. use dokuwiki\plugin\config\core\Configuration;
  11. use dokuwiki\plugin\config\core\Setting\Setting;
  12. use dokuwiki\plugin\config\core\Setting\SettingFieldset;
  13. use dokuwiki\plugin\config\core\Setting\SettingHidden;
  14. /**
  15. * All DokuWiki plugins to extend the admin function
  16. * need to inherit from this class
  17. */
  18. class admin_plugin_config extends AdminPlugin
  19. {
  20. protected const IMGDIR = DOKU_BASE . 'lib/plugins/config/images/';
  21. /** @var Configuration */
  22. protected $configuration;
  23. /** @var bool were there any errors in the submitted data? */
  24. protected $hasErrors = false;
  25. /** @var bool have the settings translations been loaded? */
  26. protected $promptsLocalized = false;
  27. /**
  28. * handle user request
  29. */
  30. public function handle()
  31. {
  32. global $ID, $INPUT;
  33. // always initialize the configuration
  34. $this->configuration = new Configuration();
  35. if (!$INPUT->bool('save') || !checkSecurityToken()) {
  36. return;
  37. }
  38. // don't go any further if the configuration is locked
  39. if ($this->configuration->isLocked()) return;
  40. // update settings and redirect of successful
  41. $ok = $this->configuration->updateSettings($INPUT->arr('config'));
  42. if ($ok) { // no errors
  43. try {
  44. if ($this->configuration->hasChanged()) {
  45. $this->configuration->save();
  46. } else {
  47. $this->configuration->touch();
  48. }
  49. msg($this->getLang('updated'), 1);
  50. } catch (Exception $e) {
  51. msg($this->getLang('error'), -1);
  52. }
  53. send_redirect(wl($ID, ['do' => 'admin', 'page' => 'config'], true, '&'));
  54. } else {
  55. $this->hasErrors = true;
  56. msg($this->getLang('error'), -1);
  57. }
  58. }
  59. /**
  60. * output appropriate html
  61. */
  62. public function html()
  63. {
  64. $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here.
  65. global $lang;
  66. global $ID;
  67. $this->setupLocale(true);
  68. echo $this->locale_xhtml('intro');
  69. echo '<div id="config__manager">';
  70. if ($this->configuration->isLocked()) {
  71. echo '<div class="info">' . $this->getLang('locked') . '</div>';
  72. }
  73. // POST to script() instead of wl($ID) so config manager still works if
  74. // rewrite config is broken. Add $ID as hidden field to remember
  75. // current ID in most cases.
  76. echo '<form id="dw__configform" action="' . script() . '" method="post">';
  77. echo '<div class="no"><input type="hidden" name="id" value="' . $ID . '" /></div>';
  78. formSecurityToken();
  79. $this->printH1('dokuwiki_settings', $this->getLang('_header_dokuwiki'));
  80. $in_fieldset = false;
  81. $first_plugin_fieldset = true;
  82. $first_template_fieldset = true;
  83. foreach ($this->configuration->getSettings() as $setting) {
  84. if ($setting instanceof SettingHidden) {
  85. continue;
  86. } elseif ($setting instanceof SettingFieldset) {
  87. // config setting group
  88. if ($in_fieldset) {
  89. echo '</table>';
  90. echo '</div>';
  91. echo '</fieldset>';
  92. } else {
  93. $in_fieldset = true;
  94. }
  95. if ($first_plugin_fieldset && $setting->getType() == 'plugin') {
  96. $this->printH1('plugin_settings', $this->getLang('_header_plugin'));
  97. $first_plugin_fieldset = false;
  98. } elseif ($first_template_fieldset && $setting->getType() == 'template') {
  99. $this->printH1('template_settings', $this->getLang('_header_template'));
  100. $first_template_fieldset = false;
  101. }
  102. echo '<fieldset id="' . $setting->getKey() . '">';
  103. echo '<legend>' . $setting->prompt($this) . '</legend>';
  104. echo '<div class="table">';
  105. echo '<table class="inline">';
  106. } else {
  107. // config settings
  108. [$label, $input] = $setting->html($this, $this->hasErrors);
  109. $class = $setting->isDefault()
  110. ? ' class="default"'
  111. : ($setting->isProtected() ? ' class="protected"' : '');
  112. $error = $setting->hasError()
  113. ? ' class="value error"'
  114. : ' class="value"';
  115. $icon = $setting->caution()
  116. ? '<img src="' . self::IMGDIR . $setting->caution() . '.png" ' .
  117. 'alt="' . $setting->caution() . '" title="' . $this->getLang($setting->caution()) . '" />'
  118. : '';
  119. echo '<tr' . $class . '>';
  120. echo '<td class="label">';
  121. echo '<span class="outkey">' . $setting->getPrettyKey() . '</span>';
  122. echo $icon . $label;
  123. echo '</td>';
  124. echo '<td' . $error . '>' . $input . '</td>';
  125. echo '</tr>';
  126. }
  127. }
  128. echo '</table>';
  129. echo '</div>';
  130. if ($in_fieldset) {
  131. echo '</fieldset>';
  132. }
  133. // show undefined settings list
  134. $undefined_settings = $this->configuration->getUndefined();
  135. if ($allow_debug && !empty($undefined_settings)) {
  136. /**
  137. * Callback for sorting settings
  138. *
  139. * @param Setting $a
  140. * @param Setting $b
  141. * @return int if $a is lower/equal/higher than $b
  142. */
  143. function settingNaturalComparison($a, $b)
  144. {
  145. return strnatcmp($a->getKey(), $b->getKey());
  146. }
  147. usort($undefined_settings, 'settingNaturalComparison');
  148. $this->printH1('undefined_settings', $this->getLang('_header_undefined'));
  149. echo '<fieldset>';
  150. echo '<div class="table">';
  151. echo '<table class="inline">';
  152. foreach ($undefined_settings as $setting) {
  153. [$label, $input] = $setting->html($this);
  154. echo '<tr>';
  155. echo '<td class="label">' . $label . '</td>';
  156. echo '<td>' . $input . '</td>';
  157. echo '</tr>';
  158. }
  159. echo '</table>';
  160. echo '</div>';
  161. echo '</fieldset>';
  162. }
  163. // finish up form
  164. echo '<p>';
  165. echo '<input type="hidden" name="do" value="admin" />';
  166. echo '<input type="hidden" name="page" value="config" />';
  167. if (!$this->configuration->isLocked()) {
  168. echo '<input type="hidden" name="save" value="1" />';
  169. echo '<button type="submit" name="submit" accesskey="s">' . $lang['btn_save'] . '</button>';
  170. echo '<button type="reset">' . $lang['btn_reset'] . '</button>';
  171. }
  172. echo '</p>';
  173. echo '</form>';
  174. echo '</div>';
  175. }
  176. /**
  177. * @param bool $prompts
  178. */
  179. public function setupLocale($prompts = false)
  180. {
  181. parent::setupLocale();
  182. if (!$prompts || $this->promptsLocalized) return;
  183. $this->lang = array_merge($this->lang, $this->configuration->getLangs());
  184. $this->promptsLocalized = true;
  185. }
  186. /**
  187. * Generates a two-level table of contents for the config plugin.
  188. *
  189. * @author Ben Coburn <btcoburn@silicodon.net>
  190. *
  191. * @return array
  192. */
  193. public function getTOC()
  194. {
  195. $this->setupLocale(true);
  196. $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here.
  197. $toc = [];
  198. $check = false;
  199. // gather settings data into three sub arrays
  200. $labels = ['dokuwiki' => [], 'plugin' => [], 'template' => []];
  201. foreach ($this->configuration->getSettings() as $setting) {
  202. if ($setting instanceof SettingFieldset) {
  203. $labels[$setting->getType()][] = $setting;
  204. }
  205. }
  206. // top header
  207. $title = $this->getLang('_configuration_manager');
  208. $toc[] = html_mktocitem(sectionID($title, $check), $title, 1);
  209. // main entries
  210. foreach (['dokuwiki', 'plugin', 'template'] as $section) {
  211. if (empty($labels[$section])) continue; // no entries, skip
  212. // create main header
  213. $toc[] = html_mktocitem(
  214. $section . '_settings',
  215. $this->getLang('_header_' . $section),
  216. 1
  217. );
  218. // create sub headers
  219. foreach ($labels[$section] as $setting) {
  220. /** @var SettingFieldset $setting */
  221. $name = $setting->prompt($this);
  222. $toc[] = html_mktocitem($setting->getKey(), $name, 2);
  223. }
  224. }
  225. // undefined settings if allowed
  226. if (count($this->configuration->getUndefined()) && $allow_debug) {
  227. $toc[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1);
  228. }
  229. return $toc;
  230. }
  231. /**
  232. * @param string $id
  233. * @param string $text
  234. */
  235. protected function printH1($id, $text)
  236. {
  237. echo '<h1 id="' . $id . '">' . $text . '</h1>';
  238. }
  239. /**
  240. * Adds a translation to this plugin's language array
  241. *
  242. * Used by some settings to set up dynamic translations
  243. *
  244. * @param string $key
  245. * @param string $value
  246. */
  247. public function addLang($key, $value)
  248. {
  249. if (!$this->localised) $this->setupLocale();
  250. $this->lang[$key] = $value;
  251. }
  252. }