Add support for blocking the changing of password for specify users.
Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -118,6 +118,7 @@
|
|||||||
- Interpret ALLOWED_HOSTS as YAML.
|
- Interpret ALLOWED_HOSTS as YAML.
|
||||||
- Don't show the document types of an index instance.
|
- Don't show the document types of an index instance.
|
||||||
- Add the tag created and tag edited events.
|
- Add the tag created and tag edited events.
|
||||||
|
- Add support for blocking the changing of password for specify users.
|
||||||
|
|
||||||
3.0.3 (2018-08-17)
|
3.0.3 (2018-08-17)
|
||||||
==================
|
==================
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ from navigation import Link
|
|||||||
from .icons import icon_logout, icon_password_change
|
from .icons import icon_logout, icon_password_change
|
||||||
|
|
||||||
|
|
||||||
def has_usable_password(context):
|
def has_usable_password_and_can_change_password(context):
|
||||||
return context['request'].user.has_usable_password
|
return (
|
||||||
|
context['request'].user.has_usable_password and
|
||||||
|
not context['request'].user.user_options.block_password_change
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
link_logout = Link(
|
link_logout = Link(
|
||||||
@@ -16,6 +19,7 @@ link_logout = Link(
|
|||||||
text=_('Logout'), view='authentication:logout_view'
|
text=_('Logout'), view='authentication:logout_view'
|
||||||
)
|
)
|
||||||
link_password_change = Link(
|
link_password_change = Link(
|
||||||
condition=has_usable_password, icon_class=icon_password_change,
|
condition=has_usable_password_and_can_change_password,
|
||||||
text=_('Change password'), view='authentication:password_change_view'
|
icon_class=icon_password_change, text=_('Change password'),
|
||||||
|
view='authentication:password_change_view'
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
from django.contrib.auth import REDIRECT_FIELD_NAME, get_user_model
|
||||||
from django.contrib.auth.views import (
|
from django.contrib.auth.views import (
|
||||||
login, password_change, password_reset, password_reset_confirm,
|
login, password_change, password_reset, password_reset_confirm,
|
||||||
password_reset_complete, password_reset_done
|
password_reset_complete, password_reset_done
|
||||||
)
|
)
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import redirect, resolve_url
|
from django.shortcuts import redirect, resolve_url
|
||||||
|
from django.template.loader import render_to_string
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.http import is_safe_url
|
from django.utils.http import is_safe_url
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
@@ -77,6 +78,14 @@ def password_change_view(request):
|
|||||||
"""
|
"""
|
||||||
extra_context = {'title': _('Current user password change')}
|
extra_context = {'title': _('Current user password change')}
|
||||||
|
|
||||||
|
if request.user.user_options.block_password_change:
|
||||||
|
messages.error(
|
||||||
|
request, _(
|
||||||
|
'Changing the password is not allowed for this account.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(reverse(settings.HOME_VIEW))
|
||||||
|
|
||||||
return password_change(
|
return password_change(
|
||||||
request, extra_context=extra_context,
|
request, extra_context=extra_context,
|
||||||
template_name='appearance/generic_form.html',
|
template_name='appearance/generic_form.html',
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db.models.signals import post_save
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from acls import ModelPermission
|
from acls import ModelPermission
|
||||||
@@ -14,12 +15,13 @@ from metadata import MetadataLookup
|
|||||||
from navigation import SourceColumn
|
from navigation import SourceColumn
|
||||||
from rest_api.fields import DynamicSerializerField
|
from rest_api.fields import DynamicSerializerField
|
||||||
|
|
||||||
|
from .handlers import handler_initialize_new_user_options
|
||||||
from .links import (
|
from .links import (
|
||||||
link_group_add, link_group_delete, link_group_edit, link_group_list,
|
link_group_add, link_group_delete, link_group_edit, link_group_list,
|
||||||
link_group_members, link_group_setup, link_user_add, link_user_delete,
|
link_group_members, link_group_setup, link_user_add, link_user_delete,
|
||||||
link_user_edit, link_user_groups, link_user_list,
|
link_user_edit, link_user_groups, link_user_list,
|
||||||
link_user_multiple_delete, link_user_multiple_set_password,
|
link_user_multiple_delete, link_user_multiple_set_password,
|
||||||
link_user_set_password, link_user_setup
|
link_user_set_options, link_user_set_password, link_user_setup
|
||||||
)
|
)
|
||||||
from .permissions import (
|
from .permissions import (
|
||||||
permission_group_delete, permission_group_edit,
|
permission_group_delete, permission_group_edit,
|
||||||
@@ -116,12 +118,13 @@ class UserManagementApp(MayanAppConfig):
|
|||||||
sources=(Group,)
|
sources=(Group,)
|
||||||
)
|
)
|
||||||
menu_object.bind_links(
|
menu_object.bind_links(
|
||||||
links=(link_acl_list, link_group_delete,), position=99, sources=(Group,)
|
links=(link_acl_list, link_group_delete,), position=99,
|
||||||
|
sources=(Group,)
|
||||||
)
|
)
|
||||||
menu_object.bind_links(
|
menu_object.bind_links(
|
||||||
links=(
|
links=(
|
||||||
link_user_edit, link_user_set_password, link_user_groups,
|
link_user_edit, link_user_set_password, link_user_groups,
|
||||||
link_acl_list, link_user_delete
|
link_user_set_options, link_acl_list, link_user_delete
|
||||||
), sources=(User,)
|
), sources=(User,)
|
||||||
)
|
)
|
||||||
menu_secondary.bind_links(
|
menu_secondary.bind_links(
|
||||||
@@ -140,5 +143,10 @@ class UserManagementApp(MayanAppConfig):
|
|||||||
)
|
)
|
||||||
menu_setup.bind_links(links=(link_user_setup, link_group_setup))
|
menu_setup.bind_links(links=(link_user_setup, link_group_setup))
|
||||||
|
|
||||||
|
post_save.connect(
|
||||||
|
dispatch_uid='user_management_handler_initialize_new_user_options',
|
||||||
|
receiver=handler_initialize_new_user_options,
|
||||||
|
sender=User
|
||||||
|
)
|
||||||
registry.register(Group)
|
registry.register(Group)
|
||||||
registry.register(User)
|
registry.register(User)
|
||||||
|
|||||||
@@ -6,5 +6,7 @@ from django.contrib.auth import get_user_model
|
|||||||
|
|
||||||
class UserForm(forms.ModelForm):
|
class UserForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
fields = (
|
||||||
|
'username', 'first_name', 'last_name', 'email', 'is_active',
|
||||||
|
)
|
||||||
model = get_user_model()
|
model = get_user_model()
|
||||||
fields = ('username', 'first_name', 'last_name', 'email', 'is_active',)
|
|
||||||
|
|||||||
12
mayan/apps/user_management/handlers.py
Normal file
12
mayan/apps/user_management/handlers.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
|
|
||||||
|
|
||||||
|
def handler_initialize_new_user_options(sender, instance, **kwargs):
|
||||||
|
UserOptions = apps.get_model(
|
||||||
|
app_label='user_management', model_name='UserOptions'
|
||||||
|
)
|
||||||
|
|
||||||
|
if kwargs['created']:
|
||||||
|
UserOptions.objects.create(user=instance)
|
||||||
@@ -63,6 +63,10 @@ link_user_multiple_set_password = Link(
|
|||||||
permissions=(permission_user_edit,), text=_('Set password'),
|
permissions=(permission_user_edit,), text=_('Set password'),
|
||||||
view='user_management:user_multiple_set_password'
|
view='user_management:user_multiple_set_password'
|
||||||
)
|
)
|
||||||
|
link_user_set_options = Link(
|
||||||
|
args='object.id', permissions=(permission_user_edit,),
|
||||||
|
text=_('User options'), view='user_management:user_options',
|
||||||
|
)
|
||||||
link_user_set_password = Link(
|
link_user_set_password = Link(
|
||||||
args='object.id', permissions=(permission_user_edit,),
|
args='object.id', permissions=(permission_user_edit,),
|
||||||
text=_('Set password'), view='user_management:user_set_password',
|
text=_('Set password'), view='user_management:user_set_password',
|
||||||
|
|||||||
55
mayan/apps/user_management/migrations/0001_initial.py
Normal file
55
mayan/apps/user_management/migrations/0001_initial.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.11 on 2018-08-26 10:01
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
def add_user_options_to_existing_users(apps, schema_editor):
|
||||||
|
User = apps.get_model(settings.AUTH_USER_MODEL)
|
||||||
|
UserOptions = apps.get_model(
|
||||||
|
app_label='user_management', model_name='UserOptions'
|
||||||
|
)
|
||||||
|
|
||||||
|
for user in User.objects.all():
|
||||||
|
UserOptions.objects.create(user=user)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_user_options_from_existing_users(apps, schema_editor):
|
||||||
|
User = apps.get_model(settings.AUTH_USER_MODEL)
|
||||||
|
UserOptions = apps.get_model(
|
||||||
|
app_label='user_management', model_name='UserOptions'
|
||||||
|
)
|
||||||
|
|
||||||
|
for user in User.objects.all():
|
||||||
|
UserOptions.objects.filter(user=user).delete()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='UserOptions',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('block_password_change', models.BooleanField(default=False, verbose_name='Forbid this user from changing their password.')),
|
||||||
|
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='user_options', to=settings.AUTH_USER_MODEL, verbose_name='User')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'User settings',
|
||||||
|
'verbose_name_plural': 'Users settings',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
code=add_user_options_to_existing_users,
|
||||||
|
reverse_code=remove_user_options_from_existing_users
|
||||||
|
),
|
||||||
|
]
|
||||||
0
mayan/apps/user_management/migrations/__init__.py
Normal file
0
mayan/apps/user_management/migrations/__init__.py
Normal file
24
mayan/apps/user_management/models.py
Normal file
24
mayan/apps/user_management/models.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class UserOptions(models.Model):
|
||||||
|
user = models.OneToOneField(
|
||||||
|
on_delete=models.CASCADE, related_name='user_options',
|
||||||
|
to=settings.AUTH_USER_MODEL, unique=True, verbose_name=_('User')
|
||||||
|
)
|
||||||
|
block_password_change = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
verbose_name=_('Forbid this user from changing their password.')
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _('User settings')
|
||||||
|
verbose_name_plural = _('Users settings')
|
||||||
|
|
||||||
|
def natural_key(self):
|
||||||
|
return self.user.natural_key()
|
||||||
|
natural_key.dependencies = [settings.AUTH_USER_MODEL]
|
||||||
@@ -9,7 +9,7 @@ from .api_views import (
|
|||||||
from .views import (
|
from .views import (
|
||||||
GroupCreateView, GroupDeleteView, GroupEditView, GroupListView,
|
GroupCreateView, GroupDeleteView, GroupEditView, GroupListView,
|
||||||
GroupMembersView, UserCreateView, UserDeleteView, UserEditView,
|
GroupMembersView, UserCreateView, UserDeleteView, UserEditView,
|
||||||
UserGroupsView, UserListView, UserSetPasswordView
|
UserGroupsView, UserListView, UserOptionsEditView, UserSetPasswordView
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -51,6 +51,11 @@ urlpatterns = [
|
|||||||
r'^user/(?P<pk>\d+)/groups/$', UserGroupsView.as_view(),
|
r'^user/(?P<pk>\d+)/groups/$', UserGroupsView.as_view(),
|
||||||
name='user_groups'
|
name='user_groups'
|
||||||
),
|
),
|
||||||
|
url(
|
||||||
|
r'^user/(?P<pk>\d+)/options/$',
|
||||||
|
UserOptionsEditView.as_view(),
|
||||||
|
name='user_options'
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
api_urls = [
|
api_urls = [
|
||||||
|
|||||||
@@ -133,8 +133,10 @@ class UserCreateView(SingleObjectCreateView):
|
|||||||
|
|
||||||
|
|
||||||
class UserDeleteView(MultipleObjectConfirmActionView):
|
class UserDeleteView(MultipleObjectConfirmActionView):
|
||||||
model = get_user_model()
|
|
||||||
object_permission = permission_user_delete
|
object_permission = permission_user_delete
|
||||||
|
queryset = get_user_model().objects.filter(
|
||||||
|
is_superuser=False, is_staff=False
|
||||||
|
)
|
||||||
success_message = _('User delete request performed on %(count)d user')
|
success_message = _('User delete request performed on %(count)d user')
|
||||||
success_message_plural = _(
|
success_message_plural = _(
|
||||||
'User delete request performed on %(count)d users'
|
'User delete request performed on %(count)d users'
|
||||||
@@ -216,8 +218,11 @@ class UserGroupsView(AssignRemoveView):
|
|||||||
'title': _('Groups of user: %s') % self.get_object()
|
'title': _('Groups of user: %s') % self.get_object()
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_object(self):
|
return get_object_or_404(
|
||||||
return get_object_or_404(get_user_model(), pk=self.kwargs['pk'])
|
get_user_model().objects.filter(
|
||||||
|
is_superuser=False, is_staff=False
|
||||||
|
), pk=self.kwargs['pk']
|
||||||
|
)
|
||||||
|
|
||||||
def left_list(self):
|
def left_list(self):
|
||||||
return AssignRemoveView.generate_choices(
|
return AssignRemoveView.generate_choices(
|
||||||
@@ -248,6 +253,31 @@ class UserListView(SingleObjectListView):
|
|||||||
).exclude(is_staff=True).order_by('last_name', 'first_name')
|
).exclude(is_staff=True).order_by('last_name', 'first_name')
|
||||||
|
|
||||||
|
|
||||||
|
class UserOptionsEditView(SingleObjectEditView):
|
||||||
|
fields = ('block_password_change',)
|
||||||
|
object_permission = permission_user_edit
|
||||||
|
|
||||||
|
def get_extra_context(self):
|
||||||
|
return {
|
||||||
|
'title': _(
|
||||||
|
'Edit options for user: %s'
|
||||||
|
) % self.get_user()
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_object(self, queryset=None):
|
||||||
|
return self.get_user().user_options
|
||||||
|
|
||||||
|
def get_post_action_redirect(self):
|
||||||
|
return reverse('user_management:user_list')
|
||||||
|
|
||||||
|
def get_user(self):
|
||||||
|
return get_object_or_404(
|
||||||
|
get_user_model().objects.filter(
|
||||||
|
is_superuser=False, is_staff=False
|
||||||
|
), pk=self.kwargs['pk']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserSetPasswordView(MultipleObjectFormActionView):
|
class UserSetPasswordView(MultipleObjectFormActionView):
|
||||||
form_class = SetPasswordForm
|
form_class = SetPasswordForm
|
||||||
model = get_user_model()
|
model = get_user_model()
|
||||||
|
|||||||
Reference in New Issue
Block a user