mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-27 10:44:33 +00:00
Use Django models to store variables
- Remove dependency on withsqlite and use Django models. This avoids depending on a module that is not available in PyPi. Withsqlite does not have Python3 support. It does not work when we choose a different database backend. Atleast partly duplicates what Django models are meant for. - Check and update database schema on every run so that newly added modules can add tables and old ones can update.
This commit is contained in:
parent
2bbaa11c96
commit
42d05bfe1f
@ -13,7 +13,7 @@ actions_dir = /usr/share/plinth/actions
|
|||||||
doc_dir = /usr/share/doc/plinth
|
doc_dir = /usr/share/doc/plinth
|
||||||
|
|
||||||
# file locations
|
# file locations
|
||||||
store_file = %(data_dir)s/store.sqlite3
|
store_file = %(data_dir)s/plinth.sqlite3
|
||||||
status_log_file = %(log_dir)s/status.log
|
status_log_file = %(log_dir)s/status.log
|
||||||
access_log_file = %(log_dir)s/access.log
|
access_log_file = %(log_dir)s/access.log
|
||||||
pidfile = %(pid_dir)s/plinth.pid
|
pidfile = %(pid_dir)s/plinth.pid
|
||||||
|
|||||||
@ -13,7 +13,7 @@ actions_dir = %(file_root)s/actions
|
|||||||
doc_dir = %(file_root)s/doc
|
doc_dir = %(file_root)s/doc
|
||||||
|
|
||||||
# file locations
|
# file locations
|
||||||
store_file = %(data_dir)s/store.sqlite3
|
store_file = %(data_dir)s/plinth.sqlite3
|
||||||
status_log_file = %(log_dir)s/status.log
|
status_log_file = %(log_dir)s/status.log
|
||||||
access_log_file = %(log_dir)s/access.log
|
access_log_file = %(log_dir)s/access.log
|
||||||
pidfile = %(pid_dir)s/plinth.pid
|
pidfile = %(pid_dir)s/plinth.pid
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import django.conf
|
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()
|
template_directories = module_loader.get_template_directories()
|
||||||
sessions_directory = os.path.join(cfg.data_dir, 'sessions')
|
sessions_directory = os.path.join(cfg.data_dir, 'sessions')
|
||||||
django.conf.settings.configure(
|
django.conf.settings.configure(
|
||||||
@ -170,12 +168,13 @@ def configure_django():
|
|||||||
{'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}},
|
{'BACKEND': 'django.core.cache.backends.dummy.DummyCache'}},
|
||||||
DATABASES={'default':
|
DATABASES={'default':
|
||||||
{'ENGINE': 'django.db.backends.sqlite3',
|
{'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': data_file}},
|
'NAME': cfg.store_file}},
|
||||||
DEBUG=cfg.debug,
|
DEBUG=cfg.debug,
|
||||||
INSTALLED_APPS=['bootstrapform',
|
INSTALLED_APPS=['bootstrapform',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.messages'],
|
'django.contrib.messages',
|
||||||
|
'plinth'],
|
||||||
LOGGING=logging_configuration,
|
LOGGING=logging_configuration,
|
||||||
LOGIN_URL='lib:login',
|
LOGIN_URL='lib:login',
|
||||||
LOGIN_REDIRECT_URL='apps:index',
|
LOGIN_REDIRECT_URL='apps:index',
|
||||||
@ -199,10 +198,9 @@ def configure_django():
|
|||||||
LOGGER.info('Configured Django')
|
LOGGER.info('Configured Django')
|
||||||
LOGGER.info('Template directories - %s', template_directories)
|
LOGGER.info('Template directories - %s', template_directories)
|
||||||
|
|
||||||
if not os.path.isfile(data_file):
|
LOGGER.info('Creating or adding new tables to data file')
|
||||||
LOGGER.info('Creating and initializing data file')
|
django.core.management.call_command('syncdb', interactive=False)
|
||||||
django.core.management.call_command('syncdb', interactive=False)
|
os.chmod(cfg.store_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
|
||||||
os.chmod(data_file, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@ -70,7 +70,3 @@ def read():
|
|||||||
|
|
||||||
global port # pylint: disable-msg=W0603
|
global port # pylint: disable-msg=W0603
|
||||||
port = int(port)
|
port = int(port)
|
||||||
|
|
||||||
global store_file # pylint: disable-msg=W0603
|
|
||||||
if store_file.endswith(".sqlite3"):
|
|
||||||
store_file = os.path.splitext(store_file)[0]
|
|
||||||
|
|||||||
42
plinth/kvstore.py
Normal file
42
plinth/kvstore.py
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
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()
|
||||||
39
plinth/models.py
Normal file
39
plinth/models.py
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
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)
|
||||||
@ -26,10 +26,9 @@ from django.http.response import HttpResponseRedirect
|
|||||||
from django.template.response import TemplateResponse
|
from django.template.response import TemplateResponse
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
|
|
||||||
from plinth import cfg
|
|
||||||
from plinth.modules.config import config
|
from plinth.modules.config import config
|
||||||
from plinth.modules.lib.auth import add_user
|
from plinth.modules.lib.auth import add_user
|
||||||
from withsqlite.withsqlite import sqlite_db
|
from plinth import kvstore
|
||||||
|
|
||||||
|
|
||||||
## TODO: flesh out these tests values
|
## TODO: flesh out these tests values
|
||||||
@ -94,7 +93,7 @@ def state0(request):
|
|||||||
user. It's a good place to put error messages.
|
user. It's a good place to put error messages.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if _read_state() >= 5:
|
if kvstore.get_default('firstboot_state', 0) >= 5:
|
||||||
return HttpResponseRedirect(reverse('index'))
|
return HttpResponseRedirect(reverse('index'))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
@ -112,7 +111,7 @@ def state0(request):
|
|||||||
|
|
||||||
if success:
|
if success:
|
||||||
# Everything is good, permanently mark and move to page 2
|
# Everything is good, permanently mark and move to page 2
|
||||||
_write_state(1)
|
kvstore.set('firstboot_state', 1)
|
||||||
return HttpResponseRedirect(reverse('first_boot:state1'))
|
return HttpResponseRedirect(reverse('first_boot:state1'))
|
||||||
else:
|
else:
|
||||||
form = State0Form(initial=status, prefix='firstboot')
|
form = State0Form(initial=status, prefix='firstboot')
|
||||||
@ -124,35 +123,29 @@ def state0(request):
|
|||||||
|
|
||||||
def get_state0():
|
def get_state0():
|
||||||
"""Return the state for form state 0"""
|
"""Return the state for form state 0"""
|
||||||
with sqlite_db(cfg.store_file, table="thisbox", autocommit=True) as \
|
return {'hostname': config.get_hostname(),
|
||||||
database:
|
'box_key': kvstore.get_default('box_key', None)}
|
||||||
return {'hostname': config.get_hostname(),
|
|
||||||
'box_key': database.get('box_key', None)}
|
|
||||||
|
|
||||||
|
|
||||||
def _apply_state0(request, old_state, new_state):
|
def _apply_state0(request, old_state, new_state):
|
||||||
"""Apply changes in state 0 form"""
|
"""Apply changes in state 0 form"""
|
||||||
success = True
|
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']:
|
if new_state['box_key']:
|
||||||
database['box_key'] = new_state['box_key']
|
kvstore.set('box_key', new_state['box_key'])
|
||||||
elif not old_state['box_key']:
|
elif not old_state['box_key']:
|
||||||
database['box_key'] = generate_box_key()
|
kvstore.set('box_key', generate_box_key())
|
||||||
|
|
||||||
if old_state['hostname'] != new_state['hostname']:
|
if old_state['hostname'] != new_state['hostname']:
|
||||||
config.set_hostname(new_state['hostname'])
|
config.set_hostname(new_state['hostname'])
|
||||||
|
|
||||||
error = add_user(new_state['username'], new_state['password'],
|
error = add_user(new_state['username'], new_state['password'],
|
||||||
'First user, please change', '', True)
|
'First user, please change', '', True)
|
||||||
if error:
|
if error:
|
||||||
messages.error(
|
messages.error(request, _('User account creation failed: %s') % error)
|
||||||
request, _('User account creation failed: %s') % error)
|
success = False
|
||||||
success = False
|
else:
|
||||||
else:
|
messages.success(request, _('User account created'))
|
||||||
messages.success(request, _('User account created'))
|
|
||||||
|
|
||||||
return success
|
return success
|
||||||
|
|
||||||
@ -168,21 +161,7 @@ def state1(request):
|
|||||||
"""
|
"""
|
||||||
# TODO complete first_boot handling
|
# TODO complete first_boot handling
|
||||||
# Make sure the user is not stuck on a dead end for now.
|
# 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',
|
return TemplateResponse(request, 'firstboot_state1.html',
|
||||||
{'title': _('Installing the Certificate')})
|
{'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
|
|
||||||
|
|||||||
@ -24,8 +24,7 @@ from django.core.urlresolvers import reverse
|
|||||||
from django.http.response import HttpResponseRedirect
|
from django.http.response import HttpResponseRedirect
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from plinth import cfg
|
from plinth import kvstore
|
||||||
from withsqlite.withsqlite import sqlite_db
|
|
||||||
|
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
@ -42,14 +41,13 @@ class FirstBootMiddleware(object):
|
|||||||
if request.path.startswith(reverse('first_boot:index')):
|
if request.path.startswith(reverse('first_boot:index')):
|
||||||
return
|
return
|
||||||
|
|
||||||
with sqlite_db(cfg.store_file, table='firstboot') as database:
|
state = kvstore.get_default('firstboot_state', 0)
|
||||||
if 'state' not in database:
|
if not state:
|
||||||
# Permanent redirect causes the browser to cache the redirect,
|
# Permanent redirect causes the browser to cache the redirect,
|
||||||
# preventing the user from navigating to /plinth until the
|
# preventing the user from navigating to /plinth until the
|
||||||
# browser is restarted.
|
# browser is restarted.
|
||||||
return HttpResponseRedirect(reverse('first_boot:index'))
|
return HttpResponseRedirect(reverse('first_boot:index'))
|
||||||
|
|
||||||
if database['state'] < 5:
|
if state < 5:
|
||||||
LOGGER.info('First boot state - %d', database['state'])
|
LOGGER.info('First boot state - %d', state)
|
||||||
return HttpResponseRedirect(reverse('first_boot:state%d' %
|
return HttpResponseRedirect(reverse('first_boot:state%d' % state))
|
||||||
database['state']))
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user