diff --git a/openslides/__main__.py b/openslides/__main__.py index b7a78f21e..b1c951688 100644 --- a/openslides/__main__.py +++ b/openslides/__main__.py @@ -8,8 +8,8 @@ import django from django.core.management import call_command, execute_from_command_line import openslides +from openslides.core.apps import startup from openslides.utils.arguments import arguments -from openslides.utils.exceptions import OpenSlidesError from openslides.utils.main import ( ExceptionArgumentParser, UnknownCommand, @@ -180,7 +180,7 @@ def get_parser(): ("backupdb", "Backups the SQLite3 database."), ("createsuperuser", "Creates or resets the admin user."), ("migrate", "Updates database schema."), - ("runserver", "Starts the Tornado webserver."), + ("runserver", "Starts the built-in webserver."), ) for django_subcommand, help_text in django_subcommands: subparsers._choices_actions.append( # type: ignore @@ -196,10 +196,6 @@ def start(args): """ Starts OpenSlides: Runs migrations and runs runserver. """ - raise OpenSlidesError( - "The start command does not work anymore. " - + "Please use `createsettings`, `migrate` and `runserver`." - ) settings_dir = args.settings_dir settings_filename = args.settings_filename local_installation = is_local_installation() @@ -231,7 +227,9 @@ def start(args): if not args.no_browser: open_browser(args.host, args.port) - # Start Daphne + startup() + + # Start the built-in webserver # # Use flag --noreload to tell Django not to reload the server. # Therefor we have to set the keyword noreload to False because Django diff --git a/openslides/asgi.py b/openslides/asgi.py index 10799265a..eed704654 100644 --- a/openslides/asgi.py +++ b/openslides/asgi.py @@ -6,6 +6,7 @@ defined in the ASGI_APPLICATION setting. import django from channels.routing import get_default_application +from .core.apps import startup from .utils.main import setup_django_settings_module @@ -13,4 +14,5 @@ from .utils.main import setup_django_settings_module # environment variable DJANGO_SETTINGS_MODULE setup_django_settings_module() django.setup() +startup() application = get_default_application() diff --git a/openslides/core/apps.py b/openslides/core/apps.py index 50f980e9c..1f8e89e4a 100644 --- a/openslides/core/apps.py +++ b/openslides/core/apps.py @@ -1,3 +1,4 @@ +import os import sys from collections import OrderedDict from operator import attrgetter @@ -41,26 +42,12 @@ class CoreAppConfig(AppConfig): ListenToProjectors, ) from ..utils.access_permissions import required_user - from ..utils.cache import element_cache - from ..utils.constants import set_constants, get_constants_from_apps from ..utils.rest_api import router from ..utils.websocket import register_client_message # Collect all config variables before getting the constants. config.collect_config_variables_from_apps() - # Skip all database related accesses during migrations. - is_normal_server_start = False - for sys_part in sys.argv: - for entry in ("runserver", "gunicorn", "daphne", "create-example-data"): - if sys_part.endswith(entry): - is_normal_server_start = True - break - - # Set constants - if is_normal_server_start: - set_constants(get_constants_from_apps()) - # Define projector elements. register_projector_elements() @@ -102,10 +89,8 @@ class CoreAppConfig(AppConfig): self.get_model("History").get_collection_string(), HistoryViewSet ) - # Sets the cache and builds the startup history - if is_normal_server_start: - element_cache.ensure_cache() - self.get_model("History").objects.build_history() + if "runserver" in sys.argv: + startup() # Register client messages register_client_message(NotifyWebsocketClientMessage()) @@ -201,3 +186,21 @@ def required_users(element: Dict[str, Any]) -> Set[int]: Returns all user ids that are displayed as chatters. """ return set(element["user_id"]) + + +def startup(): + """ + Runs commands that are needed at startup. + + Sets the cache, constants and startup history + """ + if os.environ.get("NO_STARTUP"): + return + + from openslides.utils.constants import set_constants, get_constants_from_apps + from openslides.utils.cache import element_cache + from openslides.core.models import History + + set_constants(get_constants_from_apps()) + element_cache.ensure_cache() + History.objects.build_history() diff --git a/openslides/core/migrations/0013_auto_20190119_1641.py b/openslides/core/migrations/0013_auto_20190119_1641.py index 108409989..26492d0c7 100644 --- a/openslides/core/migrations/0013_auto_20190119_1641.py +++ b/openslides/core/migrations/0013_auto_20190119_1641.py @@ -7,19 +7,23 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('core', '0012_auto_20190119_1425'), - ] + dependencies = [("core", "0012_auto_20190119_1425")] operations = [ migrations.AddField( - model_name='history', - name='restricted', + model_name="history", + name="restricted", field=models.BooleanField(default=False), ), migrations.AlterField( - model_name='history', - name='information', - field=jsonfield.fields.JSONField(dump_kwargs={'cls': jsonfield.encoder.JSONEncoder, 'separators': (',', ':')}, load_kwargs={}), + model_name="history", + name="information", + field=jsonfield.fields.JSONField( + dump_kwargs={ + "cls": jsonfield.encoder.JSONEncoder, + "separators": (",", ":"), + }, + load_kwargs={}, + ), ), ] diff --git a/openslides/motions/views.py b/openslides/motions/views.py index 1ef9237f1..6f7283895 100644 --- a/openslides/motions/views.py +++ b/openslides/motions/views.py @@ -228,7 +228,7 @@ class MotionViewSet(ModelViewSet): # Fire autoupdate again to save information to OpenSlides history. inform_changed_data( - motion, information=["Motion created"], user_id=request.user.pk, + motion, information=["Motion created"], user_id=request.user.pk ) headers = self.get_success_headers(serializer.data) @@ -418,7 +418,7 @@ class MotionViewSet(ModelViewSet): # Fire autoupdate again to save information to OpenSlides history. inform_changed_data( - motion, information=message, user_id=request.user.pk, restricted=True, + motion, information=message, user_id=request.user.pk, restricted=True ) return Response({"detail": message}) @@ -487,7 +487,9 @@ class MotionViewSet(ModelViewSet): motion_result.append(motion) # Now inform all clients. - inform_changed_data(motion_result, information=["Submitters changed"], user_id=request.user.pk) + inform_changed_data( + motion_result, information=["Submitters changed"], user_id=request.user.pk + ) # Also send all new submitters via autoupdate because users without # permission to see users may not have them but can get it now. @@ -589,7 +591,11 @@ class MotionViewSet(ModelViewSet): ) # Fire autoupdate again to save information to OpenSlides history. - inform_changed_data(motion, information=["State set to {arg1}", motion.state.name], user_id=request.user.pk) + inform_changed_data( + motion, + information=["State set to {arg1}", motion.state.name], + user_id=request.user.pk, + ) return Response({"detail": message}) @@ -659,7 +665,9 @@ class MotionViewSet(ModelViewSet): # Fire autoupdate again to save information to OpenSlides history. inform_changed_data( - motion, information=["State set to {arg1}", motion.state.name], user_id=request.user.pk, + motion, + information=["State set to {arg1}", motion.state.name], + user_id=request.user.pk, ) # Finish motion. @@ -708,7 +716,9 @@ class MotionViewSet(ModelViewSet): motion.recommendation = None # Save motion. - motion.save(update_fields=["recommendation", "last_modified"], skip_autoupdate=True) + motion.save( + update_fields=["recommendation", "last_modified"], skip_autoupdate=True + ) label = ( motion.recommendation.recommendation_label if motion.recommendation @@ -725,7 +735,9 @@ class MotionViewSet(ModelViewSet): # Fire autoupdate again to save information to OpenSlides history. inform_changed_data( - motion, information=["Recommendation set to {arg1}", label], user_id=request.user.pk, + motion, + information=["Recommendation set to {arg1}", label], + user_id=request.user.pk, ) return Response({"detail": message}) @@ -794,7 +806,9 @@ class MotionViewSet(ModelViewSet): motion.set_recommendation(recommendation_state_id) # Save motion. - motion.save(update_fields=["recommendation", "last_modified"], skip_autoupdate=True) + motion.save( + update_fields=["recommendation", "last_modified"], skip_autoupdate=True + ) label = ( motion.recommendation.recommendation_label if motion.recommendation @@ -810,7 +824,9 @@ class MotionViewSet(ModelViewSet): # Fire autoupdate and save information to OpenSlides history. inform_changed_data( - motion, information=["Recommendation set to {arg1}", label], user_id=request.user.pk, + motion, + information=["Recommendation set to {arg1}", label], + user_id=request.user.pk, ) # Finish motion. @@ -853,7 +869,11 @@ class MotionViewSet(ModelViewSet): ) # Now send all changes to the clients. - inform_changed_data(motion, information=["State set to {arg1}", motion.state.name], user_id=request.user.pk) + inform_changed_data( + motion, + information=["State set to {arg1}", motion.state.name], + user_id=request.user.pk, + ) return Response({"detail": "Recommendation followed successfully."}) @@ -876,7 +896,7 @@ class MotionViewSet(ModelViewSet): # Fire autoupdate again to save information to OpenSlides history. inform_changed_data( - motion, information=["Vote created"], user_id=request.user.pk, + motion, information=["Vote created"], user_id=request.user.pk ) return Response( @@ -1249,7 +1269,9 @@ class CategoryViewSet(ModelViewSet): error_message = "Error: At least one identifier of this category does already exist in another category." response = Response({"detail": error_message}, status=400) else: - inform_changed_data(instances, information=["Number set"], user_id=request.user.pk) + inform_changed_data( + instances, information=["Number set"], user_id=request.user.pk + ) message = f"All motions in category {category} numbered " "successfully." response = Response({"detail": message}) return response @@ -1308,7 +1330,9 @@ class MotionBlockViewSet(ModelViewSet): ) # Fire autoupdate and save information to OpenSlides history. inform_changed_data( - motion, information=["State set to {arg1}", motion.state.name], user_id=request.user.pk + motion, + information=["State set to {arg1}", motion.state.name], + user_id=request.user.pk, ) return Response({"detail": "Followed recommendations successfully."}) diff --git a/openslides/utils/main.py b/openslides/utils/main.py index aa3b7a98e..8ec54eda2 100644 --- a/openslides/utils/main.py +++ b/openslides/utils/main.py @@ -315,7 +315,7 @@ def start_browser(browser_url: str) -> None: else: def function() -> None: - # TODO: Use a nonblocking sleep event here. Tornado has such features. + # TODO: Use a nonblocking sleep event here. time.sleep(1) browser.open(browser_url) diff --git a/openslides/utils/settings.py.tpl b/openslides/utils/settings.py.tpl index 7d20f5347..80db8277e 100644 --- a/openslides/utils/settings.py.tpl +++ b/openslides/utils/settings.py.tpl @@ -23,9 +23,6 @@ OPENSLIDES_USER_DATA_DIR = %(openslides_user_data_dir)s INSTALLED_PLUGINS += ( # 'plugin_module_name', - -# Built-in plugins: -# 'tests.example_data_generator', ) INSTALLED_APPS += INSTALLED_PLUGINS diff --git a/tests/conftest.py b/tests/conftest.py index 7da8b2965..165ad3a8c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +import os + import pytest from asgiref.sync import async_to_sync from django.test import TestCase, TransactionTestCase @@ -7,6 +9,10 @@ from pytest_django.plugin import validate_django_db from openslides.utils.cache import element_cache +# Set an environment variable to stop the startup command +os.environ["NO_STARTUP"] = "1" + + def pytest_collection_modifyitems(items): """ Helper until https://github.com/pytest-dev/pytest-django/issues/214 is fixed. diff --git a/tests/example_data_generator/management/commands/create-example-data.py b/tests/example_data_generator/management/commands/create-example-data.py index 6771387d6..1f93c978f 100644 --- a/tests/example_data_generator/management/commands/create-example-data.py +++ b/tests/example_data_generator/management/commands/create-example-data.py @@ -9,6 +9,7 @@ from django.utils.crypto import get_random_string from openslides.agenda.models import Item from openslides.assignments.models import Assignment +from openslides.core.apps import startup from openslides.motions.models import Motion from openslides.topics.models import Topic from openslides.users.models import Group, User @@ -117,6 +118,7 @@ class Command(BaseCommand): ) def handle(self, *args, **options): + startup() self.create_topics(options) self.create_motions(options) self.create_assignments(options)