From ebf686ef34d6a67a628a8f66e97df88b48bd59c6 Mon Sep 17 00:00:00 2001 From: Oskar Hahn Date: Sat, 14 Jan 2017 12:29:42 +0100 Subject: [PATCH 1/3] Send all data to the client at startup --- CHANGELOG | 2 ++ openslides/agenda/apps.py | 4 ++++ openslides/assignments/apps.py | 4 ++++ openslides/core/apps.py | 15 +++++++++++---- openslides/mediafiles/apps.py | 4 ++++ openslides/motions/apps.py | 5 +++++ openslides/topics/apps.py | 4 ++++ openslides/utils/autoupdate.py | 24 +++++++++++++++++++++++- openslides/utils/collection.py | 11 +++++++++++ 9 files changed, 68 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a03480ed2..5683c42d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -95,6 +95,8 @@ Other: - Added new caching system with support for Redis. - Support https as websocket protocol (wss). - Added migration path from 2.0. +- Add an api for apps to send data when the websocket connection is established. +- Used this api for all models expect of users to send all data to the client. Version 2.0 (2016-04-18) diff --git a/openslides/agenda/apps.py b/openslides/agenda/apps.py index 81e71f295..8c94160b0 100644 --- a/openslides/agenda/apps.py +++ b/openslides/agenda/apps.py @@ -35,3 +35,7 @@ class AgendaAppConfig(AppConfig): # Register viewsets. router.register(self.get_model('Item').get_collection_string(), ItemViewSet) + + def get_startup_elements(self): + from ..utils.collection import Collection + return [Collection(self.get_model('Item').get_collection_string())] diff --git a/openslides/assignments/apps.py b/openslides/assignments/apps.py index 6ce05de3a..6a796d687 100644 --- a/openslides/assignments/apps.py +++ b/openslides/assignments/apps.py @@ -24,3 +24,7 @@ class AssignmentsAppConfig(AppConfig): # Register viewsets. router.register(self.get_model('Assignment').get_collection_string(), AssignmentViewSet) router.register('assignments/poll', AssignmentPollViewSet) + + def get_startup_elements(self): + from ..utils.collection import Collection + return [Collection(self.get_model('Assignment').get_collection_string())] diff --git a/openslides/core/apps.py b/openslides/core/apps.py index c7dc9ceb7..3abd4e47a 100644 --- a/openslides/core/apps.py +++ b/openslides/core/apps.py @@ -14,10 +14,10 @@ class CoreAppConfig(AppConfig): # Import all required stuff. from django.db.models import signals - from openslides.core.config import config - from openslides.core.signals import post_permission_creation - from openslides.utils.rest_api import router - from openslides.utils.search import index_add_instance, index_del_instance + from .config import config + from .signals import post_permission_creation + from ..utils.rest_api import router + from ..utils.search import index_add_instance, index_del_instance from .config_variables import get_config_variables from .signals import delete_django_app_permissions from .views import ( @@ -55,3 +55,10 @@ class CoreAppConfig(AppConfig): signals.m2m_changed.connect( index_add_instance, dispatch_uid='m2m_index_add_instance') + + def get_startup_elements(self): + from .config import config + from ..utils.collection import Collection + for model in ('Projector', 'ChatMessage', 'Tag', 'ProjectorMessage', 'Countdown'): + yield Collection(self.get_model(model).get_collection_string()) + yield Collection(config.get_collection_string()) diff --git a/openslides/mediafiles/apps.py b/openslides/mediafiles/apps.py index 1732f1299..31d18c7e0 100644 --- a/openslides/mediafiles/apps.py +++ b/openslides/mediafiles/apps.py @@ -18,3 +18,7 @@ class MediafilesAppConfig(AppConfig): # Register viewsets. router.register(self.get_model('Mediafile').get_collection_string(), MediafileViewSet) + + def get_startup_elements(self): + from ..utils.collection import Collection + return [Collection(self.get_model('Mediafile').get_collection_string())] diff --git a/openslides/motions/apps.py b/openslides/motions/apps.py index e82732e31..da7487943 100644 --- a/openslides/motions/apps.py +++ b/openslides/motions/apps.py @@ -34,3 +34,8 @@ class MotionsAppConfig(AppConfig): router.register(self.get_model('MotionChangeRecommendation').get_collection_string(), MotionChangeRecommendationViewSet) router.register('motions/motionpoll', MotionPollViewSet) + + def get_startup_elements(self): + from ..utils.collection import Collection + for model in ('Category', 'Motion', 'MotionBlock', 'Workflow', 'MotionChangeRecommendation'): + yield Collection(self.get_model(model).get_collection_string()) diff --git a/openslides/topics/apps.py b/openslides/topics/apps.py index 15f37e93e..49eba7af8 100644 --- a/openslides/topics/apps.py +++ b/openslides/topics/apps.py @@ -18,3 +18,7 @@ class TopicsAppConfig(AppConfig): # Register viewsets. router.register(self.get_model('Topic').get_collection_string(), TopicViewSet) + + def get_startup_elements(self): + from ..utils.collection import Collection + return [Collection(self.get_model('Topic').get_collection_string())] diff --git a/openslides/utils/autoupdate.py b/openslides/utils/autoupdate.py index cf4dfebf0..33ae81f70 100644 --- a/openslides/utils/autoupdate.py +++ b/openslides/utils/autoupdate.py @@ -4,6 +4,7 @@ from collections import Iterable from asgiref.inmemory import ChannelLayer from channels import Channel, Group from channels.auth import channel_session_user, channel_session_user_from_http +from django.apps import apps from django.db import transaction from ..core.config import config @@ -19,12 +20,33 @@ def ws_add_site(message): Adds the websocket connection to a group specific to the connecting user. The group with the name 'user-None' stands for all anonymous users. + + Send all "starup-data" through the connection. """ Group('site').add(message.reply_channel) message.channel_session['user_id'] = message.user.id # Saves the reply channel to the user. Uses 0 for anonymous users. websocket_user_cache.add(message.user.id or 0, message.reply_channel.name) - message.reply_channel.send({"accept": True}) + + # Collect all elements that shoud be send to the client when the websocket + # connection is established + output = [] + for app in apps.get_app_configs(): + try: + # Get the method get_startup_elements() from an app. + # This method has to return an iterable of Collection objects. + get_startup_elements = app.get_startup_elements + except AttributeError: + # Skip apps that do not implement get_startup_elements + continue + for collection in get_startup_elements(): + output.extend(collection.as_autoupdate_for_user(message.user)) + + # Send all data. If there is no data, then onyl accept the connection + if output: + message.reply_channel.send({'text': json.dumps(output)}) + else: + message.reply_channel.send({"accept": True}) @channel_session_user diff --git a/openslides/utils/collection.py b/openslides/utils/collection.py index e56d4e788..697fa2f27 100644 --- a/openslides/utils/collection.py +++ b/openslides/utils/collection.py @@ -352,6 +352,17 @@ class Collection: output.append(content) return output + def as_autoupdate_for_user(self, user): + """ + Returns a list of dicts, that can be send though the websocket to a user. + """ + output = [] + for collection_element in self.element_generator(): + content = collection_element.as_autoupdate_for_user(user) + if content is not None: + output.append(content) + return output + def as_list_for_user(self, user): """ Returns a list of dictonaries to send them to a user, for example over From 481a36501f96d18d2a42d5ddd493a94e92d9f281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Norman=20J=C3=A4ckel?= Date: Sat, 14 Jan 2017 09:14:42 +0100 Subject: [PATCH 2/3] Refactored WhoAmI view and startup process. --- openslides/core/static/js/core/base.js | 58 +++++---------------- openslides/core/static/js/core/site.js | 19 +------ openslides/core/static/js/core/start.js | 64 ++++++++++++++++++++++++ openslides/users/access_permissions.py | 2 + openslides/users/static/js/users/base.js | 60 ---------------------- openslides/users/static/js/users/site.js | 22 -------- openslides/users/views.py | 11 +++- 7 files changed, 89 insertions(+), 147 deletions(-) create mode 100644 openslides/core/static/js/core/start.js diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index bed46f257..c30b81050 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -69,26 +69,25 @@ angular.module('OpenSlidesApp.core', [ } var websocketPath; - if (REALM == 'site') { + if (REALM === 'site') { websocketPath = '/ws/site/'; - } else if (REALM == 'projector') { + } else if (REALM === 'projector') { websocketPath = '/ws/projector/' + ProjectorID() + '/'; } else { console.error('The constant REALM is not set properly.'); } - var Autoupdate = { - messageReceivers: [], - onMessage: function (receiver) { - this.messageReceivers.push(receiver); - }, - reconnect: function () { - if (socket) { - socket.close(); - } + var Autoupdate = {}; + Autoupdate.messageReceivers = []; + Autoupdate.onMessage = function (receiver) { + Autoupdate.messageReceivers.push(receiver); + }; + Autoupdate.reconnect = function () { + if (socket) { + socket.close(); } }; - var newConnect = function () { + Autoupdate.newConnect = function () { socket = new WebSocket(websocketProtocol + '//' + location.host + websocketPath); clearInterval(recInterval); socket.onopen = function () { @@ -98,7 +97,7 @@ angular.module('OpenSlidesApp.core', [ $rootScope.connected = false; socket = null; recInterval = setInterval(function () { - newConnect(); + Autoupdate.newConnect(); }, 1000); }; socket.onmessage = function (event) { @@ -107,8 +106,6 @@ angular.module('OpenSlidesApp.core', [ }); }; }; - - newConnect(); return Autoupdate; } ]) @@ -301,37 +298,6 @@ angular.module('OpenSlidesApp.core', [ } ]) -.factory('loadGlobalData', [ - 'ChatMessage', - 'Config', - 'Projector', - 'ProjectorMessage', - 'Countdown', - function (ChatMessage, Config, Projector, ProjectorMessage, Countdown) { - return function () { - Config.findAll(); - - // Loads all projector data and the projectiondefaults - Projector.findAll(); - ProjectorMessage.findAll(); - Countdown.findAll(); - - // Loads all chat messages data and their user_ids - // TODO: add permission check if user has required chat permission - // error if include 'operator' here: - // "Circular dependency found: loadGlobalData <- operator <- loadGlobalData" - //if (operator.hasPerms("core.can_use_chat")) { - ChatMessage.findAll().then( function(chatmessages) { - angular.forEach(chatmessages, function (chatmessage) { - ChatMessage.loadRelations(chatmessage, 'user'); - }); - }); - //} - }; - } -]) - - // Template hooks .factory('templateHooks', [ diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index ee3276337..90a2aebef 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -80,7 +80,7 @@ angular.module('OpenSlidesApp.core.site', [ var that = this; this.scope = scope; this.updateMainMenu(); - operator.onOperatorChange(function () {that.updateMainMenu();}); + // TODO: operator.onOperatorChange(function () {that.updateMainMenu();}); }, updateMainMenu: function () { this.scope.elements = this.getElements(); @@ -100,15 +100,6 @@ angular.module('OpenSlidesApp.core.site', [ } ]) -// Load the global data when the operator changes -.run([ - 'loadGlobalData', - 'operator', - function (loadGlobalData, operator) { - operator.onOperatorChange(loadGlobalData); - } -]) - .run([ 'editableOptions', 'gettext', @@ -616,14 +607,6 @@ angular.module('OpenSlidesApp.core.site', [ } ]) -// Load the global data on startup -.run([ - 'loadGlobalData', - function(loadGlobalData) { - loadGlobalData(); - } -]) - // html-tag os-form-field to generate generic from fields // TODO: make it possible to use other fields then config fields .directive('osFormField', [ diff --git a/openslides/core/static/js/core/start.js b/openslides/core/static/js/core/start.js new file mode 100644 index 000000000..3bbe85344 --- /dev/null +++ b/openslides/core/static/js/core/start.js @@ -0,0 +1,64 @@ +(function () { + +'use strict'; + +angular.module('OpenSlidesApp.core.start', []) + +.run([ + '$http', + '$rootScope', + '$state', + 'autoupdate', + 'operator', + function($http, $rootScope, $state, autoupdate, operator) { + // Put the operator into the root scope + $http.get('/users/whoami/').success(function(data) { + $rootScope.guest_enabled = data.guest_enabled; + if (data.user_id === null && !data.guest_enabled) { + // Redirect to login dialog if user is not logged in. + $state.go('login', {guest_enabled: data.guest_enabled}); + } else { + autoupdate.newConnect(); + // TODO: Connect websocket + // Then operator.setUser(data.user_id, data.user); $rootScope.operator = operator; + } + }); + } +]) + +.factory('operator', [ + 'Group', + 'User', + function (User, Group) { + var operator = { + user: null, + perms: [], + isAuthenticated: function () { + return !!this.user; + }, + setUser: function(user_id, user_data) { + if (user_id && user_data) { + operator.user = User.inject(user_data); + operator.perms = operator.user.getPerms(); + } else { + operator.user = null; + operator.perms = Group.get(1).permissions; + } + }, + // Returns true if the operator has at least one perm of the perms-list. + hasPerms: function(perms) { + if (typeof perms === 'string') { + perms = perms.split(' '); + } + return _.intersection(perms, operator.perms).length > 0; + }, + // Returns true if the operator is a member of group. + isInGroup: function(group) { + return _.indexOf(operator.user.groups_id, group.id) > -1; + }, + }; + return operator; + } +]) + +}()); diff --git a/openslides/users/access_permissions.py b/openslides/users/access_permissions.py index e99b3713a..6c7225fc7 100644 --- a/openslides/users/access_permissions.py +++ b/openslides/users/access_permissions.py @@ -42,6 +42,8 @@ class UserAccessPermissions(BaseAccessPermissions): case = MANY_DATA else: case = LITTLE_DATA + elif user.pk == full_data.get('id'): + case = LITTLE_DATA else: case = NO_DATA diff --git a/openslides/users/static/js/users/base.js b/openslides/users/static/js/users/base.js index 79f9c5540..c08351892 100644 --- a/openslides/users/static/js/users/base.js +++ b/openslides/users/static/js/users/base.js @@ -4,66 +4,6 @@ angular.module('OpenSlidesApp.users', []) -.factory('operator', [ - 'User', - 'Group', - 'loadGlobalData', - 'autoupdate', - 'DS', - function (User, Group, loadGlobalData, autoupdate, DS) { - var operatorChangeCallbacks = [autoupdate.reconnect]; - var operator = { - user: null, - perms: [], - isAuthenticated: function () { - return !!this.user; - }, - onOperatorChange: function (func) { - operatorChangeCallbacks.push(func); - }, - setUser: function(user_id) { - if (user_id) { - User.find(user_id).then(function(user) { - operator.user = user; - // TODO: load only the needed groups - Group.findAll().then(function() { - operator.perms = user.getPerms(); - _.forEach(operatorChangeCallbacks, function (callback) { - callback(); - }); - }); - }); - } else { - operator.user = null; - operator.perms = []; - DS.clear(); - _.forEach(operatorChangeCallbacks, function (callback) { - callback(); - }); - Group.find(1).then(function(group) { - operator.perms = group.permissions; - _.forEach(operatorChangeCallbacks, function (callback) { - callback(); - }); - }); - } - }, - // Returns true if the operator has at least one perm of the perms-list. - hasPerms: function(perms) { - if (typeof perms == 'string') { - perms = perms.split(' '); - } - return _.intersection(perms, operator.perms).length > 0; - }, - // Returns true if the operator is a member of group. - isInGroup: function(group) { - return _.indexOf(operator.user.groups_id, group.id) > -1; - }, - }; - return operator; - } -]) - .factory('User', [ 'DS', 'Group', diff --git a/openslides/users/static/js/users/site.js b/openslides/users/static/js/users/site.js index 0ead12237..71060f38b 100644 --- a/openslides/users/static/js/users/site.js +++ b/openslides/users/static/js/users/site.js @@ -162,28 +162,6 @@ angular.module('OpenSlidesApp.users.site', [ } ]) -.run([ - 'operator', - '$rootScope', - '$http', - '$state', - 'Group', - function(operator, $rootScope, $http, $state, Group) { - // Put the operator into the root scope - $http.get('/users/whoami/').success(function(data) { - operator.setUser(data.user_id); - $rootScope.guest_enabled = data.guest_enabled; - if (data.user_id === null && !data.guest_enabled) { - // redirect to login dialog if use is not logged in - $state.go('login', {guest_enabled: data.guest_enabled}); - } - }); - $rootScope.operator = operator; - // Load all Groups. They are needed later - Group.findAll(); - } -]) - /* * Directive to check for permissions * diff --git a/openslides/users/views.py b/openslides/users/views.py index 93e8f23c4..e7c993f61 100644 --- a/openslides/users/views.py +++ b/openslides/users/views.py @@ -13,6 +13,7 @@ from ..utils.rest_api import ( detail_route, status, ) +from ..utils.collection import CollectionElement from ..utils.views import APIView from .access_permissions import GroupAccessPermissions, UserAccessPermissions from .models import Group, User @@ -234,10 +235,18 @@ class WhoAmIView(APIView): """ Appends the user id to the context. Uses None for the anonymous user. Appends also a flag if guest users are enabled in the config. + Appends also the serialized user if available. """ + user_id = self.request.user.pk + if self.request.user.pk is not None: + user_collection = CollectionElement.from_instance(self.request.user) + user_data = user_collection.as_dict_for_user(self.request.user) + else: + user_data = None return super().get_context_data( - user_id=self.request.user.pk, + user_id=user_id, guest_enabled=config['general_system_enable_anonymous'], + user=user_data, **context) From a6d1eeb9c38a8741aa2298f22c3d76c401c90182 Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Sat, 14 Jan 2017 13:02:26 +0100 Subject: [PATCH 3/3] Worked on startup process. - fix group view on reload --- CHANGELOG | 3 +- openslides/core/static/css/app.css | 25 +++- openslides/core/static/js/core/base.js | 52 ++++++-- openslides/core/static/js/core/projector.js | 11 +- openslides/core/static/js/core/site.js | 26 +--- openslides/core/static/js/core/start.js | 51 ++------ openslides/core/static/templates/index.html | 11 +- openslides/motions/static/js/motions/base.js | 4 +- openslides/motions/static/js/motions/site.js | 8 -- openslides/users/apps.py | 7 +- openslides/users/static/js/users/site.js | 118 ++++++++----------- openslides/users/views.py | 6 +- openslides/utils/autoupdate.py | 6 +- tests/integration/users/test_views.py | 11 +- 14 files changed, 157 insertions(+), 182 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5683c42d4..b66b4e883 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -95,8 +95,7 @@ Other: - Added new caching system with support for Redis. - Support https as websocket protocol (wss). - Added migration path from 2.0. -- Add an api for apps to send data when the websocket connection is established. -- Used this api for all models expect of users to send all data to the client. +- Accelerated startup process (send all data to the client after login). Version 2.0 (2016-04-18) diff --git a/openslides/core/static/css/app.css b/openslides/core/static/css/app.css index 342d250c4..995e630b0 100644 --- a/openslides/core/static/css/app.css +++ b/openslides/core/static/css/app.css @@ -129,6 +129,25 @@ img { margin: 0 auto 0 auto; } +#startup-overlay { + display: table; + background-color: #fff; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1000; +} +#startup-overlay h1 { + font-size: 56px; + text-align: center; +} +#startup-overlay > div { + display: table-cell; + vertical-align: middle; +} + /** Header **/ #header { float: left; @@ -138,12 +157,6 @@ img { color: #999; } -#header div.unconnected { - border: 1px solid red; - position: fixed; - width: 100%; - z-index: 1000; -} #header a.headerlink { text-decoration: none; } diff --git a/openslides/core/static/js/core/base.js b/openslides/core/static/js/core/base.js index c30b81050..1dea1621a 100644 --- a/openslides/core/static/js/core/base.js +++ b/openslides/core/static/js/core/base.js @@ -53,13 +53,12 @@ angular.module('OpenSlidesApp.core', [ .factory('autoupdate', [ 'DS', - '$rootScope', 'REALM', 'ProjectorID', - function (DS, $rootScope, REALM, ProjectorID) { + '$q', + function (DS, REALM, ProjectorID, $q) { var socket = null; var recInterval = null; - $rootScope.connected = false; var websocketProtocol; if (location.protocol == 'https:') { @@ -79,6 +78,8 @@ angular.module('OpenSlidesApp.core', [ var Autoupdate = {}; Autoupdate.messageReceivers = []; + // We use later a promise to defer the first message of the established ws connection. + Autoupdate.firstMessageDeferred = $q.defer(); Autoupdate.onMessage = function (receiver) { Autoupdate.messageReceivers.push(receiver); }; @@ -90,11 +91,7 @@ angular.module('OpenSlidesApp.core', [ Autoupdate.newConnect = function () { socket = new WebSocket(websocketProtocol + '//' + location.host + websocketPath); clearInterval(recInterval); - socket.onopen = function () { - $rootScope.connected = true; - }; socket.onclose = function () { - $rootScope.connected = false; socket = null; recInterval = setInterval(function () { Autoupdate.newConnect(); @@ -104,12 +101,50 @@ angular.module('OpenSlidesApp.core', [ _.forEach(Autoupdate.messageReceivers, function (receiver) { receiver(event.data); }); + // The first message is done: resolve the promise. + // TODO: check whether the promise is already resolved. + Autoupdate.firstMessageDeferred.resolve(); }; }; return Autoupdate; } ]) +.factory('operator', [ + 'User', + 'Group', + function (User, Group) { + var operator = { + user: null, + perms: [], + isAuthenticated: function () { + return !!this.user; + }, + setUser: function(user_id, user_data) { + if (user_id && user_data) { + operator.user = User.inject(user_data); + operator.perms = operator.user.getPerms(); + } else { + operator.user = null; + operator.perms = Group.get(1).permissions; + } + }, + // Returns true if the operator has at least one perm of the perms-list. + hasPerms: function(perms) { + if (typeof perms === 'string') { + perms = perms.split(' '); + } + return _.intersection(perms, operator.perms).length > 0; + }, + // Returns true if the operator is a member of group. + isInGroup: function(group) { + return _.indexOf(operator.user.groups_id, group.id) > -1; + }, + }; + return operator; + } +]) + // gets all in OpenSlides available languages .factory('Languages', [ 'gettext', @@ -227,7 +262,7 @@ angular.module('OpenSlidesApp.core', [ var deletedElements = []; var collectionString = key; _.forEach(list, function(data) { - // uncomment this line for debugging to log all autoupdates: + // Uncomment this line for debugging to log all autoupdates: // console.log("Received object: " + data.collection + ", " + data.id); // remove (=eject) object from local DS store @@ -299,7 +334,6 @@ angular.module('OpenSlidesApp.core', [ ]) // Template hooks - .factory('templateHooks', [ function () { var hooks = {}; diff --git a/openslides/core/static/js/core/projector.js b/openslides/core/static/js/core/projector.js index 4e7bbb61d..264bd19a6 100644 --- a/openslides/core/static/js/core/projector.js +++ b/openslides/core/static/js/core/projector.js @@ -8,6 +8,13 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core']) // Can be used to find out if the projector or the side is used .constant('REALM', 'projector') +.run([ + 'autoupdate', + function (autoupdate) { + autoupdate.newConnect(); + } +]) + // Provider to register slides in a .config() statement. .provider('slides', [ function() { @@ -84,10 +91,8 @@ angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core']) '$scope', '$location', 'gettext', - 'loadGlobalData', 'Projector', - function($scope, $location, gettext, loadGlobalData, Projector) { - loadGlobalData(); + function($scope, $location, gettext, Projector) { $scope.error = ''; // watch for changes in Projector diff --git a/openslides/core/static/js/core/site.js b/openslides/core/static/js/core/site.js index 90a2aebef..2196f7833 100644 --- a/openslides/core/static/js/core/site.js +++ b/openslides/core/static/js/core/site.js @@ -5,6 +5,7 @@ // The core module for the OpenSlides site angular.module('OpenSlidesApp.core.site', [ 'OpenSlidesApp.core', + 'OpenSlidesApp.core.start', 'OpenSlidesApp.poll.majority', 'ui.router', 'angular-loading-bar', @@ -77,10 +78,7 @@ angular.module('OpenSlidesApp.core.site', [ this.$get = ['operator', function(operator) { return { registerScope: function (scope) { - var that = this; this.scope = scope; - this.updateMainMenu(); - // TODO: operator.onOperatorChange(function () {that.updateMainMenu();}); }, updateMainMenu: function () { this.scope.elements = this.getElements(); @@ -660,28 +658,6 @@ angular.module('OpenSlidesApp.core.site', [ } ]) -.directive('routeLoadingIndicator', [ - '$rootScope', - '$state', - 'gettext', - function($rootScope, $state, gettext) { - gettext('Loading ...'); - return { - restrict: 'E', - template: "

Loading ...

", - link: function(scope, elem, attrs) { - scope.isRouteLoading = false; - $rootScope.$on('$stateChangeStart', function() { - scope.isRouteLoading = true; - }); - $rootScope.$on('$stateChangeSuccess', function() { - scope.isRouteLoading = false; - }); - } - }; - } -]) - /* This directive provides a csv import template. * Papa Parse is used to parse the csv file. Accepted attributes: * * change: diff --git a/openslides/core/static/js/core/start.js b/openslides/core/static/js/core/start.js index 3bbe85344..31586d133 100644 --- a/openslides/core/static/js/core/start.js +++ b/openslides/core/static/js/core/start.js @@ -10,8 +10,10 @@ angular.module('OpenSlidesApp.core.start', []) '$state', 'autoupdate', 'operator', - function($http, $rootScope, $state, autoupdate, operator) { - // Put the operator into the root scope + 'Group', + 'mainMenu', + function($http, $rootScope, $state, autoupdate, operator, Group, mainMenu) { + $rootScope.startupWaitingEnabled = true; $http.get('/users/whoami/').success(function(data) { $rootScope.guest_enabled = data.guest_enabled; if (data.user_id === null && !data.guest_enabled) { @@ -19,46 +21,15 @@ angular.module('OpenSlidesApp.core.start', []) $state.go('login', {guest_enabled: data.guest_enabled}); } else { autoupdate.newConnect(); - // TODO: Connect websocket - // Then operator.setUser(data.user_id, data.user); $rootScope.operator = operator; + autoupdate.firstMessageDeferred.promise.then(function () { + operator.setUser(data.user_id, data.user); + $rootScope.operator = operator; + mainMenu.updateMainMenu(); + $rootScope.startupWaitingEnabled = false; + }); } }); } -]) - -.factory('operator', [ - 'Group', - 'User', - function (User, Group) { - var operator = { - user: null, - perms: [], - isAuthenticated: function () { - return !!this.user; - }, - setUser: function(user_id, user_data) { - if (user_id && user_data) { - operator.user = User.inject(user_data); - operator.perms = operator.user.getPerms(); - } else { - operator.user = null; - operator.perms = Group.get(1).permissions; - } - }, - // Returns true if the operator has at least one perm of the perms-list. - hasPerms: function(perms) { - if (typeof perms === 'string') { - perms = perms.split(' '); - } - return _.intersection(perms, operator.perms).length > 0; - }, - // Returns true if the operator is a member of group. - isInGroup: function(group) { - return _.indexOf(operator.user.groups_id, group.id) > -1; - }, - }; - return operator; - } -]) +]); }()); diff --git a/openslides/core/static/templates/index.html b/openslides/core/static/templates/index.html index 14bcab87c..b2318cec7 100644 --- a/openslides/core/static/templates/index.html +++ b/openslides/core/static/templates/index.html @@ -20,9 +20,15 @@
+ +
+
+

+
+
+