From fbce2041807785e148ce54279b786f40cafeb2ed Mon Sep 17 00:00:00 2001 From: James Valleroy Date: Thu, 2 Apr 2015 21:03:53 -0400 Subject: [PATCH] Add ikiwiki module with initial setup and option to enable site. --- actions/ikiwiki | 193 ++++++++++++++++++ data/etc/plinth/modules-enabled/ikiwiki | 1 + plinth/modules/ikiwiki/__init__.py | 33 +++ plinth/modules/ikiwiki/forms.py | 30 +++ plinth/modules/ikiwiki/templates/ikiwiki.html | 38 ++++ plinth/modules/ikiwiki/urls.py | 28 +++ plinth/modules/ikiwiki/views.py | 75 +++++++ 7 files changed, 398 insertions(+) create mode 100755 actions/ikiwiki create mode 100644 data/etc/plinth/modules-enabled/ikiwiki create mode 100644 plinth/modules/ikiwiki/__init__.py create mode 100644 plinth/modules/ikiwiki/forms.py create mode 100644 plinth/modules/ikiwiki/templates/ikiwiki.html create mode 100644 plinth/modules/ikiwiki/urls.py create mode 100644 plinth/modules/ikiwiki/views.py diff --git a/actions/ikiwiki b/actions/ikiwiki new file mode 100755 index 000000000..5c449be53 --- /dev/null +++ b/actions/ikiwiki @@ -0,0 +1,193 @@ +#!/usr/bin/python3 +# +# This file is part of Plinth. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +""" +Configuration helper for ikiwiki +""" + +import argparse +import os +import subprocess + + +CONFIG_ENABLE = '/etc/apache2/conf-enabled/ikiwiki.conf' +CONFIG_FILE = '/etc/apache2/conf-available/ikiwiki.conf' +SETUP_WIKI = '/etc/ikiwiki/plinth-wiki.setup' +SETUP_BLOG = '/etc/ikiwiki/plinth-blog.setup' +WIKI_PATH = '/var/www/ikiwiki' + + +def parse_arguments(): + """Return parsed command line arguments as dictionary.""" + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') + + # Get whether ikiwiki site is enabled + subparsers.add_parser('get-enabled', + help='Get whether ikiwiki site is enabled') + + # Enable ikiwiki site + subparsers.add_parser('enable', help='Enable ikiwiki site') + + # Disable ikiwiki site + subparsers.add_parser('disable', help='Disable ikiwiki site') + + # Create a wiki + create_wiki = subparsers.add_parser('create-wiki', help='Create a wiki') + create_wiki.add_argument('--name', help='Name of new wiki') + + # Create a blog + create_blog = subparsers.add_parser('create-blog', help='Create a blog') + create_blog.add_argument('--name', help='Name of new blog') + + return parser.parse_args() + + +def subcommand_get_enabled(_): + """Get whether ikiwiki site is enabled.""" + if os.path.isfile(CONFIG_ENABLE): + print('yes') + else: + print('no') + + +def subcommand_enable(_): + """Enable ikiwiki site.""" + if not os.path.isfile(CONFIG_FILE): + setup() + + subprocess.check_output(['a2enconf', 'ikiwiki']) + subprocess.check_output(['service', 'apache2', 'reload']) + + +def subcommand_disable(_): + """Disable ikiwiki site.""" + subprocess.check_output(['a2disconf', 'ikiwiki']) + subprocess.check_output(['service', 'apache2', 'reload']) + + +def subcommand_create_wiki(arguments): + """Create a wiki""" + subprocess.check_output(['ikiwiki', '-setup', SETUP_WIKI, arguments.name]) + + +def subcommand_create_blog(arguments): + """Create a blog""" + subprocess.check_output(['ikiwiki', '-setup', SETUP_BLOG, arguments.name]) + + +def setup(): + """Initial setup""" + if not os.path.exists(WIKI_PATH): + os.makedirs(WIKI_PATH) + + with open(CONFIG_FILE, 'w') as conffile: + conffile.writelines([ + 'Alias /ikiwiki /var/www/ikiwiki\n', + 'AddHandler cgi-script .cgi\n', + '\n', + '\n', + ' Options +ExecCGI\n', + '\n' + ]) + + with open(SETUP_WIKI, 'w') as setupfile: + setupfile.writelines([ + '#!/usr/bin/perl\n', + '# Ikiwiki setup automator for Plinth.\n', + '\n', + 'require IkiWiki::Setup::Automator;\n', + '\n', + 'our $wikiname=$ARGV[0];\n', + 'if ($wikiname eq "") {\n', + ' print "Usage: ikiwiki -setup /etc/ikiwiki/plinth-wiki.setup wiki_name";\n', + ' exit;\n', + '}\n', + '\n', + 'our $wikiname_short=IkiWiki::Setup::Automator::sanitize_wikiname($wikiname);\n', + '\n', + 'IkiWiki::Setup::Automator->import(\n', + ' wikiname => $wikiname,\n', + ' rcs => "git",\n', + ' srcdir => "/var/ikiwiki/$wikiname_short",\n', + ' destdir => "/var/www/ikiwiki/$wikiname_short",\n', + ' repository => "/var/ikiwiki/$wikiname_short.git",\n', + ' dumpsetup => "/var/ikiwiki/$wikiname_short.setup",\n', + ' url => "/ikiwiki/$wikiname_short",\n', + ' cgiurl => "/ikiwiki/$wikiname_short/ikiwiki.cgi",\n', + ' cgi_wrapper => "/var/www/ikiwiki/$wikiname_short/ikiwiki.cgi",\n', + ' add_plugins => [qw{goodstuff websetup httpauth}],\n', + ' rss => 1,\n', + ' atom => 1,\n', + ' syslog => 1,\n', + ')\n', + ]) + + with open(SETUP_BLOG, 'w') as setupfile: + setupfile.writelines([ + '#!/usr/bin/perl\n', + '# Ikiwiki setup automator for Plinth (blog version).\n', + '\n', + 'require IkiWiki::Setup::Automator;\n', + '\n', + 'our $wikiname=$ARGV[0];\n', + 'if ($wikiname eq "") {\n', + ' print "Usage: ikiwiki -setup /etc/ikiwiki/plinth-blog.setup blog_name";\n', + ' exit;\n', + '}\n', + '\n', + 'our $wikiname_short=IkiWiki::Setup::Automator::sanitize_wikiname($wikiname);\n', + '\n', + 'IkiWiki::Setup::Automator->import(\n', + ' wikiname => $wikiname,\n', + ' rcs => "git",\n', + ' srcdir => "/var/ikiwiki/$wikiname_short",\n', + ' destdir => "/var/www/ikiwiki/$wikiname_short",\n', + ' repository => "/var/ikiwiki/$wikiname_short.git",\n', + ' dumpsetup => "/var/ikiwiki/$wikiname_short.setup",\n', + ' url => "/ikiwiki/$wikiname_short",\n', + ' cgiurl => "/ikiwiki/$wikiname_short/ikiwiki.cgi",\n', + ' cgi_wrapper => "/var/www/ikiwiki/$wikiname_short/ikiwiki.cgi",\n', + ' add_plugins => [qw{goodstuff websetup comments blogspam calendar sidebar trail httpauth}],\n', + ' rss => 1,\n', + ' atom => 1,\n', + ' syslog => 1,\n', + '\n', + ' example => "blog",\n', + ' comments_pagespec => "posts/* and !*/Discussion",\n', + ' blogspam_pagespec => "postcomment(*)",\n', + ' archive_pagespec => "page(posts/*) and !*/Discussion",\n', + ' global_sidebars => 0,\n', + ' discussion => 0,\n', + ' locked_pages => "* and !postcomment(*)",\n', + ' tagbase => "tags",\n', + ')\n', + ]) + + +def main(): + """Parse arguments and perform all duties.""" + arguments = parse_arguments() + + subcommand = arguments.subcommand.replace('-', '_') + subcommand_method = globals()['subcommand_' + subcommand] + subcommand_method(arguments) + + +if __name__ == '__main__': + main() diff --git a/data/etc/plinth/modules-enabled/ikiwiki b/data/etc/plinth/modules-enabled/ikiwiki new file mode 100644 index 000000000..d46782c3d --- /dev/null +++ b/data/etc/plinth/modules-enabled/ikiwiki @@ -0,0 +1 @@ +plinth.modules.ikiwiki diff --git a/plinth/modules/ikiwiki/__init__.py b/plinth/modules/ikiwiki/__init__.py new file mode 100644 index 000000000..8031a8677 --- /dev/null +++ b/plinth/modules/ikiwiki/__init__.py @@ -0,0 +1,33 @@ +# +# This file is part of Plinth. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +""" +Plinth module to configure ikiwiki +""" + +from gettext import gettext as _ + +from plinth import cfg + + +depends = ['plinth.modules.apps'] + + +def init(): + """Initialize the ikiwiki module.""" + menu = cfg.main_menu.get('apps:index') + menu.add_urlname(_('Wiki & Blog'), 'glyphicon-edit', 'ikiwiki:index', 38) diff --git a/plinth/modules/ikiwiki/forms.py b/plinth/modules/ikiwiki/forms.py new file mode 100644 index 000000000..d6eb762ba --- /dev/null +++ b/plinth/modules/ikiwiki/forms.py @@ -0,0 +1,30 @@ +# +# This file is part of Plinth. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +""" +Forms for configuring ikiwiki +""" + +from django import forms +from gettext import gettext as _ + + +class IkiwikiForm(forms.Form): + """ikiwiki configuration form.""" + enabled = forms.BooleanField( + label=_('Enable ikiwiki site'), + required=False) diff --git a/plinth/modules/ikiwiki/templates/ikiwiki.html b/plinth/modules/ikiwiki/templates/ikiwiki.html new file mode 100644 index 000000000..413d2a235 --- /dev/null +++ b/plinth/modules/ikiwiki/templates/ikiwiki.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} +{% comment %} +# +# This file is part of Plinth. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +{% endcomment %} + +{% load bootstrap %} + +{% block content %} + +

Wiki & Blog

+ +

When enabled, the ikiwiki site will be available from + /ikiwiki path on the web server.

+ +
+ {% csrf_token %} + + {{ form|bootstrap }} + + +
+ +{% endblock %} diff --git a/plinth/modules/ikiwiki/urls.py b/plinth/modules/ikiwiki/urls.py new file mode 100644 index 000000000..eca6c5c74 --- /dev/null +++ b/plinth/modules/ikiwiki/urls.py @@ -0,0 +1,28 @@ +# +# This file is part of Plinth. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +""" +URLs for the ikiwiki module +""" + +from django.conf.urls import patterns, url + + +urlpatterns = patterns( + 'plinth.modules.ikiwiki.views', + url(r'^apps/ikiwiki/$', 'index', name='index'), + ) diff --git a/plinth/modules/ikiwiki/views.py b/plinth/modules/ikiwiki/views.py new file mode 100644 index 000000000..8c3a2ce69 --- /dev/null +++ b/plinth/modules/ikiwiki/views.py @@ -0,0 +1,75 @@ +# +# This file is part of Plinth. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +""" +Plinth module for configuring ikiwiki +""" + +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.template.response import TemplateResponse +from gettext import gettext as _ + +from .forms import IkiwikiForm +from plinth import actions +from plinth import package +from plinth.modules import ikiwiki + + +@login_required +@package.required(['ikiwiki']) +def index(request): + """Serve configuration page.""" + status = get_status() + + form = None + + if request.method == 'POST': + form = IkiwikiForm(request.POST, prefix='ikiwiki') + if form.is_valid(): + _apply_changes(request, status, form.cleaned_data) + status = get_status() + form = IkiwikiForm(initial=status, prefix='ikiwiki') + else: + form = IkiwikiForm(initial=status, prefix='ikiwiki') + + return TemplateResponse(request, 'ikiwiki.html', + {'title': _('Wiki'), + 'status': status, + 'form': form}) + + +def get_status(): + """Get the current setting.""" + output = actions.run('ikiwiki', ['get-enabled']) + enabled = (output.strip() == 'yes') + return {'enabled': enabled} + + +def _apply_changes(request, old_status, new_status): + """Apply the changes.""" + modified = False + + if old_status['enabled'] != new_status['enabled']: + sub_command = 'enable' if new_status['enabled'] else 'disable' + actions.superuser_run('ikiwiki', [sub_command]) + modified = True + + if modified: + messages.success(request, _('Configuration updated')) + else: + messages.info(request, _('Setting unchanged'))