From a9587987691893bfc2826282d039e9853db59540 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Fri, 6 Jun 2014 12:57:47 +0530
Subject: [PATCH 01/11] Remove unused Message utility class
---
util.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/util.py b/util.py
index 39e044e77..e44e62bcd 100644
--- a/util.py
+++ b/util.py
@@ -55,12 +55,6 @@ def find_keys(dic, val):
"""return the key of dictionary dic given the value"""
return [k for k, v in dic.iteritems() if v == val]
-class Message():
- def __init__(self, msg=''):
- self.text = msg
- def add(self, text):
- self.text += " %s" % text
-
def render_template(template='login_nav', **kwargs):
for key in ['sidebar_left', 'sidebar_right', 'main', 'js', 'nav', 'css',
From ef493ae243b9bd854bae1360665bd5f790a0f7b5 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Fri, 6 Jun 2014 18:21:54 +0530
Subject: [PATCH 02/11] Use new-style classes everywhere
---
filedict.py | 9 ++++++---
logger.py | 3 ++-
menu.py | 2 +-
model.py | 2 ++
modules/apps/apps.py | 5 +++--
modules/config/config.py | 5 ++---
modules/diagnostics/diagnostics.py | 14 ++++++++------
modules/expert_mode/expert_mode.py | 5 +++--
modules/firewall/firewall.py | 4 ++--
modules/first_boot/first_boot.py | 4 ++--
modules/help/help.py | 13 ++++++++-----
modules/lib/auth_page.py | 4 ++--
modules/lib/user_store.py | 3 +++
modules/owncloud/owncloud.py | 5 +++--
modules/packages/packages.py | 5 +++--
modules/pagekite/pagekite.py | 8 ++++----
modules/santiago/santiago.py | 30 ++++++++++++++++--------------
modules/system/system.py | 10 +++++-----
modules/tor/tor.py | 8 +++++---
modules/users/users.py | 14 ++++++++------
modules/xmpp/xmpp.py | 19 +++++++++++--------
plugin_mount.py | 22 ++++++++++++++--------
tests/actions_test.py | 1 -
tests/auth_test.py | 4 ++--
tests/user_store_test.py | 4 ++--
25 files changed, 117 insertions(+), 86 deletions(-)
diff --git a/filedict.py b/filedict.py
index 94f779759..955e0e09f 100644
--- a/filedict.py
+++ b/filedict.py
@@ -10,12 +10,15 @@ import json
import UserDict
import sqlite3
+
-class DefaultArg:
+class DefaultArg(object):
pass
-class Solutions:
+
+class Solutions(object):
Sqlite3 = 0
+
class FileDict(UserDict.DictMixin):
"A dictionary that stores its data persistantly in a file"
@@ -134,7 +137,7 @@ class FileDict(UserDict.DictMixin):
def batch(self):
return self._Batch(self)
- class _Batch:
+ class _Batch(object):
def __init__(self, d):
self.__d = d
diff --git a/logger.py b/logger.py
index 6fd8171fa..9a753948e 100644
--- a/logger.py
+++ b/logger.py
@@ -6,7 +6,8 @@ cherrypy.log.error_file = cfg.status_log_file
cherrypy.log.access_file = cfg.access_log_file
cherrypy.log.screen = False
-class Logger():
+
+class Logger(object):
"""By convention, log levels are DEBUG, INFO, WARNING, ERROR and CRITICAL."""
def log(self, msg, level="DEBUG"):
try:
diff --git a/menu.py b/menu.py
index 84b26c19d..0092f4561 100644
--- a/menu.py
+++ b/menu.py
@@ -3,7 +3,7 @@ import cherrypy
import cfg
-class Menu():
+class Menu(object):
"""One menu item."""
def __init__(self, label="", icon="", url="#", order=50):
"""label is the text that is displayed on the menu.
diff --git a/model.py b/model.py
index 6ad424e23..f92952221 100644
--- a/model.py
+++ b/model.py
@@ -3,6 +3,8 @@ class User(dict):
is a bcrypt hash of the password), salt, groups, and an email address.
They can be blank or None, but the keys must exist. """
def __init__(self, dict=None):
+ super(User, self).__init__()
+
for key in ['username', 'name', 'passphrase', 'salt', 'email']:
self[key] = ''
for key in ['groups']:
diff --git a/modules/apps/apps.py b/modules/apps/apps.py
index 05bb7fad3..1487a72c5 100644
--- a/modules/apps/apps.py
+++ b/modules/apps/apps.py
@@ -6,8 +6,9 @@ import util
class Apps(PagePlugin):
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Apps, self).__init__()
+
self.register_page("apps")
self.menu = cfg.main_menu.add_item("Apps", "icon-download-alt", "/apps", 80)
self.menu.add_item("Chat", "icon-comment", "/../jwchat", 30)
diff --git a/modules/config/config.py b/modules/config/config.py
index bda9dd2de..ad9e4eb91 100644
--- a/modules/config/config.py
+++ b/modules/config/config.py
@@ -91,9 +91,8 @@ and must not be greater than 63 characters in length.'),
class Configuration(PagePlugin):
"""System configuration page"""
- def __init__(self, *args, **kwargs):
- del args # Unused
- del kwargs # Unused
+ def __init__(self):
+ super(Configuration, self).__init__()
self.register_page('sys.config')
diff --git a/modules/diagnostics/diagnostics.py b/modules/diagnostics/diagnostics.py
index e82de7d11..f3db5672c 100644
--- a/modules/diagnostics/diagnostics.py
+++ b/modules/diagnostics/diagnostics.py
@@ -28,10 +28,11 @@ import cfg
import util
-class diagnostics(PagePlugin):
+class Diagnostics(PagePlugin):
order = 30
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Diagnostics, self).__init__()
+
self.register_page("sys.diagnostics")
cfg.html_root.sys.menu.add_item("Diagnostics", "icon-screenshot", "/sys/diagnostics", 30)
@@ -41,10 +42,11 @@ class diagnostics(PagePlugin):
return util.render_template(template='diagnostics',
title=_('System Diagnostics'))
-class test(PagePlugin):
+class Test(PagePlugin):
order = 31
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Test, self).__init__()
+
self.register_page("sys.diagnostics.test")
@cherrypy.expose
diff --git a/modules/expert_mode/expert_mode.py b/modules/expert_mode/expert_mode.py
index 50c2811e6..49c78e297 100644
--- a/modules/expert_mode/expert_mode.py
+++ b/modules/expert_mode/expert_mode.py
@@ -22,8 +22,9 @@ class Experts(PagePlugin):
"""Expert forms page"""
order = 60
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Experts, self).__init__()
+
self.register_page('sys.expert')
cfg.html_root.sys.menu.add_item(_('Expert Mode'), 'icon-cog',
diff --git a/modules/firewall/firewall.py b/modules/firewall/firewall.py
index ebdbf67a7..6d5214fde 100644
--- a/modules/firewall/firewall.py
+++ b/modules/firewall/firewall.py
@@ -34,8 +34,8 @@ class Firewall(PagePlugin):
"""Firewall menu entry and introduction page"""
order = 40
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Firewall, self).__init__()
self.register_page('sys.firewall')
cfg.html_root.sys.menu.add_item(_('Firewall'), 'icon-flag',
diff --git a/modules/first_boot/first_boot.py b/modules/first_boot/first_boot.py
index 7bcf98e27..204b65ac4 100644
--- a/modules/first_boot/first_boot.py
+++ b/modules/first_boot/first_boot.py
@@ -69,8 +69,8 @@ FreedomBox!'))
class FirstBoot(PagePlugin):
"""First boot wizard"""
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(FirstBoot, self).__init__()
# this is the url this page will hang off of (/firstboot)
self.register_page('firstboot')
diff --git a/modules/help/help.py b/modules/help/help.py
index 927f9e6c6..939fed89e 100644
--- a/modules/help/help.py
+++ b/modules/help/help.py
@@ -8,15 +8,17 @@ import util
class Help(PagePlugin):
order = 20 # order of running init in PagePlugins
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+
+ def __init__(self):
+ super(Help, self).__init__()
+
self.register_page("help")
self.menu = cfg.main_menu.add_item(_("Documentation"), "icon-book", "/help", 101)
self.menu.add_item(_("Where to Get Help"), "icon-search", "/help/index", 5)
self.menu.add_item(_("Developer's Manual"), "icon-info-sign", "/help/view/plinth", 10)
self.menu.add_item(_("FAQ"), "icon-question-sign", "/help/view/faq", 20)
self.menu.add_item(_("%s Wiki" % cfg.box_name), "icon-pencil", "http://wiki.debian.org/FreedomBox", 30)
- self.menu.add_item(_("About"), "icon-star", "/help/about", 100)
+ self.menu.add_item(_("About"), "icon-star", "/help/about", 100)
@cherrypy.expose
def index(self):
@@ -31,8 +33,9 @@ class Help(PagePlugin):
class View(PagePlugin):
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(View, self).__init__()
+
self.register_page("help.view")
@cherrypy.expose
diff --git a/modules/lib/auth_page.py b/modules/lib/auth_page.py
index 1d9b49ca3..2b2ab6369 100644
--- a/modules/lib/auth_page.py
+++ b/modules/lib/auth_page.py
@@ -36,8 +36,8 @@ class LoginForm(forms.Form): # pylint: disable-msg=W0232
class AuthController(PagePlugin):
"""Login and logout pages"""
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(AuthController, self).__init__()
self.register_page('auth')
diff --git a/modules/lib/user_store.py b/modules/lib/user_store.py
index 41d13f947..e6c416fb3 100644
--- a/modules/lib/user_store.py
+++ b/modules/lib/user_store.py
@@ -4,8 +4,11 @@ from model import User
from plugin_mount import UserStoreModule
from withsqlite.withsqlite import sqlite_db
+
class UserStore(UserStoreModule, sqlite_db):
def __init__(self):
+ super(UserStore, self).__init__()
+
self.db_file = cfg.user_db
sqlite_db.__init__(self, self.db_file, autocommit=True, check_same_thread=False)
self.__enter__()
diff --git a/modules/owncloud/owncloud.py b/modules/owncloud/owncloud.py
index 535ba019b..34c8554e7 100644
--- a/modules/owncloud/owncloud.py
+++ b/modules/owncloud/owncloud.py
@@ -22,8 +22,9 @@ class OwnCloud(PagePlugin):
"""ownCloud configuration page"""
order = 90
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(OwnCloud, self).__init__()
+
self.register_page('apps.owncloud')
cfg.html_root.apps.menu.add_item('Owncloud', 'icon-picture',
diff --git a/modules/packages/packages.py b/modules/packages/packages.py
index 89fe69676..d6f589238 100644
--- a/modules/packages/packages.py
+++ b/modules/packages/packages.py
@@ -48,8 +48,9 @@ class Packages(PagePlugin):
"""Package page"""
order = 20
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Packages, self).__init__()
+
self.register_page('sys.packages')
cfg.html_root.sys.menu.add_item('Package Manager', 'icon-gift',
diff --git a/modules/pagekite/pagekite.py b/modules/pagekite/pagekite.py
index cc7791a2d..57037708e 100644
--- a/modules/pagekite/pagekite.py
+++ b/modules/pagekite/pagekite.py
@@ -35,8 +35,8 @@ class PageKite(PagePlugin):
"""PageKite menu entry and introduction page"""
order = 60
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(PageKite, self).__init__()
self.register_page("apps.pagekite")
cfg.html_root.apps.menu.add_item(
@@ -109,8 +109,8 @@ class Configure(PagePlugin): # pylint: disable-msg=C0103
"""Main configuration form"""
order = 65
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Configure, self).__init__()
self.register_page("apps.pagekite.configure")
diff --git a/modules/santiago/santiago.py b/modules/santiago/santiago.py
index b052daab7..e9339fe55 100644
--- a/modules/santiago/santiago.py
+++ b/modules/santiago/santiago.py
@@ -23,14 +23,15 @@ santiago_port = 52854
# return True
class Santiago(PagePlugin):
- order = 90 # order of running init in PagePlugins
- def __init__(self, *args, **kwargs):
+ order = 90 # order of running init in PagePlugins
+ def __init__(self):
+ super(Santiago, self).__init__()
self.register_page("santiago")
self.santiago_address = self.get_santiago_address() #TODO: multiple santiago ports
#set a listener on the santiago address
- def get_santiago_address(self):
+ def get_santiago_address(self):
if 'santiago' in cfg.users['admin'] and 'address' in cfg.users['admin']['santiago']:
return cfg.users['admin']['santiago']['address']
else:
@@ -54,11 +55,11 @@ class Santiago(PagePlugin):
print "Need to add these two lines to /etc/torrc:\n%s" % hidden_service_config
return ""
- def check_for_hidden_service(self):
+ def check_for_hidden_service(self):
pass
- @cherrypy.expose
- def index(self, *args, **kw):
+ @cherrypy.expose
+ def index(self, *args, **kw):
"""
A request is a dict with some required keys:
@@ -111,12 +112,13 @@ class Santiago(PagePlugin):
## Plinth page to config santiago
class santiago(PagePlugin):
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
- self.menu = cfg.html_root.privacy.menu.add_item("Santiago", "icon-leaf", "/privacy/santiago", 10)
- self.register_page("privacy.santiago")
+ def __init__(self):
+ super(Santiago, self).__init__(self)
- @cherrypy.expose
- @require()
- def index(self):
- return "Santiago's config goes here."
+ self.menu = cfg.html_root.privacy.menu.add_item("Santiago", "icon-leaf", "/privacy/santiago", 10)
+ self.register_page("privacy.santiago")
+
+ @cherrypy.expose
+ @require()
+ def index(self):
+ return "Santiago's config goes here."
diff --git a/modules/system/system.py b/modules/system/system.py
index cfdf92515..1896e00c2 100644
--- a/modules/system/system.py
+++ b/modules/system/system.py
@@ -4,16 +4,16 @@ from plugin_mount import PagePlugin
import cfg
import util
-sys_dir = "modules/installed/sys"
-
class Sys(PagePlugin):
order = 10
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+
+ def __init__(self):
+ super(Sys, self).__init__()
+
self.register_page("sys")
self.menu = cfg.main_menu.add_item(_("System"), "icon-cog", "/sys", 100)
- self.menu.add_item(_("Users and Groups"), "icon-user", "/sys/users", 15)
+ self.menu.add_item(_("Users and Groups"), "icon-user", "/sys/users", 15)
@cherrypy.expose
def index(self):
diff --git a/modules/tor/tor.py b/modules/tor/tor.py
index 9e64240f8..f564ed6ad 100644
--- a/modules/tor/tor.py
+++ b/modules/tor/tor.py
@@ -28,10 +28,12 @@ import cfg
import util
-class tor(PagePlugin):
+class Tor(PagePlugin):
order = 60 # order of running init in PagePlugins
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+
+ def __init__(self):
+ super(Tor, self).__init__()
+
self.register_page("apps.tor")
cfg.html_root.apps.menu.add_item("Tor", "icon-eye-close", "/apps/tor",
30)
diff --git a/modules/users/users.py b/modules/users/users.py
index 5722271b7..bdcd7f044 100644
--- a/modules/users/users.py
+++ b/modules/users/users.py
@@ -11,8 +11,10 @@ import util
class Users(PagePlugin):
order = 20 # order of running init in PagePlugins
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+
+ def __init__(self):
+ super(Users, self).__init__()
+
self.register_page("sys.users")
@staticmethod
@@ -52,8 +54,8 @@ class UserAdd(PagePlugin):
"""Add user page"""
order = 30
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(UserAdd, self).__init__()
self.register_page('sys.users.add')
@@ -112,8 +114,8 @@ class UserEdit(PagePlugin):
"""User edit page"""
order = 35
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(UserEdit, self).__init__()
self.register_page('sys.users.edit')
diff --git a/modules/xmpp/xmpp.py b/modules/xmpp/xmpp.py
index ab80118c2..ff9d354fb 100644
--- a/modules/xmpp/xmpp.py
+++ b/modules/xmpp/xmpp.py
@@ -20,11 +20,12 @@ class XMPP(PagePlugin):
"""XMPP Page"""
order = 60
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(XMPP, self).__init__()
+
self.register_page('apps.xmpp')
cfg.html_root.apps.menu.add_item('XMPP', 'icon-comment',
- '/apps/xmpp', 40)
+ '/apps/xmpp', 40)
self.client_service = service.Service(
'xmpp-client', _('Chat Server - client connections'),
@@ -66,9 +67,10 @@ class Configure(PagePlugin):
"""Configuration page"""
order = 65
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
- self.register_page("apps.xmpp.configure")
+ def __init__(self):
+ super(Configure, self).__init__()
+
+ self.register_page('apps.xmpp.configure')
@cherrypy.expose
@require()
@@ -148,8 +150,9 @@ class Register(PagePlugin):
"""User registration page"""
order = 65
- def __init__(self, *args, **kwargs):
- PagePlugin.__init__(self, *args, **kwargs)
+ def __init__(self):
+ super(Register, self).__init__()
+
self.register_page('apps.xmpp.register')
@cherrypy.expose
diff --git a/plugin_mount.py b/plugin_mount.py
index 38ac1e313..0b815338c 100644
--- a/plugin_mount.py
+++ b/plugin_mount.py
@@ -18,10 +18,14 @@ class PluginMount(type):
def get_plugins(cls, *args, **kwargs):
return cls.init_plugins(*args, **kwargs)
-class MultiplePluginViolation:
+
+class MultiplePluginViolation(Exception):
+ """Multiple plugins found for a type where only one is expected"""
pass
+
class PluginMountSingular(PluginMount):
+ """Plugin mounter that allows only one plugin of this meta type"""
def __init__(cls, name, bases, attrs):
if not hasattr(cls, 'plugins'):
cls.plugins = []
@@ -29,7 +33,7 @@ class PluginMountSingular(PluginMount):
if len(cls.plugins) > 0:
raise MultiplePluginViolation
cls.plugins.append(cls)
-
+
def _setattr_deep(obj, path, value):
"""If path is 'x.y.z' or ['x', 'y', 'z'] then perform obj.x.y.z = value"""
@@ -42,7 +46,7 @@ def _setattr_deep(obj, path, value):
setattr(obj, path[-1], value)
-class PagePlugin:
+class PagePlugin(object):
"""
Mount point for page plugins. Page plugins provide display pages
in the interface (one menu item, for example).
@@ -53,18 +57,20 @@ class PagePlugin:
order = 50
__metaclass__ = PluginMount
- def __init__(self, *args, **kwargs):
+
+ def __init__(self):
"""If cfg.html_root is none, then this is the html_root."""
if not cfg.html_root:
cfg.log('Setting html root to %s' % self.__class__.__name__)
cfg.html_root = self
-
+
def register_page(self, url):
+ """Add a page to the page tree structure"""
cfg.log.info("Registering page: %s" % url)
_setattr_deep(cfg.html_root, url, self)
-class UserStoreModule:
+class UserStoreModule(object):
"""
Mount Point for plugins that will manage the user backend storage,
where we keep a hash for each user.
@@ -79,5 +85,5 @@ class UserStoreModule:
compatibility with third party software. A future version of
Plinth is likely to require LDAP.
"""
- __metaclass__ = PluginMountSingular # singular because we can only use one user store at a time
-
+ # Singular because we can only use one user store at a time
+ __metaclass__ = PluginMountSingular
diff --git a/tests/actions_test.py b/tests/actions_test.py
index c78fdce72..09fbae144 100644
--- a/tests/actions_test.py
+++ b/tests/actions_test.py
@@ -5,7 +5,6 @@ from actions import superuser_run, run
import os
import shlex
import subprocess
-import sys
import unittest
class TestPrivileged(unittest.TestCase):
diff --git a/tests/auth_test.py b/tests/auth_test.py
index 6ea5d0252..08806748b 100644
--- a/tests/auth_test.py
+++ b/tests/auth_test.py
@@ -1,18 +1,18 @@
#! /usr/bin/env python
# -*- mode: python; mode: auto-fill; fill-column: 80 -*-
-import user_store, auth
+import auth
from logger import Logger
import cfg
import unittest
import cherrypy
import plugin_mount
import os
-from model import User
cfg.log = Logger()
cherrypy.log.access_file = None
+
class Auth(unittest.TestCase):
"""Test check_credentials function of auth to confirm it works as expected"""
diff --git a/tests/user_store_test.py b/tests/user_store_test.py
index e6a3e8433..def0c0c93 100644
--- a/tests/user_store_test.py
+++ b/tests/user_store_test.py
@@ -1,7 +1,6 @@
#! /usr/bin/env python
# -*- mode: python; mode: auto-fill; fill-column: 80 -*-
-import user_store
from logger import Logger
import cfg
import unittest
@@ -13,6 +12,7 @@ cfg.log = Logger()
cherrypy.log.access_file = None
+
class UserStore(unittest.TestCase):
"""Test each function of user_store to confirm they work as expected"""
@@ -83,4 +83,4 @@ class UserStore(unittest.TestCase):
return user
if __name__ == "__main__":
- unittest.main()
\ No newline at end of file
+ unittest.main()
From 3e32715a5516770a779de22e339622fca9bcee3d Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Fri, 6 Jun 2014 20:37:48 +0530
Subject: [PATCH 03/11] Don't take unnecessary kwargs in exposed methods
---
modules/firewall/firewall.py | 4 +---
modules/packages/packages.py | 4 +---
modules/pagekite/pagekite.py | 4 +---
modules/xmpp/xmpp.py | 12 ++----------
4 files changed, 5 insertions(+), 19 deletions(-)
diff --git a/modules/firewall/firewall.py b/modules/firewall/firewall.py
index 6d5214fde..aa581d886 100644
--- a/modules/firewall/firewall.py
+++ b/modules/firewall/firewall.py
@@ -45,10 +45,8 @@ class Firewall(PagePlugin):
@cherrypy.expose
@require()
- def index(self, **kwargs):
+ def index(self):
"""Serve introcution page"""
- del kwargs # Unused
-
if not self.get_installed_status():
return util.render_template(template='firewall',
title=_("Firewall"),
diff --git a/modules/packages/packages.py b/modules/packages/packages.py
index d6f589238..9bd32cfe1 100644
--- a/modules/packages/packages.py
+++ b/modules/packages/packages.py
@@ -58,10 +58,8 @@ class Packages(PagePlugin):
@cherrypy.expose
@require()
- def index(self, *args, **kwargs):
+ def index(self, **kwargs):
"""Serve the form"""
- del args # Unused
-
status = self.get_status()
form = None
diff --git a/modules/pagekite/pagekite.py b/modules/pagekite/pagekite.py
index 57037708e..29de188ad 100644
--- a/modules/pagekite/pagekite.py
+++ b/modules/pagekite/pagekite.py
@@ -46,10 +46,8 @@ class PageKite(PagePlugin):
@staticmethod
@cherrypy.expose
@require()
- def index(**kwargs):
+ def index():
"""Serve introdution page"""
- del kwargs # Unused
-
menu = {'title': _('PageKite'),
'items': [{'url': '/apps/pagekite/configure',
'text': _('Configure PageKite')}]}
diff --git a/modules/xmpp/xmpp.py b/modules/xmpp/xmpp.py
index ff9d354fb..4da0e3427 100644
--- a/modules/xmpp/xmpp.py
+++ b/modules/xmpp/xmpp.py
@@ -40,9 +40,8 @@ class XMPP(PagePlugin):
@staticmethod
@cherrypy.expose
@require()
- def index(**kwargs):
+ def index():
"""Serve XMPP page"""
- del kwargs # Unused
main = "
XMPP Server Accounts and Configuration
"
sidebar_right = util.render_template(template='menu_block',
@@ -107,13 +106,6 @@ class Configure(PagePlugin):
return {'inband_enabled': 'inband_enable' in output.split()}
- @staticmethod
- def sidebar_right(**kwargs):
- """Return rendered string for sidebar on the right"""
- del kwargs # Unused
-
- return util.render_template(template='menu_block', menu=SIDE_MENU)
-
@staticmethod
def _apply_changes(old_status, new_status, messages):
"""Apply the form changes"""
@@ -133,7 +125,7 @@ class Configure(PagePlugin):
cfg.log.info('Option - %s' % option)
_output, error = actions.superuser_run('xmpp-setup', [option])
- del _output
+ del _output # Unused
if error:
raise Exception('Error running command - %s' % error)
From 4aeea83e46ec3b104bd0b88d7213f285d570fae1 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Fri, 6 Jun 2014 20:44:34 +0530
Subject: [PATCH 04/11] Set title to 'FreedomBox' instead of 'FreedomBox
Dashboard'
---
templates/base.html | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/templates/base.html b/templates/base.html
index ebaea525c..be6ca7dda 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -24,9 +24,9 @@
-
+
- {% if title %} {{ title }} {% else %} FreedomBox Dashboard {% endif %}
+ {% if title %} {{ title }} {% else %} FreedomBox {% endif %}
@@ -57,7 +57,7 @@
- FreedomBox Dashboard
+ FreedomBox
{% block add_nav_and_login %}
{% endblock %}
From 1ec92ee346fb9b0cdb4442dd11767b1f51014f05 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Thu, 12 Jun 2014 23:17:00 +0530
Subject: [PATCH 05/11] Add Django urlpattern files for each module
This is in anticipation of the routing changes to come. The changes themselves do nothing.
---
modules/apps/urls.py | 28 ++++++++++++++++++++++++++++
modules/config/urls.py | 28 ++++++++++++++++++++++++++++
modules/diagnostics/urls.py | 29 +++++++++++++++++++++++++++++
modules/expert_mode/urls.py | 28 ++++++++++++++++++++++++++++
modules/firewall/urls.py | 28 ++++++++++++++++++++++++++++
modules/first_boot/__init__.py | 1 -
modules/first_boot/urls.py | 30 ++++++++++++++++++++++++++++++
modules/help/urls.py | 34 ++++++++++++++++++++++++++++++++++
modules/lib/__init__.py | 1 -
modules/lib/urls.py | 29 +++++++++++++++++++++++++++++
modules/owncloud/urls.py | 28 ++++++++++++++++++++++++++++
modules/packages/urls.py | 28 ++++++++++++++++++++++++++++
modules/pagekite/urls.py | 29 +++++++++++++++++++++++++++++
modules/system/urls.py | 28 ++++++++++++++++++++++++++++
modules/tor/urls.py | 28 ++++++++++++++++++++++++++++
modules/users/urls.py | 30 ++++++++++++++++++++++++++++++
modules/xmpp/urls.py | 30 ++++++++++++++++++++++++++++++
urls.py | 28 ++++++++++++++++++++++++++++
18 files changed, 463 insertions(+), 2 deletions(-)
create mode 100644 modules/apps/urls.py
create mode 100644 modules/config/urls.py
create mode 100644 modules/diagnostics/urls.py
create mode 100644 modules/expert_mode/urls.py
create mode 100644 modules/firewall/urls.py
create mode 100644 modules/first_boot/urls.py
create mode 100644 modules/help/urls.py
create mode 100644 modules/lib/urls.py
create mode 100644 modules/owncloud/urls.py
create mode 100644 modules/packages/urls.py
create mode 100644 modules/pagekite/urls.py
create mode 100644 modules/system/urls.py
create mode 100644 modules/tor/urls.py
create mode 100644 modules/users/urls.py
create mode 100644 modules/xmpp/urls.py
create mode 100644 urls.py
diff --git a/modules/apps/urls.py b/modules/apps/urls.py
new file mode 100644
index 000000000..a65383f51
--- /dev/null
+++ b/modules/apps/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 Apps module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.apps.apps',
+ url(r'^apps/$', 'index')
+ )
diff --git a/modules/config/urls.py b/modules/config/urls.py
new file mode 100644
index 000000000..e40bdf15a
--- /dev/null
+++ b/modules/config/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 Configuration module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.config.config',
+ url(r'^sys/config/$', 'index'),
+ )
diff --git a/modules/diagnostics/urls.py b/modules/diagnostics/urls.py
new file mode 100644
index 000000000..5b3d94653
--- /dev/null
+++ b/modules/diagnostics/urls.py
@@ -0,0 +1,29 @@
+#
+# 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 Diagnostics module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.diagnostics.diagnostics',
+ url(r'^sys/diagnostics/$', 'index'),
+ url(r'^sys/diagnostics/test/$', 'test'),
+ )
diff --git a/modules/expert_mode/urls.py b/modules/expert_mode/urls.py
new file mode 100644
index 000000000..83ed46428
--- /dev/null
+++ b/modules/expert_mode/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 Expert Mode module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.expert_mode.expert_mode',
+ url(r'^sys/expert/$', 'index'),
+ )
diff --git a/modules/firewall/urls.py b/modules/firewall/urls.py
new file mode 100644
index 000000000..62ae413e7
--- /dev/null
+++ b/modules/firewall/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 Firewall module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.firewall.firewall',
+ url(r'^sys/firewall/$', 'index')
+ )
diff --git a/modules/first_boot/__init__.py b/modules/first_boot/__init__.py
index 20e972dae..b9a2a74f5 100644
--- a/modules/first_boot/__init__.py
+++ b/modules/first_boot/__init__.py
@@ -21,5 +21,4 @@ Plinth module for first boot wizard
from . import first_boot
-
__all__ = ['first_boot']
diff --git a/modules/first_boot/urls.py b/modules/first_boot/urls.py
new file mode 100644
index 000000000..6fa4aadc4
--- /dev/null
+++ b/modules/first_boot/urls.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 .
+#
+
+"""
+URLs for the First Boot module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.first_boot.first_boot',
+ url(r'^firstboot/$', 'index'),
+ url(r'^firstboot/state0/$', 'state0'),
+ url(r'^firstboot/state1/$', 'state1')
+ )
diff --git a/modules/help/urls.py b/modules/help/urls.py
new file mode 100644
index 000000000..3c623ebcc
--- /dev/null
+++ b/modules/help/urls.py
@@ -0,0 +1,34 @@
+#
+# 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 Help module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.help.help',
+ url(r'^help/$', 'index'),
+ url(r'^help/index/$', 'index'),
+ url(r'^help/about/$', 'about'),
+ url(r'^help/view/(?Pdesign)/$', 'default'),
+ url(r'^help/view/(?Pplinth)/$', 'default'),
+ url(r'^help/view/(?Phacking)/$', 'default'),
+ url(r'^help/view/(?Pfaq)/$', 'default'),
+ )
diff --git a/modules/lib/__init__.py b/modules/lib/__init__.py
index ab399cd3f..3b0136b8c 100644
--- a/modules/lib/__init__.py
+++ b/modules/lib/__init__.py
@@ -23,7 +23,6 @@ from . import auth
from . import auth_page
from . import user_store
-
__all__ = ['auth',
'auth_page',
'user_store']
diff --git a/modules/lib/urls.py b/modules/lib/urls.py
new file mode 100644
index 000000000..7a0cac762
--- /dev/null
+++ b/modules/lib/urls.py
@@ -0,0 +1,29 @@
+#
+# 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 Lib module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.lib.auth_page',
+ url(r'^auth/login/$', 'login'),
+ url(r'^auth/logout/$', 'logout')
+ )
diff --git a/modules/owncloud/urls.py b/modules/owncloud/urls.py
new file mode 100644
index 000000000..5ad666505
--- /dev/null
+++ b/modules/owncloud/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 ownCloud module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.owncloud.owncloud',
+ url(r'^apps/owncloud/$', 'index'),
+ )
diff --git a/modules/packages/urls.py b/modules/packages/urls.py
new file mode 100644
index 000000000..ae963fb4e
--- /dev/null
+++ b/modules/packages/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 Packages module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.packages.packages',
+ url(r'^sys/packages/$', 'index'),
+ )
diff --git a/modules/pagekite/urls.py b/modules/pagekite/urls.py
new file mode 100644
index 000000000..8cbad4dd5
--- /dev/null
+++ b/modules/pagekite/urls.py
@@ -0,0 +1,29 @@
+#
+# 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 PageKite module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.pagekite.pagekite',
+ url(r'^apps/pagekite/$', 'index'),
+ url(r'^apps/pagekite/configure/$', 'configure'),
+ )
diff --git a/modules/system/urls.py b/modules/system/urls.py
new file mode 100644
index 000000000..054f9afcc
--- /dev/null
+++ b/modules/system/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 System module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.system.system',
+ url(r'^sys/$', 'index'),
+ )
diff --git a/modules/tor/urls.py b/modules/tor/urls.py
new file mode 100644
index 000000000..95e0422fc
--- /dev/null
+++ b/modules/tor/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 Tor module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.tor.tor',
+ url(r'^apps/tor/$', 'index')
+ )
diff --git a/modules/users/urls.py b/modules/users/urls.py
new file mode 100644
index 000000000..8fb5d21cd
--- /dev/null
+++ b/modules/users/urls.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 .
+#
+
+"""
+URLs for the Users module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.users.users',
+ url(r'^sys/users/$', 'index'),
+ url(r'^sys/users/add/$', 'add'),
+ url(r'^sys/users/edit/$', 'edit')
+ )
diff --git a/modules/xmpp/urls.py b/modules/xmpp/urls.py
new file mode 100644
index 000000000..43a518c87
--- /dev/null
+++ b/modules/xmpp/urls.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 .
+#
+
+"""
+URLs for the XMPP module
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'modules.xmpp.xmpp',
+ url(r'^apps/xmpp/$', 'index'),
+ url(r'^apps/xmpp/configure/$', 'configure'),
+ url(r'^apps/xmpp/register/$', 'register')
+ )
diff --git a/urls.py b/urls.py
new file mode 100644
index 000000000..a2611e009
--- /dev/null
+++ b/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 .
+#
+
+"""
+Django URLconf file containing all urls
+"""
+
+from django.conf.urls import patterns, url
+
+
+urlpatterns = patterns( # pylint: disable-msg=C0103
+ 'views',
+ url(r'^$', 'index')
+ )
From 4e318ff43491211b2f43b60736c47983f896af68 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Thu, 12 Jun 2014 23:17:53 +0530
Subject: [PATCH 06/11] Add a menu method to find menu items by URL
---
menu.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/menu.py b/menu.py
index 0092f4561..451cccf5b 100644
--- a/menu.py
+++ b/menu.py
@@ -29,6 +29,17 @@ class Menu(object):
self.order = order
self.items = []
+ def find(self, url, basehref=True):
+ """Return a menu item with given URL"""
+ if basehref and url.startswith('/'):
+ url = cfg.server_dir + url
+
+ for item in self.items:
+ if item.url == url:
+ return item
+
+ raise KeyError('Menu item not found')
+
def sort_items(self):
"""Sort the items in self.items by order."""
self.items = sorted(self.items, key=lambda x: x.order, reverse=False)
From 26faa82fd4e98b18be8b4d3a2600eeee8a5a1ddf Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Thu, 12 Jun 2014 23:18:51 +0530
Subject: [PATCH 07/11] Fix minor grammatic error in firewall status page
---
modules/firewall/templates/firewall.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/modules/firewall/templates/firewall.html b/modules/firewall/templates/firewall.html
index 19c165a46..560169a2b 100644
--- a/modules/firewall/templates/firewall.html
+++ b/modules/firewall/templates/firewall.html
@@ -25,7 +25,7 @@ and outgoing network traffic on your {{ cfg.box_name }}. Keeping a
firewall enabled and properly configured reduces risk of security
threat from the Internet.
-
The following the current status:
+
The following is the current status:
{% if firewall_status = 'not_installed' %}
Firewall is not installed. Please install it. Firewall comes
From 657bb11bbcb752af64e9dd21aa9e39b34eb8ee14 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Thu, 12 Jun 2014 23:20:49 +0530
Subject: [PATCH 08/11] Add Django custom error handling pages for 404 and 500
errors
---
templates/404.html | 36 ++++++++++++++++++++++++++++++++++++
templates/500.html | 32 ++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
create mode 100644 templates/404.html
create mode 100644 templates/500.html
diff --git a/templates/404.html b/templates/404.html
new file mode 100644
index 000000000..b4e9a30d1
--- /dev/null
+++ b/templates/404.html
@@ -0,0 +1,36 @@
+{% extends 'login_nav.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 %}
+
+{% block title_block %}
+404
+{% endblock %}
+
+{% block main_block %}
+
+
Requested page {{ request_path }} was not found.
+
+
If you believe this missing page should exist, please file a bug with either
+ the Plinth project (it
+ has an issue tracker) or the people responsible for the module you are
+ trying to access.
+
+
Sorry for the mistake.
+
+{% endblock %}
diff --git a/templates/500.html b/templates/500.html
new file mode 100644
index 000000000..485f3df3c
--- /dev/null
+++ b/templates/500.html
@@ -0,0 +1,32 @@
+{% extends 'login_nav.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 %}
+
+{% block title_block %}
+500
+{% endblock %}
+
+{% block main_block %}
+
+
This is an internal error and not something you caused or can fix. Please
+ report the error on
+ the bug tracker so we
+ can fix it.
+
+{% endblock %}
From 58d13e3ed82807ff9929242d1a581ba083b207fc Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Thu, 12 Jun 2014 23:33:25 +0530
Subject: [PATCH 09/11] Use Django dispatcher instead of CherryPy dispatcher
This commit is big because anything small breaks the code.
- Django dispatcher is based on regular expressions and does not need a tree structure
- Reduces a lot of unnecessary dependencies among modules
- Use Django sessions middlewear instead of CherryPy sessions
- Introduce dependency based modules instead of numeric load order
- Remove PagePlugin and simply use Django views
- Eliminate page rendering wrappers in favor of Django context processors
- Use custom auth for now until replaced by Django auth middlewear
- Use Django templated 404 and 500 error pages
---
LICENSES | 2 +-
Makefile | 6 +-
cfg.py | 1 -
menu.py | 16 +-
module_loader.py | 137 +++++++++++++++
modules/apps/__init__.py | 6 +-
modules/apps/apps.py | 21 +--
modules/config/__init__.py | 4 +-
modules/config/config.py | 114 ++++++-------
modules/config/templates/config.html | 2 +-
modules/diagnostics/__init__.py | 6 +-
modules/diagnostics/diagnostics.py | 49 +++---
modules/expert_mode/__init__.py | 4 +-
modules/expert_mode/expert_mode.py | 104 +++++------
modules/firewall/__init__.py | 4 +-
modules/firewall/firewall.py | 210 +++++++++++------------
modules/first_boot/first_boot.py | 214 +++++++++++------------
modules/help/__init__.py | 4 +-
modules/help/help.py | 69 ++++----
modules/lib/auth.py | 101 ++---------
modules/lib/auth_page.py | 75 ++++----
modules/lib/user_store.py | 38 +++--
modules/owncloud/__init__.py | 4 +-
modules/owncloud/owncloud.py | 121 +++++++------
modules/packages/__init__.py | 4 +-
modules/packages/packages.py | 149 ++++++++--------
modules/pagekite/__init__.py | 4 +-
modules/pagekite/pagekite.py | 238 ++++++++++++--------------
modules/system/__init__.py | 3 +-
modules/system/system.py | 24 +--
modules/tor/__init__.py | 4 +-
modules/tor/tor.py | 49 +++---
modules/users/__init__.py | 4 +-
modules/users/users.py | 202 ++++++++++------------
modules/xmpp/__init__.py | 4 +-
modules/xmpp/xmpp.py | 246 ++++++++++++---------------
plinth.py | 209 ++++++++++-------------
templates/base.html | 30 ++--
templates/login_nav.html | 9 +-
templates/menu.html | 25 +--
templates/messages.html | 2 +-
views.py | 52 ++++++
42 files changed, 1281 insertions(+), 1289 deletions(-)
create mode 100644 module_loader.py
create mode 100644 views.py
diff --git a/LICENSES b/LICENSES
index 7581e1686..55f212f99 100644
--- a/LICENSES
+++ b/LICENSES
@@ -52,7 +52,7 @@ specified and linked otherwise.
- modules/first_boot/first_boot.py :: -
- modules/help/help.py :: -
- modules/lib/auth_page.py :: -
-- modules/lib/auth.py :: Derived from [[http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions][Arnar Birisson's CherryPy wiki code]].
+- modules/lib/auth.py :: -
- modules/lib/user_store.py :: -
- modules/owncloud/owncloud.py :: -
- modules/packages/packages.py :: -
diff --git a/Makefile b/Makefile
index bf6f8c021..59c53dab5 100644
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ install: default apache-install freedombox-setup-install
cp share/init.d/plinth $(DESTDIR)/etc/init.d
cp -a lib/* $(DESTDIR)/usr/lib
install plinth $(DESTDIR)/usr/bin/
- mkdir -p $(DESTDIR)/var/lib/plinth/cherrypy_sessions $(DESTDIR)/var/log/plinth $(DESTDIR)/var/run
+ mkdir -p $(DESTDIR)/var/lib/plinth/sessions $(DESTDIR)/var/log/plinth $(DESTDIR)/var/run
mkdir -p $(DESTDIR)/var/lib/plinth/data
rm -f $(DESTDIR)/var/lib/plinth/users/sqlite3.distrib
@@ -46,7 +46,7 @@ uninstall:
$(DESTDIR)/usr/share/man/man1/plinth.1.gz $(DESTDIR)/var/run/plinth.pid
dirs:
- @mkdir -p data/cherrypy_sessions
+ @mkdir -p data/sessions
config: Makefile
@test -f plinth.config || cp plinth.sample.config plinth.config
@@ -59,7 +59,7 @@ html:
@$(MAKE) -s -C doc html
clean:
- @rm -f cherrypy.config data/cherrypy_sessions/*
+ @rm -f cherrypy.config data/sessions/*
@find . -name "*~" -exec rm {} \;
@find . -name ".#*" -exec rm {} \;
@find . -name "#*" -exec rm {} \;
diff --git a/cfg.py b/cfg.py
index 01aeee2d7..124bb0ebc 100644
--- a/cfg.py
+++ b/cfg.py
@@ -32,7 +32,6 @@ pidfile = get_item(parser, 'Path', 'pidfile')
host = get_item(parser, 'Network', 'host')
port = int(get_item(parser, 'Network', 'port'))
-html_root = None
main_menu = Menu()
if store_file.endswith(".sqlite3"):
diff --git a/menu.py b/menu.py
index 451cccf5b..8688e7a9d 100644
--- a/menu.py
+++ b/menu.py
@@ -1,5 +1,4 @@
from urlparse import urlparse
-import cherrypy
import cfg
@@ -59,16 +58,17 @@ class Menu(object):
self.sort_items()
return item
- def active_p(self):
- """Returns True if this menu item is active, otherwise False.
+ def is_active(self, request_path):
+ """
+ Returns True if this menu item is active, otherwise False.
We can tell if a menu is active if the menu item points
- anywhere above url we are visiting in the url tree."""
- return urlparse(cherrypy.url()).path.startswith(self.url)
+ anywhere above url we are visiting in the url tree.
+ """
+ return request_path.startswith(self.url)
- def active_item(self):
+ def active_item(self, request):
"""Return item list (e.g. submenu) of active menu item."""
- path = urlparse(cherrypy.url()).path
for item in self.items:
- if path.startswith(item.url):
+ if request.path.startswith(item.url):
return item
diff --git a/module_loader.py b/module_loader.py
new file mode 100644
index 000000000..0c7165ac6
--- /dev/null
+++ b/module_loader.py
@@ -0,0 +1,137 @@
+#
+# 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 .
+#
+
+"""
+Discover, load and manage Plinth modules
+"""
+
+import django
+import importlib
+import os
+
+import cfg
+import urls
+
+
+def load_modules():
+ """
+ Read names of enabled modules in modules/enabled directory and
+ import them from modules directory.
+ """
+ module_names = []
+ modules = {}
+ for name in os.listdir('modules/enabled'):
+ full_name = 'modules.{module}'.format(module=name)
+
+ cfg.log.info('Importing {full_name}'.format(full_name=full_name))
+ try:
+ module = importlib.import_module(full_name)
+ modules[name] = module
+ module_names.append(name)
+ except ImportError as exception:
+ cfg.log.error(
+ 'Could not import modules/{module}: {exception}'
+ .format(module=name, exception=exception))
+
+ _include_module_urls(full_name)
+
+ ordered_modules = []
+ remaining_modules = dict(modules)
+ for module_name in modules:
+ if module_name not in remaining_modules:
+ continue
+
+ module = remaining_modules.pop(module_name)
+ try:
+ _insert_modules(module_name, module, remaining_modules,
+ ordered_modules)
+ except KeyError:
+ cfg.log.error('Unsatified dependency for module - %s' %
+ (module_name,))
+
+ cfg.log.debug('Module load order - %s' % ordered_modules)
+
+ for module_name in ordered_modules:
+ _initialize_module(modules[module_name])
+
+
+def _insert_modules(module_name, module, remaining_modules, ordered_modules):
+ """Insert modules into a list based on dependency order"""
+ if module_name in ordered_modules:
+ return
+
+ dependencies = []
+ try:
+ dependencies = module.DEPENDS
+ except AttributeError:
+ pass
+
+ for dependency in dependencies:
+ if dependency in ordered_modules:
+ continue
+
+ try:
+ module = remaining_modules.pop(dependency)
+ except KeyError:
+ cfg.log.error('Not found or circular dependency - %s, %s' %
+ (module_name, dependency))
+ raise
+
+ _insert_modules(dependency, module, remaining_modules, ordered_modules)
+
+ ordered_modules.append(module_name)
+
+
+def _include_module_urls(module_name):
+ """Include the module's URLs in global project URLs list"""
+ url_module = module_name + '.urls'
+ try:
+ urls.urlpatterns += django.conf.urls.patterns(
+ '', django.conf.urls.url(
+ r'', django.conf.urls.include(url_module)))
+ except ImportError:
+ cfg.log.debug('No URLs for {module}'.format(module=module_name))
+
+
+def _initialize_module(module):
+ """Call initialization method in the module if it exists"""
+ try:
+ init = module.init
+ except AttributeError:
+ cfg.log.debug('No init() for module - {module}'
+ .format(module=module.__name__))
+ return
+
+ try:
+ init()
+ except Exception as exception:
+ cfg.log.error('Exception while running init for {module}: {exception}'
+ .format(module=module, exception=exception))
+
+
+def get_template_directories():
+ """Return the list of template directories"""
+ directory = os.path.dirname(os.path.abspath(__file__))
+ core_directory = os.path.join(directory, 'templates')
+
+ directories = set((core_directory,))
+ for name in os.listdir('modules/enabled'):
+ directories.add(os.path.join('modules', name, 'templates'))
+
+ cfg.log.info('Template directories - %s' % directories)
+
+ return directories
diff --git a/modules/apps/__init__.py b/modules/apps/__init__.py
index bf5f66418..28d22ea0b 100644
--- a/modules/apps/__init__.py
+++ b/modules/apps/__init__.py
@@ -16,10 +16,10 @@
#
"""
-Plinth module for apps section page
+Plinth module for Apps section page
"""
from . import apps
+from .apps import init
-
-__all__ = ['apps']
+__all__ = ['apps', 'init']
diff --git a/modules/apps/apps.py b/modules/apps/apps.py
index 1487a72c5..a5ae5596f 100644
--- a/modules/apps/apps.py
+++ b/modules/apps/apps.py
@@ -1,19 +1,14 @@
-import cherrypy
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from plugin_mount import PagePlugin
+
import cfg
-import util
-class Apps(PagePlugin):
- def __init__(self):
- super(Apps, self).__init__()
+def init():
+ """Initailize the apps module"""
+ cfg.main_menu.add_item("Apps", "icon-download-alt", "/apps", 80)
- self.register_page("apps")
- self.menu = cfg.main_menu.add_item("Apps", "icon-download-alt", "/apps", 80)
- self.menu.add_item("Chat", "icon-comment", "/../jwchat", 30)
- @cherrypy.expose
- def index(self):
- return util.render_template(template='apps',
- title=_('User Applications'))
+def index(request):
+ """Serve the apps index page"""
+ return TemplateResponse(request, 'apps.html', {'title': _('Applications')})
diff --git a/modules/config/__init__.py b/modules/config/__init__.py
index aface4101..9e8ba0667 100644
--- a/modules/config/__init__.py
+++ b/modules/config/__init__.py
@@ -20,6 +20,8 @@ Plinth module for basic system configuration
"""
from . import config
+from .config import init
+__all__ = ['config', 'init']
-__all__ = ['config']
+DEPENDS = ['system']
diff --git a/modules/config/config.py b/modules/config/config.py
index ad9e4eb91..fe87dee70 100644
--- a/modules/config/config.py
+++ b/modules/config/config.py
@@ -19,17 +19,16 @@
Plinth module for configuring timezone, hostname etc.
"""
-import cherrypy
from django import forms
from django.core import validators
+from django.template.response import TemplateResponse
from gettext import gettext as _
import re
import socket
import actions
import cfg
-from ..lib.auth import require
-from plugin_mount import PagePlugin
+from ..lib.auth import login_required
import util
@@ -89,66 +88,66 @@ and must not be greater than 63 characters in length.'),
return time_zones
-class Configuration(PagePlugin):
- """System configuration page"""
- def __init__(self):
- super(Configuration, self).__init__()
+def init():
+ """Initialize the module"""
+ menu = cfg.main_menu.find('/sys')
+ menu.add_item(_('Configure'), 'icon-cog', '/sys/config', 10)
- self.register_page('sys.config')
- self.menu = cfg.html_root.sys.menu.add_item(_('Configure'), 'icon-cog',
- '/sys/config', 10)
+@login_required
+def index(request):
+ """Serve the configuration form"""
+ status = get_status()
- @cherrypy.expose
- @require()
- def index(self, **kwargs):
- """Serve the configuration form"""
- status = self.get_status()
+ form = None
+ messages = []
- form = None
- messages = []
+ is_expert = cfg.users.expert(request=request)
+ if request.method == 'POST' and is_expert:
+ form = ConfigurationForm(request.POST, prefix='configuration')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ _apply_changes(status, form.cleaned_data, messages)
+ status = get_status()
+ form = ConfigurationForm(initial=status,
+ prefix='configuration')
+ else:
+ form = ConfigurationForm(initial=status, prefix='configuration')
- if kwargs and cfg.users.expert():
- form = ConfigurationForm(kwargs, prefix='configuration')
- # pylint: disable-msg=E1101
- if form.is_valid():
- self._apply_changes(status, form.cleaned_data, messages)
- status = self.get_status()
- form = ConfigurationForm(initial=status,
- prefix='configuration')
+ return TemplateResponse(request, 'config.html',
+ {'title': _('General Configuration'),
+ 'form': form,
+ 'messages_': messages,
+ 'is_expert': is_expert})
+
+
+def get_status():
+ """Return the current status"""
+ return {'hostname': get_hostname(),
+ 'time_zone': util.slurp('/etc/timezone').rstrip()}
+
+
+def _apply_changes(old_status, new_status, messages):
+ """Apply the form changes"""
+ if old_status['hostname'] != new_status['hostname']:
+ if not set_hostname(new_status['hostname']):
+ messages.append(('error', _('Setting hostname failed')))
else:
- form = ConfigurationForm(initial=status, prefix='configuration')
-
- return util.render_template(template='config',
- title=_('General Configuration'),
- form=form, messages=messages)
-
- @staticmethod
- def get_status():
- """Return the current status"""
- return {'hostname': get_hostname(),
- 'time_zone': util.slurp('/etc/timezone').rstrip()}
-
- @staticmethod
- def _apply_changes(old_status, new_status, messages):
- """Apply the form changes"""
- if old_status['hostname'] != new_status['hostname']:
- set_hostname(new_status['hostname'])
messages.append(('success', _('Hostname set')))
- else:
- messages.append(('info', _('Hostname is unchanged')))
+ else:
+ messages.append(('info', _('Hostname is unchanged')))
- if old_status['time_zone'] != new_status['time_zone']:
- output, error = actions.superuser_run('timezone-change',
- [new_status['time_zone']])
- del output # Unused
- if error:
- messages.append(('error',
- _('Error setting time zone - %s') % error))
- else:
- messages.append(('success', _('Time zone set')))
+ if old_status['time_zone'] != new_status['time_zone']:
+ output, error = actions.superuser_run('timezone-change',
+ [new_status['time_zone']])
+ del output # Unused
+ if error:
+ messages.append(('error',
+ _('Error setting time zone - %s') % error))
else:
- messages.append(('info', _('Time zone is unchanged')))
+ messages.append(('success', _('Time zone set')))
+ else:
+ messages.append(('info', _('Time zone is unchanged')))
def set_hostname(hostname):
@@ -165,6 +164,7 @@ def set_hostname(hostname):
# don't persist/cache change unless it was saved successfuly
sys_store = util.filedict_con(cfg.store_file, 'sys')
sys_store['hostname'] = hostname
- except OSError as exception:
- raise cherrypy.HTTPError(500,
- 'Updating hostname failed: %s' % exception)
+ except OSError:
+ return False
+
+ return True
diff --git a/modules/config/templates/config.html b/modules/config/templates/config.html
index 5e5310481..591ad5e5b 100644
--- a/modules/config/templates/config.html
+++ b/modules/config/templates/config.html
@@ -22,7 +22,7 @@
{% block main_block %}
-{% if cfg.users.expert %}
+{% if is_expert %}
{% include 'messages.html' %}
diff --git a/modules/diagnostics/__init__.py b/modules/diagnostics/__init__.py
index 8c01bd990..5346b6ae7 100644
--- a/modules/diagnostics/__init__.py
+++ b/modules/diagnostics/__init__.py
@@ -16,10 +16,12 @@
#
"""
-Plinth module to system diagnostics
+Plinth module for system diagnostics
"""
from . import diagnostics
+from .diagnostics import init
+__all__ = ['diagnostics', 'init']
-__all__ = ['diagnostics']
+DEPENDS = ['system']
diff --git a/modules/diagnostics/diagnostics.py b/modules/diagnostics/diagnostics.py
index f3db5672c..2639f969c 100644
--- a/modules/diagnostics/diagnostics.py
+++ b/modules/diagnostics/diagnostics.py
@@ -19,41 +19,32 @@
Plinth module for running diagnostics
"""
-import cherrypy
from gettext import gettext as _
-from ..lib.auth import require
-from plugin_mount import PagePlugin
+from django.template.response import TemplateResponse
+
import actions
import cfg
-import util
+from ..lib.auth import login_required
-class Diagnostics(PagePlugin):
- order = 30
- def __init__(self):
- super(Diagnostics, self).__init__()
+def init():
+ """Initialize the module"""
+ menu = cfg.main_menu.find('/sys')
+ menu.add_item("Diagnostics", "icon-screenshot", "/sys/diagnostics", 30)
- self.register_page("sys.diagnostics")
- cfg.html_root.sys.menu.add_item("Diagnostics", "icon-screenshot", "/sys/diagnostics", 30)
- @cherrypy.expose
- @require()
- def index(self):
- return util.render_template(template='diagnostics',
- title=_('System Diagnostics'))
+@login_required
+def index(request):
+ """Serve the index page"""
+ return TemplateResponse(request, 'diagnostics.html',
+ {'title': _('System Diagnostics')})
-class Test(PagePlugin):
- order = 31
- def __init__(self):
- super(Test, self).__init__()
- self.register_page("sys.diagnostics.test")
-
- @cherrypy.expose
- @require()
- def index(self):
- output, error = actions.superuser_run("diagnostic-test")
- return util.render_template(template='diagnostics_test',
- title=_('Diagnostic Test'),
- diagnostics_output=output,
- diagnostics_error=error)
+@login_required
+def test(request):
+ """Run diagnostics and the output page"""
+ output, error = actions.superuser_run("diagnostic-test")
+ return TemplateResponse(request, 'diagnostics_test.html',
+ {'title': _('Diagnostic Test'),
+ 'diagnostics_output': output,
+ 'diagnostics_error': error})
diff --git a/modules/expert_mode/__init__.py b/modules/expert_mode/__init__.py
index c638fd55e..071bd92a6 100644
--- a/modules/expert_mode/__init__.py
+++ b/modules/expert_mode/__init__.py
@@ -20,6 +20,8 @@ Plinth module for expert mode configuration
"""
from . import expert_mode
+from .expert_mode import init
+__all__ = ['expert_mode', 'init']
-__all__ = ['expert_mode']
+DEPENDS = ['system']
diff --git a/modules/expert_mode/expert_mode.py b/modules/expert_mode/expert_mode.py
index 49c78e297..389aa8fe0 100644
--- a/modules/expert_mode/expert_mode.py
+++ b/modules/expert_mode/expert_mode.py
@@ -1,80 +1,66 @@
-import cherrypy
from django import forms
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from ..lib.auth import require
-from plugin_mount import PagePlugin
+
import cfg
-import util
+from ..lib.auth import login_required
class ExpertsForm(forms.Form): # pylint: disable-msg=W0232
"""Form to configure expert mode"""
-
expert_mode = forms.BooleanField(
label=_('Expert Mode'), required=False)
- # XXX: Only present due to issue with submitting empty form
- dummy = forms.CharField(label='Dummy', initial='dummy',
- widget=forms.HiddenInput())
+
+def init():
+ """Initialize the module"""
+ menu = cfg.main_menu.find('/sys')
+ menu.add_item(_('Expert Mode'), 'icon-cog', '/sys/expert', 10)
-class Experts(PagePlugin):
- """Expert forms page"""
- order = 60
+@login_required
+def index(request):
+ """Serve the configuration form"""
+ status = get_status(request)
- def __init__(self):
- super(Experts, self).__init__()
+ form = None
+ messages = []
- self.register_page('sys.expert')
-
- cfg.html_root.sys.menu.add_item(_('Expert Mode'), 'icon-cog',
- '/sys/expert', 10)
-
- @cherrypy.expose
- @require()
- def index(self, **kwargs):
- """Serve the configuration form"""
- status = self.get_status()
-
- cfg.log.info('Args - %s' % kwargs)
-
- form = None
- messages = []
-
- if kwargs:
- form = ExpertsForm(kwargs, prefix='experts')
- # pylint: disable-msg=E1101
- if form.is_valid():
- self._apply_changes(form.cleaned_data, messages)
- status = self.get_status()
- form = ExpertsForm(initial=status, prefix='experts')
- else:
+ if request.method == 'POST':
+ form = ExpertsForm(request.POST, prefix='experts')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ _apply_changes(request, form.cleaned_data, messages)
+ status = get_status(request)
form = ExpertsForm(initial=status, prefix='experts')
+ else:
+ form = ExpertsForm(initial=status, prefix='experts')
- return util.render_template(template='expert_mode',
- title=_('Expert Mode'), form=form,
- messages=messages)
+ return TemplateResponse(request, 'expert_mode.html',
+ {'title': _('Expert Mode'),
+ 'form': form,
+ 'messages_': messages})
- @staticmethod
- def get_status():
- """Return the current status"""
- return {'expert_mode': cfg.users.expert()}
- @staticmethod
- def _apply_changes(new_status, messages):
- """Apply expert mode configuration"""
- message = ('info', _('Settings unchanged'))
+def get_status(request):
+ """Return the current status"""
+ return {'expert_mode': cfg.users.expert(request=request)}
- user = cfg.users.current()
- if new_status['expert_mode']:
- if not 'expert' in user['groups']:
- user['groups'].append('expert')
- message = ('success', _('Expert mode enabled'))
- else:
- if 'expert' in user['groups']:
- user['groups'].remove('expert')
- message = ('success', _('Expert mode disabled'))
+def _apply_changes(request, new_status, messages):
+ """Apply expert mode configuration"""
+ message = ('info', _('Settings unchanged'))
- cfg.users.set(user['username'], user)
- messages.append(message)
+ user = cfg.users.current(request=request)
+
+ if new_status['expert_mode']:
+ if not 'expert' in user['groups']:
+ user['groups'].append('expert')
+ message = ('success', _('Expert mode enabled'))
+ else:
+ if 'expert' in user['groups']:
+ user['groups'].remove('expert')
+ message = ('success', _('Expert mode disabled'))
+
+ cfg.users.set(user['username'], user)
+ messages.append(message)
diff --git a/modules/firewall/__init__.py b/modules/firewall/__init__.py
index 33eb5d302..3e3718c6c 100644
--- a/modules/firewall/__init__.py
+++ b/modules/firewall/__init__.py
@@ -20,6 +20,8 @@ Plinth module to configure a firewall
"""
from . import firewall
+from .firewall import init
+__all__ = ['firewall', 'init']
-__all__ = ['firewall']
+DEPENDS = ['system']
diff --git a/modules/firewall/firewall.py b/modules/firewall/firewall.py
index aa581d886..ae0c61d0f 100644
--- a/modules/firewall/firewall.py
+++ b/modules/firewall/firewall.py
@@ -19,136 +19,134 @@
Plinth module to configure a firewall
"""
-import cherrypy
+from django.template.response import TemplateResponse
from gettext import gettext as _
import actions
import cfg
-from ..lib.auth import require
-from plugin_mount import PagePlugin
+from ..lib.auth import login_required
import service as service_module
-import util
-class Firewall(PagePlugin):
- """Firewall menu entry and introduction page"""
- order = 40
+def init():
+ """Initailze firewall module"""
+ menu = cfg.main_menu.find('/sys')
+ menu.add_item(_('Firewall'), 'icon-flag', '/sys/firewall', 50)
- def __init__(self):
- super(Firewall, self).__init__()
+ service_module.ENABLED.connect(on_service_enabled)
- self.register_page('sys.firewall')
- cfg.html_root.sys.menu.add_item(_('Firewall'), 'icon-flag',
- '/sys/firewall', 50)
- service_module.ENABLED.connect(self.on_service_enabled)
+@login_required
+def index(request):
+ """Serve introcution page"""
+ if not get_installed_status():
+ return TemplateResponse(request, 'firewall.html',
+ {'title': _('Firewall'),
+ 'firewall_status': 'not_installed'})
- @cherrypy.expose
- @require()
- def index(self):
- """Serve introcution page"""
- if not self.get_installed_status():
- return util.render_template(template='firewall',
- title=_("Firewall"),
- firewall_status='not_installed')
+ if not get_enabled_status():
+ return TemplateResponse(request, 'firewall.html',
+ {'title': _('Firewall'),
+ 'firewall_status': 'not_running'})
- if not self.get_enabled_status():
- return util.render_template(template='firewall',
- title=_("Firewall"),
- firewall_status='not_running')
+ internal_enabled_services = get_enabled_services(zone='internal')
+ external_enabled_services = get_enabled_services(zone='external')
- internal_enabled_services = self.get_enabled_services(zone='internal')
- external_enabled_services = self.get_enabled_services(zone='external')
+ return TemplateResponse(
+ request, 'firewall.html',
+ {'title': _('Firewall'),
+ 'services': service_module.SERVICES.values(),
+ 'internal_enabled_services': internal_enabled_services,
+ 'external_enabled_services': external_enabled_services})
- return util.render_template(
- template='firewall', title=_('Firewall'),
- services=service_module.SERVICES.values(),
- internal_enabled_services=internal_enabled_services,
- external_enabled_services=external_enabled_services)
- def get_installed_status(self):
- """Return whether firewall is installed"""
- output = self._run(['get-installed'], superuser=True)
- return output.split()[0] == 'installed'
+def get_installed_status():
+ """Return whether firewall is installed"""
+ output = _run(['get-installed'], superuser=True)
+ return output.split()[0] == 'installed'
- def get_enabled_status(self):
- """Return whether firewall is installed"""
- output = self._run(['get-status'], superuser=True)
- return output.split()[0] == 'running'
- def get_enabled_services(self, zone):
- """Return the status of various services currently enabled"""
- output = self._run(['get-enabled-services', '--zone', zone],
- superuser=True)
- return output.split()
+def get_enabled_status():
+ """Return whether firewall is installed"""
+ output = _run(['get-status'], superuser=True)
+ return output.split()[0] == 'running'
- def add_service(self, port, zone):
- """Enable a service in firewall"""
- self._run(['add-service', port, '--zone', zone], superuser=True)
- def remove_service(self, port, zone):
- """Remove a service in firewall"""
- self._run(['remove-service', port, '--zone', zone], superuser=True)
+def get_enabled_services(zone):
+ """Return the status of various services currently enabled"""
+ output = _run(['get-enabled-services', '--zone', zone], superuser=True)
+ return output.split()
- def on_service_enabled(self, sender, service_id, enabled, **kwargs):
- """
- Enable/disable firewall ports when a service is
- enabled/disabled.
- """
- del sender # Unused
- del kwargs # Unused
- internal_enabled_services = self.get_enabled_services(zone='internal')
- external_enabled_services = self.get_enabled_services(zone='external')
+def add_service(port, zone):
+ """Enable a service in firewall"""
+ _run(['add-service', port, '--zone', zone], superuser=True)
- cfg.log.info('Service enabled - %s, %s' % (service_id, enabled))
- service = service_module.SERVICES[service_id]
- for port in service.ports:
- if enabled:
- if port not in internal_enabled_services:
- self.add_service(port, zone='internal')
- if (service.is_external and
- port not in external_enabled_services):
- self.add_service(port, zone='external')
- else:
- # service already configured.
- pass
+def remove_service(port, zone):
+ """Remove a service in firewall"""
+ _run(['remove-service', port, '--zone', zone], superuser=True)
+
+
+def on_service_enabled(sender, service_id, enabled, **kwargs):
+ """
+ Enable/disable firewall ports when a service is
+ enabled/disabled.
+ """
+ del sender # Unused
+ del kwargs # Unused
+
+ internal_enabled_services = get_enabled_services(zone='internal')
+ external_enabled_services = get_enabled_services(zone='external')
+
+ cfg.log.info('Service enabled - %s, %s' % (service_id, enabled))
+ service = service_module.SERVICES[service_id]
+ for port in service.ports:
+ if enabled:
+ if port not in internal_enabled_services:
+ add_service(port, zone='internal')
+
+ if (service.is_external and
+ port not in external_enabled_services):
+ add_service(port, zone='external')
else:
- if port in internal_enabled_services:
- enabled_services_on_port = [
- service_.is_enabled()
- for service_ in service_module.SERVICES.values()
- if port in service_.ports and
- service_id != service_.service_id]
- if not any(enabled_services_on_port):
- self.remove_service(port, zone='internal')
-
- if port in external_enabled_services:
- enabled_services_on_port = [
- service_.is_enabled()
- for service_ in service_module.SERVICES.values()
- if port in service_.ports and
- service_id != service_.service_id and
- service_.is_external]
- if not any(enabled_services_on_port):
- self.remove_service(port, zone='external')
-
- @staticmethod
- def _run(arguments, superuser=False):
- """Run an given command and raise exception if there was an error"""
- command = 'firewall'
-
- cfg.log.info('Running command - %s, %s, %s' % (command, arguments,
- superuser))
-
- if superuser:
- output, error = actions.superuser_run(command, arguments)
+ # service already configured.
+ pass
else:
- output, error = actions.run(command, arguments)
+ if port in internal_enabled_services:
+ enabled_services_on_port = [
+ service_.is_enabled()
+ for service_ in service_module.SERVICES.values()
+ if port in service_.ports and
+ service_id != service_.service_id]
+ if not any(enabled_services_on_port):
+ remove_service(port, zone='internal')
- if error:
- raise Exception('Error setting/getting firewalld confguration - %s'
- % error)
+ if port in external_enabled_services:
+ enabled_services_on_port = [
+ service_.is_enabled()
+ for service_ in service_module.SERVICES.values()
+ if port in service_.ports and
+ service_id != service_.service_id and
+ service_.is_external]
+ if not any(enabled_services_on_port):
+ remove_service(port, zone='external')
- return output
+
+def _run(arguments, superuser=False):
+ """Run an given command and raise exception if there was an error"""
+ command = 'firewall'
+
+ cfg.log.info('Running command - %s, %s, %s' % (command, arguments,
+ superuser))
+
+ if superuser:
+ output, error = actions.superuser_run(command, arguments)
+ else:
+ output, error = actions.run(command, arguments)
+
+ if error:
+ raise Exception('Error setting/getting firewalld confguration - %s'
+ % error)
+
+ return output
diff --git a/modules/first_boot/first_boot.py b/modules/first_boot/first_boot.py
index 204b65ac4..d38f042a5 100644
--- a/modules/first_boot/first_boot.py
+++ b/modules/first_boot/first_boot.py
@@ -18,16 +18,16 @@ The Plinth first-connection process has several stages:
4. The user interacts with the box normally.
"""
-import cherrypy
from django import forms
from django.core import validators
+from django.http.response import HttpResponseRedirect
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from plugin_mount import PagePlugin
+
from ..lib.auth import add_user
from ..config import config
from withsqlite.withsqlite import sqlite_db
import cfg
-import util
## TODO: flesh out these tests values
@@ -66,132 +66,124 @@ below. This key should not be the same as your key because you are not your \
FreedomBox!'))
-class FirstBoot(PagePlugin):
- """First boot wizard"""
+def index(request):
+ """Serve the index first boot page"""
+ return state0(request)
- def __init__(self):
- super(FirstBoot, self).__init__()
- # this is the url this page will hang off of (/firstboot)
- self.register_page('firstboot')
- self.register_page('firstboot/state0')
- self.register_page('firstboot/state1')
+def generate_box_key():
+ """Generate a box key"""
+ return "fake key"
- @cherrypy.expose
- def index(self, *args, **kwargs):
- return self.state0(*args, **kwargs)
- def generate_box_key(self):
- return "fake key"
+def state0(request):
+ """
+ In this state, we do time config over HTTP, name the box and
+ server key selection.
- @cherrypy.expose
- def state0(self, **kwargs):
- """
- In this state, we do time config over HTTP, name the box and
- server key selection.
+ All the parameters are form inputs. They get passed in when
+ the form is submitted. This method checks the inputs and if
+ they validate, uses them to take action. If they do not
+ validate, it displays the form to give the user a chance to
+ input correct values. It might display an error message (in
+ the message parameter).
- All the parameters are form inputs. They get passed in when
- the form is submitted. This method checks the inputs and if
- they validate, uses them to take action. If they do not
- validate, it displays the form to give the user a chance to
- input correct values. It might display an error message (in
- the message parameter).
+ message is an optional string that we can display to the
+ user. It's a good place to put error messages.
+ """
+ try:
+ if _read_state() >= 5:
+ return HttpResponseRedirect(cfg.server_dir)
+ except KeyError:
+ pass
- message is an optional string that we can display to the
- user. It's a good place to put error messages.
- """
- try:
- if FirstBoot._read_state() >= 5:
- raise cherrypy.HTTPRedirect(cfg.server_dir, 302)
- except KeyError:
- pass
+ ## Until LDAP is in place, we'll put the box key in the cfg.store_file
+ status = get_state0()
- ## Until LDAP is in place, we'll put the box key in the cfg.store_file
- status = self.get_state0()
+ form = None
+ messages = []
- form = None
- messages = []
+ if request.method == 'POST':
+ form = State0Form(request.POST, prefix='firstboot')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ success = _apply_state0(status, form.cleaned_data, messages)
- if kwargs:
- form = State0Form(kwargs, prefix='firstboot')
- # pylint: disable-msg=E1101
- if form.is_valid():
- success = self._apply_state0(status, form.cleaned_data,
- messages)
+ if success:
+ # Everything is good, permanently mark and move to page 2
+ _write_state(1)
+ return HttpResponseRedirect(
+ cfg.server_dir + '/firstboot/state1')
+ else:
+ form = State0Form(initial=status, prefix='firstboot')
- if success:
- # Everything is good, permanently mark and move to page 2
- FirstBoot._write_state(1)
- raise cherrypy.HTTPRedirect('state1', 302)
+ return TemplateResponse(request, 'firstboot_state0.html',
+ {'title': _('First Boot!'),
+ 'form': form,
+ 'messages_': messages})
+
+
+def get_state0():
+ """Return the state for form state 0"""
+ with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as \
+ database:
+ return {'hostname': config.get_hostname(),
+ 'box_key': database.get('box_key', None)}
+
+
+def _apply_state0(old_state, new_state, messages):
+ """Apply changes in state 0 form"""
+ success = True
+ with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as \
+ database:
+ database['about'] = 'Information about this FreedomBox'
+
+ if new_state['box_key']:
+ database['box_key'] = new_state['box_key']
+ elif not old_state['box_key']:
+ database['box_key'] = generate_box_key()
+
+ if old_state['hostname'] != new_state['hostname']:
+ config.set_hostname(new_state['hostname'])
+
+ error = add_user(new_state['username'], new_state['password'],
+ 'First user, please change', '', True)
+ if error:
+ messages.append(
+ ('error', _('User account creation failed: %s') % error))
+ success = False
else:
- form = State0Form(initial=status, prefix='firstboot')
+ messages.append(('success', _('User account created')))
- return util.render_template(template='firstboot_state0',
- title=_('First Boot!'), form=form,
- messages=messages)
+ return success
- @staticmethod
- def get_state0():
- """Return the state for form state 0"""
- with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as \
- database:
- return {'hostname': config.get_hostname(),
- 'box_key': database.get('box_key', None)}
- def _apply_state0(self, old_state, new_state, messages):
- """Apply changes in state 0 form"""
- success = True
- with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as \
- database:
- database['about'] = 'Information about this FreedomBox'
+def state1(request):
+ """
+ State 1 is when we have a box name and key. In this state,
+ our task is to provide a certificate and maybe to guide the
+ user through installing it. We automatically move to State 2,
+ which is an HTTPS connection.
- if new_state['box_key']:
- database['box_key'] = new_state['box_key']
- elif not old_state['box_key']:
- database['box_key'] = self.generate_box_key()
+ TODO: HTTPS failure in State 2 should returns to state 1.
+ """
+ # TODO complete first_boot handling
+ # Make sure the user is not stuck on a dead end for now.
+ _write_state(5)
- if old_state['hostname'] != new_state['hostname']:
- config.set_hostname(new_state['hostname'])
+ return TemplateResponse(request, 'firstboot_state1.html',
+ {'title': _('Installing the Certificate')})
- error = add_user(new_state['username'], new_state['password'],
- 'First user, please change', '', True)
- if error:
- messages.append(
- ('error', _('User account creation failed: %s') % error))
- success = False
- else:
- messages.append(('success', _('User account created')))
- return success
+def _read_state():
+ """Read the current state from database"""
+ with sqlite_db(cfg.store_file, table='firstboot',
+ autocommit=True) as database:
+ return database['state']
- @staticmethod
- @cherrypy.expose
- def state1():
- """
- State 1 is when we have a box name and key. In this state,
- our task is to provide a certificate and maybe to guide the
- user through installing it. We automatically move to State 2,
- which is an HTTPS connection.
- TODO: HTTPS failure in State 2 should returns to state 1.
- """
- # TODO complete first_boot handling
- # Make sure the user is not stuck on a dead end for now.
- FirstBoot._write_state(5)
-
- return util.render_template(template='firstboot_state1',
- title=_('Installing the Certificate'))
-
- @staticmethod
- def _read_state():
- """Read the current state from database"""
- with sqlite_db(cfg.store_file, table='firstboot',
- autocommit=True) as database:
- return database['state']
-
- @staticmethod
- def _write_state(state):
- """Write state to database"""
- with sqlite_db(cfg.store_file, table='firstboot',
- autocommit=True) as database:
- database['state'] = state
+def _write_state(state):
+ """Write state to database"""
+ with sqlite_db(cfg.store_file, table='firstboot',
+ autocommit=True) as database:
+ database['state'] = state
diff --git a/modules/help/__init__.py b/modules/help/__init__.py
index 9ef609e2d..27adfedfb 100644
--- a/modules/help/__init__.py
+++ b/modules/help/__init__.py
@@ -20,6 +20,6 @@ Plinth module for help pages
"""
from . import help # pylint: disable-msg=W0622
+from .help import init
-
-__all__ = ['help']
+__all__ = ['help', 'init']
diff --git a/modules/help/help.py b/modules/help/help.py
index 939fed89e..4dadd45d5 100644
--- a/modules/help/help.py
+++ b/modules/help/help.py
@@ -1,49 +1,40 @@
import os
-import cherrypy
from gettext import gettext as _
-from plugin_mount import PagePlugin
+from django.template.response import TemplateResponse
+
import cfg
-import util
-class Help(PagePlugin):
- order = 20 # order of running init in PagePlugins
-
- def __init__(self):
- super(Help, self).__init__()
-
- self.register_page("help")
- self.menu = cfg.main_menu.add_item(_("Documentation"), "icon-book", "/help", 101)
- self.menu.add_item(_("Where to Get Help"), "icon-search", "/help/index", 5)
- self.menu.add_item(_("Developer's Manual"), "icon-info-sign", "/help/view/plinth", 10)
- self.menu.add_item(_("FAQ"), "icon-question-sign", "/help/view/faq", 20)
- self.menu.add_item(_("%s Wiki" % cfg.box_name), "icon-pencil", "http://wiki.debian.org/FreedomBox", 30)
- self.menu.add_item(_("About"), "icon-star", "/help/about", 100)
-
- @cherrypy.expose
- def index(self):
- return util.render_template(template='help',
- title=_('Documentation and FAQ'))
-
- @cherrypy.expose
- def about(self):
- return util.render_template(
- template='about',
- title=_('About the {box_name}').format(box_name=cfg.box_name))
+def init():
+ """Initialize the Help module"""
+ menu = cfg.main_menu.add_item(_('Documentation'), 'icon-book', '/help',
+ 101)
+ menu.add_item(_("Where to Get Help"), "icon-search", "/help/index", 5)
+ menu.add_item(_('Developer\'s Manual'), 'icon-info-sign',
+ '/help/view/plinth', 10)
+ menu.add_item(_('FAQ'), 'icon-question-sign', '/help/view/faq', 20)
+ menu.add_item(_('%s Wiki' % cfg.box_name), 'icon-pencil',
+ 'http://wiki.debian.org/FreedomBox', 30)
+ menu.add_item(_('About'), 'icon-star', '/help/about', 100)
-class View(PagePlugin):
- def __init__(self):
- super(View, self).__init__()
+def index(request):
+ """Serve the index page"""
+ return TemplateResponse(request, 'help.html',
+ {'title': _('Documentation and FAQ')})
- self.register_page("help.view")
- @cherrypy.expose
- def default(self, page=''):
- if page not in ['design', 'plinth', 'hacking', 'faq']:
- raise cherrypy.HTTPError(404, "The path '/help/view/%s' was not found." % page)
+def about(request):
+ """Serve the about page"""
+ title = _('About the {box_name}').format(box_name=cfg.box_name)
+ return TemplateResponse(request, 'about.html', {'title': title})
- with open(os.path.join("doc", "%s.part.html" % page), 'r') as IF:
- main = IF.read()
- return util.render_template(title=_("%s Documentation" %
- cfg.product_name), main=main)
+
+def default(request, page=''):
+ """Serve the documentation pages"""
+ with open(os.path.join('doc', '%s.part.html' % page), 'r') as input_file:
+ main = input_file.read()
+
+ title = _('%s Documentation') % cfg.product_name
+ return TemplateResponse(request, 'login_nav.html',
+ {'title': title, 'main': main})
diff --git a/modules/lib/auth.py b/modules/lib/auth.py
index 974ecef93..61f5e0702 100644
--- a/modules/lib/auth.py
+++ b/modules/lib/auth.py
@@ -1,20 +1,13 @@
-# Form based authentication for CherryPy. Requires the
-# Session tool to be loaded.
-#
-# Thanks for this code is owed to Arnar Birgisson -at - gmail.com. It
-# is based on code he wrote that was retrieved from
-# http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
-# on 1 February 2011.
-
-import cherrypy
-import urllib
+from django.http.response import HttpResponseRedirect
+import functools
from passlib.hash import bcrypt
from passlib.exc import PasswordSizeError
+
import cfg
-import random
from model import User
-cfg.session_key = '_cp_username'
+cfg.session_key = '_username'
+
def add_user(username, passphrase, name='', email='', expert=False):
"""Add a new user with specified username and passphrase.
@@ -49,6 +42,7 @@ def add_user(username, passphrase, name='', email='', expert=False):
cfg.log(error)
return error
+
def check_credentials(username, passphrase):
"""Verifies credentials for username and passphrase.
@@ -87,79 +81,20 @@ def check_credentials(username, passphrase):
if error:
cfg.log(error)
+
return error
-def check_auth(*args, **kwargs):
- """A tool that looks in config for 'auth.require'. If found and it
- is not None, a login is required and the entry is evaluated as a
- list of conditions that the user must fulfill"""
- conditions = cherrypy.request.config.get('auth.require', None)
- # format GET params
- get_params = urllib.quote(cherrypy.request.request_line.split()[1])
- if conditions is not None:
- username = cherrypy.session.get(cfg.session_key)
- if username:
- cherrypy.request.login = username
- for condition in conditions:
- # A condition is just a callable that returns true or false
- if not condition():
- # Send old page as from_page parameter
- raise cherrypy.HTTPRedirect(cfg.server_dir + "/auth/login?from_page=%s" % get_params)
- else:
- # Send old page as from_page parameter
- raise cherrypy.HTTPRedirect(cfg.server_dir + "/auth/login?from_page=%s" % get_params)
-cherrypy.tools.auth = cherrypy.Tool('before_handler', check_auth)
-
-def require(*conditions):
- """A decorator that appends conditions to the auth.require config
- variable."""
- def decorate(f):
- if not hasattr(f, '_cp_config'):
- f._cp_config = dict()
- if 'auth.require' not in f._cp_config:
- f._cp_config['auth.require'] = []
- f._cp_config['auth.require'].extend(conditions)
- return f
- return decorate
-
-
-# Conditions are callables that return True
-# if the user fulfills the conditions they define, False otherwise
-#
-# They can access the current username as cherrypy.request.login
-#
-# Define those at will however suits the application.
-
-def member_of(groupname):
- def check():
- # replace with actual check if is in
- return cherrypy.request.login == 'joe' and groupname == 'admin'
- return check
-
-def name_is(reqd_username):
- return lambda: reqd_username == cherrypy.request.login
-
-# These might be handy
-
-def any_of(*conditions):
- """Returns True if any of the conditions match"""
- def check():
- for c in conditions:
- if c():
- return True
- return False
- return check
-
-# By default all conditions are required, but this might still be
-# needed if you want to use it inside of an any_of(...) condition
-def all_of(*conditions):
- """Returns True if all of the conditions match"""
- def check():
- for c in conditions:
- if not c():
- return False
- return True
- return check
+# XXX: Only required until we start using Django authentication system properly
+def login_required(func):
+ """A decorator to ensure that user is logged in before accessing a view"""
+ @functools.wraps(func)
+ def wrapper(request, *args, **kwargs):
+ """Check that user is logged in"""
+ if not request.session.get(cfg.session_key, None):
+ return HttpResponseRedirect(
+ cfg.server_dir + "/auth/login?from_page=%s" % request.path)
+ return func(request, *args, **kwargs)
+ return wrapper
diff --git a/modules/lib/auth_page.py b/modules/lib/auth_page.py
index 2b2ab6369..750ec5809 100644
--- a/modules/lib/auth_page.py
+++ b/modules/lib/auth_page.py
@@ -2,19 +2,17 @@
Controller to provide login and logout actions
"""
-import cherrypy
import cfg
from django import forms
+from django.http.response import HttpResponseRedirect
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from plugin_mount import PagePlugin
-import auth
-import util
+
+from . import auth
class LoginForm(forms.Form): # pylint: disable-msg=W0232
"""Login form"""
- from_page = forms.CharField(widget=forms.HiddenInput(), required=False)
-
username = forms.CharField(label=_('Username'))
password = forms.CharField(label=_('Passphrase'),
widget=forms.PasswordInput())
@@ -33,48 +31,37 @@ class LoginForm(forms.Form): # pylint: disable-msg=W0232
return self.cleaned_data
-class AuthController(PagePlugin):
- """Login and logout pages"""
+def login(request):
+ """Serve the login page"""
+ form = None
- def __init__(self):
- super(AuthController, self).__init__()
+ if request.method == 'POST':
+ form = LoginForm(request.POST, prefix='auth')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ username = form.cleaned_data['username']
+ request.session[cfg.session_key] = username
+ return HttpResponseRedirect(_get_from_page(request))
+ else:
+ form = LoginForm(prefix='auth')
- self.register_page('auth')
+ return TemplateResponse(request, 'form.html',
+ {'title': _('Login'),
+ 'form': form,
+ 'submit_text': _('Login')})
- def on_login(self, username):
- """Called on successful login"""
- def on_logout(self, username):
- """Called on logout"""
+def logout(request):
+ """Logout and redirect to origin page"""
+ try:
+ del request.session[cfg.session_key]
+ request.session.flush()
+ except KeyError:
+ pass
- @cherrypy.expose
- def login(self, from_page=cfg.server_dir+"/", **kwargs):
- """Serve the login page"""
- form = None
+ return HttpResponseRedirect(_get_from_page(request))
- if kwargs:
- form = LoginForm(kwargs, prefix='auth')
- # pylint: disable-msg=E1101
- if form.is_valid():
- username = form.cleaned_data['username']
- cherrypy.session[cfg.session_key] = username
- cherrypy.request.login = username
- self.on_login(username)
- raise cherrypy.HTTPRedirect(from_page or
- (cfg.server_dir + "/"))
- else:
- form = LoginForm(prefix='auth')
- return util.render_template(template='form', title=_('Login'),
- form=form, submit_text=_('Login'))
-
- @cherrypy.expose
- def logout(self, from_page=cfg.server_dir+"/"):
- sess = cherrypy.session
- username = sess.get(cfg.session_key, None)
- sess[cfg.session_key] = None
- if username:
- cherrypy.request.login = None
- self.on_logout(username)
-
- raise cherrypy.HTTPRedirect(from_page or (cfg.server_dir + "/"))
+def _get_from_page(request):
+ """Return the 'from page' of a request"""
+ return request.GET.get('from_page', cfg.server_dir + '/')
diff --git a/modules/lib/user_store.py b/modules/lib/user_store.py
index e6c416fb3..c3622ede7 100644
--- a/modules/lib/user_store.py
+++ b/modules/lib/user_store.py
@@ -1,4 +1,3 @@
-import cherrypy
import cfg
from model import User
from plugin_mount import UserStoreModule
@@ -16,25 +15,36 @@ class UserStore(UserStoreModule, sqlite_db):
def close(self):
self.__exit__(None,None,None)
- def current(self, name=False):
+ def current(self, request=None, name=False):
"""Return current user, if there is one, else None.
If name = True, return the username instead of the user."""
- try:
- username = cherrypy.session.get(cfg.session_key)
- if name:
- return username
- else:
- return self.get(username)
- except AttributeError:
+ if not request:
return None
-
- def expert(self, username=None):
+
+ try:
+ username = request.session[cfg.session_key]
+ except KeyError:
+ return None
+
+ if name:
+ return username
+
+ return self.get(username)
+
+ def expert(self, username=None, request=None):
+ """Return whether the current or provided user is an expert"""
if not username:
- username = self.current(name=True)
- groups = self.attr(username,"groups")
+ if not request:
+ return False
+
+ username = self.current(request=request, name=True)
+
+ groups = self.attr(username, 'groups')
+
if not groups:
return False
- return 'expert' in groups
+
+ return 'expert' in groups
def attr(self, username=None, field=None):
return self.get(username)[field]
diff --git a/modules/owncloud/__init__.py b/modules/owncloud/__init__.py
index 544b2ebc7..e77100b70 100644
--- a/modules/owncloud/__init__.py
+++ b/modules/owncloud/__init__.py
@@ -20,6 +20,8 @@ Plinth module to configure ownCloud
"""
from . import owncloud
+from .owncloud import init
+__all__ = ['owncloud', 'init']
-__all__ = ['owncloud']
+DEPENDS = ['apps']
diff --git a/modules/owncloud/owncloud.py b/modules/owncloud/owncloud.py
index 34c8554e7..f2b1afff7 100644
--- a/modules/owncloud/owncloud.py
+++ b/modules/owncloud/owncloud.py
@@ -1,86 +1,81 @@
-import cherrypy
from django import forms
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from ..lib.auth import require
-from plugin_mount import PagePlugin
+
import actions
import cfg
+from ..lib.auth import login_required
import service
-import util
+
+
+SERVICE = None
class OwnCloudForm(forms.Form): # pylint: disable-msg=W0232
"""ownCloud configuration form"""
enabled = forms.BooleanField(label=_('Enable ownCloud'), required=False)
- # XXX: Only present due to issue with submitting empty form
- dummy = forms.CharField(label='Dummy', initial='dummy',
- widget=forms.HiddenInput())
+
+def init():
+ """Initialize the ownCloud module"""
+ menu = cfg.main_menu.find('/apps')
+ menu.add_item('Owncloud', 'icon-picture', '/apps/owncloud', 35)
+
+ status = get_status()
+
+ global SERVICE # pylint: disable-msg=W0603
+ SERVICE = service.Service('owncloud', _('ownCloud'), ['http', 'https'],
+ is_external=True, enabled=status['enabled'])
-class OwnCloud(PagePlugin):
- """ownCloud configuration page"""
- order = 90
+@login_required
+def index(request):
+ """Serve the ownCloud configuration page"""
+ status = get_status()
- def __init__(self):
- super(OwnCloud, self).__init__()
+ form = None
+ messages = []
- self.register_page('apps.owncloud')
-
- cfg.html_root.apps.menu.add_item('Owncloud', 'icon-picture',
- '/apps/owncloud', 35)
-
- status = self.get_status()
- self.service = service.Service('owncloud', _('ownCloud'),
- ['http', 'https'], is_external=True,
- enabled=status['enabled'])
-
- @cherrypy.expose
- @require()
- def index(self, **kwargs):
- """Serve the ownCloud configuration page"""
- status = self.get_status()
-
- form = None
- messages = []
-
- if kwargs:
- form = OwnCloudForm(kwargs, prefix='owncloud')
- # pylint: disable-msg=E1101
- if form.is_valid():
- self._apply_changes(status, form.cleaned_data, messages)
- status = self.get_status()
- form = OwnCloudForm(initial=status, prefix='owncloud')
- else:
+ if request.method == 'POST':
+ form = OwnCloudForm(request.POST, prefix='owncloud')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ _apply_changes(status, form.cleaned_data, messages)
+ status = get_status()
form = OwnCloudForm(initial=status, prefix='owncloud')
+ else:
+ form = OwnCloudForm(initial=status, prefix='owncloud')
- return util.render_template(template='owncloud', title=_('ownCloud'),
- form=form, messages=messages)
+ return TemplateResponse(request, 'owncloud.html',
+ {'title': _('ownCloud'),
+ 'form': form,
+ 'messages_': messages})
- @staticmethod
- def get_status():
- """Return the current status"""
- output, error = actions.run('owncloud-setup', 'status')
- if error:
- raise Exception('Error getting ownCloud status: %s' % error)
- return {'enabled': 'enable' in output.split()}
+def get_status():
+ """Return the current status"""
+ output, error = actions.run('owncloud-setup', 'status')
+ if error:
+ raise Exception('Error getting ownCloud status: %s' % error)
- def _apply_changes(self, old_status, new_status, messages):
- """Apply the changes"""
- if old_status['enabled'] == new_status['enabled']:
- messages.append(('info', _('Setting unchanged')))
- return
+ return {'enabled': 'enable' in output.split()}
- if new_status['enabled']:
- messages.append(('success', _('ownCloud enabled')))
- option = 'enable'
- else:
- messages.append(('success', _('ownCloud disabled')))
- option = 'noenable'
- actions.superuser_run('owncloud-setup', [option], async=True)
+def _apply_changes(old_status, new_status, messages):
+ """Apply the changes"""
+ if old_status['enabled'] == new_status['enabled']:
+ messages.append(('info', _('Setting unchanged')))
+ return
- # Send a signal to other modules that the service is
- # enabled/disabled
- self.service.notify_enabled(self, new_status['enabled'])
+ if new_status['enabled']:
+ messages.append(('success', _('ownCloud enabled')))
+ option = 'enable'
+ else:
+ messages.append(('success', _('ownCloud disabled')))
+ option = 'noenable'
+
+ actions.superuser_run('owncloud-setup', [option], async=True)
+
+ # Send a signal to other modules that the service is
+ # enabled/disabled
+ SERVICE.notify_enabled(None, new_status['enabled'])
diff --git a/modules/packages/__init__.py b/modules/packages/__init__.py
index f84ac44c1..f448daaab 100644
--- a/modules/packages/__init__.py
+++ b/modules/packages/__init__.py
@@ -20,6 +20,8 @@ Plinth module to manage packages
"""
from . import packages
+from .packages import init
+__all__ = ['packages', 'init']
-__all__ = ['packages']
+DEPENDS = ['system']
diff --git a/modules/packages/packages.py b/modules/packages/packages.py
index 9bd32cfe1..8db985c85 100644
--- a/modules/packages/packages.py
+++ b/modules/packages/packages.py
@@ -1,11 +1,10 @@
-import cherrypy
from django import forms
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from ..lib.auth import require
-from plugin_mount import PagePlugin
+
import actions
import cfg
-import util
+from ..lib.auth import login_required
def get_modules_available():
@@ -28,10 +27,6 @@ def get_modules_enabled():
class PackagesForm(forms.Form):
"""Packages form"""
- # XXX: Only present due to issue with submitting empty form
- dummy = forms.CharField(label='Dummy', initial='dummy',
- widget=forms.HiddenInput())
-
def __init__(self, *args, **kwargs):
# pylint: disable-msg=E1002, E1101
super(forms.Form, self).__init__(*args, **kwargs)
@@ -44,89 +39,83 @@ class PackagesForm(forms.Form):
label=label, required=False)
-class Packages(PagePlugin):
- """Package page"""
- order = 20
+def init():
+ """Initialize the Packages module"""
+ menu = cfg.main_menu.find('/sys')
+ menu.add_item('Package Manager', 'icon-gift', '/sys/packages', 20)
- def __init__(self):
- super(Packages, self).__init__()
- self.register_page('sys.packages')
+@login_required
+def index(request):
+ """Serve the form"""
+ status = get_status()
- cfg.html_root.sys.menu.add_item('Package Manager', 'icon-gift',
- '/sys/packages', 20)
+ form = None
+ messages = []
- @cherrypy.expose
- @require()
- def index(self, **kwargs):
- """Serve the form"""
- status = self.get_status()
-
- form = None
- messages = []
-
- if kwargs:
- form = PackagesForm(kwargs, prefix='packages')
- # pylint: disable-msg=E1101
- if form.is_valid():
- self._apply_changes(status, form.cleaned_data, messages)
- status = self.get_status()
- form = PackagesForm(initial=status, prefix='packages')
- else:
+ if request.method == 'POST':
+ form = PackagesForm(request.POST, prefix='packages')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ _apply_changes(status, form.cleaned_data, messages)
+ status = get_status()
form = PackagesForm(initial=status, prefix='packages')
+ else:
+ form = PackagesForm(initial=status, prefix='packages')
- return util.render_template(template='packages',
- title=_('Add/Remove Plugins'),
- form=form, messages=messages)
+ return TemplateResponse(request, 'packages.html',
+ {'title': _('Add/Remove Plugins'),
+ 'form': form,
+ 'messages_': messages})
- @staticmethod
- def get_status():
- """Return the current status"""
- modules_available = get_modules_available()
- modules_enabled = get_modules_enabled()
- return {module + '_enabled': module in modules_enabled
- for module in modules_available}
+def get_status():
+ """Return the current status"""
+ modules_available = get_modules_available()
+ modules_enabled = get_modules_enabled()
- @staticmethod
- def _apply_changes(old_status, new_status, messages):
- """Apply form changes"""
- for field, enabled in new_status.items():
- if not field.endswith('_enabled'):
- continue
+ return {module + '_enabled': module in modules_enabled
+ for module in modules_available}
- if old_status[field] == new_status[field]:
- continue
- module = field.split('_enabled')[0]
- if enabled:
- output, error = actions.superuser_run(
- 'module-manager', ['enable', cfg.python_root, module])
- del output # Unused
+def _apply_changes(old_status, new_status, messages):
+ """Apply form changes"""
+ for field, enabled in new_status.items():
+ if not field.endswith('_enabled'):
+ continue
- # TODO: need to get plinth to load the module we just
- # enabled
- if error:
- messages.append(
- ('error', _('Error enabling module - {module}').format(
- module=module)))
- else:
- messages.append(
- ('success', _('Module enabled - {module}').format(
+ if old_status[field] == new_status[field]:
+ continue
+
+ module = field.split('_enabled')[0]
+ if enabled:
+ output, error = actions.superuser_run(
+ 'module-manager', ['enable', cfg.python_root, module])
+ del output # Unused
+
+ # TODO: need to get plinth to load the module we just
+ # enabled
+ if error:
+ messages.append(
+ ('error', _('Error enabling module - {module}').format(
+ module=module)))
+ else:
+ messages.append(
+ ('success', _('Module enabled - {module}').format(
+ module=module)))
+ else:
+ output, error = actions.superuser_run(
+ 'module-manager', ['disable', cfg.python_root, module])
+ del output # Unused
+
+ # TODO: need a smoother way for plinth to unload the
+ # module
+ if error:
+ messages.append(
+ ('error',
+ _('Error disabling module - {module}').format(
module=module)))
else:
- output, error = actions.superuser_run(
- 'module-manager', ['disable', cfg.python_root, module])
- del output # Unused
-
- # TODO: need a smoother way for plinth to unload the
- # module
- if error:
- messages.append(
- ('error',
- _('Error disabling module - {module}').format(
- module=module)))
- else:
- messages.append(
- ('success', _('Module disabled - {module}').format(
- module=module)))
+ messages.append(
+ ('success', _('Module disabled - {module}').format(
+ module=module)))
diff --git a/modules/pagekite/__init__.py b/modules/pagekite/__init__.py
index fa247ab25..3a017a1cd 100644
--- a/modules/pagekite/__init__.py
+++ b/modules/pagekite/__init__.py
@@ -20,6 +20,8 @@ Plinth module to configure PageKite
"""
from . import pagekite
+from .pagekite import init
+__all__ = ['pagekite', 'init']
-__all__ = ['pagekite']
+DEPENDS = ['apps']
diff --git a/modules/pagekite/pagekite.py b/modules/pagekite/pagekite.py
index 29de188ad..8ad48587b 100644
--- a/modules/pagekite/pagekite.py
+++ b/modules/pagekite/pagekite.py
@@ -19,43 +19,38 @@
Plinth module for configuring PageKite service
"""
-import cherrypy
from django import forms
from django.core import validators
+from django.template import RequestContext
+from django.template.loader import render_to_string
+from django.template.response import TemplateResponse
from gettext import gettext as _
import actions
import cfg
-from ..lib.auth import require
-from plugin_mount import PagePlugin
-import util
+from ..lib.auth import login_required
-class PageKite(PagePlugin):
- """PageKite menu entry and introduction page"""
- order = 60
+def init():
+ """Intialize the PageKite module"""
+ menu = cfg.main_menu.find('/apps')
+ menu.add_item(_('Public Visibility (PageKite)'), 'icon-flag',
+ '/apps/pagekite', 50)
- def __init__(self):
- super(PageKite, self).__init__()
- self.register_page("apps.pagekite")
- cfg.html_root.apps.menu.add_item(
- _("Public Visibility (PageKite)"), "icon-flag",
- "/apps/pagekite", 50)
+@login_required
+def index(request):
+ """Serve introdution page"""
+ menu = {'title': _('PageKite'),
+ 'items': [{'url': '/apps/pagekite/configure',
+ 'text': _('Configure PageKite')}]}
- @staticmethod
- @cherrypy.expose
- @require()
- def index():
- """Serve introdution page"""
- menu = {'title': _('PageKite'),
- 'items': [{'url': '/apps/pagekite/configure',
- 'text': _('Configure PageKite')}]}
- sidebar_right = util.render_template(template='menu_block', menu=menu)
+ sidebar_right = render_to_string('menu_block.html', {'menu': menu},
+ RequestContext(request))
- return util.render_template(template='pagekite_introduction',
- title=_("Public Visibility (PageKite)"),
- sidebar_right=sidebar_right)
+ return TemplateResponse(request, 'pagekite_introduction.html',
+ {'title': _('Public Visibility (PageKite)'),
+ 'sidebar_right': sidebar_right})
class TrimmedCharField(forms.CharField):
@@ -103,121 +98,114 @@ for your account if no secret is set on the kite'))
https://pagekite.net/wiki/Howto/SshOverPageKite/">instructions'))
-class Configure(PagePlugin): # pylint: disable-msg=C0103
- """Main configuration form"""
- order = 65
+@login_required
+def configure(request):
+ """Serve the configuration form"""
+ status = get_status()
- def __init__(self):
- super(Configure, self).__init__()
+ form = None
+ messages = []
- self.register_page("apps.pagekite.configure")
-
- @cherrypy.expose
- @require()
- def index(self, **kwargs):
- """Serve the configuration form"""
- status = self.get_status()
-
- form = None
- messages = []
-
- if kwargs:
- form = ConfigureForm(kwargs, prefix='pagekite')
- # pylint: disable-msg=E1101
- if form.is_valid():
- self._apply_changes(status, form.cleaned_data, messages)
- status = self.get_status()
- form = ConfigureForm(initial=status, prefix='pagekite')
- else:
+ if request.method == 'POST':
+ form = ConfigureForm(request.POST, prefix='pagekite')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ _apply_changes(status, form.cleaned_data, messages)
+ status = get_status()
form = ConfigureForm(initial=status, prefix='pagekite')
+ else:
+ form = ConfigureForm(initial=status, prefix='pagekite')
- return util.render_template(template='pagekite_configure',
- title=_('Configure PageKite'), form=form,
- messages=messages)
+ return TemplateResponse(request, 'pagekite_configure.html',
+ {'title': _('Configure PageKite'),
+ 'form': form,
+ 'messages_': messages})
- def get_status(self):
- """
- Return the current status of PageKite configuration by
- executing various actions.
- """
- status = {}
- # Check if PageKite is installed
- output = self._run(['get-installed'])
- cfg.log('Output - %s' % output)
- if output.split()[0] != 'installed':
- return None
+def get_status():
+ """
+ Return the current status of PageKite configuration by
+ executing various actions.
+ """
+ status = {}
- # PageKite service enabled/disabled
- output = self._run(['get-status'])
- status['enabled'] = (output.split()[0] == 'enabled')
+ # Check if PageKite is installed
+ output = _run(['get-installed'])
+ cfg.log('Output - %s' % output)
+ if output.split()[0] != 'installed':
+ return None
- # PageKite kite details
- output = self._run(['get-kite'])
- kite_details = output.split()
- status['kite_name'] = kite_details[0]
- status['kite_secret'] = kite_details[1]
+ # PageKite service enabled/disabled
+ output = _run(['get-status'])
+ status['enabled'] = (output.split()[0] == 'enabled')
- # Service status
- status['service'] = {}
- for service in ('http', 'ssh'):
- output = self._run(['get-service-status', service])
- status[service + '_enabled'] = (output.split()[0] == 'enabled')
+ # PageKite kite details
+ output = _run(['get-kite'])
+ kite_details = output.split()
+ status['kite_name'] = kite_details[0]
+ status['kite_secret'] = kite_details[1]
- return status
+ # Service status
+ status['service'] = {}
+ for service in ('http', 'ssh'):
+ output = _run(['get-service-status', service])
+ status[service + '_enabled'] = (output.split()[0] == 'enabled')
- def _apply_changes(self, old_status, new_status, messages):
- """Apply the changes to PageKite configuration"""
- cfg.log.info('New status is - %s' % new_status)
+ return status
- if old_status != new_status:
- self._run(['stop'])
- if old_status['enabled'] != new_status['enabled']:
- if new_status['enabled']:
- self._run(['set-status', 'enable'])
- messages.append(('success', _('PageKite enabled')))
- else:
- self._run(['set-status', 'disable'])
- messages.append(('success', _('PageKite disabled')))
+def _apply_changes(old_status, new_status, messages):
+ """Apply the changes to PageKite configuration"""
+ cfg.log.info('New status is - %s' % new_status)
- if old_status['kite_name'] != new_status['kite_name'] or \
- old_status['kite_secret'] != new_status['kite_secret']:
- self._run(['set-kite', '--kite-name', new_status['kite_name'],
- '--kite-secret', new_status['kite_secret']])
- messages.append(('success', _('Kite details set')))
+ if old_status != new_status:
+ _run(['stop'])
- for service in ['http', 'ssh']:
- if old_status[service + '_enabled'] != \
- new_status[service + '_enabled']:
- if new_status[service + '_enabled']:
- self._run(['set-service-status', service, 'enable'])
- messages.append(('success', _('Service enabled: {service}')
- .format(service=service)))
- else:
- self._run(['set-service-status', service, 'disable'])
- messages.append(('success',
- _('Service disabled: {service}')
- .format(service=service)))
-
- if old_status != new_status:
- self._run(['start'])
-
- @staticmethod
- def _run(arguments, superuser=True):
- """Run an given command and raise exception if there was an error"""
- command = 'pagekite-configure'
-
- cfg.log.info('Running command - %s, %s, %s' % (command, arguments,
- superuser))
-
- if superuser:
- output, error = actions.superuser_run(command, arguments)
+ if old_status['enabled'] != new_status['enabled']:
+ if new_status['enabled']:
+ _run(['set-status', 'enable'])
+ messages.append(('success', _('PageKite enabled')))
else:
- output, error = actions.run(command, arguments)
+ _run(['set-status', 'disable'])
+ messages.append(('success', _('PageKite disabled')))
- if error:
- raise Exception('Error setting/getting PageKite confguration - %s'
- % error)
+ if old_status['kite_name'] != new_status['kite_name'] or \
+ old_status['kite_secret'] != new_status['kite_secret']:
+ _run(['set-kite', '--kite-name', new_status['kite_name'],
+ '--kite-secret', new_status['kite_secret']])
+ messages.append(('success', _('Kite details set')))
- return output
+ for service in ['http', 'ssh']:
+ if old_status[service + '_enabled'] != \
+ new_status[service + '_enabled']:
+ if new_status[service + '_enabled']:
+ _run(['set-service-status', service, 'enable'])
+ messages.append(('success', _('Service enabled: {service}')
+ .format(service=service)))
+ else:
+ _run(['set-service-status', service, 'disable'])
+ messages.append(('success',
+ _('Service disabled: {service}')
+ .format(service=service)))
+
+ if old_status != new_status:
+ _run(['start'])
+
+
+def _run(arguments, superuser=True):
+ """Run an given command and raise exception if there was an error"""
+ command = 'pagekite-configure'
+
+ cfg.log.info('Running command - %s, %s, %s' % (command, arguments,
+ superuser))
+
+ if superuser:
+ output, error = actions.superuser_run(command, arguments)
+ else:
+ output, error = actions.run(command, arguments)
+
+ if error:
+ raise Exception('Error setting/getting PageKite confguration - %s'
+ % error)
+
+ return output
diff --git a/modules/system/__init__.py b/modules/system/__init__.py
index bd46fa10c..1d9349bb0 100644
--- a/modules/system/__init__.py
+++ b/modules/system/__init__.py
@@ -20,6 +20,7 @@ Plinth module for system section page
"""
from . import system
+from system import init
-__all__ = ['system']
+__all__ = ['system', 'init']
diff --git a/modules/system/system.py b/modules/system/system.py
index 1896e00c2..e94c85b85 100644
--- a/modules/system/system.py
+++ b/modules/system/system.py
@@ -1,21 +1,15 @@
-import cherrypy
from gettext import gettext as _
-from plugin_mount import PagePlugin
+from django.template.response import TemplateResponse
+
import cfg
-import util
-class Sys(PagePlugin):
- order = 10
+def init():
+ """Initialize the system module"""
+ cfg.main_menu.add_item(_('System'), 'icon-cog', '/sys', 100)
- def __init__(self):
- super(Sys, self).__init__()
- self.register_page("sys")
- self.menu = cfg.main_menu.add_item(_("System"), "icon-cog", "/sys", 100)
- self.menu.add_item(_("Users and Groups"), "icon-user", "/sys/users", 15)
-
- @cherrypy.expose
- def index(self):
- return util.render_template(template='system',
- title=_("System Configuration"))
+def index(request):
+ """Serve the index page"""
+ return TemplateResponse(request, 'system.html',
+ {'title': _('System Configuration')})
diff --git a/modules/tor/__init__.py b/modules/tor/__init__.py
index 4b42293f9..0a806432a 100644
--- a/modules/tor/__init__.py
+++ b/modules/tor/__init__.py
@@ -20,6 +20,8 @@ Plinth module to configure Tor
"""
from . import tor
+from .tor import init
+__all__ = ['tor', 'init']
-__all__ = ['tor']
+DEPENDS = ['apps']
diff --git a/modules/tor/tor.py b/modules/tor/tor.py
index f564ed6ad..1438955de 100644
--- a/modules/tor/tor.py
+++ b/modules/tor/tor.py
@@ -19,38 +19,35 @@
Plinth module for configuring Tor
"""
-import cherrypy
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from plugin_mount import PagePlugin
-from ..lib.auth import require
+
import actions
import cfg
-import util
+from ..lib.auth import login_required
-class Tor(PagePlugin):
- order = 60 # order of running init in PagePlugins
+def init():
+ """Initialize the Tor module"""
+ menu = cfg.main_menu.find('/apps')
+ menu.add_item("Tor", "icon-eye-close", "/apps/tor", 30)
- def __init__(self):
- super(Tor, self).__init__()
- self.register_page("apps.tor")
- cfg.html_root.apps.menu.add_item("Tor", "icon-eye-close", "/apps/tor",
- 30)
+@login_required
+def index(request):
+ """Service the index page"""
+ output, error = actions.superuser_run("tor-get-ports")
+ del error # Unused
- @cherrypy.expose
- @require()
- def index(self):
- output, error = actions.superuser_run("tor-get-ports")
- port_info = output.split("\n")
- tor_ports = {}
- for line in port_info:
- try:
- (key, val) = line.split()
- tor_ports[key] = val
- except ValueError:
- continue
+ port_info = output.split("\n")
+ tor_ports = {}
+ for line in port_info:
+ try:
+ (key, val) = line.split()
+ tor_ports[key] = val
+ except ValueError:
+ continue
- return util.render_template(template='tor',
- title=_('Tor Control Panel'),
- tor_ports=tor_ports)
+ return TemplateResponse(request, 'tor.html',
+ {'title': _('Tor Control Panel'),
+ 'tor_ports': tor_ports})
diff --git a/modules/users/__init__.py b/modules/users/__init__.py
index 7cb056bb5..3dc71aeb5 100644
--- a/modules/users/__init__.py
+++ b/modules/users/__init__.py
@@ -20,6 +20,8 @@ Plinth module to manage users
"""
from . import users
+from .users import init
+__all__ = ['users', 'init']
-__all__ = ['users']
+DEPENDS = ['system']
diff --git a/modules/users/users.py b/modules/users/users.py
index bdcd7f044..0103c7c53 100644
--- a/modules/users/users.py
+++ b/modules/users/users.py
@@ -1,36 +1,36 @@
-import cherrypy
from django import forms
from django.core import validators
+from django.template import RequestContext
+from django.template.loader import render_to_string
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from ..lib.auth import require, add_user
-from plugin_mount import PagePlugin
+
import cfg
+from ..lib.auth import add_user, login_required
from model import User
-import util
-class Users(PagePlugin):
- order = 20 # order of running init in PagePlugins
+def init():
+ """Intialize the module"""
+ menu = cfg.main_menu.find('/sys')
+ menu.add_item(_('Users and Groups'), 'icon-user', '/sys/users', 15)
- def __init__(self):
- super(Users, self).__init__()
- self.register_page("sys.users")
+@login_required
+def index(request):
+ """Return a rendered users page"""
+ menu = {'title': _('Users and Groups'),
+ 'items': [{'url': '/sys/users/add',
+ 'text': _('Add User')},
+ {'url': '/sys/users/edit',
+ 'text': _('Edit Users')}]}
- @staticmethod
- @cherrypy.expose
- @require()
- def index():
- """Return a rendered users page"""
- menu = {'title': _('Users and Groups'),
- 'items': [{'url': '/sys/users/add',
- 'text': _('Add User')},
- {'url': '/sys/users/edit',
- 'text': _('Edit Users')}]}
- sidebar_right = util.render_template(template='menu_block',
- menu=menu)
- return util.render_template(title="Manage Users and Groups",
- sidebar_right=sidebar_right)
+ sidebar_right = render_to_string('menu_block.html', {'menu': menu},
+ RequestContext(request))
+
+ return TemplateResponse(request, 'login_nav.html',
+ {'title': _('Manage Users and Groups'),
+ 'sidebar_right': sidebar_right})
class UserAddForm(forms.Form): # pylint: disable-msg=W0232
@@ -50,48 +50,40 @@ and alphabet'),
email = forms.EmailField(label=_('Email'), required=False)
-class UserAdd(PagePlugin):
- """Add user page"""
- order = 30
+@login_required
+def add(request):
+ """Serve the form"""
+ form = None
+ messages = []
- def __init__(self):
- super(UserAdd, self).__init__()
-
- self.register_page('sys.users.add')
-
- @cherrypy.expose
- @require()
- def index(self, **kwargs):
- """Serve the form"""
- form = None
- messages = []
-
- if kwargs:
- form = UserAddForm(kwargs, prefix='user')
- # pylint: disable-msg=E1101
- if form.is_valid():
- self._add_user(form.cleaned_data, messages)
- form = UserAddForm(prefix='user')
- else:
+ if request.method == 'POST':
+ form = UserAddForm(request.POST, prefix='user')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ _add_user(form.cleaned_data, messages)
form = UserAddForm(prefix='user')
+ else:
+ form = UserAddForm(prefix='user')
- return util.render_template(template='users_add', title=_('Add User'),
- form=form, messages=messages)
+ return TemplateResponse(request, 'users_add.html',
+ {'title': _('Add User'),
+ 'form': form,
+ 'messages_': messages})
- @staticmethod
- def _add_user(data, messages):
- """Add a user"""
- if cfg.users.exists(data['username']):
- messages.append(
- ('error', _('User "{username}" already exists').format(
- username=data['username'])))
- return
- add_user(data['username'], data['password'], data['full_name'],
- data['email'], False)
+def _add_user(data, messages):
+ """Add a user"""
+ if cfg.users.exists(data['username']):
messages.append(
- ('success', _('User "{username}" added').format(
+ ('error', _('User "{username}" already exists').format(
username=data['username'])))
+ return
+
+ add_user(data['username'], data['password'], data['full_name'],
+ data['email'], False)
+ messages.append(
+ ('success', _('User "{username}" added').format(
+ username=data['username'])))
class UserEditForm(forms.Form): # pylint: disable-msg=W0232
@@ -110,64 +102,56 @@ class UserEditForm(forms.Form): # pylint: disable-msg=W0232
self.fields['delete_user_' + user['username']] = field
-class UserEdit(PagePlugin):
- """User edit page"""
- order = 35
+@login_required
+def edit(request):
+ """Serve the edit form"""
+ form = None
+ messages = []
- def __init__(self):
- super(UserEdit, self).__init__()
-
- self.register_page('sys.users.edit')
-
- @cherrypy.expose
- @require()
- def index(self, **kwargs):
- """Serve the form"""
- form = None
- messages = []
-
- if kwargs:
- form = UserEditForm(kwargs, prefix='user')
- # pylint: disable-msg=E1101
- if form.is_valid():
- self._apply_changes(form.cleaned_data, messages)
- form = UserEditForm(prefix='user')
- else:
+ if request.method == 'POST':
+ form = UserEditForm(request.POST, prefix='user')
+ # pylint: disable-msg=E1101
+ if form.is_valid():
+ _apply_edit_changes(request, form.cleaned_data, messages)
form = UserEditForm(prefix='user')
+ else:
+ form = UserEditForm(prefix='user')
- return util.render_template(template='users_edit',
- title=_('Edit or Delete User'),
- form=form, messages=messages)
+ return TemplateResponse(request, 'users_edit.html',
+ {'title': _('Edit or Delete User'),
+ 'form': form,
+ 'messages_': messages})
- @staticmethod
- def _apply_changes(data, messages):
- """Apply form changes"""
- for field, value in data.items():
- if not value:
- continue
- if not field.startswith('delete_user_'):
- continue
+def _apply_edit_changes(request, data, messages):
+ """Apply form changes"""
+ for field, value in data.items():
+ if not value:
+ continue
- username = field.split('delete_user_')[1]
+ if not field.startswith('delete_user_'):
+ continue
- cfg.log.info('%s asked to delete %s' %
- (cherrypy.session.get(cfg.session_key), username))
+ username = field.split('delete_user_')[1]
- if username == cfg.users.current(name=True):
- messages.append(
- ('error',
- _('Can not delete current account - "%s"') % username))
- continue
+ requesting_user = request.session.get(cfg.session_key, None)
+ cfg.log.info('%s asked to delete %s' %
+ (requesting_user, username))
- if not cfg.users.exists(username):
- messages.append(('error',
- _('User "%s" does not exist') % username))
- continue
+ if username == cfg.users.current(request=request, name=True):
+ messages.append(
+ ('error',
+ _('Can not delete current account - "%s"') % username))
+ continue
- try:
- cfg.users.remove(username)
- messages.append(('success', _('User "%s" deleted') % username))
- except IOError as exception:
- messages.append(('error', _('Error deleting "%s" - %s') %
- (username, exception)))
+ if not cfg.users.exists(username):
+ messages.append(('error',
+ _('User "%s" does not exist') % username))
+ continue
+
+ try:
+ cfg.users.remove(username)
+ messages.append(('success', _('User "%s" deleted') % username))
+ except IOError as exception:
+ messages.append(('error', _('Error deleting "%s" - %s') %
+ (username, exception)))
diff --git a/modules/xmpp/__init__.py b/modules/xmpp/__init__.py
index a55e739c3..578564afb 100644
--- a/modules/xmpp/__init__.py
+++ b/modules/xmpp/__init__.py
@@ -20,6 +20,8 @@ Plinth module to configure XMPP server
"""
from . import xmpp
+from .xmpp import init
+__all__ = ['xmpp', 'init']
-__all__ = ['xmpp']
+DEPENDS = ['apps']
diff --git a/modules/xmpp/xmpp.py b/modules/xmpp/xmpp.py
index 4da0e3427..2974607bb 100644
--- a/modules/xmpp/xmpp.py
+++ b/modules/xmpp/xmpp.py
@@ -1,12 +1,13 @@
-import cherrypy
from django import forms
+from django.template import RequestContext
+from django.template.loader import render_to_string
+from django.template.response import TemplateResponse
from gettext import gettext as _
-from ..lib.auth import require
-from plugin_mount import PagePlugin
-import cfg
+
import actions
+import cfg
+from ..lib.auth import login_required
import service
-import util
SIDE_MENU = {'title': _('XMPP'),
@@ -16,38 +17,35 @@ SIDE_MENU = {'title': _('XMPP'),
'text': 'Register XMPP Account'}]}
-class XMPP(PagePlugin):
- """XMPP Page"""
- order = 60
+def init():
+ """Initialize the XMPP module"""
+ menu = cfg.main_menu.find('/apps')
+ menu.add_item('Chat', 'icon-comment', '/../jwchat', 20)
+ menu.add_item('XMPP', 'icon-comment', '/apps/xmpp', 40)
- def __init__(self):
- super(XMPP, self).__init__()
+ service.Service(
+ 'xmpp-client', _('Chat Server - client connections'),
+ is_external=True, enabled=True)
+ service.Service(
+ 'xmpp-server', _('Chat Server - server connections'),
+ is_external=True, enabled=True)
+ service.Service(
+ 'xmpp-bosh', _('Chat Server - web interface'), is_external=True,
+ enabled=True)
- self.register_page('apps.xmpp')
- cfg.html_root.apps.menu.add_item('XMPP', 'icon-comment',
- '/apps/xmpp', 40)
- self.client_service = service.Service(
- 'xmpp-client', _('Chat Server - client connections'),
- is_external=True, enabled=True)
- self.server_service = service.Service(
- 'xmpp-server', _('Chat Server - server connections'),
- is_external=True, enabled=True)
- self.bosh_service = service.Service(
- 'xmpp-bosh', _('Chat Server - web interface'), is_external=True,
- enabled=True)
+@login_required
+def index(request):
+ """Serve XMPP page"""
+ main = "
If you believe this
- missing page should exist, please file a bug with either the Plinth
- project (it has
- an issue tracker) or the people responsible for the module you
- are trying to access.
-
-
Sorry for the mistake.
- """)
-
-def error_page_500(status, message, traceback, version):
- cfg.log.error("500 Internal Server Error. Trackback is above.")
- more="""
This is an internal error and not something you caused
- or can fix. Please report the error on the bug tracker so
- we can fix it.
"""
- return error_page(status, message, "
%s
%s
" % (more, "\n".join(traceback.split("\n"))))
-
-class Root(plugin_mount.PagePlugin):
- @cherrypy.expose
- def index(self):
- ## TODO: firstboot hijacking root should probably be in the firstboot module with a hook in plinth.py
- with sqlite_db(cfg.store_file, table="firstboot") as db:
- if not 'state' in db:
- # if we created a new user db, make sure it can't be read by everyone
- userdb_fname = '{}.sqlite3'.format(cfg.user_db)
- os.chmod(userdb_fname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
- # cherrypy.InternalRedirect throws a 301, causing the
- # browser to cache the redirect, preventing the user from
- # navigating to /plinth until the browser is restarted.
- raise cherrypy.HTTPRedirect('firstboot', 307)
- elif db['state'] < 5:
- cfg.log("First Boot state = %d" % db['state'])
- raise cherrypy.InternalRedirect('firstboot/state%d' % db['state'])
- if cherrypy.session.get(cfg.session_key, None):
- raise cherrypy.InternalRedirect('apps')
- else:
- raise cherrypy.InternalRedirect('help/about')
-
-
-def load_modules():
- """
- Read names of enabled modules in modules/enabled directory and
- import them from modules directory.
- """
- for name in os.listdir('modules/enabled'):
- cfg.log.info('Importing modules/%s' % name)
- try:
- importlib.import_module('modules.{module}'.format(module=name))
- except ImportError as exception:
- cfg.log.error(
- 'Could not import modules/{module}: {exception}'
- .format(module=name, exception=exception))
-
-
-def get_template_directories():
- """Return the list of template directories"""
- directory = os.path.dirname(os.path.abspath(__file__))
- core_directory = os.path.join(directory, 'templates')
-
- directories = set((core_directory,))
- for name in os.listdir('modules/enabled'):
- directories.add(os.path.join('modules', name, 'templates'))
-
- cfg.log.info('Template directories - %s' % directories)
-
- return directories
-
def parse_arguments():
parser = argparse.ArgumentParser(description='Plinth web interface for the FreedomBox.')
@@ -144,7 +65,13 @@ def set_config(args, element, default):
# it wasn't in the config file, but set the default anyway.
setattr(cfg, element, default)
-def setup():
+
+def setup_logging():
+ """Setup logging framework"""
+ cfg.log = Logger()
+
+
+def setup_configuration():
cfg = parse_arguments()
try:
@@ -155,55 +82,91 @@ def setup():
pass
os.chdir(cfg.python_root)
- cherrypy.config.update({'error_page.404': error_page_404})
- cherrypy.config.update({'error_page.500': error_page_500})
- cfg.log = Logger()
- load_modules()
- cfg.html_root = Root()
- cfg.users = plugin_mount.UserStoreModule.get_plugins()[0]
- cfg.page_plugins = plugin_mount.PagePlugin.get_plugins()
- cfg.log("Loaded %d page plugins" % len(cfg.page_plugins))
- # Add an extra server
- server = _cpserver.Server()
- server.socket_host = '127.0.0.1'
- server.socket_port = 52854
- server.subscribe()
+def setup_server():
+ """Setup CherryPy server"""
+ # Add an extra server
+ server = _cpserver.Server()
+ server.socket_host = '127.0.0.1'
+ server.socket_port = 52854
+ server.subscribe()
- # Configure default server
- cherrypy.config.update(
- {'server.socket_host': cfg.host,
- 'server.socket_port': cfg.port,
- 'server.thread_pool':10,
- 'tools.staticdir.root': cfg.file_root,
- 'tools.sessions.on':True,
- 'tools.auth.on':True,
- 'tools.sessions.storage_type':"file",
- 'tools.sessions.timeout':90,
- 'tools.sessions.storage_path':"%s/cherrypy_sessions" % cfg.data_dir,})
+ # Configure default server
+ cherrypy.config.update(
+ {'server.socket_host': cfg.host,
+ 'server.socket_port': cfg.port,
+ 'server.thread_pool': 10})
+
+ application = django.core.wsgi.get_wsgi_application()
+ cherrypy.tree.graft(application, cfg.server_dir)
+
+ config = {
+ '/': {'tools.staticdir.root': '%s/static' % cfg.file_root,
+ 'tools.staticdir.on': True,
+ 'tools.staticdir.dir': '.'}}
+ cherrypy.tree.mount(None, cfg.server_dir + '/static', config)
+
+ cherrypy.engine.signal_handler.subscribe()
+
+
+def context_processor(request):
+ """Add additional context values to RequestContext for use in templates"""
+ path_parts = request.path.split('/')
+ active_menu_urls = ['/'.join(path_parts[:length])
+ for length in xrange(1, len(path_parts))]
+ return {
+ 'cfg': cfg,
+ 'main_menu': cfg.main_menu,
+ 'submenu': cfg.main_menu.active_item(request),
+ 'request_path': request.path,
+ 'basehref': cfg.server_dir,
+ 'username': request.session.get(cfg.session_key, None),
+ 'active_menu_urls': active_menu_urls
+ }
+
+
+def configure_django():
+ """Setup Django configuration in the absense of .settings file"""
+ context_processors = [
+ 'django.contrib.auth.context_processors.auth',
+ 'django.core.context_processors.debug',
+ 'django.core.context_processors.i18n',
+ 'django.core.context_processors.media',
+ 'django.core.context_processors.static',
+ 'django.core.context_processors.tz',
+ 'django.contrib.messages.context_processors.messages',
+ 'plinth.context_processor']
+
+ template_directories = module_loader.get_template_directories()
+ sessions_directory = os.path.join(cfg.data_dir, 'sessions')
+ django.conf.settings.configure(
+ DEBUG=False,
+ ALLOWED_HOSTS=['127.0.0.1', 'localhost'],
+ TEMPLATE_DIRS=template_directories,
+ INSTALLED_APPS=['bootstrapform'],
+ ROOT_URLCONF='urls',
+ SESSION_ENGINE='django.contrib.sessions.backends.file',
+ SESSION_FILE_PATH=sessions_directory,
+ STATIC_URL=cfg.server_dir + '/static/',
+ TEMPLATE_CONTEXT_PROCESSORS=context_processors)
- config = {
- '/': {'tools.staticdir.root': '%s/static' % cfg.file_root,
- 'tools.proxy.on': True,},
- '/static': {'tools.staticdir.on': True,
- 'tools.staticdir.dir': "."},
- '/favicon.ico':{'tools.staticfile.on': True,
- 'tools.staticfile.filename':
- "%s/static/theme/favicon.ico" % cfg.file_root}}
- cherrypy.tree.mount(cfg.html_root, cfg.server_dir, config=config)
- cherrypy.engine.signal_handler.subscribe()
def main():
- # Initialize basic services
+ """Intialize and start the application"""
+ setup_logging()
+
service.init()
- setup()
+ setup_configuration()
- # Configure Django
- template_directories = get_template_directories()
- django.conf.settings.configure(TEMPLATE_DIRS=template_directories,
- INSTALLED_APPS=['bootstrapform'])
+ configure_django()
+
+ module_loader.load_modules()
+
+ cfg.users = plugin_mount.UserStoreModule.get_plugins()[0]
+
+ setup_server()
cherrypy.engine.start()
cherrypy.engine.block()
diff --git a/templates/base.html b/templates/base.html
index be6ca7dda..e26f099b3 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -1,3 +1,4 @@
+{% load static %}
@@ -29,20 +30,20 @@
{% if title %} {{ title }} {% else %} FreedomBox {% endif %}
-
+
-
-
-
+
+
+
-
+
-
-
+
+
{{ css|safe }}
@@ -57,7 +58,10 @@
- FreedomBox
+
+
+
+ FreedomBox
{% block add_nav_and_login %}
{% endblock %}
@@ -111,10 +115,6 @@
free software offered to you under the terms of
the GNU Affero General Public
License, Version 3 or later. This Plinth theme was built by Sean "Diggity" O'Brien.
-
diff --git a/templates/messages.html b/templates/messages.html
index fa5404495..4aac25d88 100644
--- a/templates/messages.html
+++ b/templates/messages.html
@@ -17,7 +17,7 @@
#
{% endcomment %}
-{% for severity, message in messages %}
+{% for severity, message in messages_ %}
×
{{ message }}
diff --git a/views.py b/views.py
new file mode 100644
index 000000000..140962f5c
--- /dev/null
+++ b/views.py
@@ -0,0 +1,52 @@
+#
+# 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 .
+#
+
+"""
+Main Plinth views
+"""
+
+from django.http.response import HttpResponseRedirect
+import os
+import stat
+
+import cfg
+from withsqlite.withsqlite import sqlite_db
+
+
+def index(request):
+ """Serve the main index page"""
+ # TODO: Move firstboot handling to firstboot module somehow
+ with sqlite_db(cfg.store_file, table='firstboot') as database:
+ if not 'state' in database:
+ # If we created a new user db, make sure it can't be read by
+ # everyone
+ userdb_fname = '{}.sqlite3'.format(cfg.user_db)
+ os.chmod(userdb_fname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
+ # Permanent redirect causes the browser to cache the redirect,
+ # preventing the user from navigating to /plinth until the
+ # browser is restarted.
+ return HttpResponseRedirect(cfg.server_dir + '/firstboot')
+
+ if database['state'] < 5:
+ cfg.log('First boot state = %d' % database['state'])
+ return HttpResponseRedirect(
+ cfg.server_dir + '/firstboot/state%d' % database['state'])
+
+ if request.session.get(cfg.session_key, None):
+ return HttpResponseRedirect(cfg.server_dir + '/apps')
+
+ return HttpResponseRedirect(cfg.server_dir + '/help/about')
From 59c285bf650f313732f9d9b8ec2d9479ea87eb73 Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Thu, 12 Jun 2014 23:33:39 +0530
Subject: [PATCH 10/11] Remove unused PagePlugin
---
plugin_mount.py | 35 -----------------------------------
1 file changed, 35 deletions(-)
diff --git a/plugin_mount.py b/plugin_mount.py
index 0b815338c..09d95d09d 100644
--- a/plugin_mount.py
+++ b/plugin_mount.py
@@ -35,41 +35,6 @@ class PluginMountSingular(PluginMount):
cls.plugins.append(cls)
-def _setattr_deep(obj, path, value):
- """If path is 'x.y.z' or ['x', 'y', 'z'] then perform obj.x.y.z = value"""
- if isinstance(path, basestring):
- path = path.split('.')
-
- for part in path[:-1]:
- obj = getattr(obj, part)
-
- setattr(obj, path[-1], value)
-
-
-class PagePlugin(object):
- """
- Mount point for page plugins. Page plugins provide display pages
- in the interface (one menu item, for example).
-
- order - How early should this plugin be loaded? Lower order is earlier.
- """
-
- order = 50
-
- __metaclass__ = PluginMount
-
- def __init__(self):
- """If cfg.html_root is none, then this is the html_root."""
- if not cfg.html_root:
- cfg.log('Setting html root to %s' % self.__class__.__name__)
- cfg.html_root = self
-
- def register_page(self, url):
- """Add a page to the page tree structure"""
- cfg.log.info("Registering page: %s" % url)
- _setattr_deep(cfg.html_root, url, self)
-
-
class UserStoreModule(object):
"""
Mount Point for plugins that will manage the user backend storage,
From db3b0ab9e65dee9f8c68c9e385c0016d769b4b7b Mon Sep 17 00:00:00 2001
From: Sunil Mohan Adapa
Date: Thu, 12 Jun 2014 23:34:00 +0530
Subject: [PATCH 11/11] Remove unused template rendering wrapper
---
util.py | 21 ---------------------
1 file changed, 21 deletions(-)
diff --git a/util.py b/util.py
index e44e62bcd..b5d66d932 100644
--- a/util.py
+++ b/util.py
@@ -1,10 +1,8 @@
import os
import sys
-import cherrypy
import cfg
import sqlite3
-from django.template.loader import render_to_string
from filedict import FileDict
@@ -56,25 +54,6 @@ def find_keys(dic, val):
return [k for k, v in dic.iteritems() if v == val]
-def render_template(template='login_nav', **kwargs):
- for key in ['sidebar_left', 'sidebar_right', 'main', 'js', 'nav', 'css',
- 'title', 'basehref']:
- if not key in kwargs:
- kwargs[key] = ''
-
- if kwargs['basehref'] == '':
- kwargs['basehref'] = cfg.server_dir
-
- kwargs['template'] = template
- kwargs['main_menu'] = cfg.main_menu
- kwargs['submenu'] = cfg.main_menu.active_item()
- kwargs['current_url'] = cherrypy.url()
- kwargs['username'] = cherrypy.session.get(cfg.session_key)
- kwargs['cfg'] = cfg
-
- return render_to_string(template + '.html', kwargs)
-
-
def filedict_con(filespec=None, table='dict'):
"""TODO: better error handling in filedict_con"""
try: