Random improvements

This commit is contained in:
Marc Aymerich 2014-11-14 15:51:18 +00:00
parent d2b96dac40
commit 4d9feb690f
9 changed files with 104 additions and 48 deletions

View File

@ -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?

View File

@ -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(), {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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, {

View File

@ -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)

View File

@ -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