diff --git a/plinth/frontpage.py b/plinth/frontpage.py
new file mode 100644
index 000000000..7e149dbb8
--- /dev/null
+++ b/plinth/frontpage.py
@@ -0,0 +1,42 @@
+#
+# 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 .
+#
+
+"""
+Manage application shortcuts on front page.
+"""
+
+shortcuts = {}
+
+
+def get_shortcuts():
+ """Return menu items in sorted order according to current locale."""
+ return sorted(shortcuts.values(), key=lambda x: x['label'])
+
+
+def add_shortcut(app, label, url, icon):
+ """Add shortcut to front page."""
+ shortcuts[app] = {
+ 'label': label,
+ 'url': url,
+ 'icon': icon,
+ }
+
+
+def remove_shortcut(app):
+ """Remove shortcut from front page."""
+ if app in shortcuts:
+ del shortcuts[app]
diff --git a/plinth/modules/deluge/__init__.py b/plinth/modules/deluge/__init__.py
index 620617c5e..dcda57808 100644
--- a/plinth/modules/deluge/__init__.py
+++ b/plinth/modules/deluge/__init__.py
@@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import action_utils
from plinth import cfg
+from plinth import frontpage
from plinth import service as service_module
@@ -59,12 +60,20 @@ def init():
managed_services[0], title, ports=['http', 'https'], is_external=True,
is_enabled=is_enabled, enable=enable, disable=disable)
+ if is_enabled():
+ add_shortcut()
+
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'deluge', ['enable'])
helper.call('post', service.notify_enabled, None, True)
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut('deluge', title, '/deluge', 'glyphicon-magnet')
def is_enabled():
@@ -76,11 +85,13 @@ def is_enabled():
def enable():
"""Enable the module."""
actions.superuser_run('deluge', ['enable'])
+ add_shortcut()
def disable():
"""Disable the module."""
actions.superuser_run('deluge', ['disable'])
+ frontpage.remove_shortcut('deluge')
def diagnose():
diff --git a/plinth/modules/ikiwiki/__init__.py b/plinth/modules/ikiwiki/__init__.py
index 9e65c961a..1c9b6c3ed 100644
--- a/plinth/modules/ikiwiki/__init__.py
+++ b/plinth/modules/ikiwiki/__init__.py
@@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import action_utils
from plinth import cfg
+from plinth import frontpage
from plinth import service as service_module
@@ -58,12 +59,20 @@ def init():
'ikiwiki', title, ports=['http', 'https'], is_external=True,
is_enabled=is_enabled, enable=enable, disable=disable)
+ if is_enabled():
+ add_shortcut()
+
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'ikiwiki', ['setup'])
helper.call('post', service.notify_enabled, None, True)
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut('ikiwiki', title, '/ikiwiki', 'glyphicon-edit')
def is_enabled():
@@ -74,11 +83,13 @@ def is_enabled():
def enable():
"""Enable the module."""
actions.superuser_run('ikiwiki', ['enable'])
+ add_shortcut()
def disable():
"""Enable the module."""
actions.superuser_run('ikiwiki', ['disable'])
+ frontpage.remove_shortcut('ikiwiki')
def diagnose():
diff --git a/plinth/modules/roundcube/__init__.py b/plinth/modules/roundcube/__init__.py
index d924cf1b0..7c0886483 100644
--- a/plinth/modules/roundcube/__init__.py
+++ b/plinth/modules/roundcube/__init__.py
@@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import action_utils
from plinth import cfg
+from plinth import frontpage
from plinth import service as service_module
@@ -70,12 +71,21 @@ def init():
'roundcube', title, ports=['http', 'https'], is_external=True,
is_enabled=is_enabled, enable=enable, disable=disable)
+ if is_enabled():
+ add_shortcut()
+
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.call('pre', actions.superuser_run, 'roundcube', ['pre-install'])
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'roundcube', ['setup'])
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut(
+ 'roundcube', title, '/roundcube', 'glyphicon-envelope')
def is_enabled():
@@ -86,11 +96,13 @@ def is_enabled():
def enable():
"""Enable the module."""
actions.superuser_run('roundcube', ['enable'])
+ add_shortcut()
def disable():
"""Enable the module."""
actions.superuser_run('roundcube', ['disable'])
+ frontpage.remove_shortcut('roundcube')
def diagnose():
diff --git a/plinth/modules/shaarli/__init__.py b/plinth/modules/shaarli/__init__.py
index 70f182410..2c1f51112 100644
--- a/plinth/modules/shaarli/__init__.py
+++ b/plinth/modules/shaarli/__init__.py
@@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import action_utils
from plinth import cfg
+from plinth import frontpage
from plinth import service as service_module
@@ -57,11 +58,19 @@ def init():
'shaarli', title, ports=['http', 'https'], is_external=True,
is_enabled=is_enabled, enable=enable, disable=disable)
+ if is_enabled():
+ add_shortcut()
+
def setup(helper, old_version=None):
"""Install and configure the module."""
helper.install(managed_packages)
helper.call('post', service.notify_enabled, None, True)
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut('shaarli', title, '/shaarli', 'glyphicon-bookmark')
def is_enabled():
@@ -72,8 +81,10 @@ def is_enabled():
def enable():
"""Enable the module."""
actions.superuser_run('shaarli', ['enable'])
+ add_shortcut()
def disable():
"""Enable the module."""
actions.superuser_run('shaarli', ['disable'])
+ frontpage.remove_shortcut('shaarli')
diff --git a/plinth/modules/transmission/__init__.py b/plinth/modules/transmission/__init__.py
index 3a5a02a0c..fa9e9f34a 100644
--- a/plinth/modules/transmission/__init__.py
+++ b/plinth/modules/transmission/__init__.py
@@ -25,6 +25,7 @@ import json
from plinth import actions
from plinth import action_utils
from plinth import cfg
+from plinth import frontpage
from plinth import service as service_module
@@ -58,6 +59,9 @@ def init():
managed_services[0], title, ports=['http', 'https'], is_external=True,
is_enabled=is_enabled, enable=enable, disable=disable)
+ if is_enabled():
+ add_shortcut()
+
def setup(helper, old_version=None):
"""Install and configure the module."""
@@ -70,6 +74,12 @@ def setup(helper, old_version=None):
helper.call('post', actions.superuser_run, 'transmission', ['enable'])
helper.call('post', service.notify_enabled, None, True)
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut(
+ 'transmission', title, '/transmission', 'glyphicon-save')
def is_enabled():
@@ -81,11 +91,13 @@ def is_enabled():
def enable():
"""Enable the module."""
actions.superuser_run('transmission', ['enable'])
+ add_shortcut()
def disable():
"""Enable the module."""
actions.superuser_run('transmission', ['disable'])
+ frontpage.remove_shortcut('transmission')
def diagnose():
diff --git a/plinth/modules/ttrss/__init__.py b/plinth/modules/ttrss/__init__.py
index 1bcda91c5..98a8b9007 100644
--- a/plinth/modules/ttrss/__init__.py
+++ b/plinth/modules/ttrss/__init__.py
@@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import actions
from plinth import action_utils
from plinth import cfg
+from plinth import frontpage
from plinth import service as service_module
@@ -59,6 +60,9 @@ def init():
managed_services[0], title, ports=['http', 'https'], is_external=True,
is_enabled=is_enabled, enable=enable, disable=disable)
+ if is_enabled():
+ add_shortcut()
+
def setup(helper, old_version=None):
"""Install and configure the module."""
@@ -66,6 +70,11 @@ def setup(helper, old_version=None):
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'ttrss', ['setup'])
helper.call('post', service.notify_enabled, None, True)
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut('ttrss', title, '/tt-rss', 'glyphicon-envelope')
def is_enabled():
@@ -77,11 +86,13 @@ def is_enabled():
def enable():
"""Enable the module."""
actions.superuser_run('ttrss', ['enable'])
+ add_shortcut()
def disable():
"""Enable the module."""
actions.superuser_run('ttrss', ['disable'])
+ frontpage.remove_shortcut('ttrss')
def diagnose():
diff --git a/plinth/modules/xmpp/__init__.py b/plinth/modules/xmpp/__init__.py
index cb36ea49a..9fa650509 100644
--- a/plinth/modules/xmpp/__init__.py
+++ b/plinth/modules/xmpp/__init__.py
@@ -26,6 +26,7 @@ import socket
from plinth import actions
from plinth import action_utils
from plinth import cfg
+from plinth import frontpage
from plinth import service as service_module
from plinth.views import ServiceView
from plinth.signals import pre_hostname_change, post_hostname_change
@@ -72,6 +73,9 @@ def init():
post_hostname_change.connect(on_post_hostname_change)
domainname_change.connect(on_domainname_change)
+ if is_enabled():
+ add_shortcut()
+
def setup(helper, old_version=None):
"""Install and configure the module."""
@@ -83,6 +87,11 @@ def setup(helper, old_version=None):
helper.install(managed_packages)
helper.call('post', actions.superuser_run, 'xmpp', ['setup'])
helper.call('post', service.notify_enabled, None, True)
+ helper.call('post', add_shortcut)
+
+
+def add_shortcut():
+ frontpage.add_shortcut('xmpp', title, '/jwchat', 'glyphicon-comment')
class EjabberdServiceView(ServiceView):
@@ -112,11 +121,13 @@ def get_domainname():
def enable():
"""Enable the module."""
actions.superuser_run('xmpp', ['enable'])
+ add_shortcut()
def disable():
"""Enable the module."""
actions.superuser_run('xmpp', ['disable'])
+ frontpage.remove_shortcut('xmpp')
def on_pre_hostname_change(sender, old_hostname, new_hostname, **kwargs):
diff --git a/plinth/templates/base.html b/plinth/templates/base.html
index d3f76308d..57ac20e5c 100644
--- a/plinth/templates/base.html
+++ b/plinth/templates/base.html
@@ -86,11 +86,13 @@
{% block mainmenu_left %}
-
+
-
-
+
+
{% endblock %}
diff --git a/plinth/templates/index.html b/plinth/templates/index.html
new file mode 100644
index 000000000..ac11b978d
--- /dev/null
+++ b/plinth/templates/index.html
@@ -0,0 +1,96 @@
+{% 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 i18n %}
+
+{% block content %}
+
+ {% if shortcuts %}
+
+ {% for shortcut in shortcuts %}
+
+ {% endfor %}
+
+ {% else %}
+
+
+ {% url 'apps:index' as apps_url %}
+ {% blocktrans trimmed %}
+
+ Enable some applications to add
+ shortcuts to this page.
+
+ {% endblocktrans %}
+
+
+ {% endif %}
+
+{% endblock %}
+
+
+{% block sidebar %}
+
+
+ {% blocktrans trimmed %}
+ Welcome to {{ box_name }}!
+ {% endblocktrans %}
+
+
+
+ {% blocktrans trimmed %}
+
+ {{ box_name }} is a 100% free software self-hosting web server
+ to deploy social applications on small machines. It provides
+ online communication tools respecting your privacy and data
+ ownership.
+
+ {% endblocktrans %}
+
+
+
+ {% blocktrans trimmed %}
+
+ More info about {{ box_name }} is available on the
+ project homepage
+ and wiki.
+
+ {% endblocktrans %}
+
+
+
+ {% blocktrans trimmed %}
+
+ This portal is a part of Plinth, the {{ box_name }} web
+ interface. Plinth is free software, distributed under the GNU
+ Affero General Public License, Version 3 or later.
+
+ {% endblocktrans %}
+
+
+{% endblock %}
diff --git a/plinth/views.py b/plinth/views.py
index 2c403afca..0e5d2f6cb 100644
--- a/plinth/views.py
+++ b/plinth/views.py
@@ -21,20 +21,23 @@ Main Plinth views
from django.contrib import messages
from django.core.exceptions import ImproperlyConfigured
-from django.http.response import HttpResponseRedirect
+from django.template.response import TemplateResponse
from django.views.generic import TemplateView
from django.views.generic.edit import FormView
-from django.urls import reverse
from django.utils.translation import ugettext as _
+from stronghold.decorators import public
import time
-from . import forms
+from . import forms, frontpage
import plinth
+@public
def index(request):
"""Serve the main index page."""
- return HttpResponseRedirect(reverse('apps:index'))
+ return TemplateResponse(request, 'index.html',
+ {'title': _('FreedomBox'),
+ 'shortcuts': frontpage.get_shortcuts()})
class ServiceView(FormView):