Random improvements
This commit is contained in:
parent
d2b96dac40
commit
4d9feb690f
1
TODO.md
1
TODO.md
|
@ -177,3 +177,4 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
||||||
* ServiceBackend.validate() : used for server paths validation
|
* ServiceBackend.validate() : used for server paths validation
|
||||||
* ServiceBackend.grant_access() : used for granting access
|
* ServiceBackend.grant_access() : used for granting access
|
||||||
* bottom line: allow arbitrary backend methods (underscore method names that are not to be executed?)
|
* bottom line: allow arbitrary backend methods (underscore method names that are not to be executed?)
|
||||||
|
* HowTo?? Signals ? what?
|
||||||
|
|
|
@ -39,8 +39,7 @@ class ChangeListDefaultFilter(object):
|
||||||
defaults.append(key)
|
defaults.append(key)
|
||||||
# hack response cl context in order to hook default filter awaearness
|
# hack response cl context in order to hook default filter awaearness
|
||||||
# into search_form.html template
|
# into search_form.html template
|
||||||
response = super(ChangeListDefaultFilter, self).changelist_view(request,
|
response = super(ChangeListDefaultFilter, self).changelist_view(request, extra_context)
|
||||||
extra_context=extra_context)
|
|
||||||
if hasattr(response, 'context_data') and 'cl' in response.context_data:
|
if hasattr(response, 'context_data') and 'cl' in response.context_data:
|
||||||
response.context_data['cl'].default_changelist_filters = defaults
|
response.context_data['cl'].default_changelist_filters = defaults
|
||||||
return response
|
return response
|
||||||
|
@ -100,7 +99,7 @@ class ChangeViewActionsMixin(object):
|
||||||
kwargs['extra_context'] = {}
|
kwargs['extra_context'] = {}
|
||||||
obj = self.get_object(request, unquote(object_id))
|
obj = self.get_object(request, unquote(object_id))
|
||||||
kwargs['extra_context']['object_tools_items'] = [
|
kwargs['extra_context']['object_tools_items'] = [
|
||||||
action.__dict__ for action in self.get_change_view_actions(obj=obj)
|
action.__dict__ for action in self.get_change_view_actions(obj)
|
||||||
]
|
]
|
||||||
return super(ChangeViewActionsMixin, self).change_view(request, object_id, **kwargs)
|
return super(ChangeViewActionsMixin, self).change_view(request, object_id, **kwargs)
|
||||||
|
|
||||||
|
@ -116,11 +115,11 @@ class ChangeAddFieldsMixin(object):
|
||||||
|
|
||||||
def get_prepopulated_fields(self, request, obj=None):
|
def get_prepopulated_fields(self, request, obj=None):
|
||||||
if not obj:
|
if not obj:
|
||||||
return super(ChangeAddFieldsMixin, self).get_prepopulated_fields(request, obj=obj)
|
return super(ChangeAddFieldsMixin, self).get_prepopulated_fields(request, obj)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_readonly_fields(self, request, obj=None):
|
def get_readonly_fields(self, request, obj=None):
|
||||||
fields = super(ChangeAddFieldsMixin, self).get_readonly_fields(request, obj=obj)
|
fields = super(ChangeAddFieldsMixin, self).get_readonly_fields(request, obj)
|
||||||
if obj:
|
if obj:
|
||||||
return fields + self.change_readonly_fields
|
return fields + self.change_readonly_fields
|
||||||
return fields
|
return fields
|
||||||
|
@ -131,7 +130,7 @@ class ChangeAddFieldsMixin(object):
|
||||||
return self.add_fieldsets
|
return self.add_fieldsets
|
||||||
elif self.add_fields:
|
elif self.add_fields:
|
||||||
return [(None, {'fields': self.add_fields})]
|
return [(None, {'fields': self.add_fields})]
|
||||||
return super(ChangeAddFieldsMixin, self).get_fieldsets(request, obj=obj)
|
return super(ChangeAddFieldsMixin, self).get_fieldsets(request, obj)
|
||||||
|
|
||||||
def get_inline_instances(self, request, obj=None):
|
def get_inline_instances(self, request, obj=None):
|
||||||
""" add_inlines and inline.parent_object """
|
""" add_inlines and inline.parent_object """
|
||||||
|
@ -139,7 +138,7 @@ class ChangeAddFieldsMixin(object):
|
||||||
self.inlines = type(self).inlines
|
self.inlines = type(self).inlines
|
||||||
else:
|
else:
|
||||||
self.inlines = self.add_inlines or self.inlines
|
self.inlines = self.add_inlines or self.inlines
|
||||||
inlines = super(ChangeAddFieldsMixin, self).get_inline_instances(request, obj=obj)
|
inlines = super(ChangeAddFieldsMixin, self).get_inline_instances(request, obj)
|
||||||
for inline in inlines:
|
for inline in inlines:
|
||||||
inline.parent_object = obj
|
inline.parent_object = obj
|
||||||
return inlines
|
return inlines
|
||||||
|
@ -200,7 +199,7 @@ class ChangePasswordAdminMixin(object):
|
||||||
related.append(rel)
|
related.append(rel)
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = self.change_password_form(user, request.POST, related=related)
|
form = self.change_password_form(user, request.POST, related)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
form.save()
|
form.save()
|
||||||
change_message = self.construct_change_message(request, form, None)
|
change_message = self.construct_change_message(request, form, None)
|
||||||
|
@ -210,7 +209,7 @@ class ChangePasswordAdminMixin(object):
|
||||||
update_session_auth_hash(request, form.user) # This is safe
|
update_session_auth_hash(request, form.user) # This is safe
|
||||||
return HttpResponseRedirect('..')
|
return HttpResponseRedirect('..')
|
||||||
else:
|
else:
|
||||||
form = self.change_password_form(user, related=related)
|
form = self.change_password_form(user, related)
|
||||||
|
|
||||||
fieldsets = [
|
fieldsets = [
|
||||||
(user._meta.verbose_name.capitalize(), {
|
(user._meta.verbose_name.capitalize(), {
|
||||||
|
|
|
@ -3,6 +3,7 @@ from rest_framework.response import Response
|
||||||
from rest_framework.reverse import reverse
|
from rest_framework.reverse import reverse
|
||||||
|
|
||||||
from .. import settings
|
from .. import settings
|
||||||
|
from ..core import services, accounts
|
||||||
|
|
||||||
|
|
||||||
class APIRoot(views.APIView):
|
class APIRoot(views.APIView):
|
||||||
|
@ -15,6 +16,10 @@ class APIRoot(views.APIView):
|
||||||
'<%s>; rel="%s"' % (root_url, 'api-root'),
|
'<%s>; rel="%s"' % (root_url, 'api-root'),
|
||||||
'<%s>; rel="%s"' % (token_url, 'api-get-auth-token'),
|
'<%s>; rel="%s"' % (token_url, 'api-get-auth-token'),
|
||||||
]
|
]
|
||||||
|
body = {
|
||||||
|
'accountancy': [],
|
||||||
|
'services': [],
|
||||||
|
}
|
||||||
if not request.user.is_anonymous():
|
if not request.user.is_anonymous():
|
||||||
list_name = '{basename}-list'
|
list_name = '{basename}-list'
|
||||||
detail_name = '{basename}-detail'
|
detail_name = '{basename}-detail'
|
||||||
|
@ -30,17 +35,34 @@ class APIRoot(views.APIView):
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
url = reverse(url_name, request=request, format=format, kwargs=kwargs)
|
url = reverse(url_name, request=request, format=format, kwargs=kwargs)
|
||||||
links.append('<%s>; rel="%s"' % (url, url_name))
|
links.append('<%s>; rel="%s"' % (url, url_name))
|
||||||
|
model = viewset.model
|
||||||
|
group = None
|
||||||
|
if model in services:
|
||||||
|
group = 'services'
|
||||||
|
menu = services[model].menu
|
||||||
|
elif model in accounts:
|
||||||
|
group = 'accountancy'
|
||||||
|
menu = accounts[model].menu
|
||||||
|
if group and menu:
|
||||||
|
body[group].append({
|
||||||
|
'url': url,
|
||||||
|
'name': basename,
|
||||||
|
'verbose_name': model._meta.verbose_name,
|
||||||
|
'verbose_name_plural': model._meta.verbose_name_plural,
|
||||||
|
})
|
||||||
headers = {
|
headers = {
|
||||||
'Link': ', '.join(links)
|
'Link': ', '.join(links)
|
||||||
}
|
}
|
||||||
body = {
|
body.update({
|
||||||
name.lower(): getattr(settings, name, None) for name in self.names
|
name.lower(): getattr(settings, name, None)
|
||||||
}
|
for name in self.names
|
||||||
|
})
|
||||||
return Response(body, headers=headers)
|
return Response(body, headers=headers)
|
||||||
|
|
||||||
def metadata(self, request):
|
def metadata(self, request):
|
||||||
ret = super(APIRoot, self).metadata(request)
|
ret = super(APIRoot, self).metadata(request)
|
||||||
ret['settings'] = {
|
ret['settings'] = {
|
||||||
name.lower(): getattr(settings, name, None) for name in self.names
|
name.lower(): getattr(settings, name, None)
|
||||||
|
for name in self.names
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
|
|
@ -11,11 +11,15 @@ from . import settings, validators, utils
|
||||||
|
|
||||||
class Domain(models.Model):
|
class Domain(models.Model):
|
||||||
name = models.CharField(_("name"), max_length=256, unique=True,
|
name = models.CharField(_("name"), max_length=256, unique=True,
|
||||||
validators=[validators.validate_domain_name, validators.validate_allowed_domain],
|
help_text=_("Domain or subdomain name."),
|
||||||
help_text=_("Domain or subdomain name."))
|
validators=[
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
validators.validate_domain_name,
|
||||||
related_name='domains', blank=True, help_text=_("Automatically selected for subdomains."))
|
validators.validate_allowed_domain
|
||||||
top = models.ForeignKey('domains.Domain', null=True, related_name='subdomain_set', editable=False)
|
])
|
||||||
|
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), blank=True,
|
||||||
|
related_name='domains', help_text=_("Automatically selected for subdomains."))
|
||||||
|
top = models.ForeignKey('domains.Domain', null=True, related_name='subdomain_set',
|
||||||
|
editable=False)
|
||||||
serial = models.IntegerField(_("serial"), default=utils.generate_zone_serial,
|
serial = models.IntegerField(_("serial"), default=utils.generate_zone_serial,
|
||||||
help_text=_("Serial number"))
|
help_text=_("Serial number"))
|
||||||
|
|
||||||
|
@ -88,17 +92,24 @@ class Domain(models.Model):
|
||||||
# Update serial and insert at 0
|
# Update serial and insert at 0
|
||||||
value = record.value.split()
|
value = record.value.split()
|
||||||
value[2] = str(self.serial)
|
value[2] = str(self.serial)
|
||||||
records.insert(0,
|
records.insert(0, AttrDict(
|
||||||
AttrDict(type=record.SOA, ttl=record.get_ttl(), value=' '.join(value))
|
type=record.SOA,
|
||||||
)
|
ttl=record.get_ttl(),
|
||||||
|
value=' '.join(value)
|
||||||
|
))
|
||||||
else:
|
else:
|
||||||
records.append(
|
records.append(AttrDict(
|
||||||
AttrDict(type=record.type, ttl=record.get_ttl(), value=record.value)
|
type=record.type,
|
||||||
)
|
ttl=record.get_ttl(),
|
||||||
|
value=record.value
|
||||||
|
))
|
||||||
if self.is_top:
|
if self.is_top:
|
||||||
if Record.NS not in types:
|
if Record.NS not in types:
|
||||||
for ns in settings.DOMAINS_DEFAULT_NS:
|
for ns in settings.DOMAINS_DEFAULT_NS:
|
||||||
records.append(AttrDict(type=Record.NS, value=ns))
|
records.append(AttrDict(
|
||||||
|
type=Record.NS,
|
||||||
|
value=ns
|
||||||
|
))
|
||||||
if Record.SOA not in types:
|
if Record.SOA not in types:
|
||||||
soa = [
|
soa = [
|
||||||
"%s." % settings.DOMAINS_DEFAULT_NAME_SERVER,
|
"%s." % settings.DOMAINS_DEFAULT_NAME_SERVER,
|
||||||
|
@ -109,27 +120,42 @@ class Domain(models.Model):
|
||||||
settings.DOMAINS_DEFAULT_EXPIRATION,
|
settings.DOMAINS_DEFAULT_EXPIRATION,
|
||||||
settings.DOMAINS_DEFAULT_MIN_CACHING_TIME
|
settings.DOMAINS_DEFAULT_MIN_CACHING_TIME
|
||||||
]
|
]
|
||||||
records.insert(0, AttrDict(type=Record.SOA, value=' '.join(soa)))
|
records.insert(0, AttrDict(
|
||||||
|
type=Record.SOA,
|
||||||
|
value=' '.join(soa)
|
||||||
|
))
|
||||||
is_a = not types or Record.A in types or Record.AAAA in types
|
is_a = not types or Record.A in types or Record.AAAA in types
|
||||||
if Record.MX not in types and is_a:
|
if Record.MX not in types and is_a:
|
||||||
for mx in settings.DOMAINS_DEFAULT_MX:
|
for mx in settings.DOMAINS_DEFAULT_MX:
|
||||||
records.append(AttrDict(type=Record.MX, value=mx))
|
records.append(AttrDict(
|
||||||
|
type=Record.MX,
|
||||||
|
value=mx
|
||||||
|
))
|
||||||
if (Record.A not in types and Record.AAAA not in types) and is_a:
|
if (Record.A not in types and Record.AAAA not in types) and is_a:
|
||||||
records.append(AttrDict(type=Record.A, value=settings.DOMAINS_DEFAULT_A))
|
records.append(AttrDict(
|
||||||
|
type=Record.A,
|
||||||
|
value=settings.DOMAINS_DEFAULT_A
|
||||||
|
))
|
||||||
result = ''
|
result = ''
|
||||||
for record in records:
|
for record in records:
|
||||||
name = '{name}.{spaces}'.format(
|
name = '{name}.{spaces}'.format(
|
||||||
name=self.name, spaces=' ' * (37-len(self.name))
|
name=self.name,
|
||||||
|
spaces=' ' * (37-len(self.name))
|
||||||
)
|
)
|
||||||
ttl = record.get('ttl', settings.DOMAINS_DEFAULT_TTL)
|
ttl = record.get('ttl', settings.DOMAINS_DEFAULT_TTL)
|
||||||
ttl = '{spaces}{ttl}'.format(
|
ttl = '{spaces}{ttl}'.format(
|
||||||
spaces=' ' * (7-len(ttl)), ttl=ttl
|
spaces=' ' * (7-len(ttl)),
|
||||||
|
ttl=ttl
|
||||||
)
|
)
|
||||||
type = '{type} {spaces}'.format(
|
type = '{type} {spaces}'.format(
|
||||||
type=record.type, spaces=' ' * (7-len(record.type))
|
type=record.type,
|
||||||
|
spaces=' ' * (7-len(record.type))
|
||||||
)
|
)
|
||||||
result += '{name} {ttl} IN {type} {value}\n'.format(
|
result += '{name} {ttl} IN {type} {value}\n'.format(
|
||||||
name=name, ttl=ttl, type=type, value=record.value
|
name=name,
|
||||||
|
ttl=ttl,
|
||||||
|
type=type,
|
||||||
|
value=record.value
|
||||||
)
|
)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,7 @@ class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
|
||||||
""" Checks if everything is consistent """
|
""" Checks if everything is consistent """
|
||||||
instance = super(DomainSerializer, self).full_clean(instance)
|
instance = super(DomainSerializer, self).full_clean(instance)
|
||||||
if instance and instance.name:
|
if instance and instance.name:
|
||||||
records = self.init_data['records']
|
records = self.init_data.get('records', [])
|
||||||
domain = domain_for_validation(instance, records)
|
domain = domain_for_validation(instance, records)
|
||||||
try:
|
|
||||||
validators.validate_zone(domain.render_zone())
|
validators.validate_zone(domain.render_zone())
|
||||||
except ValidationError as err:
|
|
||||||
self._errors = {
|
|
||||||
'all': err.message
|
|
||||||
}
|
|
||||||
return None
|
|
||||||
return instance
|
return instance
|
||||||
|
|
|
@ -51,7 +51,7 @@ class Miscellaneous(models.Model):
|
||||||
verbose_name_plural = _("miscellaneous")
|
verbose_name_plural = _("miscellaneous")
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.identifier or str(self.service)
|
return self.identifier or self.description[:32] or str(self.service)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def active(self):
|
def active(self):
|
||||||
|
|
|
@ -21,7 +21,9 @@ from .models import SystemUser
|
||||||
|
|
||||||
|
|
||||||
class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('username', 'account_link', 'shell', 'display_home', 'display_active', 'display_main')
|
list_display = (
|
||||||
|
'username', 'account_link', 'shell', 'display_home', 'display_active', 'display_main'
|
||||||
|
)
|
||||||
list_filter = ('is_active', 'shell', IsMainListFilter)
|
list_filter = ('is_active', 'shell', IsMainListFilter)
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {
|
(None, {
|
||||||
|
|
|
@ -24,8 +24,9 @@ class SystemUser(models.Model):
|
||||||
""" System users """
|
""" System users """
|
||||||
username = models.CharField(_("username"), max_length=64, unique=True,
|
username = models.CharField(_("username"), max_length=64, unique=True,
|
||||||
help_text=_("Required. 64 characters or fewer. Letters, digits and ./-/_ only."),
|
help_text=_("Required. 64 characters or fewer. Letters, digits and ./-/_ only."),
|
||||||
validators=[validators.RegexValidator(r'^[\w.-]+$',
|
validators=[
|
||||||
_("Enter a valid username."), 'invalid')])
|
validators.RegexValidator(r'^[\w.-]+$', _("Enter a valid username."))
|
||||||
|
])
|
||||||
password = models.CharField(_("password"), max_length=128)
|
password = models.CharField(_("password"), max_length=128)
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||||
related_name='systemusers')
|
related_name='systemusers')
|
||||||
|
@ -82,7 +83,10 @@ class SystemUser(models.Model):
|
||||||
return settings.SYSTEMUSERS_HOME % context
|
return settings.SYSTEMUSERS_HOME % context
|
||||||
|
|
||||||
def get_home(self):
|
def get_home(self):
|
||||||
return os.path.join(self.home or self.get_base_home(), self.directory)
|
return os.path.join(
|
||||||
|
self.home or self.get_base_home(),
|
||||||
|
self.directory
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
services.register(SystemUser)
|
services.register(SystemUser)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
from ..utils.python import AttrDict
|
||||||
|
|
||||||
|
|
||||||
class Register(object):
|
class Register(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._registry = {}
|
self._registry = {}
|
||||||
|
@ -5,17 +8,22 @@ class Register(object):
|
||||||
def __contains__(self, key):
|
def __contains__(self, key):
|
||||||
return key in self._registry
|
return key in self._registry
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._registry[key]
|
||||||
|
|
||||||
def register(self, model, **kwargs):
|
def register(self, model, **kwargs):
|
||||||
if model in self._registry:
|
if model in self._registry:
|
||||||
raise KeyError("%s already registered" % str(model))
|
raise KeyError("%s already registered" % str(model))
|
||||||
plural = kwargs.get('verbose_name_plural', model._meta.verbose_name_plural)
|
plural = kwargs.get('verbose_name_plural', model._meta.verbose_name_plural)
|
||||||
self._registry[model] = {
|
self._registry[model] = AttrDict(**{
|
||||||
'verbose_name': kwargs.get('verbose_name', model._meta.verbose_name),
|
'verbose_name': kwargs.get('verbose_name', model._meta.verbose_name),
|
||||||
'verbose_name_plural': plural,
|
'verbose_name_plural': plural,
|
||||||
'menu': kwargs.get('menu', True)
|
'menu': kwargs.get('menu', True)
|
||||||
}
|
})
|
||||||
|
|
||||||
def get(self):
|
def get(self, *args):
|
||||||
|
if args:
|
||||||
|
return self._registry[arg[0]]
|
||||||
return self._registry
|
return self._registry
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue