Fixed errors with systemuser form and serializer

This commit is contained in:
Marc 2014-11-14 22:19:58 +00:00
parent b93be150c2
commit a0b531ed68
4 changed files with 116 additions and 43 deletions

View file

@ -17,6 +17,7 @@ from orchestra.forms import UserCreationForm, UserChangeForm
from . import settings
from .actions import grant_permission
from .filters import IsMainListFilter
from .forms import SystemUserCreationForm, SystemUserChangeForm
from .models import SystemUser
@ -46,8 +47,8 @@ class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende
change_readonly_fields = ('username',)
filter_horizontal = ('groups',)
filter_by_account_fields = ('groups',)
add_form = UserCreationForm
form = UserChangeForm
add_form = SystemUserCreationForm
form = SystemUserChangeForm
ordering = ('-id',)
actions = (grant_permission,)
change_view_actions = actions
@ -70,49 +71,13 @@ class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende
def get_form(self, request, obj=None, **kwargs):
form = super(SystemUserAdmin, self).get_form(request, obj=obj, **kwargs)
duplicate = lambda n: (n, n)
form.account = self.account
if obj:
# Has to be done here and not in the form because of strange phenomenon
# derived from monkeypatching formfield.widget.render on AccountAdminMinxin,
# don't ask.
formfield = form.base_fields['groups']
formfield.queryset = formfield.queryset.exclude(id=obj.id)
username = obj.username
choices=(
duplicate(self.account.main_systemuser.get_home()),
duplicate(obj.get_home()),
)
else:
username = '<username>'
choices=(
duplicate(self.account.main_systemuser.get_home()),
duplicate(SystemUser(username=username).get_home()),
)
form.base_fields['home'].widget = forms.Select(choices=choices)
if obj and (obj.is_main or obj.has_shell):
# hidde home option for shell users
form.base_fields['home'].widget = forms.HiddenInput()
form.base_fields['directory'].widget = forms.HiddenInput()
else:
# Some javascript for hidde home/directory inputs when convinient
form.base_fields['shell'].widget.attrs = {
'onChange': textwrap.dedent("""\
field = $(".form-row.field-home.field-directory");
if ($.inArray(this.value, %s) < 0) {
field.addClass("hidden");
} else {
field.removeClass("hidden");
};""" % str(list(settings.SYSTEMUSERS_DISABLED_SHELLS)))
}
form.base_fields['home'].widget.attrs = {
'onChange': textwrap.dedent("""\
field = $(".field-box.field-directory");
if (this.value.search("%s") > 0) {
field.addClass("hidden");
} else {
field.removeClass("hidden");
};""" % username)
}
return form
def has_delete_permission(self, request, obj=None):

View file

@ -0,0 +1,72 @@
import textwrap
from django import forms
from orchestra.forms import UserCreationForm, UserChangeForm
from . import settings
from .models import SystemUser
class SystemUserFormMixin(object):
MOCK_USERNAME = '<username>'
def __init__(self, *args, **kwargs):
super(SystemUserFormMixin, self).__init__(*args, **kwargs)
duplicate = lambda n: (n, n)
if self.instance.pk:
username = self.instance.username
choices=(
duplicate(self.account.main_systemuser.get_base_home()),
duplicate(self.instance.get_base_home()),
)
else:
username = self.MOCK_USERNAME
choices=(
duplicate(self.account.main_systemuser.get_base_home()),
duplicate(SystemUser(username=username).get_base_home()),
)
self.fields['home'].widget = forms.Select(choices=choices)
if self.instance.pk and (self.instance.is_main or self.instance.has_shell):
# hidde home option for shell users
self.fields['home'].widget = forms.HiddenInput()
self.fields['directory'].widget = forms.HiddenInput()
elif self.instance.pk and (self.instance.get_base_home() == self.instance.home):
self.fields['directory'].widget = forms.HiddenInput()
if self.instance.pk and not self.instance.is_main:
# Some javascript for hidde home/directory inputs when convinient
self.fields['shell'].widget.attrs = {
'onChange': textwrap.dedent("""\
field = $(".field-home, .field-directory");
input = $("#id_home, #id_directory");
if ($.inArray(this.value, %s) < 0) {
field.addClass("hidden");
} else {
field.removeClass("hidden");
input.removeAttr("type");
};""" % str(list(settings.SYSTEMUSERS_DISABLED_SHELLS)))
}
self.fields['home'].widget.attrs = {
'onChange': textwrap.dedent("""\
field = $(".field-box.field-directory");
input = $("#id_directory");
if (this.value.search("%s") > 0) {
field.addClass("hidden");
} else {
field.removeClass("hidden");
input.removeAttr("type");
};""" % username)
}
def clean(self):
home = self.cleaned_data.get('home')
if home and self.MOCK_USERNAME in home:
username = self.cleaned_data.get('username', '')
self.cleaned_data['home'] = home.replace(self.MOCK_USERNAME, username)
class SystemUserCreationForm(SystemUserFormMixin, UserCreationForm):
pass
class SystemUserChangeForm(SystemUserFormMixin, UserChangeForm):
pass

View file

@ -2,6 +2,7 @@ import os
from django.contrib.auth.hashers import make_password
from django.core import validators
from django.core.exceptions import ValidationError
from django.core.mail import send_mail
from django.db import models
from django.utils.functional import cached_property
@ -30,7 +31,7 @@ class SystemUser(models.Model):
password = models.CharField(_("password"), max_length=128)
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
related_name='systemusers')
home = models.CharField(_("home"), max_length=256, blank=False,
home = models.CharField(_("home"), max_length=256, blank=True,
help_text=_("Starting location when login with this no-shell user."))
directory = models.CharField(_("directory"), max_length=256, blank=True,
help_text=_("Optional directory relative to user's home."))
@ -68,10 +69,26 @@ class SystemUser(models.Model):
def has_shell(self):
return self.shell not in settings.SYSTEMUSERS_DISABLED_SHELLS
def clean(self):
if self.has_shell or self.is_main:
def save(self, *args, **kwargs):
if not self.home:
self.home = self.get_base_home()
self.directory = ''
super(SystemUser, self).save(*args, **kwargs)
def clean(self):
# TODO do it right
if self.has_shell and self.directory:
raise ValidationError({
'directory': _("Directory with shell users can not be specified.")
})
if self.pk and self.is_main and self.directory:
raise ValidationError({
'directory': _("Directory with main system users can not be specified.")
})
if self.home == self.get_base_home() and self.directory:
raise ValidationError({
'directory': _("Directory on the user's base home is not allowed.")
})
# TODO valid home exists
def set_password(self, raw_password):
self.password = make_password(raw_password)

View file

@ -1,4 +1,5 @@
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.forms import widgets
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext, ugettext_lazy as _
@ -34,6 +35,24 @@ class SystemUserSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
)
postonly_fields = ('username',)
def validate(self, attrs):
user = SystemUser(
username=attrs.get('username') or self.object.username,
shell=attrs.get('shell') or self.object.shell,
)
if 'home' in attrs and attrs['home']:
home = attrs['home'].rstrip('/') + '/'
if user.has_shell:
if home != user.get_base_home():
raise ValidationError({
'home': _("Not a valid home directory.")
})
elif home not in (user.get_home(), self.account.main_systemuser.get_home()):
raise ValidationError({
'home': _("Not a valid home directory.")
})
return attrs
def validate_password(self, attrs, source):
""" POST only password """
if self.object: