summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/websetup.pm
blob: a0c396067633663dcde79aea12cf1f629466b6af (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 @default_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 => \@default_force_plugins,
  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}}, @rcs_plugins) {
  150. return 0;
  151. }
  152. elsif (! exists $config{websetup_force_plugins} &&
  153. grep { $_ eq $plugin } @default_force_plugins, @rcs_plugins) {
  154. return 0;
  155. }
  156. $form->field(
  157. ame => "enable.$plugin",
  158. label => "",
  159. type => "checkbox",
  160. options => [ [ 1 => sprintf(gettext("enable %s?"), $plugin) ] ],
  161. value => $enabled,
  162. fieldset => $section,
  163. );
  164. return 1;
  165. } #}}}
  166. sub showform ($$) { #{{{
  167. my $cgi=shift;
  168. my $session=shift;
  169. if (! defined $session->param("name") ||
  170. ! IkiWiki::is_admin($session->param("name"))) {
  171. error(gettext("you are not logged in as an admin"));
  172. }
  173. eval q{use CGI::FormBuilder};
  174. error($@) if $@;
  175. my $form = CGI::FormBuilder->new(
  176. title => "setup",
  177. name => "setup",
  178. header => 0,
  179. charset => "utf-8",
  180. method => 'POST',
  181. javascript => 0,
  182. reset => 1,
  183. params => $cgi,
  184. action => $config{cgiurl},
  185. template => {type => 'div'},
  186. stylesheet => IkiWiki::baseurl()."style.css",
  187. );
  188. my $buttons=["Save Setup", "Cancel"];
  189. IkiWiki::decode_form_utf8($form);
  190. IkiWiki::run_hooks(formbuilder_setup => sub {
  191. shift->(form => $form, cgi => $cgi, session => $session,
  192. buttons => $buttons);
  193. });
  194. IkiWiki::decode_form_utf8($form);
  195. $form->field(name => "do", type => "hidden", value => "setup",
  196. force => 1);
  197. my %fields=showfields($form, undef, undef, IkiWiki::getsetup());
  198. # record all currently enabled plugins before all are loaded
  199. my %enabled_plugins=%IkiWiki::loaded_plugins;
  200. # per-plugin setup
  201. require IkiWiki::Setup;
  202. my %plugins=map { $_ => 1 } IkiWiki::listplugins();
  203. foreach my $pair (IkiWiki::Setup::getsetup()) {
  204. my $plugin=$pair->[0];
  205. my $setup=$pair->[1];
  206. # skip all rcs plugins except for the one in use
  207. next if $plugin ne $config{rcs} && grep { $_ eq $plugin } @rcs_plugins;
  208. my %shown=showfields($form, $plugin, $enabled_plugins{$plugin}, @{$setup});
  209. if (%shown) {
  210. delete $plugins{$plugin};
  211. $fields{$_}=$shown{$_} foreach keys %shown;
  212. }
  213. }
  214. # list all remaining plugins (with no setup options) at the end
  215. foreach (sort keys %plugins) {
  216. if (showplugintoggle($form, $_, $enabled_plugins{$_}, gettext("other plugins"))) {
  217. $fields{"enable.$_"}=[$_];
  218. }
  219. }
  220. if ($form->submitted eq "Cancel") {
  221. IkiWiki::redirect($cgi, $config{url});
  222. return;
  223. }
  224. elsif (($form->submitted eq 'Save Setup' || $form->submitted eq 'Rebuild Wiki') && $form->validate) {
  225. my %rebuild;
  226. foreach my $field (keys %fields) {
  227. # TODO plugin enable/disable
  228. next if $field=~/^enable\./; # plugin
  229. my $key=$fields{$field}->[0];
  230. my %info=%{$fields{$field}->[1]};
  231. my $value=$form->field($field);
  232. if (! $info{safe}) {
  233. error("unsafe field $key"); # should never happen
  234. }
  235. next unless defined $value;
  236. # Avoid setting fields to empty strings,
  237. # if they were not set before.
  238. next if ! defined $config{$key} && ! length $value;
  239. if ($info{rebuild} && (! defined $config{$key} || $config{$key} ne $value)) {
  240. $rebuild{$field}=1;
  241. }
  242. $config{$key}=$value;
  243. }
  244. if (%rebuild && $form->submitted eq 'Save Setup') {
  245. $form->text(gettext("The configuration changes shown below require a wiki rebuild to take effect."));
  246. foreach my $field ($form->field) {
  247. next if $rebuild{$field};
  248. $form->field(name => $field, type => "hidden",
  249. force => 1);
  250. }
  251. $form->reset(0); # doesn't really make sense here
  252. $buttons=["Rebuild Wiki", "Cancel"];
  253. }
  254. else {
  255. # TODO save to real path
  256. IkiWiki::Setup::dump("/tmp/s");
  257. $form->text(gettext("Setup saved."));
  258. if (%rebuild) {
  259. # TODO rebuild
  260. }
  261. }
  262. }
  263. IkiWiki::showform($form, $buttons, $session, $cgi);
  264. } #}}}
  265. sub sessioncgi ($$) { #{{{
  266. my $cgi=shift;
  267. my $session=shift;
  268. if ($cgi->param("do") eq "setup") {
  269. showform($cgi, $session);
  270. exit;
  271. }
  272. } #}}}
  273. sub formbuilder_setup (@) { #{{{
  274. my %params=@_;
  275. my $form=$params{form};
  276. if ($form->title eq "preferences") {
  277. push @{$params{buttons}}, "Wiki Setup";
  278. if ($form->submitted && $form->submitted eq "Wiki Setup") {
  279. showform($params{cgi}, $params{session});
  280. exit;
  281. }
  282. }
  283. } #}}}
  284. 1