summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/websetup.pm
blob: 4c936741066d90fcad61b42b6d6d3020e7eeac71 (plain)
  1. #!/usr/bin/perl
  2. package IkiWiki::Plugin::websetup;
  3. use warnings;
  4. use strict;
  5. use IkiWiki 2.00;
  6. sub import { #{{{
  7. hook(type => "getsetup", id => "websetup", call => \&getsetup);
  8. hook(type => "checkconfig", id => "websetup", call => \&checkconfig);
  9. hook(type => "sessioncgi", id => "websetup", call => \&sessioncgi);
  10. hook(type => "formbuilder_setup", id => "websetup",
  11. call => \&formbuilder_setup);
  12. } # }}}
  13. sub getsetup () { #{{{
  14. return
  15. websetup_force_plugins => {
  16. type => "string",
  17. example => [],
  18. description => "list of plugins that cannot be enabled/disabled via the web interface",
  19. safe => 0,
  20. rebuild => 0,
  21. },
  22. websetup_show_unsafe => {
  23. type => "boolean",
  24. example => 1,
  25. description => "show unsafe settings, read-only, in web interface?",
  26. safe => 0,
  27. rebuild => 0,
  28. },
  29. } #}}}
  30. sub checkconfig () { #{{{
  31. if (! exists $config{websetup_show_unsafe}) {
  32. $config{websetup_show_unsafe}=1;
  33. }
  34. } #}}}
  35. sub formatexample ($$) { #{{{
  36. my $example=shift;
  37. my $value=shift;
  38. if (defined $value && length $value) {
  39. return "";
  40. }
  41. elsif (defined $example && ! ref $example && length $example) {
  42. return "<br/ ><small>Example: <tt>$example</tt></small>";
  43. }
  44. else {
  45. return "";
  46. }
  47. } #}}}
  48. sub showfields ($$$@) { #{{{
  49. my $form=shift;
  50. my $plugin=shift;
  51. my $enabled=shift;
  52. my @show;
  53. my %plugininfo;
  54. while (@_) {
  55. my $key=shift;
  56. my %info=%{shift()};
  57. # skip internal settings
  58. next if defined $info{type} && $info{type} eq "internal";
  59. # XXX hashes not handled yet
  60. next if ref $config{$key} && ref $config{$key} eq 'HASH' || ref $info{example} eq 'HASH';
  61. # maybe skip unsafe settings
  62. next if ! $info{safe} && ! ($config{websetup_show_unsafe} && $config{websetup_advanced});
  63. # maybe skip advanced settings
  64. next if $info{advanced} && ! $config{websetup_advanced};
  65. # these are handled specially, so don't show
  66. next if $key eq 'add_plugins' || $key eq 'disable_plugins';
  67. if ($key eq 'plugin') {
  68. %plugininfo=%info;
  69. next;
  70. }
  71. push @show, $key, \%info;
  72. }
  73. my $plugin_forced=defined $plugin && (! $plugininfo{safe} ||
  74. (exists $config{websetup_force_plugins} && grep { $_ eq $plugin } @{$config{websetup_force_plugins}}));
  75. if ($plugin_forced && ! $enabled) {
  76. # plugin is forced disabled, so skip its configuration
  77. @show=();
  78. }
  79. my %shownfields;
  80. my %skippedfields;
  81. my $section=defined $plugin ? $plugin." ".gettext("plugin") : "main";
  82. while (@show) {
  83. my $key=shift @show;
  84. my %info=%{shift @show};
  85. my $description=$info{description};
  86. if (exists $info{link} && length $info{link}) {
  87. if ($info{link} =~ /^\w+:\/\//) {
  88. $description="<a href=\"$info{link}\">$description</a>";
  89. }
  90. else {
  91. $description=htmllink("", "", $info{link}, noimageinline => 1, linktext => $description);
  92. }
  93. }
  94. # multiple plugins can have the same field
  95. my $name=defined $plugin ? $plugin.".".$key : $key;
  96. my $value=$config{$key};
  97. if ($info{safe} && (ref $config{$key} eq 'ARRAY' || ref $info{example} eq 'ARRAY')) {
  98. push @{$value}, "", ""; # blank items for expansion
  99. }
  100. if ($info{type} eq "string") {
  101. $form->field(
  102. name => $name,
  103. label => $description,
  104. comment => formatexample($info{example}, $value),
  105. type => "text",
  106. value => $value,
  107. size => 60,
  108. fieldset => $section,
  109. );
  110. }
  111. elsif ($info{type} eq "pagespec") {
  112. $form->field(
  113. name => $name,
  114. label => $description,
  115. comment => formatexample($info{example}, $value),
  116. type => "text",
  117. value => $value,
  118. size => 60,
  119. validate => \&IkiWiki::pagespec_valid,
  120. fieldset => $section,
  121. );
  122. }
  123. elsif ($info{type} eq "integer") {
  124. $form->field(
  125. name => $name,
  126. label => $description,
  127. comment => formatexample($info{example}, $value),
  128. type => "text",
  129. value => $value,
  130. size => 5,
  131. validate => '/^[0-9]+$/',
  132. fieldset => $section,
  133. );
  134. }
  135. elsif ($info{type} eq "boolean") {
  136. $form->field(
  137. name => $name,
  138. label => "",
  139. type => "checkbox",
  140. value => $value,
  141. options => [ [ 1 => $description ] ],
  142. fieldset => $section,
  143. );
  144. }
  145. if (! $info{safe}) {
  146. $form->field(name => $name, disabled => 1);
  147. $skippedfields{$name}=1;
  148. }
  149. else {
  150. $shownfields{$name}=[$key, \%info];
  151. }
  152. }
  153. if (defined $plugin && (! $plugin_forced || $config{websetup_advanced})) {
  154. my $name="enable.$plugin";
  155. $section="plugins" unless %shownfields || (%skippedfields && $config{websetup_advanced});
  156. $form->field(
  157. name => $name,
  158. label => "",
  159. type => "checkbox",
  160. options => [ [ 1 => sprintf(gettext("enable %s?"), $plugin) ] ],
  161. value => $enabled,
  162. fieldset => $section,
  163. );
  164. if ($plugin_forced) {
  165. $form->field(name => $name, disabled => 1);
  166. }
  167. else {
  168. $shownfields{$name}=[$name, \%plugininfo];
  169. }
  170. }
  171. return %shownfields;
  172. } #}}}
  173. sub showform ($$) { #{{{
  174. my $cgi=shift;
  175. my $session=shift;
  176. if (! defined $session->param("name") ||
  177. ! IkiWiki::is_admin($session->param("name"))) {
  178. error(gettext("you are not logged in as an admin"));
  179. }
  180. eval q{use CGI::FormBuilder};
  181. error($@) if $@;
  182. my $form = CGI::FormBuilder->new(
  183. title => "setup",
  184. name => "setup",
  185. header => 0,
  186. charset => "utf-8",
  187. method => 'POST',
  188. javascript => 0,
  189. reset => 1,
  190. params => $cgi,
  191. fieldsets => [
  192. [main => gettext("main")],
  193. [plugins => gettext("plugins")]
  194. ],
  195. action => $config{cgiurl},
  196. template => {type => 'div'},
  197. stylesheet => IkiWiki::baseurl()."style.css",
  198. );
  199. if ($form->submitted eq 'Basic Mode') {
  200. $form->field(name => "showadvanced", type => "hidden",
  201. value => 0, force => 1);
  202. }
  203. elsif ($form->submitted eq 'Advanced Mode') {
  204. $form->field(name => "showadvanced", type => "hidden",
  205. value => 1, force => 1);
  206. }
  207. my $advancedtoggle;
  208. if ($form->field("showadvanced")) {
  209. $config{websetup_advanced}=1;
  210. $advancedtoggle="Basic Mode";
  211. }
  212. else {
  213. $config{websetup_advanced}=0;
  214. $advancedtoggle="Advanced Mode";
  215. }
  216. my $buttons=["Save Setup", $advancedtoggle, "Cancel"];
  217. IkiWiki::decode_form_utf8($form);
  218. IkiWiki::run_hooks(formbuilder_setup => sub {
  219. shift->(form => $form, cgi => $cgi, session => $session,
  220. buttons => $buttons);
  221. });
  222. IkiWiki::decode_form_utf8($form);
  223. $form->field(name => "do", type => "hidden", value => "setup",
  224. force => 1);
  225. my %fields=showfields($form, undef, undef, IkiWiki::getsetup());
  226. # record all currently enabled plugins before all are loaded
  227. my %enabled_plugins=%IkiWiki::loaded_plugins;
  228. # per-plugin setup
  229. require IkiWiki::Setup;
  230. my %plugins=map { $_ => 1 } IkiWiki::listplugins();
  231. foreach my $pair (IkiWiki::Setup::getsetup()) {
  232. my $plugin=$pair->[0];
  233. my $setup=$pair->[1];
  234. my %shown=showfields($form, $plugin, $enabled_plugins{$plugin}, @{$setup});
  235. if (%shown) {
  236. delete $plugins{$plugin};
  237. $fields{$_}=$shown{$_} foreach keys %shown;
  238. }
  239. }
  240. if ($form->submitted eq "Cancel") {
  241. IkiWiki::redirect($cgi, $config{url});
  242. return;
  243. }
  244. elsif (($form->submitted eq 'Save Setup' || $form->submitted eq 'Rebuild Wiki') && $form->validate) {
  245. my %rebuild;
  246. foreach my $field (keys %fields) {
  247. if ($field=~/^enable\./) {
  248. # rebuild is overkill for many plugins,
  249. # but no good way to tell which
  250. $rebuild{$field}=1; # TODO only if state changed tho
  251. # TODO plugin enable/disable
  252. next;
  253. }
  254. my %info=%{$fields{$field}->[1]};
  255. my $key=$fields{$field}->[0];
  256. my @value=$form->field($field);
  257. if (! $info{safe}) {
  258. error("unsafe field $key"); # should never happen
  259. }
  260. next unless @value;
  261. # Avoid setting fields to empty strings,
  262. # if they were not set before.
  263. next if ! defined $config{$key} && ! grep { length $_ } @value;
  264. if (ref $config{$key} eq "ARRAY" || ref $info{example} eq "ARRAY") {
  265. if ($info{rebuild} && (! defined $config{$key} || (@{$config{$key}}) != (@value))) {
  266. $rebuild{$field}=1;
  267. }
  268. $config{$key}=\@value;
  269. }
  270. elsif (ref $config{$key} || ref $info{example}) {
  271. error("complex field $key"); # should never happen
  272. }
  273. else {
  274. if ($info{rebuild} && (! defined $config{$key} || $config{$key} ne $value[0])) {
  275. $rebuild{$field}=1;
  276. }
  277. $config{$key}=$value[0];
  278. }
  279. }
  280. if (%rebuild && $form->submitted eq 'Save Setup') {
  281. $form->text(gettext("The configuration changes shown below require a wiki rebuild to take effect."));
  282. foreach my $field ($form->field) {
  283. next if $rebuild{$field};
  284. $form->field(name => $field, type => "hidden",
  285. force => 1);
  286. }
  287. $form->reset(0); # doesn't really make sense here
  288. $buttons=["Rebuild Wiki", "Cancel"];
  289. }
  290. else {
  291. # TODO save to real path
  292. IkiWiki::Setup::dump("/tmp/s");
  293. $form->text(gettext("Setup saved."));
  294. if (%rebuild) {
  295. # TODO rebuild
  296. }
  297. }
  298. }
  299. IkiWiki::showform($form, $buttons, $session, $cgi);
  300. } #}}}
  301. sub sessioncgi ($$) { #{{{
  302. my $cgi=shift;
  303. my $session=shift;
  304. if ($cgi->param("do") eq "setup") {
  305. showform($cgi, $session);
  306. exit;
  307. }
  308. } #}}}
  309. sub formbuilder_setup (@) { #{{{
  310. my %params=@_;
  311. my $form=$params{form};
  312. if ($form->title eq "preferences") {
  313. push @{$params{buttons}}, "Wiki Setup";
  314. if ($form->submitted && $form->submitted eq "Wiki Setup") {
  315. showform($params{cgi}, $params{session});
  316. exit;
  317. }
  318. }
  319. } #}}}
  320. 1