diff --git a/.travis.yml b/.travis.yml index 83b540317..d9c90f81c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,7 @@ before_install: install: - pip install --upgrade setuptools - pip install --upgrade --requirement requirements.txt + - pip freeze - npm install - node_modules/.bin/gulp --production script: diff --git a/CHANGELOG b/CHANGELOG index 78e4f041e..f39077aa6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -99,6 +99,8 @@ Other: - Support https as websocket protocol (wss). - Added migration path from 2.0. - Accelerated startup process (send all data to the client after login). +- Added function utils.auth.anonymous_is_enabled which returns true, if it is. +- Changed has_perm to support an user id or None (for anyonmous) as first argument. Version 2.0 (2016-04-18) diff --git a/openslides/core/access_permissions.py b/openslides/core/access_permissions.py index 9ecbd37c0..685979d1f 100644 --- a/openslides/core/access_permissions.py +++ b/openslides/core/access_permissions.py @@ -1,5 +1,5 @@ from ..utils.access_permissions import BaseAccessPermissions -from ..utils.auth import DjangoAnonymousUser, has_perm +from ..utils.auth import DjangoAnonymousUser, anonymous_is_enabled, has_perm class ProjectorAccessPermissions(BaseAccessPermissions): @@ -29,11 +29,9 @@ class TagAccessPermissions(BaseAccessPermissions): """ Returns True if the user has read access model instances. """ - from .config import config - # Every authenticated user can retrieve tags. Anonymous users can do # so if they are enabled. - return not isinstance(user, DjangoAnonymousUser) or config['general_system_enable_anonymous'] + return not isinstance(user, DjangoAnonymousUser) or anonymous_is_enabled() def get_serializer_class(self, user=None): """ @@ -112,11 +110,9 @@ class ConfigAccessPermissions(BaseAccessPermissions): """ Returns True if the user has read access model instances. """ - from .config import config - # Every authenticated user can see the metadata and list or retrieve # the config. Anonymous users can do so if they are enabled. - return not isinstance(user, DjangoAnonymousUser) or config['general_system_enable_anonymous'] + return not isinstance(user, DjangoAnonymousUser) or anonymous_is_enabled() def get_full_data(self, instance): """ diff --git a/openslides/core/views.py b/openslides/core/views.py index 48f3f7be3..9c27645cf 100644 --- a/openslides/core/views.py +++ b/openslides/core/views.py @@ -17,6 +17,7 @@ from django.utils.translation import ugettext as _ from .. import __version__ as version from ..utils import views as utils_views +from ..utils.auth import anonymous_is_enabled from ..utils.autoupdate import inform_changed_data, inform_deleted_data from ..utils.collection import Collection, CollectionElement from ..utils.plugins import ( @@ -573,7 +574,7 @@ class TagViewSet(ModelViewSet): elif self.action == 'metadata': # Every authenticated user can see the metadata. # Anonymous users can do so if they are enabled. - result = self.request.user.is_authenticated() or config['general_system_enable_anonymous'] + result = self.request.user.is_authenticated() or anonymous_is_enabled() elif self.action in ('create', 'update', 'destroy'): result = self.request.user.has_perm('core.can_manage_tags') else: @@ -630,7 +631,7 @@ class ConfigViewSet(ViewSet): # Every authenticated user can see the metadata and list or # retrieve the config. Anonymous users can do so if they are # enabled. - result = self.request.user.is_authenticated() or config['general_system_enable_anonymous'] + result = self.request.user.is_authenticated() or anonymous_is_enabled() elif self.action == 'update': result = self.request.user.has_perm('core.can_manage_config') else: diff --git a/openslides/users/access_permissions.py b/openslides/users/access_permissions.py index 6c7225fc7..373b9f356 100644 --- a/openslides/users/access_permissions.py +++ b/openslides/users/access_permissions.py @@ -1,5 +1,5 @@ from ..utils.access_permissions import BaseAccessPermissions -from ..utils.auth import DjangoAnonymousUser, has_perm +from ..utils.auth import DjangoAnonymousUser, anonymous_is_enabled, has_perm class UserAccessPermissions(BaseAccessPermissions): @@ -90,14 +90,12 @@ class GroupAccessPermissions(BaseAccessPermissions): """ Returns True if the user has read access model instances. """ - from ..core.config import config - # Every authenticated user can retrieve groups. Anonymous users can do # so if they are enabled. # Our AnonymousUser is a subclass of the DjangoAnonymousUser. Normaly, a # DjangoAnonymousUser means, that AnonymousUser is disabled. But this is # no garanty. send_data uses the AnonymousUser in any case. - return not isinstance(user, DjangoAnonymousUser) or config['general_system_enable_anonymous'] + return not isinstance(user, DjangoAnonymousUser) or anonymous_is_enabled() def get_serializer_class(self, user=None): """ diff --git a/openslides/users/views.py b/openslides/users/views.py index b3990e6a4..9194acf2b 100644 --- a/openslides/users/views.py +++ b/openslides/users/views.py @@ -5,6 +5,7 @@ from django.utils.encoding import force_text from django.utils.translation import ugettext as _ from ..core.config import config +from ..utils.auth import anonymous_is_enabled from ..utils.collection import CollectionElement from ..utils.rest_api import ( ModelViewSet, @@ -137,7 +138,7 @@ class GroupViewSet(ModelViewSet): elif self.action == 'metadata': # Every authenticated user can see the metadata. # Anonymous users can do so if they are enabled. - result = self.request.user.is_authenticated() or config['general_system_enable_anonymous'] + result = self.request.user.is_authenticated() or anonymous_is_enabled() elif self.action in ('create', 'partial_update', 'update', 'destroy'): # Users with all app permissions can edit groups. result = (self.request.user.has_perm('users.can_see_name') and @@ -247,7 +248,7 @@ class WhoAmIView(APIView): user_data = None return super().get_context_data( user_id=user_id, - guest_enabled=config['general_system_enable_anonymous'], + guest_enabled=anonymous_is_enabled(), user=user_data, **context) diff --git a/openslides/utils/auth.py b/openslides/utils/auth.py index 33e505355..16a017ae9 100644 --- a/openslides/utils/auth.py +++ b/openslides/utils/auth.py @@ -62,12 +62,11 @@ class RESTFrameworkAnonymousAuthentication(BaseAuthentication): Authentication class for the Django REST framework. Sets the user to the our AnonymousUser but only if - general_system_enable_anonymous is set to True in the config. + anonymous user is enabled in the config. """ def authenticate(self, request): - from ..core.config import config - if config['general_system_enable_anonymous']: + if anonymous_is_enabled(): return (AnonymousUser(), None) return None @@ -99,13 +98,12 @@ def get_user(request): This is a mix of django.contrib.auth.get_user and django.contrib.auth.middleware.get_user which uses our anonymous user. """ - from ..core.config import config try: return_user = request._cached_user except AttributeError: # Get the user. If it is a DjangoAnonymousUser, then use our AnonymousUser return_user = _get_user(request) - if config['general_system_enable_anonymous'] and isinstance(return_user, DjangoAnonymousUser): + if anonymous_is_enabled() and isinstance(return_user, DjangoAnonymousUser): return_user = AnonymousUser() request._cached_user = return_user return return_user @@ -114,7 +112,18 @@ def get_user(request): def has_perm(user, perm): """ Checks that user has a specific permission. + + User can be an user object, an user id None (for anonymous) or a + CollectionElement for a user. """ + # First, convert a user id or None to an anonymous user or an CollectionElement + if user is None and anonymous_is_enabled(): + user = AnonymousUser() + elif user is None: + user = DjangoAnonymousUser() + elif isinstance(user, int): + user = CollectionElement.from_values('users/user', user) + if isinstance(user, AnonymousUser): # Our anonymous user has a has_perm-method that works with the cache # system. So we can use it here. @@ -142,3 +151,8 @@ def has_perm(user, perm): else: has_perm = False return has_perm + + +def anonymous_is_enabled(): + from ..core.config import config + return config['general_system_enable_anonymous'] diff --git a/openslides/utils/autoupdate.py b/openslides/utils/autoupdate.py index d66477973..cccda00b7 100644 --- a/openslides/utils/autoupdate.py +++ b/openslides/utils/autoupdate.py @@ -9,7 +9,7 @@ from django.db import transaction from ..core.config import config from ..core.models import Projector -from .auth import AnonymousUser +from .auth import AnonymousUser, anonymous_is_enabled from .cache import websocket_user_cache from .collection import Collection, CollectionElement, CollectionElementList @@ -40,7 +40,7 @@ def ws_add_site(message): # 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)) + output.extend(collection.as_autoupdate_for_user(message.user.id)) # Send all data. If there is no data, then only accept the connection if output: @@ -66,7 +66,7 @@ def ws_add_projector(message, projector_id): """ user = message.user # user is the django anonymous user. We have our own. - if user.is_anonymous and config['general_system_enable_anonymous']: + if user.is_anonymous and anonymous_is_enabled(): user = AnonymousUser() if not user.has_perm('core.can_see_projector'): diff --git a/openslides/utils/collection.py b/openslides/utils/collection.py index 697fa2f27..8a0655fb4 100644 --- a/openslides/utils/collection.py +++ b/openslides/utils/collection.py @@ -117,6 +117,9 @@ class CollectionElement: """ Returns a dict that can be sent through the autoupdate system for a site user. + + The argument `user` can be anything, that is allowd as argument for + utils.auth.has_perm(). """ return self.as_autoupdate( 'get_restricted_data', @@ -133,6 +136,9 @@ class CollectionElement: def as_dict_for_user(self, user): """ Returns a dict with the data for a user. Can be used for the rest api. + + The argument `user` can be anything, that is allowd as argument for + utils.auth.has_perm(). """ return self.get_access_permissions().get_restricted_data( self.get_full_data(), @@ -259,6 +265,9 @@ class CollectionElementList(list): def as_autoupdate_for_user(self, user): """ Returns a list of dicts, that can be send though the websocket to a user. + + The argument `user` can be anything, that is allowd as argument for + utils.auth.has_perm(). """ result = [] for element in self: @@ -355,6 +364,9 @@ class Collection: def as_autoupdate_for_user(self, user): """ Returns a list of dicts, that can be send though the websocket to a user. + + The argument `user` can be anything, that is allowd as argument for + utils.auth.has_perm(). """ output = [] for collection_element in self.element_generator(): @@ -367,6 +379,9 @@ class Collection: """ Returns a list of dictonaries to send them to a user, for example over the rest api. + + The argument `user` can be anything, that is allowd as argument for + utils.auth.has_perm(). """ output = [] for collection_element in self.element_generator():