Cosmetics
This commit is contained in:
parent
8a0a73a640
commit
4a7ac71a38
|
@ -5,14 +5,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from orchestra.core.validators import validate_password
|
||||
from orchestra.forms.widgets import ReadOnlyWidget
|
||||
|
||||
from .models import Account
|
||||
|
||||
|
||||
class AccountCreationForm(auth.forms.UserCreationForm):
|
||||
# class Meta:
|
||||
# model = Account
|
||||
# fields = ("username",)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AccountCreationForm, self).__init__(*args, **kwargs)
|
||||
self.fields['password1'].validators.append(validate_password)
|
||||
|
@ -21,8 +15,9 @@ class AccountCreationForm(auth.forms.UserCreationForm):
|
|||
# Since model.clean() will check this, this is redundant,
|
||||
# but it sets a nicer error message than the ORM and avoids conflicts with contrib.auth
|
||||
username = self.cleaned_data["username"]
|
||||
if hasattr(Account, 'systemusers'):
|
||||
systemuser_model = Account.systemusers.related.model
|
||||
account_model = self._meta.model
|
||||
if hasattr(account_model, 'systemusers'):
|
||||
systemuser_model = account_model.systemusers.related.model
|
||||
if systemuser_model.objects.filter(username=username).exists():
|
||||
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
||||
return username
|
||||
|
|
|
@ -55,8 +55,8 @@ class Bill(models.Model):
|
|||
type = models.CharField(_("type"), max_length=16, choices=TYPES)
|
||||
created_on = models.DateField(_("created on"), auto_now_add=True)
|
||||
closed_on = models.DateField(_("closed on"), blank=True, null=True)
|
||||
is_open = models.BooleanField(_("is open"), default=True)
|
||||
is_sent = models.BooleanField(_("is sent"), default=False)
|
||||
is_open = models.BooleanField(_("open"), default=True)
|
||||
is_sent = models.BooleanField(_("sent"), default=False)
|
||||
due_on = models.DateField(_("due on"), null=True, blank=True)
|
||||
updated_on = models.DateField(_("updated on"), auto_now=True)
|
||||
total = models.DecimalField(max_digits=12, decimal_places=2, default=0)
|
||||
|
|
|
@ -40,7 +40,7 @@ class Role(models.Model):
|
|||
related_name='roles')
|
||||
user = models.ForeignKey('databases.DatabaseUser', verbose_name=_("user"),
|
||||
related_name='roles')
|
||||
is_owner = models.BooleanField(_("is owener"), default=False)
|
||||
is_owner = models.BooleanField(_("owner"), default=False)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('database', 'user')
|
||||
|
|
|
@ -20,7 +20,7 @@ class Mailbox(models.Model):
|
|||
validators=[validators.validate_sieve],
|
||||
help_text=_("Arbitrary email filtering in sieve language. "
|
||||
"This overrides any automatic junk email filtering"))
|
||||
is_active = models.BooleanField(_("is active"), default=True)
|
||||
is_active = models.BooleanField(_("active"), default=True)
|
||||
# addresses = models.ManyToManyField('mails.Address',
|
||||
# verbose_name=_("addresses"),
|
||||
# related_name='mailboxes', blank=True)
|
||||
|
|
|
@ -6,11 +6,11 @@ from orchestra.core import services
|
|||
|
||||
class MiscService(models.Model):
|
||||
name = models.CharField(_("name"), max_length=256)
|
||||
description = models.TextField(blank=True)
|
||||
has_amount = models.BooleanField(default=False,
|
||||
description = models.TextField(_("description"), blank=True)
|
||||
has_amount = models.BooleanField(_("has amount"), default=False,
|
||||
help_text=_("Designates whether this service has <tt>amount</tt> "
|
||||
"property or not."))
|
||||
is_active = models.BooleanField(default=True,
|
||||
is_active = models.BooleanField(_("active"), default=True,
|
||||
help_text=_("Whether new instances of this service can be created "
|
||||
"or not. Unselect this instead of deleting services."))
|
||||
|
||||
|
@ -25,7 +25,7 @@ class Miscellaneous(models.Model):
|
|||
related_name='miscellaneous')
|
||||
description = models.TextField(_("description"), blank=True)
|
||||
amount = models.PositiveIntegerField(_("amount"), default=1)
|
||||
is_active = models.BooleanField(default=True,
|
||||
is_active = models.BooleanField(_("active"), default=True,
|
||||
help_text=_("Designates whether this service should be treated as "
|
||||
"active. Unselect this instead of deleting services."))
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ class Route(models.Model):
|
|||
# async = models.BooleanField(default=False)
|
||||
# method = models.CharField(_("method"), max_lenght=32, choices=method_choices,
|
||||
# default=MethodBackend.get_default())
|
||||
is_active = models.BooleanField(_("is active"), default=True)
|
||||
is_active = models.BooleanField(_("active"), default=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('backend', 'host')
|
||||
|
|
|
@ -22,7 +22,7 @@ class PaymentSource(models.Model):
|
|||
method = models.CharField(_("method"), max_length=32,
|
||||
choices=PaymentMethod.get_plugin_choices())
|
||||
data = JSONField(_("data"))
|
||||
is_active = models.BooleanField(_("is active"), default=True)
|
||||
is_active = models.BooleanField(_("active"), default=True)
|
||||
|
||||
objects = PaymentSourcesQueryset.as_manager()
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ class Resource(models.Model):
|
|||
monitors = fields.MultiSelectField(_("monitors"), max_length=256, blank=True,
|
||||
choices=ServiceMonitor.get_plugin_choices(),
|
||||
help_text=_("Monitor backends used for monitoring this resource."))
|
||||
is_active = models.BooleanField(_("is active"), default=True)
|
||||
is_active = models.BooleanField(_("active"), default=True)
|
||||
|
||||
objects = ResourceQuerySet.as_manager()
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ from .handlers import ServiceHandler
|
|||
|
||||
class Plan(models.Model):
|
||||
name = models.CharField(_("plan"), max_length=128)
|
||||
is_default = models.BooleanField(_("is default"), default=False)
|
||||
is_combinable = models.BooleanField(_("is combinable"), default=True)
|
||||
allow_multiple = models.BooleanField(_("allow multipls"), default=False)
|
||||
is_default = models.BooleanField(_("default"), default=False)
|
||||
is_combinable = models.BooleanField(_("combinable"), default=True)
|
||||
allow_multiple = models.BooleanField(_("allow multiple"), default=False)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
@ -107,7 +107,7 @@ class Service(models.Model):
|
|||
"enables customized behaviour far beyond what options "
|
||||
"here allow to."),
|
||||
choices=ServiceHandler.get_plugin_choices())
|
||||
is_active = models.BooleanField(_("is active"), default=True)
|
||||
is_active = models.BooleanField(_("active"), default=True)
|
||||
# Billing
|
||||
billing_period = models.CharField(_("billing period"), max_length=16,
|
||||
help_text=_("Renewal period for recurring invoicing"),
|
||||
|
@ -133,7 +133,7 @@ class Service(models.Model):
|
|||
# (ONE_MONTH, _("One month")),
|
||||
# ),
|
||||
# default=ONE_MONTH, blank=True)
|
||||
is_fee = models.BooleanField(_("is fee"), default=False,
|
||||
is_fee = models.BooleanField(_("fee"), default=False,
|
||||
help_text=_("Designates whether this service should be billed as "
|
||||
" membership fee or not"))
|
||||
# Pricing
|
||||
|
|
|
@ -17,7 +17,7 @@ class SystemUserAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
|||
list_filter = ('is_active',)
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('username', 'password', 'is_active', 'account_link')
|
||||
'fields': ('username', 'password', 'account_link', 'is_active')
|
||||
}),
|
||||
(_("System"), {
|
||||
'fields': ('home', 'shell', 'groups'),
|
||||
|
|
|
@ -5,14 +5,9 @@ from django.utils.translation import ugettext, ugettext_lazy as _
|
|||
from orchestra.apps.accounts.models import Account
|
||||
from orchestra.core.validators import validate_password
|
||||
|
||||
from .models import SystemUser
|
||||
|
||||
|
||||
# TODO orchestra.UserCretionForm
|
||||
class UserCreationForm(auth.forms.UserCreationForm):
|
||||
# class Meta:
|
||||
# model = SystemUser
|
||||
# fields = ('username',)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(UserCreationForm, self).__init__(*args, **kwargs)
|
||||
self.fields['password1'].validators.append(validate_password)
|
||||
|
@ -21,12 +16,13 @@ class UserCreationForm(auth.forms.UserCreationForm):
|
|||
# Since model.clean() will check this, this is redundant,
|
||||
# but it sets a nicer error message than the ORM and avoids conflicts with contrib.auth
|
||||
username = self.cleaned_data["username"]
|
||||
account_model = SystemUser.account.field.rel.to
|
||||
account_model = self._meta.model.account.field.rel.to
|
||||
if account_model.objects.filter(username=username).exists():
|
||||
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
||||
return username
|
||||
|
||||
|
||||
# TODO orchestra.UserCretionForm
|
||||
class UserChangeForm(forms.ModelForm):
|
||||
password = auth.forms.ReadOnlyPasswordHashField(label=_("Password"),
|
||||
help_text=_("Raw passwords are not stored, so there is no way to see "
|
||||
|
|
|
@ -26,7 +26,7 @@ class SystemUser(models.Model):
|
|||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||
related_name='systemusers')
|
||||
home = models.CharField(_("home"), max_length=256, blank=True,
|
||||
help_text=_("Home directory relative to account's ~primary_user"))
|
||||
help_text=_("Home directory relative to account's ~main_user"))
|
||||
shell = models.CharField(_("shell"), max_length=32,
|
||||
choices=settings.USERS_SHELLS, default=settings.USERS_DEFAULT_SHELL)
|
||||
groups = models.ManyToManyField('systemusers.Group', blank=True,
|
||||
|
|
|
@ -8,9 +8,10 @@ USERS_SYSTEMUSER_HOME = getattr(settings, 'USERES_SYSTEMUSER_HOME', '/home/%(use
|
|||
USERS_FTP_LOG_PATH = getattr(settings, 'USERS_FTP_LOG_PATH', '/var/log/vsftpd.log')
|
||||
|
||||
USERS_SHELLS = getattr(settings, 'USERS_SHELLS', (
|
||||
('/bin/false', _("FTP/sFTP only")),
|
||||
('/bin/rsync', _("rsync shell")),
|
||||
('/bin/bash', "Bash"),
|
||||
('/bin/false', _("No shell, FTP only")),
|
||||
('/bin/rsync', _("No shell, SFTP/RSYNC only")),
|
||||
('/bin/bash', "/bin/bash"),
|
||||
('/bin/sh', "/bin/sh"),
|
||||
))
|
||||
|
||||
USERS_DEFAULT_SHELL = getattr(settings, 'USERS_DEFAULT_SHELL', '/bin/false')
|
||||
|
|
|
@ -11,23 +11,21 @@ from orchestra.apps.accounts.admin import AccountAdminMixin
|
|||
|
||||
from .forms import UserCreationForm, UserChangeForm
|
||||
from .models import User
|
||||
from .roles.filters import role_list_filter_factory
|
||||
|
||||
|
||||
class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
||||
list_display = ('username', 'account_link', 'is_main', 'is_superuser', 'is_active')
|
||||
list_filter = ('is_main', 'is_superuser', 'is_active')
|
||||
list_display = ('username', 'display_is_main')
|
||||
list_filter = ('is_staff', 'is_superuser', 'is_active')
|
||||
fieldsets = (
|
||||
(None, {
|
||||
'fields': ('username', 'password', 'account_link')
|
||||
}),
|
||||
(_("System"), {
|
||||
'fields': ('home', 'shell', 'groups'),
|
||||
'fields': ('account', 'username', 'password')
|
||||
}),
|
||||
(_("Personal info"), {
|
||||
'fields': ('first_name', 'last_name', 'email')
|
||||
}),
|
||||
(_("Permissions"), {
|
||||
'fields': ('is_main', 'is_active', 'is_superuser')
|
||||
'fields': ('is_active', 'is_staff', 'is_superuser', 'display_is_main')
|
||||
}),
|
||||
(_("Important dates"), {
|
||||
'fields': ('last_login', 'date_joined')
|
||||
|
@ -39,25 +37,74 @@ class UserAdmin(AccountAdminMixin, auth.UserAdmin, ExtendedModelAdmin):
|
|||
'fields': ('username', 'password1', 'password2', 'account'),
|
||||
}),
|
||||
)
|
||||
search_fields = ['username']
|
||||
readonly_fields = ('is_main', 'account_link',)
|
||||
search_fields = ['username', 'account__user__username']
|
||||
readonly_fields = ('display_is_main', 'account_link')
|
||||
change_readonly_fields = ('username',)
|
||||
filter_horizontal = ()
|
||||
filter_by_account_fields = ('groups',)
|
||||
add_form = UserCreationForm
|
||||
form = UserChangeForm
|
||||
roles = []
|
||||
ordering = ('-id',)
|
||||
change_form_template = 'admin/users/user/change_form.html'
|
||||
|
||||
def get_form(self, request, obj=None, **kwargs):
|
||||
""" exclude self reference on groups """
|
||||
form = super(AccountAdminMixin, self).get_form(request, obj=obj, **kwargs)
|
||||
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)
|
||||
return form
|
||||
def display_is_main(self, instance):
|
||||
return instance.is_main
|
||||
display_is_main.short_description = _("is main")
|
||||
display_is_main.boolean = True
|
||||
|
||||
def get_urls(self):
|
||||
""" Returns the additional urls for the change view links """
|
||||
urls = super(UserAdmin, self).get_urls()
|
||||
opts = self.model._meta
|
||||
new_urls = patterns("")
|
||||
for role in self.roles:
|
||||
new_urls += patterns("",
|
||||
url('^(\d+)/%s/$' % role.url_name,
|
||||
wrap_admin_view(self, role().change_view),
|
||||
name='%s_%s_%s_change' % (opts.app_label, opts.model_name, role.name)),
|
||||
url('^(\d+)/%s/delete/$' % role.url_name,
|
||||
wrap_admin_view(self, role().delete_view),
|
||||
name='%s_%s_%s_delete' % (opts.app_label, opts.model_name, role.name))
|
||||
)
|
||||
return new_urls + urls
|
||||
|
||||
def get_fieldsets(self, request, obj=None):
|
||||
fieldsets = super(UserAdmin, self).get_fieldsets(request, obj=obj)
|
||||
if obj and obj.account:
|
||||
fieldsets[0][1]['fields'] = ('account_link',) + fieldsets[0][1]['fields'][1:]
|
||||
return fieldsets
|
||||
|
||||
def get_list_display(self, request):
|
||||
roles = []
|
||||
for role in self.roles:
|
||||
def has_role(user, role_class=role):
|
||||
role = role_class(user=user)
|
||||
if role.exists:
|
||||
return '<img src="/static/admin/img/icon-yes.gif" alt="True">'
|
||||
url = reverse('admin:users_user_%s_change' % role.name, args=(user.pk,))
|
||||
false = '<img src="/static/admin/img/icon-no.gif" alt="False">'
|
||||
return '<a href="%s">%s</a>' % (url, false)
|
||||
has_role.short_description = _("Has %s") % role.name
|
||||
has_role.admin_order_field = role.name
|
||||
has_role.allow_tags = True
|
||||
roles.append(has_role)
|
||||
return list(self.list_display) + roles + ['account_link']
|
||||
|
||||
def get_list_filter(self, request):
|
||||
roles = [ role_list_filter_factory(role) for role in self.roles ]
|
||||
return list(self.list_filter) + roles
|
||||
|
||||
def change_view(self, request, object_id, **kwargs):
|
||||
user = self.get_object(User, unquote(object_id))
|
||||
extra_context = kwargs.get('extra_context', {})
|
||||
extra_context['roles'] = [ role(user=user) for role in self.roles ]
|
||||
kwargs['extra_context'] = extra_context
|
||||
return super(UserAdmin, self).change_view(request, object_id, **kwargs)
|
||||
|
||||
def get_queryset(self, request):
|
||||
""" Select related for performance """
|
||||
related = ['account__user'] + [ role.name for role in self.roles ]
|
||||
return super(UserAdmin, self).get_queryset(request).select_related(*related)
|
||||
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
|
|
@ -10,6 +10,11 @@ from .serializers import UserSerializer
|
|||
class UserViewSet(AccountApiMixin, SetPasswordApiMixin, viewsets.ModelViewSet):
|
||||
model = get_user_model()
|
||||
serializer_class = UserSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
""" select related roles """
|
||||
qs = super(UserViewSet, self).get_queryset()
|
||||
return qs.select_related(*self.inserted)
|
||||
|
||||
|
||||
router.register(r'users', UserViewSet)
|
||||
|
|
|
@ -47,4 +47,3 @@ class UserChangeForm(forms.ModelForm):
|
|||
# This is done here, rather than on the field, because the
|
||||
# field does not have access to the initial value
|
||||
return self.initial["password"]
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from orchestra.core import services
|
||||
|
||||
from . import settings
|
||||
|
||||
|
||||
class User(auth.AbstractBaseUser):
|
||||
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||
|
@ -16,22 +14,19 @@ class User(auth.AbstractBaseUser):
|
|||
"./-/_ only."),
|
||||
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
||||
_("Enter a valid username."), 'invalid')])
|
||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), related_name='users')
|
||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||
related_name='users')
|
||||
first_name = models.CharField(_("first name"), max_length=30, blank=True)
|
||||
last_name = models.CharField(_("last name"), max_length=30, blank=True)
|
||||
email = models.EmailField(_("email address"), blank=True)
|
||||
email = models.EmailField(_('email address'), blank=True)
|
||||
is_superuser = models.BooleanField(_("superuser status"), default=False,
|
||||
help_text=_("Designates that this user has all permissions without "
|
||||
"explicitly assigning them."))
|
||||
is_main = models.BooleanField(_("is main"), default=False)
|
||||
# system_password = models.CharField(_("system password"), max_length=128)
|
||||
home = models.CharField(_("home"), max_length=256, blank=True,
|
||||
help_text=_("Home directory relative to account's ~primary_user"))
|
||||
shell = models.CharField(_("shell"), max_length=32,
|
||||
choices=settings.USERS_SHELLS, default=settings.USERS_DEFAULT_SHELL)
|
||||
groups = models.ManyToManyField('self', blank=True,
|
||||
help_text=_("A new group will be created for the user. "
|
||||
"Which additional groups would you like them to be a member of?"))
|
||||
help_text=_("Designates that this user has all permissions without "
|
||||
"explicitly assigning them."))
|
||||
is_staff = models.BooleanField(_("staff status"), default=False,
|
||||
help_text=_("Designates whether the user can log into this admin "
|
||||
"site."))
|
||||
is_admin = models.BooleanField(_("admin status"), default=False,
|
||||
help_text=_("Designates whether the user can administrate its account."))
|
||||
is_active = models.BooleanField(_("active"), default=True,
|
||||
help_text=_("Designates whether this user should be treated as "
|
||||
"active. Unselect this instead of deleting accounts."))
|
||||
|
@ -40,11 +35,11 @@ class User(auth.AbstractBaseUser):
|
|||
objects = auth.UserManager()
|
||||
|
||||
USERNAME_FIELD = 'username'
|
||||
REQUIRED_FIELDS = []
|
||||
REQUIRED_FIELDS = ['email']
|
||||
|
||||
@property
|
||||
def is_staff(self):
|
||||
return self.is_superuser or self.is_main
|
||||
def is_main(self):
|
||||
return self.account.user == self
|
||||
|
||||
def get_full_name(self):
|
||||
full_name = '%s %s' % (self.first_name, self.last_name)
|
||||
|
@ -92,9 +87,6 @@ class User(auth.AbstractBaseUser):
|
|||
if self.is_active and self.is_superuser:
|
||||
return True
|
||||
return auth._user_has_module_perms(self, app_label)
|
||||
#
|
||||
# def set_system_password(self, raw_password):
|
||||
# self.system_password = make_password(raw_password)
|
||||
|
||||
|
||||
services.register(User)
|
||||
services.register(User, menu=False)
|
||||
|
|
|
@ -33,4 +33,3 @@ class UserSerializer(AccountSerializerMixin, serializers.HyperlinkedModelSeriali
|
|||
if not obj.pk:
|
||||
obj.set_password(obj.password)
|
||||
super(UserSerializer, self).save_object(obj, **kwargs)
|
||||
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
from django.conf import settings
|
||||
|
||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||
|
||||
|
||||
USERS_SYSTEMUSER_HOME = getattr(settings, 'USERES_SYSTEMUSER_HOME', '/home/%(username)s')
|
||||
|
||||
USERS_FTP_LOG_PATH = getattr(settings, 'USERS_FTP_LOG_PATH', '/var/log/vsftpd.log')
|
||||
|
||||
USERS_SHELLS = getattr(settings, 'USERS_SHELLS', (
|
||||
('/bin/false', _("FTP/sFTP only")),
|
||||
('/bin/rsync', _("rsync shell")),
|
||||
('/bin/bash', "Bash"),
|
||||
))
|
||||
|
||||
USERS_DEFAULT_SHELL = getattr(settings, 'USERS_DEFAULT_SHELL', '/bin/false')
|
||||
|
|
|
@ -28,7 +28,7 @@ class Website(models.Model):
|
|||
domains = models.ManyToManyField(settings.WEBSITES_DOMAIN_MODEL,
|
||||
related_name='websites', verbose_name=_("domains"))
|
||||
contents = models.ManyToManyField('webapps.WebApp', through='websites.Content')
|
||||
is_active = models.BooleanField(_("is active"), default=True)
|
||||
is_active = models.BooleanField(_("active"), default=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
|
Loading…
Reference in a new issue