diff --git a/src/c3nav/control/__init__.py b/src/c3nav/control/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/c3nav/control/admin.py b/src/c3nav/control/admin.py new file mode 100644 index 00000000..4026b14b --- /dev/null +++ b/src/c3nav/control/admin.py @@ -0,0 +1,24 @@ +from django.contrib import admin +from django.contrib.auth.admin import UserAdmin as BaseUserAdmin +from django.contrib.auth.models import User +from django.utils.translation import ugettext_lazy as _ + +from c3nav.control.models import UserPermissions + + +class UserPermissionsInline(admin.StackedInline): + model = UserPermissions + can_delete = False + + +class UserAdmin(BaseUserAdmin): + fieldsets = ( + (None, {'fields': ('username', 'password', 'email')}), + (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser')}), + (_('Important dates'), {'fields': ('last_login', 'date_joined')}), + ) + inlines = (UserPermissionsInline, ) + + +admin.site.unregister(User) +admin.site.register(User, UserAdmin) diff --git a/src/c3nav/control/migrations/0001_initial.py b/src/c3nav/control/migrations/0001_initial.py new file mode 100644 index 00000000..deac31ec --- /dev/null +++ b/src/c3nav/control/migrations/0001_initial.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.7 on 2017-12-08 13:33 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='UserPermissions', + fields=[ + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='permissions', serialize=False, to=settings.AUTH_USER_MODEL)), + ('review_changesets', models.BooleanField(default=False, verbose_name='can review changesets')), + ('direct_edit', models.BooleanField(default=False, verbose_name='can activate direct editing')), + ('control_panel', models.BooleanField(default=False, verbose_name='can access control panel')), + ('grant_permissions', models.BooleanField(default=False, verbose_name='can grant control permissions')), + ('manage_announcements', models.BooleanField(default=False, verbose_name='manage announcements')), + ], + options={ + 'verbose_name': 'User Permissions', + 'verbose_name_plural': 'User Permissions', + 'default_related_name': 'permissions', + }, + ), + ] diff --git a/src/c3nav/control/migrations/__init__.py b/src/c3nav/control/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/c3nav/control/models.py b/src/c3nav/control/models.py new file mode 100644 index 00000000..4990c2d1 --- /dev/null +++ b/src/c3nav/control/models.py @@ -0,0 +1,45 @@ +from django.conf import settings +from django.core.cache import cache +from django.db import models +from django.utils.translation import ugettext_lazy as _ + + +class UserPermissions(models.Model): + """ + User Permissions + """ + user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True) + review_changesets = models.BooleanField(default=False, verbose_name=_('can review changesets')) + direct_edit = models.BooleanField(default=False, verbose_name=_('can activate direct editing')) + control_panel = models.BooleanField(default=False, verbose_name=_('can access control panel')) + grant_permissions = models.BooleanField(default=False, verbose_name=_('can grant control permissions')) + manage_announcements = models.BooleanField(default=False, verbose_name=_('manage announcements')) + + class Meta: + verbose_name = _('User Permissions') + verbose_name_plural = _('User Permissions') + default_related_name = 'permissions' + + @staticmethod + def get_cache_key(pk): + return 'control:permissions:%d' % pk + + @classmethod + def get_for_user(cls, user, force=False) -> 'UserPermissions': + cache_key = cls.get_cache_key(user.pk) + result = None + if not force: + result = cache.get(cache_key, None) + for field in cls._meta.get_fields(): + if not hasattr(result, field.attname): + result = None + break + if result: + return result + result = user.permissions + cache.set(cache_key, result, 900) + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + cache_key = self.get_cache_key(self.pk) + cache.set(cache_key, self, 900) diff --git a/src/c3nav/control/urls.py b/src/c3nav/control/urls.py new file mode 100644 index 00000000..dfd5e4bc --- /dev/null +++ b/src/c3nav/control/urls.py @@ -0,0 +1,6 @@ +# from django.conf.urls import url + + +urlpatterns = [ + # url(r'^register$', register_view, name='control.index'), +] diff --git a/src/c3nav/control/views.py b/src/c3nav/control/views.py new file mode 100644 index 00000000..e69de29b diff --git a/src/c3nav/editor/migrations/0020_remove_permissions.py b/src/c3nav/editor/migrations/0020_remove_permissions.py new file mode 100644 index 00000000..2e4048cb --- /dev/null +++ b/src/c3nav/editor/migrations/0020_remove_permissions.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.7 on 2017-12-08 13:35 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('editor', '0019_permissions'), + ] + + operations = [ + migrations.AlterModelOptions( + name='changeset', + options={'verbose_name': 'Change Set', 'verbose_name_plural': 'Change Sets'}, + ), + ] diff --git a/src/c3nav/editor/models/changeset.py b/src/c3nav/editor/models/changeset.py index 51f59faf..4b317dbd 100644 --- a/src/c3nav/editor/models/changeset.py +++ b/src/c3nav/editor/models/changeset.py @@ -17,6 +17,7 @@ from django.utils.timezone import make_naive from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ungettext_lazy +from c3nav.control.models import UserPermissions from c3nav.editor.models.changedobject import ApplyToInstanceError, ChangedObject from c3nav.editor.wrappers import ModelInstanceWrapper, ModelWrapper, is_created_pk from c3nav.mapdata.models import LocationSlug, MapUpdate @@ -56,11 +57,6 @@ class ChangeSet(models.Model): verbose_name_plural = _('Change Sets') default_related_name = 'changesets' - permissions = ( - ('review_changeset', _('Can review change sets')), - ('direct_edit', _('Can use direct edit')), - ) - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.changed_objects = None @@ -491,12 +487,11 @@ class ChangeSet(models.Model): return self.author_id == request.user.pk and self.state in ('proposed', 'reproposed') def can_review(self, request): - return request.user.has_perm('editor.review_changeset') + return UserPermissions.get_for_user(request.user).review_changesets @classmethod def can_direct_edit(cls, request): - print(request.user.has_perm('editor.direct_edit')) - return request.user.has_perm('editor.direct_edit') + return UserPermissions.get_for_user(request.user).direct_edit def can_start_review(self, request): return self.can_review(request) and self.state in ('proposed', 'reproposed') diff --git a/src/c3nav/settings.py b/src/c3nav/settings.py index 6ebec07d..5fbe9dd2 100644 --- a/src/c3nav/settings.py +++ b/src/c3nav/settings.py @@ -189,6 +189,7 @@ INSTALLED_APPS = [ 'c3nav.mapdata', 'c3nav.routing', 'c3nav.site', + 'c3nav.control', 'c3nav.editor', ] diff --git a/src/c3nav/urls.py b/src/c3nav/urls.py index d6047a75..66399054 100644 --- a/src/c3nav/urls.py +++ b/src/c3nav/urls.py @@ -5,6 +5,7 @@ from django.conf.urls import include, url from django.contrib import admin import c3nav.api.urls +import c3nav.control.urls import c3nav.editor.urls import c3nav.mapdata.urls import c3nav.site.urls @@ -14,6 +15,7 @@ urlpatterns = [ url(r'^api/', include(c3nav.api.urls, namespace='api')), url(r'^map/', include(c3nav.mapdata.urls)), url(r'^admin/', admin.site.urls), + url(r'^control/', include(c3nav.control.urls)), url(r'^locales/', include('django.conf.urls.i18n')), url(r'^', include(c3nav.site.urls)), ]