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