diff --git a/modules/apps.py b/modules/apps.py
deleted file mode 120000
index d69ec8059..000000000
--- a/modules/apps.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/apps/apps.py
\ No newline at end of file
diff --git a/modules/auth.py b/modules/auth.py
deleted file mode 120000
index 7a4c6eccd..000000000
--- a/modules/auth.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/lib/auth.py
\ No newline at end of file
diff --git a/modules/auth_page.py b/modules/auth_page.py
deleted file mode 120000
index 7ce3ca22a..000000000
--- a/modules/auth_page.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/lib/auth_page.py
\ No newline at end of file
diff --git a/modules/config.py b/modules/config.py
deleted file mode 120000
index a7104c23d..000000000
--- a/modules/config.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/config/config.py
\ No newline at end of file
diff --git a/modules/diagnostics.py b/modules/diagnostics.py
deleted file mode 120000
index 2400f0df8..000000000
--- a/modules/diagnostics.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/diagnostics/diagnostics.py
\ No newline at end of file
diff --git a/modules/enabled/apps b/modules/enabled/apps
new file mode 120000
index 000000000..1e5ce6875
--- /dev/null
+++ b/modules/enabled/apps
@@ -0,0 +1 @@
+../installed/apps/
\ No newline at end of file
diff --git a/modules/enabled/config b/modules/enabled/config
new file mode 120000
index 000000000..95f5d5d11
--- /dev/null
+++ b/modules/enabled/config
@@ -0,0 +1 @@
+../installed/config/
\ No newline at end of file
diff --git a/modules/enabled/diagnostics b/modules/enabled/diagnostics
new file mode 120000
index 000000000..7575508ad
--- /dev/null
+++ b/modules/enabled/diagnostics
@@ -0,0 +1 @@
+../installed/diagnostics/
\ No newline at end of file
diff --git a/modules/enabled/expert_mode b/modules/enabled/expert_mode
new file mode 120000
index 000000000..899eb7ef1
--- /dev/null
+++ b/modules/enabled/expert_mode
@@ -0,0 +1 @@
+../installed/expert_mode/
\ No newline at end of file
diff --git a/modules/enabled/firewall b/modules/enabled/firewall
new file mode 120000
index 000000000..fa24d8415
--- /dev/null
+++ b/modules/enabled/firewall
@@ -0,0 +1 @@
+../installed/firewall/
\ No newline at end of file
diff --git a/modules/enabled/first_boot b/modules/enabled/first_boot
new file mode 120000
index 000000000..ffd4685cc
--- /dev/null
+++ b/modules/enabled/first_boot
@@ -0,0 +1 @@
+../installed/first_boot/
\ No newline at end of file
diff --git a/modules/enabled/help b/modules/enabled/help
new file mode 120000
index 000000000..7f4f221a6
--- /dev/null
+++ b/modules/enabled/help
@@ -0,0 +1 @@
+../installed/help/
\ No newline at end of file
diff --git a/modules/enabled/lib b/modules/enabled/lib
new file mode 120000
index 000000000..7cd28ddb5
--- /dev/null
+++ b/modules/enabled/lib
@@ -0,0 +1 @@
+../installed/lib/
\ No newline at end of file
diff --git a/modules/enabled/owncloud b/modules/enabled/owncloud
new file mode 120000
index 000000000..63da55329
--- /dev/null
+++ b/modules/enabled/owncloud
@@ -0,0 +1 @@
+../installed/owncloud/
\ No newline at end of file
diff --git a/modules/enabled/packages b/modules/enabled/packages
new file mode 120000
index 000000000..b6441c789
--- /dev/null
+++ b/modules/enabled/packages
@@ -0,0 +1 @@
+../installed/packages/
\ No newline at end of file
diff --git a/modules/enabled/pagekite b/modules/enabled/pagekite
new file mode 120000
index 000000000..e19e08de2
--- /dev/null
+++ b/modules/enabled/pagekite
@@ -0,0 +1 @@
+../installed/pagekite/
\ No newline at end of file
diff --git a/modules/enabled/system b/modules/enabled/system
new file mode 120000
index 000000000..e47f3142b
--- /dev/null
+++ b/modules/enabled/system
@@ -0,0 +1 @@
+../installed/system/
\ No newline at end of file
diff --git a/modules/enabled/tor b/modules/enabled/tor
new file mode 120000
index 000000000..62dc28af9
--- /dev/null
+++ b/modules/enabled/tor
@@ -0,0 +1 @@
+../installed/tor/
\ No newline at end of file
diff --git a/modules/enabled/users b/modules/enabled/users
new file mode 120000
index 000000000..8f8a47d96
--- /dev/null
+++ b/modules/enabled/users
@@ -0,0 +1 @@
+../installed/users/
\ No newline at end of file
diff --git a/modules/enabled/xmpp b/modules/enabled/xmpp
new file mode 120000
index 000000000..726e67c0e
--- /dev/null
+++ b/modules/enabled/xmpp
@@ -0,0 +1 @@
+../installed/xmpp/
\ No newline at end of file
diff --git a/modules/expert_mode.py b/modules/expert_mode.py
deleted file mode 120000
index 2dbc00d05..000000000
--- a/modules/expert_mode.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/expert_mode/expert_mode.py
\ No newline at end of file
diff --git a/modules/firewall.py b/modules/firewall.py
deleted file mode 120000
index 5bb891767..000000000
--- a/modules/firewall.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/firewall/firewall.py
\ No newline at end of file
diff --git a/modules/first_boot.py b/modules/first_boot.py
deleted file mode 120000
index 2003115bb..000000000
--- a/modules/first_boot.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/first_boot/first_boot.py
\ No newline at end of file
diff --git a/modules/help.py b/modules/help.py
deleted file mode 120000
index 3fc0799d2..000000000
--- a/modules/help.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/help/help.py
\ No newline at end of file
diff --git a/modules/installed/__init__.py b/modules/installed/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/modules/installed/apps/__init__.py b/modules/installed/apps/__init__.py
new file mode 100644
index 000000000..bf5f66418
--- /dev/null
+++ b/modules/installed/apps/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module for apps section page
+"""
+
+from . import apps
+
+
+__all__ = ['apps']
diff --git a/modules/installed/apps/apps.py b/modules/installed/apps/apps.py
index 521aa29c2..05bb7fad3 100644
--- a/modules/installed/apps/apps.py
+++ b/modules/installed/apps/apps.py
@@ -1,6 +1,5 @@
import cherrypy
from gettext import gettext as _
-from modules.auth import require
from plugin_mount import PagePlugin
import cfg
import util
diff --git a/modules/installed/config/__init__.py b/modules/installed/config/__init__.py
new file mode 100644
index 000000000..aface4101
--- /dev/null
+++ b/modules/installed/config/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module for basic system configuration
+"""
+
+from . import config
+
+
+__all__ = ['config']
diff --git a/modules/installed/config/config.py b/modules/installed/config/config.py
index 808681f2e..bda9dd2de 100644
--- a/modules/installed/config/config.py
+++ b/modules/installed/config/config.py
@@ -28,7 +28,7 @@ import socket
import actions
import cfg
-from modules.auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import util
diff --git a/modules/installed/diagnostics/__init__.py b/modules/installed/diagnostics/__init__.py
new file mode 100644
index 000000000..8c01bd990
--- /dev/null
+++ b/modules/installed/diagnostics/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to system diagnostics
+"""
+
+from . import diagnostics
+
+
+__all__ = ['diagnostics']
diff --git a/modules/installed/diagnostics/diagnostics.py b/modules/installed/diagnostics/diagnostics.py
index db05738a2..e82de7d11 100644
--- a/modules/installed/diagnostics/diagnostics.py
+++ b/modules/installed/diagnostics/diagnostics.py
@@ -21,7 +21,7 @@ Plinth module for running diagnostics
import cherrypy
from gettext import gettext as _
-from auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import actions
import cfg
diff --git a/modules/installed/expert_mode/__init__.py b/modules/installed/expert_mode/__init__.py
new file mode 100644
index 000000000..c638fd55e
--- /dev/null
+++ b/modules/installed/expert_mode/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module for expert mode configuration
+"""
+
+from . import expert_mode
+
+
+__all__ = ['expert_mode']
diff --git a/modules/installed/expert_mode/expert_mode.py b/modules/installed/expert_mode/expert_mode.py
index 19ee30f0d..50c2811e6 100644
--- a/modules/installed/expert_mode/expert_mode.py
+++ b/modules/installed/expert_mode/expert_mode.py
@@ -1,7 +1,7 @@
import cherrypy
from django import forms
from gettext import gettext as _
-from modules.auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import cfg
import util
diff --git a/modules/installed/firewall/__init__.py b/modules/installed/firewall/__init__.py
new file mode 100644
index 000000000..33eb5d302
--- /dev/null
+++ b/modules/installed/firewall/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to configure a firewall
+"""
+
+from . import firewall
+
+
+__all__ = ['firewall']
diff --git a/modules/installed/firewall/firewall.py b/modules/installed/firewall/firewall.py
index e736627f1..ebdbf67a7 100644
--- a/modules/installed/firewall/firewall.py
+++ b/modules/installed/firewall/firewall.py
@@ -24,7 +24,7 @@ from gettext import gettext as _
import actions
import cfg
-from modules.auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import service as service_module
import util
diff --git a/modules/installed/first_boot/__init__.py b/modules/installed/first_boot/__init__.py
new file mode 100644
index 000000000..20e972dae
--- /dev/null
+++ b/modules/installed/first_boot/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module for first boot wizard
+"""
+
+from . import first_boot
+
+
+__all__ = ['first_boot']
diff --git a/modules/installed/first_boot/first_boot.py b/modules/installed/first_boot/first_boot.py
index 7bd616ca3..7bcf98e27 100644
--- a/modules/installed/first_boot/first_boot.py
+++ b/modules/installed/first_boot/first_boot.py
@@ -23,10 +23,10 @@ from django import forms
from django.core import validators
from gettext import gettext as _
from plugin_mount import PagePlugin
-from modules.auth import add_user
+from ..lib.auth import add_user
+from ..config import config
from withsqlite.withsqlite import sqlite_db
import cfg
-import config
import util
diff --git a/modules/installed/help/__init__.py b/modules/installed/help/__init__.py
new file mode 100644
index 000000000..9ef609e2d
--- /dev/null
+++ b/modules/installed/help/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module for help pages
+"""
+
+from . import help # pylint: disable-msg=W0622
+
+
+__all__ = ['help']
diff --git a/modules/installed/lib/__init__.py b/modules/installed/lib/__init__.py
new file mode 100644
index 000000000..ab399cd3f
--- /dev/null
+++ b/modules/installed/lib/__init__.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 .
+#
+
+"""
+Plinth library modules
+"""
+
+from . import auth
+from . import auth_page
+from . import user_store
+
+
+__all__ = ['auth',
+ 'auth_page',
+ 'user_store']
diff --git a/modules/installed/owncloud/__init__.py b/modules/installed/owncloud/__init__.py
new file mode 100644
index 000000000..544b2ebc7
--- /dev/null
+++ b/modules/installed/owncloud/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to configure ownCloud
+"""
+
+from . import owncloud
+
+
+__all__ = ['owncloud']
diff --git a/modules/installed/owncloud/owncloud.py b/modules/installed/owncloud/owncloud.py
index 7ed4dfcdb..535ba019b 100644
--- a/modules/installed/owncloud/owncloud.py
+++ b/modules/installed/owncloud/owncloud.py
@@ -1,7 +1,7 @@
import cherrypy
from django import forms
from gettext import gettext as _
-from modules.auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import actions
import cfg
diff --git a/modules/installed/packages/__init__.py b/modules/installed/packages/__init__.py
new file mode 100644
index 000000000..f84ac44c1
--- /dev/null
+++ b/modules/installed/packages/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to manage packages
+"""
+
+from . import packages
+
+
+__all__ = ['packages']
diff --git a/modules/installed/packages/packages.py b/modules/installed/packages/packages.py
index 63df8cab0..89fe69676 100644
--- a/modules/installed/packages/packages.py
+++ b/modules/installed/packages/packages.py
@@ -1,7 +1,7 @@
import cherrypy
from django import forms
from gettext import gettext as _
-from auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import actions
import cfg
diff --git a/modules/installed/pagekite/__init__.py b/modules/installed/pagekite/__init__.py
new file mode 100644
index 000000000..fa247ab25
--- /dev/null
+++ b/modules/installed/pagekite/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to configure PageKite
+"""
+
+from . import pagekite
+
+
+__all__ = ['pagekite']
diff --git a/modules/installed/pagekite/pagekite.py b/modules/installed/pagekite/pagekite.py
index 5bb4726da..cc7791a2d 100644
--- a/modules/installed/pagekite/pagekite.py
+++ b/modules/installed/pagekite/pagekite.py
@@ -26,7 +26,7 @@ from gettext import gettext as _
import actions
import cfg
-from modules.auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import util
diff --git a/modules/installed/santiago/__init__.py b/modules/installed/santiago/__init__.py
new file mode 100644
index 000000000..abe7409d6
--- /dev/null
+++ b/modules/installed/santiago/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to configure santiago port
+"""
+
+from . import santiago
+
+
+__all__ = ['santiago']
diff --git a/modules/installed/system/__init__.py b/modules/installed/system/__init__.py
new file mode 100644
index 000000000..bd46fa10c
--- /dev/null
+++ b/modules/installed/system/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module for system section page
+"""
+
+from . import system
+
+
+__all__ = ['system']
diff --git a/modules/installed/tor/__init__.py b/modules/installed/tor/__init__.py
new file mode 100644
index 000000000..4b42293f9
--- /dev/null
+++ b/modules/installed/tor/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to configure Tor
+"""
+
+from . import tor
+
+
+__all__ = ['tor']
diff --git a/modules/installed/tor/tor.py b/modules/installed/tor/tor.py
index b09daf417..9e64240f8 100644
--- a/modules/installed/tor/tor.py
+++ b/modules/installed/tor/tor.py
@@ -22,7 +22,7 @@ Plinth module for configuring Tor
import cherrypy
from gettext import gettext as _
from plugin_mount import PagePlugin
-from modules.auth import require
+from ..lib.auth import require
import actions
import cfg
import util
diff --git a/modules/installed/users/__init__.py b/modules/installed/users/__init__.py
new file mode 100644
index 000000000..7cb056bb5
--- /dev/null
+++ b/modules/installed/users/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to manage users
+"""
+
+from . import users
+
+
+__all__ = ['users']
diff --git a/modules/installed/users/users.py b/modules/installed/users/users.py
index 1b7550405..5722271b7 100644
--- a/modules/installed/users/users.py
+++ b/modules/installed/users/users.py
@@ -2,8 +2,7 @@ import cherrypy
from django import forms
from django.core import validators
from gettext import gettext as _
-import auth
-from auth import require
+from ..lib.auth import require, add_user
from plugin_mount import PagePlugin
import cfg
from model import User
@@ -86,8 +85,8 @@ class UserAdd(PagePlugin):
username=data['username'])))
return
- auth.add_user(data['username'], data['password'], data['full_name'],
- data['email'], False)
+ add_user(data['username'], data['password'], data['full_name'],
+ data['email'], False)
messages.append(
('success', _('User "{username}" added').format(
username=data['username'])))
diff --git a/modules/installed/xmpp/__init__.py b/modules/installed/xmpp/__init__.py
new file mode 100644
index 000000000..a55e739c3
--- /dev/null
+++ b/modules/installed/xmpp/__init__.py
@@ -0,0 +1,25 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Plinth module to configure XMPP server
+"""
+
+from . import xmpp
+
+
+__all__ = ['xmpp']
diff --git a/modules/installed/xmpp/xmpp.py b/modules/installed/xmpp/xmpp.py
index 6a65b764c..ab80118c2 100644
--- a/modules/installed/xmpp/xmpp.py
+++ b/modules/installed/xmpp/xmpp.py
@@ -1,7 +1,7 @@
import cherrypy
from django import forms
from gettext import gettext as _
-from modules.auth import require
+from ..lib.auth import require
from plugin_mount import PagePlugin
import cfg
import actions
diff --git a/modules/owncloud.py b/modules/owncloud.py
deleted file mode 120000
index 0fbf23189..000000000
--- a/modules/owncloud.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/owncloud/owncloud.py
\ No newline at end of file
diff --git a/modules/packages.py b/modules/packages.py
deleted file mode 120000
index 8c473f1ac..000000000
--- a/modules/packages.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/packages/packages.py
\ No newline at end of file
diff --git a/modules/pagekite.py b/modules/pagekite.py
deleted file mode 120000
index d30c4701f..000000000
--- a/modules/pagekite.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/pagekite/pagekite.py
\ No newline at end of file
diff --git a/modules/system.py b/modules/system.py
deleted file mode 120000
index 6eddf3e2d..000000000
--- a/modules/system.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/system/system.py
\ No newline at end of file
diff --git a/modules/tor.py b/modules/tor.py
deleted file mode 120000
index 4c888a3a1..000000000
--- a/modules/tor.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/tor/tor.py
\ No newline at end of file
diff --git a/modules/user_store.py b/modules/user_store.py
deleted file mode 120000
index 09e8f90fe..000000000
--- a/modules/user_store.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/lib/user_store.py
\ No newline at end of file
diff --git a/modules/users.py b/modules/users.py
deleted file mode 120000
index f807cf4fc..000000000
--- a/modules/users.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/users/users.py
\ No newline at end of file
diff --git a/modules/xmpp.py b/modules/xmpp.py
deleted file mode 120000
index 4e0dfe42c..000000000
--- a/modules/xmpp.py
+++ /dev/null
@@ -1 +0,0 @@
-installed/xmpp/xmpp.py
\ No newline at end of file
diff --git a/plinth.py b/plinth.py
index 7a7eb94f6..ee3dd1571 100755
--- a/plinth.py
+++ b/plinth.py
@@ -4,8 +4,10 @@ import os, stat, sys, argparse
from gettext import gettext as _
import cfg
import django.conf
+import importlib
if not os.path.join(cfg.file_root, "vendor") in sys.path:
sys.path.append(os.path.join(cfg.file_root, "vendor"))
+import re
import cherrypy
from cherrypy import _cpserver
@@ -74,20 +76,21 @@ class Root(plugin_mount.PagePlugin):
else:
raise cherrypy.InternalRedirect('help/about')
+
def load_modules():
- """Import all the symlinked .py files in the modules directory and
- all the .py files in directories linked in the modules directory
- (but don't dive deeper than that). Also, ignore the installed
- directory."""
- for name in os.listdir("modules"):
- if name.endswith(".py") and not name.startswith('.'):
- cfg.log.info("importing modules/%s" % name)
- try:
- __import__("modules.%s" % (name[:-3]))
- except ImportError, e:
- cfg.log.error(_("Couldn't import modules/%s: %s") % (name, e))
- else:
- cfg.log("skipping %s" % name)
+ """
+ Read names of enabled modules in modules/enabled directory and
+ import them from modules/installed directory.
+ """
+ for name in os.listdir('modules/enabled'):
+ cfg.log.info('Importing modules/installed/%s' % name)
+ try:
+ importlib.import_module(
+ 'modules.installed.{module}'.format(module=name))
+ except ImportError as exception:
+ cfg.log.error(
+ 'Could not import modules/installed/{module}: {exception}'
+ .format(module=name, exception=exception))
def get_template_directories():
@@ -96,13 +99,9 @@ def get_template_directories():
core_directory = os.path.join(directory, 'templates')
directories = set((core_directory,))
- for name in os.listdir('modules'):
- if not name.endswith(".py") or name.startswith('.'):
- continue
-
- real_name = os.path.realpath(os.path.join('modules', name))
- directory = os.path.dirname(real_name)
- directories.add(os.path.join(directory, 'templates'))
+ for name in os.listdir('modules/enabled'):
+ directories.add(os.path.join('modules', 'installed', name,
+ 'templates'))
cfg.log.info('Template directories - %s' % directories)
diff --git a/plugin_mount.py b/plugin_mount.py
index e3ef5db41..38ac1e313 100644
--- a/plugin_mount.py
+++ b/plugin_mount.py
@@ -1,7 +1,4 @@
-import cherrypy
-from modules.auth import require
import cfg
-import util
class PluginMount(type):