diff --git a/data/etc/plinth/plinth.config b/data/etc/plinth/plinth.config
index cf89d43c9..297f22730 100644
--- a/data/etc/plinth/plinth.config
+++ b/data/etc/plinth/plinth.config
@@ -13,7 +13,7 @@ actions_dir = /usr/share/plinth/actions
doc_dir = /usr/share/doc/plinth
# file locations
-store_file = %(data_dir)s/store.sqlite3
+store_file = %(data_dir)s/plinth.sqlite3
status_log_file = %(log_dir)s/status.log
access_log_file = %(log_dir)s/access.log
pidfile = %(pid_dir)s/plinth.pid
diff --git a/plinth.config b/plinth.config
index 8aeb93ba6..76979e838 100644
--- a/plinth.config
+++ b/plinth.config
@@ -13,7 +13,7 @@ actions_dir = %(file_root)s/actions
doc_dir = %(file_root)s/doc
# file locations
-store_file = %(data_dir)s/store.sqlite3
+store_file = %(data_dir)s/plinth.sqlite3
status_log_file = %(log_dir)s/status.log
access_log_file = %(log_dir)s/access.log
pidfile = %(pid_dir)s/plinth.pid
diff --git a/plinth/__main__.py b/plinth/__main__.py
index dcfc6cf0d..0afabe998 100644
--- a/plinth/__main__.py
+++ b/plinth/__main__.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
import argparse
import django.conf
@@ -160,8 +160,6 @@ def configure_django():
}
}
- data_file = os.path.join(cfg.data_dir, 'plinth.sqlite3')
-
template_directories = module_loader.get_template_directories()
sessions_directory = os.path.join(cfg.data_dir, 'sessions')
django.conf.settings.configure(
@@ -170,12 +168,13 @@ def configure_django():
{'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}},
DATABASES={'default':
{'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': data_file}},
+ 'NAME': cfg.store_file}},
DEBUG=cfg.debug,
INSTALLED_APPS=['bootstrapform',
'django.contrib.auth',
'django.contrib.contenttypes',
- 'django.contrib.messages'],
+ 'django.contrib.messages',
+ 'plinth'],
LOGGING=logging_configuration,
LOGIN_URL='lib:login',
LOGIN_REDIRECT_URL='apps:index',
@@ -199,10 +198,9 @@ def configure_django():
LOGGER.info('Configured Django')
LOGGER.info('Template directories - %s', template_directories)
- if not os.path.isfile(data_file):
- LOGGER.info('Creating and initializing data file')
- django.core.management.call_command('syncdb', interactive=False)
- os.chmod(data_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
+ LOGGER.info('Creating or adding new tables to data file')
+ django.core.management.call_command('syncdb', interactive=False)
+ os.chmod(cfg.store_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
def main():
diff --git a/plinth/cfg.py b/plinth/cfg.py
index 12a620fae..c816f52ac 100644
--- a/plinth/cfg.py
+++ b/plinth/cfg.py
@@ -70,7 +70,3 @@ def read():
global port # pylint: disable-msg=W0603
port = int(port)
-
- global store_file # pylint: disable-msg=W0603
- if store_file.endswith(".sqlite3"):
- store_file = os.path.splitext(store_file)[0]
diff --git a/plinth/kvstore.py b/plinth/kvstore.py
new file mode 100644
index 000000000..864b288ce
--- /dev/null
+++ b/plinth/kvstore.py
@@ -0,0 +1,42 @@
+#
+# This file is part of Plinth.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+
+"""
+Simple key/value store using Django models
+"""
+
+from plinth.models import KVStore
+
+
+def get(key):
+ """Return the value of a key"""
+ # pylint: disable-msg=E1101
+ return KVStore.objects.get(pk=key).value
+
+
+def get_default(key, default_value):
+ """Return the value of the key if key exists else return default_value"""
+ try:
+ return get(key)
+ except Exception:
+ return default_value
+
+
+def set(key, value): # pylint: disable-msg=W0622
+ """Store the value of a key"""
+ store = KVStore(key=key, value=value)
+ store.save()
diff --git a/plinth/models.py b/plinth/models.py
new file mode 100644
index 000000000..8dc1cfd03
--- /dev/null
+++ b/plinth/models.py
@@ -0,0 +1,39 @@
+#
+# 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 models for the main application
+"""
+
+from django.db import models
+import json
+
+
+class KVStore(models.Model):
+ """Model to store retrieve key/value configuration"""
+ key = models.TextField(primary_key=True)
+ value_json = models.TextField()
+
+ @property
+ def value(self):
+ """Return the JSON decoded value of the key/value pair"""
+ return json.loads(self.value_json)
+
+ @value.setter
+ def value(self, val):
+ """Store the value of the key/value pair by JSON encoding it"""
+ self.value_json = json.dumps(val)
diff --git a/plinth/modules/first_boot/first_boot.py b/plinth/modules/first_boot/first_boot.py
index 748e7ff4b..d997e71a9 100644
--- a/plinth/modules/first_boot/first_boot.py
+++ b/plinth/modules/first_boot/first_boot.py
@@ -26,10 +26,9 @@ from django.http.response import HttpResponseRedirect
from django.template.response import TemplateResponse
from gettext import gettext as _
-from plinth import cfg
from plinth.modules.config import config
from plinth.modules.lib.auth import add_user
-from withsqlite.withsqlite import sqlite_db
+from plinth import kvstore
## TODO: flesh out these tests values
@@ -94,7 +93,7 @@ def state0(request):
user. It's a good place to put error messages.
"""
try:
- if _read_state() >= 5:
+ if kvstore.get_default('firstboot_state', 0) >= 5:
return HttpResponseRedirect(reverse('index'))
except KeyError:
pass
@@ -112,7 +111,7 @@ def state0(request):
if success:
# Everything is good, permanently mark and move to page 2
- _write_state(1)
+ kvstore.set('firstboot_state', 1)
return HttpResponseRedirect(reverse('first_boot:state1'))
else:
form = State0Form(initial=status, prefix='firstboot')
@@ -124,35 +123,29 @@ def state0(request):
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)}
+ return {'hostname': config.get_hostname(),
+ 'box_key': kvstore.get_default('box_key', None)}
def _apply_state0(request, old_state, new_state):
"""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 new_state['box_key']:
+ kvstore.set('box_key', new_state['box_key'])
+ elif not old_state['box_key']:
+ kvstore.set('box_key', generate_box_key())
- if old_state['hostname'] != new_state['hostname']:
- config.set_hostname(new_state['hostname'])
+ 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.error(
- request, _('User account creation failed: %s') % error)
- success = False
- else:
- messages.success(request, _('User account created'))
+ error = add_user(new_state['username'], new_state['password'],
+ 'First user, please change', '', True)
+ if error:
+ messages.error(request, _('User account creation failed: %s') % error)
+ success = False
+ else:
+ messages.success(request, _('User account created'))
return success
@@ -168,21 +161,7 @@ def state1(request):
"""
# TODO complete first_boot handling
# Make sure the user is not stuck on a dead end for now.
- _write_state(5)
+ kvstore.set('firstboot_state', 5)
return TemplateResponse(request, 'firstboot_state1.html',
{'title': _('Installing the Certificate')})
-
-
-def _read_state():
- """Read the current state from database"""
- with sqlite_db(cfg.store_file, table='firstboot',
- autocommit=True) as database:
- return database['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/plinth/modules/first_boot/middleware.py b/plinth/modules/first_boot/middleware.py
index ee7d7f5db..061230907 100644
--- a/plinth/modules/first_boot/middleware.py
+++ b/plinth/modules/first_boot/middleware.py
@@ -24,8 +24,7 @@ from django.core.urlresolvers import reverse
from django.http.response import HttpResponseRedirect
import logging
-from plinth import cfg
-from withsqlite.withsqlite import sqlite_db
+from plinth import kvstore
LOGGER = logging.getLogger(__name__)
@@ -42,14 +41,13 @@ class FirstBootMiddleware(object):
if request.path.startswith(reverse('first_boot:index')):
return
- with sqlite_db(cfg.store_file, table='firstboot') as database:
- if 'state' not in database:
- # Permanent redirect causes the browser to cache the redirect,
- # preventing the user from navigating to /plinth until the
- # browser is restarted.
- return HttpResponseRedirect(reverse('first_boot:index'))
+ state = kvstore.get_default('firstboot_state', 0)
+ if not state:
+ # Permanent redirect causes the browser to cache the redirect,
+ # preventing the user from navigating to /plinth until the
+ # browser is restarted.
+ return HttpResponseRedirect(reverse('first_boot:index'))
- if database['state'] < 5:
- LOGGER.info('First boot state - %d', database['state'])
- return HttpResponseRedirect(reverse('first_boot:state%d' %
- database['state']))
+ if state < 5:
+ LOGGER.info('First boot state - %d', state)
+ return HttpResponseRedirect(reverse('first_boot:state%d' % state))