websites: Prevent multiple domains on the same port

This commit is contained in:
Marc Aymerich 2015-02-25 17:29:39 +00:00
parent 01842f224b
commit f2dbc0ed42
6 changed files with 79 additions and 24 deletions

View File

@ -131,15 +131,17 @@ class PostfixAddressBackend(ServiceController):
self.append('sed -i "/^%(domain)s\s*/d" %(virtual_alias_domains)s' % context) self.append('sed -i "/^%(domain)s\s*/d" %(virtual_alias_domains)s' % context)
def update_virtual_alias_maps(self, address, context): def update_virtual_alias_maps(self, address, context):
destination = [] # Virtual mailbox stuff
for mailbox in address.get_mailboxes(): # destination = []
context['mailbox'] = mailbox # for mailbox in address.get_mailboxes():
destination.append("%(mailbox)s@%(mailbox_domain)s" % context) # context['mailbox'] = mailbox
for forward in address.forward: # destination.append("%(mailbox)s@%(mailbox_domain)s" % context)
if '@' in forward: # for forward in address.forward:
destination.append(forward) # if '@' in forward:
# destination.append(forward)
destination = address.destination
if destination: if destination:
context['destination'] = ' '.join(destination) context['destination'] = destination
self.append(textwrap.dedent(""" self.append(textwrap.dedent("""
LINE="%(email)s\t%(destination)s" LINE="%(email)s\t%(destination)s"
if [[ ! $(grep "^%(email)s\s" %(virtual_alias_maps)s) ]]; then if [[ ! $(grep "^%(email)s\s" %(virtual_alias_maps)s) ]]; then
@ -153,7 +155,7 @@ class PostfixAddressBackend(ServiceController):
fi""") % context) fi""") % context)
else: else:
logger.warning("Address %i is empty" % address.pk) logger.warning("Address %i is empty" % address.pk)
self.append('sed -i "/^%(email)s\s/d" %(virtual_alias_maps)s') self.append('sed -i "/^%(email)s\s/d" %(virtual_alias_maps)s' % context)
self.append('UPDATED_VIRTUAL_ALIAS_MAPS=1') self.append('UPDATED_VIRTUAL_ALIAS_MAPS=1')
def exclude_virtual_alias_maps(self, context): def exclude_virtual_alias_maps(self, context):
@ -180,6 +182,7 @@ class PostfixAddressBackend(ServiceController):
[[ $UPDATED_VIRTUAL_ALIAS_DOMAINS == 1 ]] && { /etc/init.d/postfix reload; } [[ $UPDATED_VIRTUAL_ALIAS_DOMAINS == 1 ]] && { /etc/init.d/postfix reload; }
""") % context """) % context
) )
self.append('exit 0')
def get_context_files(self): def get_context_files(self):
return { return {

View File

@ -111,12 +111,12 @@ class Address(models.Model):
def email(self): def email(self):
return "%s@%s" % (self.name, self.domain) return "%s@%s" % (self.name, self.domain)
# @property @cached_property
# def destination(self): def destination(self):
# destinations = list(self.mailboxes.values_list('name', flat=True)) destinations = list(self.mailboxes.values_list('name', flat=True))
# if self.forward: if self.forward:
# destinations.append(self.forward) destinations += self.forward
# return ' '.join(destinations) return ' '.join(destinations)
def clean(self): def clean(self):
if self.account_id: if self.account_id:

View File

@ -1,13 +1,17 @@
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
from django.core.urlresolvers import resolve
from django.db.models import Q
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.admin import ExtendedModelAdmin from orchestra.admin import ExtendedModelAdmin
from orchestra.admin.utils import admin_link, change_url 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 orchestra.forms.widgets import DynamicHelpTextSelect from orchestra.forms.widgets import DynamicHelpTextSelect
from . import settings from . import settings
from .forms import WebsiteAdminForm
from .models import Content, Website, WebsiteOption from .models import Content, Website, WebsiteOption
@ -65,6 +69,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
'fields': ('account_link', 'name', 'port', 'domains', 'is_active'), 'fields': ('account_link', 'name', 'port', 'domains', 'is_active'),
}), }),
) )
form = WebsiteAdminForm
filter_by_account_fields = ['domains'] filter_by_account_fields = ['domains']
list_prefetch_related = ('domains', 'content_set__webapp') list_prefetch_related = ('domains', 'content_set__webapp')
search_fields = ('name', 'account__username', 'domains__name') search_fields = ('name', 'account__username', 'domains__name')
@ -91,9 +96,21 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
display_webapps.short_description = _("Web apps") display_webapps.short_description = _("Web apps")
def formfield_for_dbfield(self, db_field, **kwargs): def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'root': """
kwargs['widget'] = forms.TextInput(attrs={'size':'100'}) Exclude domains with exhausted ports
return super(WebsiteAdmin, self).formfield_for_dbfield(db_field, **kwargs) has to be done here, on the form doesn't work because of filter_by_account_fields
"""
formfield = super(WebsiteAdmin, self).formfield_for_dbfield(db_field, **kwargs)
if db_field.name == 'domains':
qset = Q()
for port, __ in settings.WEBSITES_PORT_CHOICES:
qset = qset & Q(websites__port=port)
args = resolve(kwargs['request'].path).args
if args:
object_id = args[0]
qset = Q(qset & ~Q(websites__pk=object_id))
formfield.queryset = formfield.queryset.exclude(qset)
return formfield
admin.site.register(Website, WebsiteAdmin) admin.site.register(Website, WebsiteAdmin)

View File

@ -0,0 +1,20 @@
from django import forms
from django.core.exceptions import ValidationError
class WebsiteAdminForm(forms.ModelForm):
def clean(self):
""" Prevent multiples domains on the same port """
domains = self.cleaned_data.get('domains')
port = self.cleaned_data.get('port')
existing = []
for domain in domains.all():
if domain.websites.filter(port=port).exclude(pk=self.instance.pk).exists():
existing.append(domain.name)
if existing:
context = (', '.join(existing), port)
raise ValidationError({
'domains': 'A website is already defined for "%s" on port %s' % context
})
return self.cleaned_data

View File

@ -32,12 +32,6 @@ class Website(models.Model):
def unique_name(self): def unique_name(self):
return "%s-%i" % (self.name, self.pk) return "%s-%i" % (self.name, self.pk)
@cached
def get_options(self):
return {
opt.name: opt.value for opt in self.options.all()
}
@property @property
def protocol(self): def protocol(self):
if self.port == 80: if self.port == 80:
@ -46,6 +40,12 @@ class Website(models.Model):
return 'https' return 'https'
raise TypeError('No protocol for port "%s"' % self.port) raise TypeError('No protocol for port "%s"' % self.port)
@cached
def get_options(self):
return {
opt.name: opt.value for opt in self.options.all()
}
def get_absolute_url(self): def get_absolute_url(self):
domain = self.domains.first() domain = self.domains.first()
if domain: if domain:

View File

@ -1,3 +1,4 @@
from django.core.exceptions import ValidationError
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from rest_framework import serializers from rest_framework import serializers
@ -49,3 +50,17 @@ class WebsiteSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
model = Website model = Website
fields = ('url', 'name', 'port', 'domains', 'is_active', 'contents', 'options') fields = ('url', 'name', 'port', 'domains', 'is_active', 'contents', 'options')
postonly_fileds = ('name',) postonly_fileds = ('name',)
def full_clean(self, instance):
""" Prevent multiples domains on the same port """
existing = []
for domain in instance._m2m_data['domains']:
if domain.websites.filter(port=instance.port).exclude(pk=instance.pk).exists():
existing.append(domain.name)
if existing:
context = (', '.join(existing), instance.port)
raise ValidationError({
'domains': 'A website is already defined for "%s" on port %s' % context
})
return instance