Random fixes
This commit is contained in:
parent
04b9ee51cb
commit
0e65c65433
|
@ -252,14 +252,8 @@ class ChangePasswordAdminMixin(object):
|
||||||
related.append(user.account)
|
related.append(user.account)
|
||||||
else:
|
else:
|
||||||
account = user
|
account = user
|
||||||
# TODO plugability
|
for rel in account.get_related_passwords():
|
||||||
if user._meta.model_name != 'systemuser':
|
if not isinstance(user, type(rel)):
|
||||||
rel = account.systemusers.filter(username=username).first()
|
|
||||||
if rel:
|
|
||||||
related.append(rel)
|
|
||||||
if user._meta.model_name != 'mailbox':
|
|
||||||
rel = account.mailboxes.filter(name=username).first()
|
|
||||||
if rel:
|
|
||||||
related.append(rel)
|
related.append(rel)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
import copy
|
||||||
|
import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf.urls import patterns, url
|
from django.conf.urls import patterns, url
|
||||||
from django.contrib import admin, messages
|
from django.contrib import admin, messages
|
||||||
from django.contrib.admin.util import unquote
|
from django.contrib.admin.util import unquote
|
||||||
from django.contrib.auth import admin as auth
|
from django.contrib.auth import admin as auth
|
||||||
|
from django.db.models.loading import get_model
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.six.moves.urllib.parse import parse_qsl
|
from django.utils.six.moves.urllib.parse import parse_qsl
|
||||||
|
@ -13,6 +17,7 @@ from orchestra.admin.utils import wrap_admin_view, admin_link, set_url_query, ch
|
||||||
from orchestra.core import services, accounts
|
from orchestra.core import services, accounts
|
||||||
from orchestra.forms import UserChangeForm
|
from orchestra.forms import UserChangeForm
|
||||||
|
|
||||||
|
from . import settings
|
||||||
from .actions import disable
|
from .actions import disable
|
||||||
from .filters import HasMainUserListFilter
|
from .filters import HasMainUserListFilter
|
||||||
from .forms import AccountCreationForm
|
from .forms import AccountCreationForm
|
||||||
|
@ -84,12 +89,27 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
|
||||||
return super(AccountAdmin, self).change_view(request, object_id,
|
return super(AccountAdmin, self).change_view(request, object_id,
|
||||||
form_url=form_url, extra_context=context)
|
form_url=form_url, extra_context=context)
|
||||||
|
|
||||||
|
def get_fieldsets(self, request, obj=None):
|
||||||
|
fieldsets = super(AccountAdmin, self).get_fieldsets(request, obj=obj)
|
||||||
|
if not obj:
|
||||||
|
fields = AccountCreationForm.create_related_fields
|
||||||
|
if fields:
|
||||||
|
fieldsets = copy.deepcopy(fieldsets)
|
||||||
|
fieldsets = list(fieldsets)
|
||||||
|
fieldsets.insert(1, (_("Related services"), {'fields': fields}))
|
||||||
|
return fieldsets
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
""" Select related for performance """
|
""" Select related for performance """
|
||||||
qs = super(AccountAdmin, self).get_queryset(request)
|
qs = super(AccountAdmin, self).get_queryset(request)
|
||||||
related = ('invoicecontact',)
|
related = ('invoicecontact',)
|
||||||
return qs.select_related(*related)
|
return qs.select_related(*related)
|
||||||
|
|
||||||
|
def save_model(self, request, obj, form, change):
|
||||||
|
super(AccountAdmin, self).save_model(request, obj, form, change)
|
||||||
|
if not change:
|
||||||
|
form.save_related(obj)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Account, AccountAdmin)
|
admin.site.register(Account, AccountAdmin)
|
||||||
|
|
||||||
|
@ -162,6 +182,7 @@ class AccountAdminMixin(object):
|
||||||
def render(*args, **kwargs):
|
def render(*args, **kwargs):
|
||||||
output = old_render(*args, **kwargs)
|
output = old_render(*args, **kwargs)
|
||||||
output = output.replace('/add/"', '/add/?account=%s"' % self.account.pk)
|
output = output.replace('/add/"', '/add/?account=%s"' % self.account.pk)
|
||||||
|
output = re.sub(r'/add/\?([^".]*)"', r'/add/?\1&account=%s"' % self.account.pk, output)
|
||||||
return mark_safe(output)
|
return mark_safe(output)
|
||||||
formfield.widget.render = render
|
formfield.widget.render = render
|
||||||
# Filter related object by account
|
# Filter related object by account
|
||||||
|
|
|
@ -1,21 +1,60 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import auth
|
from django.db.models.loading import get_model
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.core.validators import validate_password
|
|
||||||
from orchestra.forms import UserCreationForm
|
from orchestra.forms import UserCreationForm
|
||||||
from orchestra.forms.widgets import ReadOnlyWidget
|
|
||||||
|
from . import settings
|
||||||
|
from .models import Account
|
||||||
|
|
||||||
|
|
||||||
|
def create_account_creation_form():
|
||||||
|
fields = {}
|
||||||
|
for model, key, kwargs, help_text in settings.ACCOUNTS_CREATE_RELATED:
|
||||||
|
model = get_model(model)
|
||||||
|
field_name = 'create_%s' % model._meta.model_name
|
||||||
|
label = _("Create related %s") % model._meta.verbose_name
|
||||||
|
fields[field_name] = forms.BooleanField(initial=True, required=False, label=label,
|
||||||
|
help_text=help_text)
|
||||||
|
|
||||||
class AccountCreationForm(UserCreationForm):
|
def clean(self):
|
||||||
def clean_username(self):
|
""" unique usernames between accounts and system users """
|
||||||
# Since model.clean() will check this, this is redundant,
|
cleaned_data = UserCreationForm.clean(self)
|
||||||
# but it sets a nicer error message than the ORM and avoids conflicts with contrib.auth
|
try:
|
||||||
username = self.cleaned_data["username"]
|
account = Account(
|
||||||
account_model = self._meta.model
|
username=cleaned_data['username'],
|
||||||
if hasattr(account_model, 'systemusers'):
|
password=cleaned_data['password1']
|
||||||
systemuser_model = account_model.systemusers.related.model
|
)
|
||||||
if systemuser_model.objects.filter(username=username).exists():
|
except KeyError:
|
||||||
raise forms.ValidationError(self.error_messages['duplicate_username'])
|
# Previous validation error
|
||||||
return username
|
return
|
||||||
|
for model, key, related_kwargs, __ in settings.ACCOUNTS_CREATE_RELATED:
|
||||||
|
model = get_model(model)
|
||||||
|
kwargs = {
|
||||||
|
key: eval(related_kwargs[key], {'account': account})
|
||||||
|
}
|
||||||
|
if model.objects.filter(**kwargs).exists():
|
||||||
|
verbose_name = model._meta.verbose_name
|
||||||
|
raise forms.ValidationError(
|
||||||
|
_("A %s with this name already exists") % verbose_name
|
||||||
|
)
|
||||||
|
|
||||||
|
def save_related(self, account):
|
||||||
|
for model, key, related_kwargs, __ in settings.ACCOUNTS_CREATE_RELATED:
|
||||||
|
model = get_model(model)
|
||||||
|
field_name = 'create_%s' % model._meta.model_name
|
||||||
|
if self.cleaned_data[field_name]:
|
||||||
|
for key, value in related_kwargs.iteritems():
|
||||||
|
related_kwargs[key] = eval(value, {'account': account})
|
||||||
|
model.objects.create(account=account, **related_kwargs)
|
||||||
|
|
||||||
|
fields.update({
|
||||||
|
'create_related_fields': fields.keys(),
|
||||||
|
'clean': clean,
|
||||||
|
'save_related': save_related,
|
||||||
|
})
|
||||||
|
|
||||||
|
return type('AccountCreationForm', (UserCreationForm,), fields)
|
||||||
|
|
||||||
|
|
||||||
|
AccountCreationForm = create_account_creation_form()
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.contrib.auth import models as auth
|
||||||
from django.conf import settings as djsettings
|
from django.conf import settings as djsettings
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models.loading import get_model
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -57,19 +58,6 @@ class Account(auth.AbstractBaseUser):
|
||||||
def get_main(cls):
|
def get_main(cls):
|
||||||
return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK)
|
return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK)
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
""" unique usernames between accounts and system users """
|
|
||||||
if not self.pk and hasattr(self, 'systemusers'):
|
|
||||||
if self.systemusers.model.objects.filter(username=self.username).exists():
|
|
||||||
raise validators.ValidationError(_("A user with this name already exists"))
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
|
||||||
created = not self.pk
|
|
||||||
super(Account, self).save(*args, **kwargs)
|
|
||||||
if created and hasattr(self, 'systemusers'):
|
|
||||||
self.systemusers.create(username=self.username, account=self,
|
|
||||||
password=self.password, is_main=True)
|
|
||||||
|
|
||||||
def disable(self):
|
def disable(self):
|
||||||
self.is_active = False
|
self.is_active = False
|
||||||
self.save(update_fields=['is_active'])
|
self.save(update_fields=['is_active'])
|
||||||
|
@ -133,5 +121,21 @@ class Account(auth.AbstractBaseUser):
|
||||||
return True
|
return True
|
||||||
return auth._user_has_module_perms(self, app_label)
|
return auth._user_has_module_perms(self, app_label)
|
||||||
|
|
||||||
|
def get_related_passwords(self):
|
||||||
|
related = []
|
||||||
|
for model, key, kwargs, __ in settings.ACCOUNTS_CREATE_RELATED:
|
||||||
|
if 'password' not in kwargs:
|
||||||
|
continue
|
||||||
|
model = get_model(model)
|
||||||
|
kwargs = {
|
||||||
|
key: eval(kwargs[key], {'account': self})
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
rel = model.objects.get(account=self, **kwargs)
|
||||||
|
except model.DoesNotExist:
|
||||||
|
continue
|
||||||
|
related.append(rel)
|
||||||
|
return related
|
||||||
|
|
||||||
|
|
||||||
services.register(Account, menu=False)
|
services.register(Account, menu=False)
|
||||||
|
|
|
@ -22,3 +22,32 @@ ACCOUNTS_DEFAULT_LANGUAGE = getattr(settings, 'ACCOUNTS_DEFAULT_LANGUAGE', 'en')
|
||||||
|
|
||||||
|
|
||||||
ACCOUNTS_MAIN_PK = getattr(settings, 'ACCOUNTS_MAIN_PK', 1)
|
ACCOUNTS_MAIN_PK = getattr(settings, 'ACCOUNTS_MAIN_PK', 1)
|
||||||
|
|
||||||
|
|
||||||
|
ACCOUNTS_CREATE_RELATED = getattr(settings, 'ACCOUNTS_CREATE_RELATED', (
|
||||||
|
# <model>, <key field>, <kwargs>, <help_text>
|
||||||
|
('systemusers.SystemUser',
|
||||||
|
'username',
|
||||||
|
{
|
||||||
|
'username': 'account.username',
|
||||||
|
'password': 'account.password',
|
||||||
|
'is_main': 'True',
|
||||||
|
},
|
||||||
|
_("Designates whether to creates a related system users with the same username and password or not."),
|
||||||
|
),
|
||||||
|
('mailboxes.Mailbox',
|
||||||
|
'name',
|
||||||
|
{
|
||||||
|
'name': 'account.username',
|
||||||
|
'password': 'account.password',
|
||||||
|
},
|
||||||
|
_("Designates whether to creates a related mailbox with the same name and password or not."),
|
||||||
|
),
|
||||||
|
('domains.Domain',
|
||||||
|
'name',
|
||||||
|
{
|
||||||
|
'name': '"%s.orchestra.lan" % account.username'
|
||||||
|
},
|
||||||
|
_("Designates whether to creates a related subdomain <username>.orchestra.lan or not."),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
|
|
@ -11,14 +11,14 @@ def validate_contact(request, bill, error=True):
|
||||||
'You should <a href="{url}#invoicecontact-group">provide one</a>')
|
'You should <a href="{url}#invoicecontact-group">provide one</a>')
|
||||||
valid = True
|
valid = True
|
||||||
send = messages.error if error else messages.warning
|
send = messages.error if error else messages.warning
|
||||||
if not hasattr(bill.account, 'invoicecontact'):
|
if not hasattr(bill.account, 'billcontact'):
|
||||||
account = force_text(bill.account)
|
account = force_text(bill.account)
|
||||||
url = reverse('admin:accounts_account_change', args=(bill.account_id,))
|
url = reverse('admin:accounts_account_change', args=(bill.account_id,))
|
||||||
message = msg.format(relation=_("Related"), account=account, url=url)
|
message = msg.format(relation=_("Related"), account=account, url=url)
|
||||||
send(request, mark_safe(message))
|
send(request, mark_safe(message))
|
||||||
valid = False
|
valid = False
|
||||||
main = type(bill).account.field.rel.to.get_main()
|
main = type(bill).account.field.rel.to.get_main()
|
||||||
if not hasattr(main, 'invoicecontact'):
|
if not hasattr(main, 'billcontact'):
|
||||||
account = force_text(main)
|
account = force_text(main)
|
||||||
url = reverse('admin:accounts_account_change', args=(main.id,))
|
url = reverse('admin:accounts_account_change', args=(main.id,))
|
||||||
message = msg.format(relation=_("Main"), account=account, url=url)
|
message = msg.format(relation=_("Main"), account=account, url=url)
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||||
from orchestra.admin.utils import admin_link
|
from orchestra.admin.utils import admin_link, change_url
|
||||||
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
from orchestra.apps.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||||
|
|
||||||
from .forms import DatabaseCreationForm, DatabaseUserChangeForm, DatabaseUserCreationForm
|
from .forms import DatabaseCreationForm, DatabaseUserChangeForm, DatabaseUserCreationForm
|
||||||
|
@ -13,7 +13,7 @@ from .models import Database, DatabaseUser
|
||||||
|
|
||||||
|
|
||||||
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'type', 'account_link')
|
list_display = ('name', 'type', 'display_users', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
search_fields = ['name']
|
search_fields = ['name']
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
|
@ -21,7 +21,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
'classes': ('extrapretty',),
|
'classes': ('extrapretty',),
|
||||||
'fields': ('account_link', 'name', 'type', 'users'),
|
'fields': ('account_link', 'name', 'type', 'users', 'display_users'),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
|
@ -39,6 +39,18 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
add_form = DatabaseCreationForm
|
add_form = DatabaseCreationForm
|
||||||
|
readonly_fields = ('account_link', 'display_users',)
|
||||||
|
filter_horizontal = ['users']
|
||||||
|
|
||||||
|
def display_users(self, db):
|
||||||
|
links = []
|
||||||
|
for user in db.users.all():
|
||||||
|
link = '<a href="%s">%s</a>' % (change_url(user), user.username)
|
||||||
|
links.append(link)
|
||||||
|
return ', '.join(links)
|
||||||
|
display_users.short_description = _("Users")
|
||||||
|
display_users.allow_tags = True
|
||||||
|
display_users.admin_order_field = 'users__username'
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
super(DatabaseAdmin, self).save_model(request, obj, form, change)
|
super(DatabaseAdmin, self).save_model(request, obj, form, change)
|
||||||
|
@ -56,7 +68,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, ExtendedModelAdmin):
|
class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('username', 'type', 'account_link')
|
list_display = ('username', 'type', 'display_databases', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
search_fields = ['username']
|
search_fields = ['username']
|
||||||
form = DatabaseUserChangeForm
|
form = DatabaseUserChangeForm
|
||||||
|
@ -65,7 +77,7 @@ class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, Exten
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
'classes': ('extrapretty',),
|
'classes': ('extrapretty',),
|
||||||
'fields': ('account_link', 'username', 'password', 'type')
|
'fields': ('account_link', 'username', 'password', 'type', 'display_databases')
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
|
@ -74,6 +86,17 @@ class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, Exten
|
||||||
'fields': ('account_link', 'username', 'password1', 'password2', 'type')
|
'fields': ('account_link', 'username', 'password1', 'password2', 'type')
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
readonly_fields = ('account_link', 'display_databases',)
|
||||||
|
|
||||||
|
def display_databases(self, user):
|
||||||
|
links = []
|
||||||
|
for db in user.databases.all():
|
||||||
|
link = '<a href="%s">%s</a>' % (change_url(db), db.name)
|
||||||
|
links.append(link)
|
||||||
|
return ', '.join(links)
|
||||||
|
display_databases.short_description = _("Databases")
|
||||||
|
display_databases.allow_tags = True
|
||||||
|
display_databases.admin_order_field = 'databases__name'
|
||||||
|
|
||||||
def get_urls(self):
|
def get_urls(self):
|
||||||
useradmin = UserAdmin(DatabaseUser, self.admin_site)
|
useradmin = UserAdmin(DatabaseUser, self.admin_site)
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
def update_conf(self, context):
|
def update_conf(self, context):
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
sed '/zone "%(name)s".*/,/^\s*};\s*$/!d' %(conf_path)s | diff -B -I"^\s*//" - <(echo '%(conf)s') || {
|
sed '/zone "%(name)s".*/,/^\s*};\s*$/!d' %(conf_path)s | diff -B -I"^\s*//" - <(echo '%(conf)s') || {
|
||||||
sed -i -e '/zone "%(name)s".*/,/^\s*};/d' \\
|
sed -i -e '/zone\s\s*"%(name)s".*/,/^\s*};/d' \\
|
||||||
-e 'N; /^\\n$/d; P; D' %(conf_path)s
|
-e 'N; /^\\n$/d; P; D' %(conf_path)s
|
||||||
echo '%(conf)s' >> %(conf_path)s
|
echo '%(conf)s' >> %(conf_path)s
|
||||||
UPDATED=1
|
UPDATED=1
|
||||||
|
@ -47,7 +47,7 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
))
|
))
|
||||||
# Delete ex-top-domains that are now subdomains
|
# Delete ex-top-domains that are now subdomains
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
sed -i -e '/zone ".*\.%(name)s".*/,/^\s*};\s*$/d' \\
|
sed -i -e '/zone\s\s*".*\.%(name)s".*/,/^\s*};\s*$/d' \\
|
||||||
-e 'N; /^\\n$/d; P; D' %(conf_path)s""" % context
|
-e 'N; /^\\n$/d; P; D' %(conf_path)s""" % context
|
||||||
))
|
))
|
||||||
if 'zone_path' in context:
|
if 'zone_path' in context:
|
||||||
|
@ -64,7 +64,7 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
# These can never be top level domains
|
# These can never be top level domains
|
||||||
return
|
return
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
sed -e '/zone ".*\.%(name)s".*/,/^\s*};\s*$/d' \\
|
sed -e '/zone\s\s*"%(name)s".*/,/^\s*};\s*$/d' \\
|
||||||
-e 'N; /^\\n$/d; P; D' %(conf_path)s > %(conf_path)s.tmp""" % context
|
-e 'N; /^\\n$/d; P; D' %(conf_path)s > %(conf_path)s.tmp""" % context
|
||||||
))
|
))
|
||||||
self.append('diff -B -I"^\s*//" %(conf_path)s.tmp %(conf_path)s || UPDATED=1' % context)
|
self.append('diff -B -I"^\s*//" %(conf_path)s.tmp %(conf_path)s || UPDATED=1' % context)
|
||||||
|
|
|
@ -21,6 +21,17 @@ class Domain(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_top_domain(cls, name):
|
||||||
|
split = name.split('.')
|
||||||
|
top = None
|
||||||
|
for i in range(1, len(split)-1):
|
||||||
|
name = '.'.join(split[i:])
|
||||||
|
domain = Domain.objects.filter(name=name)
|
||||||
|
if domain:
|
||||||
|
top = domain.get()
|
||||||
|
return top
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def origin(self):
|
def origin(self):
|
||||||
return self.top or self
|
return self.top or self
|
||||||
|
@ -39,14 +50,7 @@ class Domain(models.Model):
|
||||||
return self.origin.subdomains.all()
|
return self.origin.subdomains.all()
|
||||||
|
|
||||||
def get_top(self):
|
def get_top(self):
|
||||||
split = self.name.split('.')
|
return type(self).get_top_domain(self.name)
|
||||||
top = None
|
|
||||||
for i in range(1, len(split)-1):
|
|
||||||
name = '.'.join(split[i:])
|
|
||||||
domain = Domain.objects.filter(name=name)
|
|
||||||
if domain:
|
|
||||||
top = domain.get()
|
|
||||||
return top
|
|
||||||
|
|
||||||
def render_zone(self):
|
def render_zone(self):
|
||||||
origin = self.origin
|
origin = self.origin
|
||||||
|
|
|
@ -27,6 +27,14 @@ class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||||
fields = ('url', 'name', 'records')
|
fields = ('url', 'name', 'records')
|
||||||
postonly_fields = ('name',)
|
postonly_fields = ('name',)
|
||||||
|
|
||||||
|
def clean_name(self, attrs, source):
|
||||||
|
""" prevent users creating subdomains of other users domains """
|
||||||
|
name = attrs[source]
|
||||||
|
top = Domain.get_top_domain(name)
|
||||||
|
if top and top.account != self.account:
|
||||||
|
raise ValidationError(_("Can not create subdomains of other users domains"))
|
||||||
|
return attrs
|
||||||
|
|
||||||
def full_clean(self, instance):
|
def full_clean(self, instance):
|
||||||
""" Checks if everything is consistent """
|
""" Checks if everything is consistent """
|
||||||
instance = super(DomainSerializer, self).full_clean(instance)
|
instance = super(DomainSerializer, self).full_clean(instance)
|
||||||
|
|
|
@ -124,7 +124,7 @@ class MailmanBackend(ServiceController):
|
||||||
'name': mail_list.name,
|
'name': mail_list.name,
|
||||||
'password': mail_list.password,
|
'password': mail_list.password,
|
||||||
'domain': mail_list.address_domain or settings.LISTS_DEFAULT_DOMAIN,
|
'domain': mail_list.address_domain or settings.LISTS_DEFAULT_DOMAIN,
|
||||||
'address_name': mail_list.address_name,
|
'address_name': mail_list.get_address_name,
|
||||||
'address_domain': mail_list.address_domain,
|
'address_domain': mail_list.address_domain,
|
||||||
'admin': mail_list.admin_email,
|
'admin': mail_list.admin_email,
|
||||||
'mailman_root': settings.LISTS_MAILMAN_ROOT_PATH,
|
'mailman_root': settings.LISTS_MAILMAN_ROOT_PATH,
|
||||||
|
|
|
@ -12,9 +12,6 @@ class CleanAddressMixin(object):
|
||||||
if name and not domain:
|
if name and not domain:
|
||||||
msg = _("Domain should be selected for provided address name")
|
msg = _("Domain should be selected for provided address name")
|
||||||
raise forms.ValidationError(msg)
|
raise forms.ValidationError(msg)
|
||||||
elif not name and domain:
|
|
||||||
msg = _("Address name should be provided for this selected domain")
|
|
||||||
raise forms.ValidationError(msg)
|
|
||||||
return domain
|
return domain
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@ class List(models.Model):
|
||||||
return "%s@%s" % (self.address_name, self.address_domain)
|
return "%s@%s" % (self.address_name, self.address_domain)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def get_address_name(self):
|
||||||
|
return self.address_name or self.name
|
||||||
|
|
||||||
def get_username(self):
|
def get_username(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
|
@ -40,15 +40,15 @@ class ListSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||||
raise serializers.ValidationError(_("Password required"))
|
raise serializers.ValidationError(_("Password required"))
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate_address_domain(self, attrs, source):
|
||||||
address_domain = attrs.get('address_domain')
|
address_domain = attrs.get(source)
|
||||||
address_name = attrs.get('address_name', )
|
address_name = attrs.get('address_name')
|
||||||
if self.object:
|
if self.object:
|
||||||
address_domain = address_domain or self.object.address_domain
|
address_domain = address_domain or self.object.address_domain
|
||||||
address_name = address_name or self.object.address_name
|
address_name = address_name or self.object.address_name
|
||||||
if bool(address_domain) != bool(address_name):
|
if address_name and not address_domain:
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
_("address_name and address_domain should go in tandem"))
|
_("address_domains should should be provided when providing an addres_name"))
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def save_object(self, obj, **kwargs):
|
def save_object(self, obj, **kwargs):
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin
|
from orchestra.admin import ExtendedModelAdmin
|
||||||
from orchestra.admin.utils import change_url
|
from orchestra.admin.utils import change_url
|
||||||
from orchestra.apps.accounts.admin import SelectAccountAdminMixin
|
from orchestra.apps.accounts.admin import AccountAdminMixin
|
||||||
|
|
||||||
from .models import WebApp, WebAppOption
|
from .models import WebApp, WebAppOption
|
||||||
|
|
||||||
|
@ -25,10 +25,11 @@ class WebAppOptionInline(admin.TabularInline):
|
||||||
return super(WebAppOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
return super(WebAppOptionInline, self).formfield_for_dbfield(db_field, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class WebAppAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class WebAppAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
fields = ('account_link', 'name', 'type')
|
|
||||||
list_display = ('name', 'type', 'display_websites', 'account_link')
|
list_display = ('name', 'type', 'display_websites', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
|
add_fields = ('account', 'name', 'type')
|
||||||
|
fields = ('account_link', 'name', 'type')
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link',)
|
readonly_fields = ('account_link',)
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
|
|
|
@ -41,7 +41,7 @@ def validate_name(value):
|
||||||
"""
|
"""
|
||||||
A single non-empty line of free-form text with no whitespace.
|
A single non-empty line of free-form text with no whitespace.
|
||||||
"""
|
"""
|
||||||
validators.RegexValidator('^[\.\w]+$',
|
validators.RegexValidator('^[\.\w\-]+$',
|
||||||
_("Enter a valid name (text without whitspaces)."), 'invalid')(value)
|
_("Enter a valid name (text without whitspaces)."), 'invalid')(value)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ class UserCreationForm(forms.ModelForm):
|
||||||
"""
|
"""
|
||||||
error_messages = {
|
error_messages = {
|
||||||
'password_mismatch': _("The two password fields didn't match."),
|
'password_mismatch': _("The two password fields didn't match."),
|
||||||
|
'duplicate_username': _("A user with that username already exists."),
|
||||||
}
|
}
|
||||||
password1 = forms.CharField(label=_("Password"),
|
password1 = forms.CharField(label=_("Password"),
|
||||||
widget=forms.PasswordInput, validators=[validate_password])
|
widget=forms.PasswordInput, validators=[validate_password])
|
||||||
|
|
Loading…
Reference in a new issue