Clean up main.py and move code to __main__.py and utils/main.py.
This commit is contained in:
parent
563f40a889
commit
c63b7f995f
2
fabfile.py
vendored
2
fabfile.py
vendored
@ -23,7 +23,7 @@ def test(module='tests'):
|
|||||||
environment variable DJANGO_SETTINGS_MODULE is set to 'tests.settings'.
|
environment variable DJANGO_SETTINGS_MODULE is set to 'tests.settings'.
|
||||||
"""
|
"""
|
||||||
django.settings_module('tests.settings')
|
django.settings_module('tests.settings')
|
||||||
local('coverage run ./manage.py test %s' % module)
|
local('coverage run ./manage.py django test %s' % module)
|
||||||
|
|
||||||
|
|
||||||
def coverage_report_plain():
|
def coverage_report_plain():
|
||||||
|
19
manage.py
19
manage.py
@ -1,18 +1,19 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Django's execute manager.
|
Manage script for OpenSlides.
|
||||||
|
|
||||||
:copyright: 2011, 2012 by OpenSlides team, see AUTHORS.
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os, sys
|
import sys
|
||||||
from django.core.management import execute_from_command_line
|
|
||||||
from openslides.main import get_user_config_path, setup_django_environment
|
|
||||||
|
from openslides.__main__ import main
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if 'DJANGO_SETTINGS_MODULE' not in os.environ:
|
if len(sys.argv) == 1:
|
||||||
setup_django_environment(
|
sys.argv.append('--help')
|
||||||
get_user_config_path('openslides', 'settings.py'))
|
exit(main())
|
||||||
execute_from_command_line(sys.argv)
|
|
||||||
|
530
openslides/__main__.py
Normal file
530
openslides/__main__.py
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
openslides.__main__
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Main script for OpenSlides
|
||||||
|
|
||||||
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import base64
|
||||||
|
import imp
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import socket
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
|
from django.conf import ENVIRONMENT_VARIABLE
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
from openslides import get_version
|
||||||
|
from openslides.utils.tornado_webserver import run_tornado
|
||||||
|
from openslides.utils.main import (
|
||||||
|
filesystem2unicode,
|
||||||
|
detect_openslides_type,
|
||||||
|
get_win32_app_data_path,
|
||||||
|
get_win32_portable_path,
|
||||||
|
UNIX_VERSION,
|
||||||
|
WINDOWS_VERSION,
|
||||||
|
WINDOWS_PORTABLE_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
SETTINGS_TEMPLATE = """# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Settings file for OpenSlides
|
||||||
|
#
|
||||||
|
|
||||||
|
%(import_function)s
|
||||||
|
from openslides.global_settings import *
|
||||||
|
|
||||||
|
# Use 'DEBUG = True' to get more details for server errors. Default for releases: False
|
||||||
|
DEBUG = False
|
||||||
|
TEMPLATE_DEBUG = DEBUG
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': %(database_path_value)s,
|
||||||
|
'USER': '',
|
||||||
|
'PASSWORD': '',
|
||||||
|
'HOST': '',
|
||||||
|
'PORT': '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set timezone
|
||||||
|
TIME_ZONE = 'Europe/Berlin'
|
||||||
|
|
||||||
|
# Make this unique, and don't share it with anybody.
|
||||||
|
SECRET_KEY = %(secret_key)r
|
||||||
|
|
||||||
|
# Add OpenSlides plugins to this list (see example entry in comment)
|
||||||
|
INSTALLED_PLUGINS = (
|
||||||
|
# 'pluginname',
|
||||||
|
)
|
||||||
|
|
||||||
|
INSTALLED_APPS += INSTALLED_PLUGINS
|
||||||
|
|
||||||
|
# Absolute path to the directory that holds media.
|
||||||
|
# Example: "/home/media/media.lawrence.com/"
|
||||||
|
MEDIA_ROOT = %(media_path_value)s
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Main entrance to OpenSlides.
|
||||||
|
"""
|
||||||
|
# Parse all command line args.
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
# Setup settings path: Take it either from command line or get default path
|
||||||
|
if not hasattr(args, 'settings') or not args.settings:
|
||||||
|
openslides_type = detect_openslides_type()
|
||||||
|
args.settings = get_default_settings_path(openslides_type)
|
||||||
|
|
||||||
|
# Create settings if if still does not exist.
|
||||||
|
if not os.path.exists(args.settings):
|
||||||
|
# Setup path for local data (SQLite3 database, media, search index, ...):
|
||||||
|
# Take it either from command line or get default path
|
||||||
|
if not hasattr(args, 'localpath') or not args.localpath:
|
||||||
|
openslides_type = detect_openslides_type()
|
||||||
|
args.localpath = get_default_local_path(openslides_type)
|
||||||
|
localpath_values = get_localpath_values(localpath=args.localpath, default=True, openslides_type=openslides_type)
|
||||||
|
else:
|
||||||
|
localpath_values = get_localpath_values(localpath=args.localpath, default=False)
|
||||||
|
create_settings(args.settings, localpath_values)
|
||||||
|
|
||||||
|
# Setup DJANGO_SETTINGS_MODULE environment variable
|
||||||
|
if 'DJANGO_SETTINGS_MODULE' not in os.environ:
|
||||||
|
setup_django_settings_module(args.settings)
|
||||||
|
|
||||||
|
# Process the subcommand's callback
|
||||||
|
return args.callback(args)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
"""
|
||||||
|
Parses all command line arguments. The subcommand 'django' links to
|
||||||
|
Django's command-line utility.
|
||||||
|
"""
|
||||||
|
if len(sys.argv) == 1:
|
||||||
|
sys.argv.append('start')
|
||||||
|
|
||||||
|
description = 'Start script for OpenSlides.'
|
||||||
|
if 'manage.py' not in sys.argv[0]:
|
||||||
|
description += (' If it is called without any argument, this will be '
|
||||||
|
'treated as if it is called with the "start" subcommand. '
|
||||||
|
'That means OpenSlides will setup settings and database, '
|
||||||
|
'start the tornado webserver, launch the default web '
|
||||||
|
'browser and open the webinterface.')
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=description)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--version',
|
||||||
|
action='version',
|
||||||
|
version=get_version(),
|
||||||
|
help='Show version number and exit.')
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(
|
||||||
|
dest='subcommand',
|
||||||
|
title='Available subcommands',
|
||||||
|
description="Type 'python %s <subcommand> --help' for help on a specific subcommand." % parser.prog,
|
||||||
|
help='You can choose only one subcommand at once.')
|
||||||
|
|
||||||
|
settings_args, settings_kwargs = (
|
||||||
|
('-s', '--settings'),
|
||||||
|
dict(help='Path to settings file.'))
|
||||||
|
localpath_args, localpath_kwargs = (
|
||||||
|
('-l', '--localpath'),
|
||||||
|
dict(help='Path to the directory for local files like SQLite3 database, '
|
||||||
|
'uploaded media and search index. This is only used, when a new '
|
||||||
|
'settings file is created.'))
|
||||||
|
address_args, address_kwargs = (
|
||||||
|
('-a', '--address',),
|
||||||
|
dict(default='0.0.0.0', help='IP address to listen on. Default is %(default)s.'))
|
||||||
|
port_args, port_kwargs = (
|
||||||
|
('-p', '--port'),
|
||||||
|
dict(type=int, default=80, help='Port to listen on. Default as admin or root is %(default)d, else 8000.'))
|
||||||
|
|
||||||
|
# Subcommand start
|
||||||
|
subcommand_start = subparsers.add_parser(
|
||||||
|
'start',
|
||||||
|
help='Setup settings and database, start tornado webserver, launch the '
|
||||||
|
'default web browser and open the webinterface.')
|
||||||
|
subcommand_start.add_argument(*settings_args, **settings_kwargs)
|
||||||
|
subcommand_start.add_argument(*localpath_args, **localpath_kwargs)
|
||||||
|
subcommand_start.add_argument(*address_args, **address_kwargs)
|
||||||
|
subcommand_start.add_argument(*port_args, **port_kwargs)
|
||||||
|
subcommand_start.set_defaults(callback=start)
|
||||||
|
|
||||||
|
# Subcommand runserver
|
||||||
|
subcommand_runserver = subparsers.add_parser(
|
||||||
|
'runserver',
|
||||||
|
help='Run OpenSlides using tornado webserver.')
|
||||||
|
subcommand_runserver.add_argument(*settings_args, **settings_kwargs)
|
||||||
|
subcommand_runserver.add_argument(*localpath_args, **localpath_kwargs)
|
||||||
|
subcommand_runserver.add_argument(*address_args, **address_kwargs)
|
||||||
|
subcommand_runserver.add_argument(*port_args, **port_kwargs)
|
||||||
|
subcommand_runserver.add_argument(
|
||||||
|
'--start-browser',
|
||||||
|
action='store_true',
|
||||||
|
help='Launch the default web browser and open the webinterface.')
|
||||||
|
subcommand_runserver.add_argument(
|
||||||
|
'--no-reload',
|
||||||
|
action='store_true',
|
||||||
|
help='Do not reload the webserver if source code changes.')
|
||||||
|
subcommand_runserver.set_defaults(callback=runserver)
|
||||||
|
|
||||||
|
# Subcommand syncdb
|
||||||
|
subcommand_syncdb = subparsers.add_parser(
|
||||||
|
'syncdb',
|
||||||
|
help='Create or update database tables.')
|
||||||
|
subcommand_syncdb.add_argument(*settings_args, **settings_kwargs)
|
||||||
|
subcommand_syncdb.add_argument(*localpath_args, **localpath_kwargs)
|
||||||
|
subcommand_syncdb.set_defaults(callback=syncdb)
|
||||||
|
|
||||||
|
# Subcommand createsuperuser
|
||||||
|
subcommand_createsuperuser = subparsers.add_parser(
|
||||||
|
'createsuperuser',
|
||||||
|
help="Make sure the user 'admin' exists and uses 'admin' as password.")
|
||||||
|
subcommand_createsuperuser.add_argument(*settings_args, **settings_kwargs)
|
||||||
|
subcommand_createsuperuser.add_argument(*localpath_args, **localpath_kwargs)
|
||||||
|
subcommand_createsuperuser.set_defaults(callback=createsuperuser)
|
||||||
|
|
||||||
|
# Subcommand backupdb
|
||||||
|
subcommand_backupdb = subparsers.add_parser(
|
||||||
|
'backupdb',
|
||||||
|
help='Store a backup copy of the SQLite3 database.')
|
||||||
|
subcommand_backupdb.add_argument(*settings_args, **settings_kwargs)
|
||||||
|
subcommand_backupdb.add_argument(*localpath_args, **localpath_kwargs)
|
||||||
|
subcommand_backupdb.add_argument(
|
||||||
|
'path',
|
||||||
|
help='Path to the backup file. An existing file will be overwritten.')
|
||||||
|
subcommand_backupdb.set_defaults(callback=backupdb)
|
||||||
|
|
||||||
|
# Subcommand deletedb
|
||||||
|
subcommand_deletedb = subparsers.add_parser(
|
||||||
|
'deletedb',
|
||||||
|
help='Delete the SQLite3 database.')
|
||||||
|
subcommand_deletedb.add_argument(*settings_args, **settings_kwargs)
|
||||||
|
subcommand_deletedb.add_argument(*localpath_args, **localpath_kwargs)
|
||||||
|
subcommand_deletedb.set_defaults(callback=deletedb)
|
||||||
|
|
||||||
|
# Subcommand django
|
||||||
|
subcommand_django_command_line_utility = subparsers.add_parser(
|
||||||
|
'django',
|
||||||
|
description="Link to Django's command-line utility. Type 'python %s django help' for more help on this." % parser.prog,
|
||||||
|
help="Call Django's command-line utility.")
|
||||||
|
subcommand_django_command_line_utility.set_defaults(
|
||||||
|
callback=django_command_line_utility,
|
||||||
|
django_args=['%s' % subcommand_django_command_line_utility.prog])
|
||||||
|
|
||||||
|
known_args, unknown_args = parser.parse_known_args()
|
||||||
|
|
||||||
|
if known_args.subcommand == 'django':
|
||||||
|
if not unknown_args:
|
||||||
|
unknown_args.append('help')
|
||||||
|
known_args.django_args.extend(unknown_args)
|
||||||
|
else:
|
||||||
|
if unknown_args:
|
||||||
|
parser.error('Unknown arguments %s found.' % ' '.join(unknown_args))
|
||||||
|
|
||||||
|
return known_args
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_settings_path(openslides_type):
|
||||||
|
"""
|
||||||
|
Returns the default settings path according to the OpenSlides type.
|
||||||
|
|
||||||
|
The argument 'openslides_type' has to be one of the three types mentioned in
|
||||||
|
openslides.utils.main.
|
||||||
|
"""
|
||||||
|
if openslides_type == UNIX_VERSION:
|
||||||
|
parent_directory = filesystem2unicode(os.environ.get(
|
||||||
|
'XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config')))
|
||||||
|
elif openslides_type == WINDOWS_VERSION:
|
||||||
|
parent_directory = get_win32_app_data_path()
|
||||||
|
elif openslides_type == WINDOWS_PORTABLE_VERSION:
|
||||||
|
parent_directory = get_win32_portable_path()
|
||||||
|
else:
|
||||||
|
raise TypeError('%s is not a valid OpenSlides type.' % openslides_type)
|
||||||
|
return os.path.join(parent_directory, 'openslides', 'settings.py')
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_local_path(openslides_type):
|
||||||
|
"""
|
||||||
|
Returns the default local path according to the OpenSlides type.
|
||||||
|
|
||||||
|
The argument 'openslides_type' has to be one of the three types mentioned in
|
||||||
|
openslides.utils.main.
|
||||||
|
"""
|
||||||
|
if openslides_type == UNIX_VERSION:
|
||||||
|
default_local_path = filesystem2unicode(os.environ.get(
|
||||||
|
'XDG_DATA_HOME', os.path.join(os.path.expanduser('~'), '.local', 'share')))
|
||||||
|
elif openslides_type == WINDOWS_VERSION:
|
||||||
|
default_local_path = get_win32_app_data_path()
|
||||||
|
elif openslides_type == WINDOWS_PORTABLE_VERSION:
|
||||||
|
default_local_path = get_win32_portable_path()
|
||||||
|
else:
|
||||||
|
raise TypeError('%s is not a valid OpenSlides type.' % openslides_type)
|
||||||
|
return default_local_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_localpath_values(localpath, default=False, openslides_type=None):
|
||||||
|
"""
|
||||||
|
Returns the local path values for the new settings file.
|
||||||
|
|
||||||
|
The argument 'localpath' is a path to the directory where OpenSlides should
|
||||||
|
store the local data like SQLite3 database, media and search index.
|
||||||
|
|
||||||
|
The argument 'default' is a simple flag. If it is True and the OpenSlides
|
||||||
|
type is the Windows portable version, this function returns callable
|
||||||
|
functions for the settings file, else it returns string paths.
|
||||||
|
|
||||||
|
The argument 'openslides_type' can to be one of the three types mentioned in
|
||||||
|
openslides.utils.main.
|
||||||
|
"""
|
||||||
|
localpath_values = {}
|
||||||
|
if default and openslides_type == WINDOWS_PORTABLE_VERSION:
|
||||||
|
localpath_values['import_function'] = 'from openslides.utils.main import get_portable_paths'
|
||||||
|
localpath_values['database_path_value'] = "get_portable_paths('database')"
|
||||||
|
localpath_values['media_path_value'] = "get_portable_paths('media')"
|
||||||
|
else:
|
||||||
|
localpath_values['import_function'] = ''
|
||||||
|
# TODO: Decide whether to use only absolute paths here.
|
||||||
|
localpath_values['database_path_value'] = "'%s'" % os.path.join(localpath, 'openslides', 'database.sqlite')
|
||||||
|
# TODO: Decide whether to use only absolute paths here.
|
||||||
|
localpath_values['media_path_value'] = "'%s'" % os.path.join(localpath, 'openslides', 'media', '')
|
||||||
|
return localpath_values
|
||||||
|
|
||||||
|
|
||||||
|
def create_settings(settings_path, local_path_values):
|
||||||
|
"""
|
||||||
|
Creates the settings file at the given path using the given values for the
|
||||||
|
file template.
|
||||||
|
"""
|
||||||
|
settings_module = os.path.realpath(os.path.dirname(settings_path))
|
||||||
|
if not os.path.exists(settings_module):
|
||||||
|
os.makedirs(settings_module)
|
||||||
|
context = {'secret_key': base64.b64encode(os.urandom(30))}
|
||||||
|
context.update(local_path_values)
|
||||||
|
settings_content = SETTINGS_TEMPLATE % context
|
||||||
|
with open(settings_path, 'w') as settings_file:
|
||||||
|
settings_file.write(settings_content)
|
||||||
|
print('Settings file at %s successfully created.' % settings_path)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_django_settings_module(settings_path):
|
||||||
|
"""
|
||||||
|
Sets the environment variable DJANGO_SETTINGS_MODULE to the given settings.
|
||||||
|
"""
|
||||||
|
settings_file = os.path.basename(settings_path)
|
||||||
|
settings_module_name = "".join(settings_file.split('.')[:-1])
|
||||||
|
if '.' in settings_module_name:
|
||||||
|
print("'.' is not an allowed character in the settings-file")
|
||||||
|
sys.exit(1)
|
||||||
|
settings_module_dir = os.path.dirname(settings_path)
|
||||||
|
sys.path.append(settings_module_dir)
|
||||||
|
os.environ[ENVIRONMENT_VARIABLE] = '%s' % settings_module_name
|
||||||
|
|
||||||
|
|
||||||
|
def start(args):
|
||||||
|
"""
|
||||||
|
Starts OpenSlides: Runs syncdb and runs runserver (tornado webserver) with
|
||||||
|
the flag 'start_browser'.
|
||||||
|
"""
|
||||||
|
syncdb(args)
|
||||||
|
args.start_browser = True
|
||||||
|
args.no_reload = False
|
||||||
|
runserver(args)
|
||||||
|
|
||||||
|
|
||||||
|
def runserver(args):
|
||||||
|
"""
|
||||||
|
Runs tornado webserver. Runs the function start_browser if the respective
|
||||||
|
argument is given.
|
||||||
|
"""
|
||||||
|
port = get_port(address=args.address, port=args.port)
|
||||||
|
if args.start_browser:
|
||||||
|
browser_url = get_browser_url(address=args.address, port=port)
|
||||||
|
start_browser(browser_url)
|
||||||
|
run_tornado(args.address, port, not args.no_reload)
|
||||||
|
|
||||||
|
|
||||||
|
def get_port(address, port):
|
||||||
|
"""
|
||||||
|
Returns the port for the server. If port 80 is given, checks if it is
|
||||||
|
available. If not returns port 8000.
|
||||||
|
|
||||||
|
The argument 'address' should be an IP address. The argument 'port' should
|
||||||
|
be an integer.
|
||||||
|
"""
|
||||||
|
if port == 80:
|
||||||
|
# test if we can use port 80
|
||||||
|
s = socket.socket()
|
||||||
|
try:
|
||||||
|
s.bind((address, port))
|
||||||
|
s.listen(-1)
|
||||||
|
except socket.error:
|
||||||
|
port = 8000
|
||||||
|
finally:
|
||||||
|
s.close()
|
||||||
|
return port
|
||||||
|
|
||||||
|
|
||||||
|
def get_browser_url(address, port):
|
||||||
|
"""
|
||||||
|
Returns the url to open the web browser.
|
||||||
|
|
||||||
|
The argument 'address' should be an IP address. The argument 'port' should
|
||||||
|
be an integer.
|
||||||
|
"""
|
||||||
|
browser_url = 'http://'
|
||||||
|
if address == '0.0.0.0':
|
||||||
|
browser_url += 'localhost'
|
||||||
|
else:
|
||||||
|
browser_url += address
|
||||||
|
if not port == 80:
|
||||||
|
browser_url += ":%d" % port
|
||||||
|
return browser_url
|
||||||
|
|
||||||
|
|
||||||
|
def start_browser(browser_url):
|
||||||
|
"""
|
||||||
|
Launches the default web browser at the given url and opens the
|
||||||
|
webinterface.
|
||||||
|
"""
|
||||||
|
browser = webbrowser.get()
|
||||||
|
|
||||||
|
def function():
|
||||||
|
time.sleep(1)
|
||||||
|
browser.open(browser_url)
|
||||||
|
|
||||||
|
thread = threading.Thread(target=function)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
|
def syncdb(args):
|
||||||
|
"""
|
||||||
|
Run syncdb to create or update the database.
|
||||||
|
"""
|
||||||
|
# TODO: Check use of filesystem2unicode here.
|
||||||
|
path = filesystem2unicode(os.path.dirname(get_database_path_from_settings(args.settings)))
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
execute_from_command_line(["", "syncdb", "--noinput"])
|
||||||
|
|
||||||
|
|
||||||
|
def get_database_path_from_settings(settings_path):
|
||||||
|
"""
|
||||||
|
Retrieves the database path out of the given settings file. Returns None,
|
||||||
|
if it is not a SQLite3 database.
|
||||||
|
"""
|
||||||
|
from django.conf import settings as django_settings
|
||||||
|
from django.db import DEFAULT_DB_ALIAS
|
||||||
|
|
||||||
|
db_settings = django_settings.DATABASES
|
||||||
|
default = db_settings.get(DEFAULT_DB_ALIAS)
|
||||||
|
if not default:
|
||||||
|
raise Exception("Default databases is not configured")
|
||||||
|
database_path = default.get('NAME')
|
||||||
|
if not database_path:
|
||||||
|
raise Exception('No path specified for default database.')
|
||||||
|
if default.get('ENGINE') != 'django.db.backends.sqlite3':
|
||||||
|
database_path = None
|
||||||
|
return database_path
|
||||||
|
|
||||||
|
|
||||||
|
def createsuperuser(args):
|
||||||
|
"""
|
||||||
|
Creates or resets the admin user. Returns 0 to show success.
|
||||||
|
"""
|
||||||
|
# can't be imported in global scope as it already requires
|
||||||
|
# the settings module during import
|
||||||
|
from openslides.participant.api import create_or_reset_admin_user
|
||||||
|
if create_or_reset_admin_user():
|
||||||
|
print('Admin user successfully created.')
|
||||||
|
else:
|
||||||
|
print('Admin user successfully reset.')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def backupdb(args):
|
||||||
|
"""
|
||||||
|
Stores a backup copy of the SQlite3 database.
|
||||||
|
"""
|
||||||
|
from django.db import connection, transaction
|
||||||
|
|
||||||
|
@transaction.commit_manually
|
||||||
|
def do_backup(src_path, dest_path):
|
||||||
|
# perform a simple file-copy backup of the database
|
||||||
|
# first we need a shared lock on the database, issuing a select()
|
||||||
|
# will do this for us
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute("SELECT count(*) from sqlite_master")
|
||||||
|
# now copy the file
|
||||||
|
try:
|
||||||
|
shutil.copy(src_path, dest_path)
|
||||||
|
except IOError as e:
|
||||||
|
raise Exception("Database backup failed.")
|
||||||
|
# and release the lock again
|
||||||
|
transaction.commit()
|
||||||
|
|
||||||
|
database_path = get_database_path_from_settings(args.settings)
|
||||||
|
if database_path:
|
||||||
|
do_backup(database_path, args.path)
|
||||||
|
print('Database %s successfully stored at %s.' % (database_path, args.path))
|
||||||
|
return_value = 0
|
||||||
|
else:
|
||||||
|
print('Error: Default database is not SQLite3. Only SQLite3 databases can currently be backuped.')
|
||||||
|
return_value = 1
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
|
def deletedb(args):
|
||||||
|
"""
|
||||||
|
Deletes the sqlite3 database. Returns 0 on success, else 1.
|
||||||
|
"""
|
||||||
|
database_path = get_database_path_from_settings(args.settings)
|
||||||
|
if database_path and os.path.exists(database_path):
|
||||||
|
os.remove(database_path)
|
||||||
|
print('SQLite3 database file %s successfully deleted.' % database_path)
|
||||||
|
return_value = 0
|
||||||
|
else:
|
||||||
|
print('SQLite3 database file %s does not exist.' % database_path)
|
||||||
|
return_value = 1
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
|
def django_command_line_utility(args):
|
||||||
|
"""
|
||||||
|
Runs Django's command line utility. Returns 0 on success, else 1.
|
||||||
|
"""
|
||||||
|
if 'runserver' in args.django_args:
|
||||||
|
command = 'runserver'
|
||||||
|
elif 'syncdb' in args.django_args:
|
||||||
|
command = 'syncdb'
|
||||||
|
elif 'createsuperuser' in args.django_args:
|
||||||
|
command = 'createsuperuser'
|
||||||
|
else:
|
||||||
|
command = None
|
||||||
|
if command:
|
||||||
|
print("Error: The command '%s' is disabled for use via Django's command line utility." % command)
|
||||||
|
return_value = 1
|
||||||
|
else:
|
||||||
|
execute_from_command_line(args.django_args)
|
||||||
|
return_value = 0
|
||||||
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
exit(main())
|
@ -1,53 +0,0 @@
|
|||||||
import shutil
|
|
||||||
from optparse import make_option
|
|
||||||
|
|
||||||
import django.conf
|
|
||||||
import django.db
|
|
||||||
import django.db.transaction
|
|
||||||
from django.core.management.base import CommandError, NoArgsCommand
|
|
||||||
|
|
||||||
|
|
||||||
class Command(NoArgsCommand):
|
|
||||||
help = "Backup the openslides database"
|
|
||||||
option_list = NoArgsCommand.option_list + (
|
|
||||||
make_option(
|
|
||||||
"--destination", action="store",
|
|
||||||
help="path to the backup database (will be overwritten)"),
|
|
||||||
)
|
|
||||||
|
|
||||||
def handle_noargs(self, *args, **kw):
|
|
||||||
db_settings = django.conf.settings.DATABASES
|
|
||||||
default = db_settings.get(django.db.DEFAULT_DB_ALIAS)
|
|
||||||
if not default:
|
|
||||||
raise CommandError("Default databases is not configured")
|
|
||||||
|
|
||||||
if default.get("ENGINE") != "django.db.backends.sqlite3":
|
|
||||||
raise CommandError(
|
|
||||||
"Only sqlite3 databases can currently be backuped")
|
|
||||||
|
|
||||||
src_path = default.get("NAME")
|
|
||||||
if not src_path:
|
|
||||||
raise CommandError("No path specified for default database")
|
|
||||||
|
|
||||||
dest_path = kw.get("destination")
|
|
||||||
if not dest_path:
|
|
||||||
raise CommandError("--destination must be specified")
|
|
||||||
|
|
||||||
self.do_backup(src_path, dest_path)
|
|
||||||
|
|
||||||
@django.db.transaction.commit_manually
|
|
||||||
def do_backup(self, src_path, dest_path):
|
|
||||||
# perform a simple file-copy backup of the database
|
|
||||||
# first we need a shared lock on the database, issuing a select()
|
|
||||||
# will do this for us
|
|
||||||
cursor = django.db.connection.cursor()
|
|
||||||
cursor.execute("SELECT count(*) from sqlite_master")
|
|
||||||
|
|
||||||
# now copy the file
|
|
||||||
try:
|
|
||||||
shutil.copy(src_path, dest_path)
|
|
||||||
except IOError as e:
|
|
||||||
raise CommandError("{0}\nDatabase backup failed!".format(e))
|
|
||||||
|
|
||||||
# and release the lock again
|
|
||||||
django.db.transaction.commit()
|
|
@ -1,27 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
openslides.utils.management.commands.runserver
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Overrides the Django runserver command to start the tornado webserver.
|
|
||||||
|
|
||||||
:copyright: (c) 2011-2013 by the OpenSlides team, see AUTHORS.
|
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
|
||||||
|
|
||||||
from openslides.main import main
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
"""
|
|
||||||
Start the application using the tornado webserver
|
|
||||||
"""
|
|
||||||
|
|
||||||
help = 'Start the application using the tornado webserver'
|
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
|
||||||
main(manage_runserver=True)
|
|
@ -11,7 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from openslides.main import fs2unicode
|
from openslides.utils.main import filesystem2unicode
|
||||||
|
|
||||||
|
|
||||||
SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
|
SITE_ROOT = os.path.realpath(os.path.dirname(__file__))
|
||||||
@ -44,7 +44,7 @@ USE_I18N = True
|
|||||||
USE_L10N = True
|
USE_L10N = True
|
||||||
|
|
||||||
LOCALE_PATHS = (
|
LOCALE_PATHS = (
|
||||||
fs2unicode(os.path.join(SITE_ROOT, 'locale')),
|
filesystem2unicode(os.path.join(SITE_ROOT, 'locale')),
|
||||||
)
|
)
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||||
@ -54,7 +54,7 @@ MEDIA_URL = '/media/'
|
|||||||
|
|
||||||
# Absolute path to the directory that holds static media from ``collectstatic``
|
# Absolute path to the directory that holds static media from ``collectstatic``
|
||||||
# Example: "/home/media/static.lawrence.com/"
|
# Example: "/home/media/static.lawrence.com/"
|
||||||
STATIC_ROOT = fs2unicode(os.path.join(SITE_ROOT, '../collected-site-static'))
|
STATIC_ROOT = filesystem2unicode(os.path.join(SITE_ROOT, '../collected-site-static'))
|
||||||
|
|
||||||
# URL that handles the media served from STATIC_ROOT. Make sure to use a
|
# URL that handles the media served from STATIC_ROOT. Make sure to use a
|
||||||
# trailing slash if there is a path component (optional in other cases).
|
# trailing slash if there is a path component (optional in other cases).
|
||||||
@ -64,12 +64,14 @@ STATIC_URL = '/static/'
|
|||||||
# Additional directories containing static files (not application specific)
|
# Additional directories containing static files (not application specific)
|
||||||
# Examples: "/home/media/lawrence.com/extra-static/"
|
# Examples: "/home/media/lawrence.com/extra-static/"
|
||||||
STATICFILES_DIRS = (
|
STATICFILES_DIRS = (
|
||||||
fs2unicode(os.path.join(SITE_ROOT, 'static')),
|
filesystem2unicode(os.path.join(SITE_ROOT, 'static')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#XXX: Note this setting (as well as our workaround finder)
|
||||||
|
# can be removed again once django-bug-#18404 has been resolved
|
||||||
STATICFILES_FINDERS = (
|
STATICFILES_FINDERS = (
|
||||||
'django.contrib.staticfiles.finders.FileSystemFinder',
|
'django.contrib.staticfiles.finders.FileSystemFinder',
|
||||||
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
|
'openslides.utils.staticfiles.AppDirectoriesFinder',
|
||||||
)
|
)
|
||||||
|
|
||||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
||||||
@ -97,7 +99,7 @@ TEMPLATE_DIRS = (
|
|||||||
# "C:/www/django/templates".
|
# "C:/www/django/templates".
|
||||||
# Always use forward slashes, even on Windows.
|
# Always use forward slashes, even on Windows.
|
||||||
# Don't forget to use absolute paths, not relative paths.
|
# Don't forget to use absolute paths, not relative paths.
|
||||||
fs2unicode(os.path.join(SITE_ROOT, 'templates')),
|
filesystem2unicode(os.path.join(SITE_ROOT, 'templates')),
|
||||||
)
|
)
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
INSTALLED_APPS = (
|
||||||
|
@ -1,423 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
openslides.main
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Main script to start and set up OpenSlides.
|
|
||||||
|
|
||||||
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
|
||||||
:license: GNU GPL, see LICENSE for more details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import base64
|
|
||||||
import ctypes
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import webbrowser
|
|
||||||
|
|
||||||
from django.conf import ENVIRONMENT_VARIABLE
|
|
||||||
from django.core.management import execute_from_command_line
|
|
||||||
|
|
||||||
from openslides import get_version
|
|
||||||
from openslides.utils.tornado_webserver import run_tornado
|
|
||||||
|
|
||||||
|
|
||||||
CONFIG_TEMPLATE = """#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import openslides.main
|
|
||||||
from openslides.global_settings import *
|
|
||||||
|
|
||||||
|
|
||||||
# Use 'DEBUG = True' to get more details for server errors
|
|
||||||
# (Default for releases: 'False')
|
|
||||||
DEBUG = False
|
|
||||||
TEMPLATE_DEBUG = DEBUG
|
|
||||||
|
|
||||||
DBPATH = %(dbpath)s
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
|
||||||
'NAME': DBPATH,
|
|
||||||
'USER': '',
|
|
||||||
'PASSWORD': '',
|
|
||||||
'HOST': '',
|
|
||||||
'PORT': '',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set timezone
|
|
||||||
TIME_ZONE = 'Europe/Berlin'
|
|
||||||
|
|
||||||
# Make this unique, and don't share it with anybody.
|
|
||||||
SECRET_KEY = %(default_key)r
|
|
||||||
|
|
||||||
# Add OpenSlides plugins to this list (see example entry in comment)
|
|
||||||
INSTALLED_PLUGINS = (
|
|
||||||
# 'pluginname',
|
|
||||||
)
|
|
||||||
|
|
||||||
INSTALLED_APPS += INSTALLED_PLUGINS
|
|
||||||
|
|
||||||
# Absolute path to the directory that holds media.
|
|
||||||
# Example: "/home/media/media.lawrence.com/"
|
|
||||||
MEDIA_ROOT = %(media_root_path)s
|
|
||||||
|
|
||||||
# Path to Whoosh search index
|
|
||||||
HAYSTACK_CONNECTIONS['default']['PATH'] = %(whoosh_index_path)s
|
|
||||||
"""
|
|
||||||
|
|
||||||
KEY_LENGTH = 30
|
|
||||||
|
|
||||||
# sentinel used to signal that the database ought to be stored
|
|
||||||
# relative to the portable's directory
|
|
||||||
_portable_db_path = object()
|
|
||||||
|
|
||||||
|
|
||||||
def process_options(argv=None, manage_runserver=False):
|
|
||||||
if argv is None:
|
|
||||||
argv = sys.argv[1:]
|
|
||||||
|
|
||||||
parser = optparse.OptionParser(
|
|
||||||
description="Run openslides using the tornado webserver")
|
|
||||||
parser.add_option(
|
|
||||||
"-a", "--address",
|
|
||||||
help="IP Address to listen on. Default: 0.0.0.0")
|
|
||||||
parser.add_option(
|
|
||||||
"-p", "--port", type="int",
|
|
||||||
help="Port to listen on. Default: 8000 (start as admin/root: 80)")
|
|
||||||
parser.add_option(
|
|
||||||
"--syncdb", action="store_true",
|
|
||||||
help="Update/create database before starting the server.")
|
|
||||||
parser.add_option(
|
|
||||||
"--backupdb", action="store", metavar="BACKUP_PATH",
|
|
||||||
help="Make a backup copy of the database to BACKUP_PATH.")
|
|
||||||
parser.add_option(
|
|
||||||
"--reset-admin", action="store_true",
|
|
||||||
help="Make sure the user 'admin' exists and uses 'admin' as password.")
|
|
||||||
parser.add_option(
|
|
||||||
"-s", "--settings", help="Set the path to the settings file.")
|
|
||||||
parser.add_option(
|
|
||||||
"--no-browser",
|
|
||||||
action="store_false", dest="start_browser", default=True,
|
|
||||||
help="Do not automatically start the web browser.")
|
|
||||||
parser.add_option(
|
|
||||||
"--no-reload", action="store_true",
|
|
||||||
help="Do not reload the web server.")
|
|
||||||
parser.add_option(
|
|
||||||
"--no-run", action="store_true",
|
|
||||||
help="Do not start the web server.")
|
|
||||||
parser.add_option(
|
|
||||||
"--version", action="store_true",
|
|
||||||
help="Show version and exit.")
|
|
||||||
|
|
||||||
opts, args = parser.parse_args(argv)
|
|
||||||
|
|
||||||
# Do not parse any argv if the script is started via manage.py runserver.
|
|
||||||
# This simulates the django runserver command
|
|
||||||
if manage_runserver:
|
|
||||||
opts.start_browser = False
|
|
||||||
opts.no_reload = False
|
|
||||||
return opts
|
|
||||||
|
|
||||||
if opts.version:
|
|
||||||
print get_version()
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
if args:
|
|
||||||
sys.stderr.write("This command does not take arguments!\n\n")
|
|
||||||
parser.print_help()
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
return opts
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None, manage_runserver=False):
|
|
||||||
opts = process_options(argv, manage_runserver)
|
|
||||||
_main(opts)
|
|
||||||
|
|
||||||
|
|
||||||
def win32_portable_main(argv=None):
|
|
||||||
"""special entry point for the win32 portable version"""
|
|
||||||
|
|
||||||
opts = process_options(argv)
|
|
||||||
|
|
||||||
database_path = None
|
|
||||||
|
|
||||||
if opts.settings is None:
|
|
||||||
portable_dir = get_portable_path()
|
|
||||||
try:
|
|
||||||
fd, test_file = tempfile.mkstemp(dir=portable_dir)
|
|
||||||
except OSError:
|
|
||||||
portable_dir_writeable = False
|
|
||||||
else:
|
|
||||||
portable_dir_writeable = True
|
|
||||||
os.close(fd)
|
|
||||||
os.unlink(test_file)
|
|
||||||
|
|
||||||
if portable_dir_writeable:
|
|
||||||
opts.settings = os.path.join(
|
|
||||||
portable_dir, "openslides", "settings.py")
|
|
||||||
database_path = _portable_db_path
|
|
||||||
|
|
||||||
_main(opts, database_path=database_path)
|
|
||||||
|
|
||||||
|
|
||||||
def _main(opts, database_path=None):
|
|
||||||
# Find the path to the settings
|
|
||||||
settings_path = opts.settings
|
|
||||||
if settings_path is None:
|
|
||||||
settings_path = get_user_config_path('openslides', 'settings.py')
|
|
||||||
|
|
||||||
# Create settings if necessary
|
|
||||||
if not os.path.exists(settings_path):
|
|
||||||
create_settings(settings_path, database_path)
|
|
||||||
|
|
||||||
# Set the django environment to the settings
|
|
||||||
setup_django_environment(settings_path)
|
|
||||||
|
|
||||||
# Find url to openslides
|
|
||||||
addr, port = detect_listen_opts(opts.address, opts.port)
|
|
||||||
|
|
||||||
# Create Database if necessary
|
|
||||||
if not database_exists() or opts.syncdb:
|
|
||||||
run_syncdb()
|
|
||||||
|
|
||||||
# Reset Admin
|
|
||||||
elif opts.reset_admin:
|
|
||||||
reset_admin_user()
|
|
||||||
|
|
||||||
if opts.backupdb:
|
|
||||||
backup_database(opts.backupdb)
|
|
||||||
|
|
||||||
if opts.no_run:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Start OpenSlides
|
|
||||||
reload = True
|
|
||||||
if opts.no_reload:
|
|
||||||
reload = False
|
|
||||||
|
|
||||||
if opts.start_browser:
|
|
||||||
if opts.address:
|
|
||||||
prefix = opts.address
|
|
||||||
else:
|
|
||||||
prefix = 'localhost'
|
|
||||||
if port == 80:
|
|
||||||
suffix = ""
|
|
||||||
else:
|
|
||||||
suffix = ":%d" % port
|
|
||||||
start_browser("http://%s%s" % (prefix, suffix))
|
|
||||||
|
|
||||||
# Start the server
|
|
||||||
run_tornado(addr, port, reload)
|
|
||||||
|
|
||||||
|
|
||||||
def create_settings(settings_path, database_path=None):
|
|
||||||
settings_module = os.path.dirname(settings_path)
|
|
||||||
|
|
||||||
if database_path is _portable_db_path:
|
|
||||||
database_path = get_portable_db_path()
|
|
||||||
dbpath_value = 'openslides.main.get_portable_db_path()'
|
|
||||||
media_root_path_value = 'openslides.main.get_portable_media_root_path()'
|
|
||||||
whoosh_index_path_value = 'openslides.main.get_portable_whoosh_index_path()'
|
|
||||||
else:
|
|
||||||
if database_path is None:
|
|
||||||
database_path = get_user_data_path('openslides', 'database.sqlite')
|
|
||||||
dbpath_value = repr(fs2unicode(database_path))
|
|
||||||
media_root_path_value = repr(fs2unicode(get_user_data_path('openslides', 'media', '')))
|
|
||||||
whoosh_index_path_value = repr(fs2unicode(get_user_data_path('openslides', 'whoosh_index', '')))
|
|
||||||
|
|
||||||
settings_content = CONFIG_TEMPLATE % dict(
|
|
||||||
default_key=base64.b64encode(os.urandom(KEY_LENGTH)),
|
|
||||||
dbpath=dbpath_value,
|
|
||||||
media_root_path=media_root_path_value,
|
|
||||||
whoosh_index_path=whoosh_index_path_value)
|
|
||||||
|
|
||||||
if not os.path.exists(settings_module):
|
|
||||||
os.makedirs(settings_module)
|
|
||||||
|
|
||||||
if not os.path.exists(os.path.dirname(database_path)):
|
|
||||||
os.makedirs(os.path.dirname(database_path))
|
|
||||||
|
|
||||||
with open(settings_path, 'w') as file:
|
|
||||||
file.write(settings_content)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_django_environment(settings_path):
|
|
||||||
settings_file = os.path.basename(settings_path)
|
|
||||||
settings_module_name = "".join(settings_file.split('.')[:-1])
|
|
||||||
if '.' in settings_module_name:
|
|
||||||
print "'.' is not an allowed character in the settings-file"
|
|
||||||
sys.exit(1)
|
|
||||||
settings_module_dir = os.path.dirname(settings_path)
|
|
||||||
sys.path.append(settings_module_dir)
|
|
||||||
os.environ[ENVIRONMENT_VARIABLE] = '%s' % settings_module_name
|
|
||||||
|
|
||||||
|
|
||||||
def detect_listen_opts(address=None, port=None):
|
|
||||||
if address is None:
|
|
||||||
address = "0.0.0.0"
|
|
||||||
|
|
||||||
if port is None:
|
|
||||||
# test if we can use port 80
|
|
||||||
s = socket.socket()
|
|
||||||
port = 80
|
|
||||||
try:
|
|
||||||
s.bind((address, port))
|
|
||||||
s.listen(-1)
|
|
||||||
except socket.error:
|
|
||||||
port = 8000
|
|
||||||
finally:
|
|
||||||
s.close()
|
|
||||||
|
|
||||||
return address, port
|
|
||||||
|
|
||||||
|
|
||||||
def database_exists():
|
|
||||||
"""Detect if database exists"""
|
|
||||||
# can't be imported in global scope as they already require
|
|
||||||
# the settings module during import
|
|
||||||
from django.db import DatabaseError
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
|
||||||
from openslides.participant.models import User
|
|
||||||
|
|
||||||
try:
|
|
||||||
# TODO: Use another model, the User could be deactivated
|
|
||||||
User.objects.count()
|
|
||||||
except DatabaseError:
|
|
||||||
return False
|
|
||||||
except ImproperlyConfigured:
|
|
||||||
print "Your settings file seems broken"
|
|
||||||
sys.exit(0)
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def run_syncdb():
|
|
||||||
# now initialize the database
|
|
||||||
argv = ["", "syncdb", "--noinput"]
|
|
||||||
execute_from_command_line(argv)
|
|
||||||
|
|
||||||
|
|
||||||
def reset_admin_user():
|
|
||||||
# can't be imported in global scope as it already requires
|
|
||||||
# the settings module during import
|
|
||||||
from openslides.participant.api import create_or_reset_admin_user
|
|
||||||
create_or_reset_admin_user()
|
|
||||||
|
|
||||||
|
|
||||||
def backup_database(dest_path):
|
|
||||||
argv = ["", "backupdb", "--destination={0}".format(dest_path)]
|
|
||||||
execute_from_command_line(argv)
|
|
||||||
|
|
||||||
|
|
||||||
def start_browser(url):
|
|
||||||
browser = webbrowser.get()
|
|
||||||
|
|
||||||
def f():
|
|
||||||
time.sleep(1)
|
|
||||||
browser.open(url)
|
|
||||||
|
|
||||||
t = threading.Thread(target=f)
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
|
|
||||||
def fs2unicode(s):
|
|
||||||
if isinstance(s, unicode):
|
|
||||||
return s
|
|
||||||
fs_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
|
||||||
return s.decode(fs_encoding)
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_config_path(*args):
|
|
||||||
if sys.platform == "win32":
|
|
||||||
return win32_get_app_data_path(*args)
|
|
||||||
|
|
||||||
config_home = os.environ.get(
|
|
||||||
'XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config'))
|
|
||||||
|
|
||||||
return os.path.join(fs2unicode(config_home), *args)
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_data_path(*args):
|
|
||||||
if sys.platform == "win32":
|
|
||||||
return win32_get_app_data_path(*args)
|
|
||||||
|
|
||||||
data_home = os.environ.get(
|
|
||||||
'XDG_DATA_HOME', os.path.join(
|
|
||||||
os.path.expanduser('~'), '.local', 'share'))
|
|
||||||
|
|
||||||
return os.path.join(fs2unicode(data_home), *args)
|
|
||||||
|
|
||||||
|
|
||||||
def is_portable():
|
|
||||||
"""Return True if openslides is run as portable version"""
|
|
||||||
|
|
||||||
# NOTE: sys.executable is the path of the *interpreter*
|
|
||||||
# the portable version embeds python so it *is* the interpreter.
|
|
||||||
# The wrappers generated by pip and co. will spawn
|
|
||||||
# the usual python(w).exe, so there is no danger of mistaking
|
|
||||||
# them for the portable even though they may also be called
|
|
||||||
# openslides.exe
|
|
||||||
exename = os.path.basename(sys.executable).lower()
|
|
||||||
return exename == "openslides.exe"
|
|
||||||
|
|
||||||
|
|
||||||
def get_portable_path(*args):
|
|
||||||
# NOTE: sys.executable will be the path to openslides.exe
|
|
||||||
# since it is essentially a small wrapper that embeds the
|
|
||||||
# python interpreter
|
|
||||||
|
|
||||||
if not is_portable():
|
|
||||||
raise Exception(
|
|
||||||
"Cannot determine portable path when "
|
|
||||||
"not running as portable")
|
|
||||||
|
|
||||||
portable_dir = fs2unicode(os.path.dirname(os.path.abspath(sys.executable)))
|
|
||||||
return os.path.join(portable_dir, *args)
|
|
||||||
|
|
||||||
|
|
||||||
def get_portable_db_path():
|
|
||||||
return get_portable_path('openslides', 'database.sqlite')
|
|
||||||
|
|
||||||
|
|
||||||
def get_portable_media_root_path():
|
|
||||||
return get_portable_path('openslides', 'media', '')
|
|
||||||
|
|
||||||
|
|
||||||
def get_portable_whoosh_index_path():
|
|
||||||
return get_portable_path('openslides', 'whoosh_index', '')
|
|
||||||
|
|
||||||
|
|
||||||
def win32_get_app_data_path(*args):
|
|
||||||
shell32 = ctypes.WinDLL("shell32.dll")
|
|
||||||
SHGetFolderPath = shell32.SHGetFolderPathW
|
|
||||||
SHGetFolderPath.argtypes = (
|
|
||||||
ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_uint32,
|
|
||||||
ctypes.c_wchar_p)
|
|
||||||
SHGetFolderPath.restype = ctypes.c_uint32
|
|
||||||
|
|
||||||
CSIDL_LOCAL_APPDATA = 0x001c
|
|
||||||
MAX_PATH = 260
|
|
||||||
|
|
||||||
buf = ctypes.create_unicode_buffer(MAX_PATH)
|
|
||||||
res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf)
|
|
||||||
if res != 0:
|
|
||||||
raise Exception("Could not deterime APPDATA path")
|
|
||||||
|
|
||||||
return os.path.join(buf.value, *args)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if is_portable():
|
|
||||||
win32_portable_main()
|
|
||||||
else:
|
|
||||||
main()
|
|
@ -130,8 +130,11 @@ def create_or_reset_admin_user():
|
|||||||
admin = User()
|
admin = User()
|
||||||
admin.username = 'admin'
|
admin.username = 'admin'
|
||||||
admin.last_name = 'Administrator'
|
admin.last_name = 'Administrator'
|
||||||
|
created = True
|
||||||
|
else:
|
||||||
|
created = False
|
||||||
admin.default_password = 'admin'
|
admin.default_password = 'admin'
|
||||||
admin.set_password(admin.default_password)
|
admin.set_password(admin.default_password)
|
||||||
admin.save()
|
admin.save()
|
||||||
admin.groups.add(group_staff)
|
admin.groups.add(group_staff)
|
||||||
|
return created
|
||||||
|
114
openslides/utils/main.py
Normal file
114
openslides/utils/main.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
openslides.utils.main
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Some functions for OpenSlides.
|
||||||
|
|
||||||
|
:copyright: 2011–2013 by OpenSlides team, see AUTHORS.
|
||||||
|
:license: GNU GPL, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import ctypes
|
||||||
|
|
||||||
|
|
||||||
|
UNIX_VERSION = 'Unix Version'
|
||||||
|
WINDOWS_VERSION = 'Windows Version'
|
||||||
|
WINDOWS_PORTABLE_VERSION = 'Windows Portable Version'
|
||||||
|
|
||||||
|
|
||||||
|
def filesystem2unicode(path):
|
||||||
|
"""
|
||||||
|
Transforms a path string to unicode according to the filesystem's encoding.
|
||||||
|
"""
|
||||||
|
# TODO: Delete this function after switch to Python 3.
|
||||||
|
if not isinstance(path, unicode):
|
||||||
|
filesystem_encoding = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
||||||
|
path = path.decode(filesystem_encoding)
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def detect_openslides_type():
|
||||||
|
"""
|
||||||
|
Returns the type of this version.
|
||||||
|
"""
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
if os.path.basename(sys.executable).lower() == 'openslides.exe':
|
||||||
|
# Note: sys.executable is the path of the *interpreter*
|
||||||
|
# the portable version embeds python so it *is* the interpreter.
|
||||||
|
# The wrappers generated by pip and co. will spawn the usual
|
||||||
|
# python(w).exe, so there is no danger of mistaking them
|
||||||
|
# for the portable even though they may also be called
|
||||||
|
# openslides.exe
|
||||||
|
openslides_type = WINDOWS_PORTABLE_VERSION
|
||||||
|
else:
|
||||||
|
openslides_type = WINDOWS_VERSION
|
||||||
|
else:
|
||||||
|
openslides_type = UNIX_VERSION
|
||||||
|
return openslides_type
|
||||||
|
|
||||||
|
|
||||||
|
def is_portable():
|
||||||
|
"""
|
||||||
|
Helper function just for the GUI.
|
||||||
|
"""
|
||||||
|
# TODO: Remove this function.
|
||||||
|
return detect_openslides_type() == WINDOWS_PORTABLE_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
def get_win32_app_data_path():
|
||||||
|
"""
|
||||||
|
Returns the path to Windows' AppData directory.
|
||||||
|
"""
|
||||||
|
shell32 = ctypes.WinDLL("shell32.dll")
|
||||||
|
SHGetFolderPath = shell32.SHGetFolderPathW
|
||||||
|
SHGetFolderPath.argtypes = (
|
||||||
|
ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_uint32,
|
||||||
|
ctypes.c_wchar_p)
|
||||||
|
SHGetFolderPath.restype = ctypes.c_uint32
|
||||||
|
|
||||||
|
CSIDL_LOCAL_APPDATA = 0x001c
|
||||||
|
MAX_PATH = 260
|
||||||
|
|
||||||
|
buf = ctypes.create_unicode_buffer(MAX_PATH)
|
||||||
|
res = SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, 0, buf)
|
||||||
|
if res != 0:
|
||||||
|
raise Exception("Could not deterime APPDATA path")
|
||||||
|
|
||||||
|
return buf.value
|
||||||
|
|
||||||
|
|
||||||
|
def get_win32_portable_path():
|
||||||
|
"""
|
||||||
|
Returns the path to the Windows portable version.
|
||||||
|
"""
|
||||||
|
# NOTE: sys.executable will be the path to openslides.exe
|
||||||
|
# since it is essentially a small wrapper that embeds the
|
||||||
|
# python interpreter
|
||||||
|
portable_path = filesystem2unicode(os.path.dirname(os.path.abspath(sys.executable)))
|
||||||
|
try:
|
||||||
|
fd, test_file = tempfile.mkstemp(dir=portable_path)
|
||||||
|
except OSError:
|
||||||
|
raise Exception('Portable directory is not writeable. Please choose another directory for settings and local files.')
|
||||||
|
finally:
|
||||||
|
os.close(fd)
|
||||||
|
os.unlink(test_file)
|
||||||
|
return portable_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_portable_paths(name):
|
||||||
|
"""
|
||||||
|
Returns the paths for the Windows portable version on runtime for the
|
||||||
|
SQLite3 database and the media directory. The argument 'name' can be
|
||||||
|
'database' or 'media'.
|
||||||
|
"""
|
||||||
|
if name == 'database':
|
||||||
|
path = os.path.join(get_win32_portable_path(), 'openslides', 'database.sqlite')
|
||||||
|
elif name == 'media':
|
||||||
|
path = os.path.join(get_win32_portable_path(), 'openslides', 'media', '')
|
||||||
|
else:
|
||||||
|
raise TypeError('Unknow type %s' % name)
|
||||||
|
return path
|
2
setup.py
2
setup.py
@ -45,4 +45,4 @@ setup(
|
|||||||
packages=find_packages(exclude=['tests', 'tests.*']),
|
packages=find_packages(exclude=['tests', 'tests.*']),
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=install_requires,
|
install_requires=install_requires,
|
||||||
entry_points={'console_scripts': ['openslides = openslides.main:main']})
|
entry_points={'console_scripts': ['openslides = openslides.__main__:main']})
|
||||||
|
Loading…
Reference in New Issue
Block a user