mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-04-15 09:51:21 +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
|
||||
|
||||
# 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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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():
|
||||
|
||||
@ -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]
|
||||
|
||||
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 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
|
||||
|
||||
@ -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))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user