Impreved admin cross-reference between mailboxes and address

This commit is contained in:
Marc Aymerich 2016-05-05 11:58:35 +00:00
parent 51ac729ce1
commit 202d1fd632
4 changed files with 46 additions and 34 deletions

View File

@ -4,7 +4,7 @@ from urllib.parse import parse_qs
from django import forms from django import forms
from django.contrib import admin, messages from django.contrib import admin, messages
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.models import F, Value as V from django.db.models import F, Count, Value as V
from django.db.models.functions import Concat from django.db.models.functions import Concat
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -96,7 +96,7 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
url = change_url(addr) url = change_url(addr)
forwards.append('<a href="%s">%s</a>' % (url, addr.email)) forwards.append('<a href="%s">%s</a>' % (url, addr.email))
return '<br>'.join(forwards) return '<br>'.join(forwards)
display_forwards.short_description = _("Forwards") display_forwards.short_description = _("Forward from")
display_forwards.allow_tags = True display_forwards.allow_tags = True
def display_filtering(self, mailbox): def display_filtering(self, mailbox):
@ -203,13 +203,13 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
'display_email', 'account_link', 'domain_link', 'display_mailboxes', 'display_forward', 'display_email', 'account_link', 'domain_link', 'display_mailboxes', 'display_forward',
) )
list_filter = (HasMailboxListFilter, HasForwardListFilter) list_filter = (HasMailboxListFilter, HasForwardListFilter)
fields = ('account_link', 'email_link', 'mailboxes', 'forward') fields = ('account_link', 'email_link', 'mailboxes', 'forward', 'display_all_mailboxes')
add_fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward') add_fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward')
# inlines = [AutoresponseInline] # inlines = [AutoresponseInline]
search_fields = ( search_fields = (
'forward', 'mailboxes__name', 'account__username', 'computed_email', 'domain__name' 'forward', 'mailboxes__name', 'account__username', 'computed_email', 'domain__name'
) )
readonly_fields = ('account_link', 'domain_link', 'email_link') readonly_fields = ('account_link', 'domain_link', 'email_link', 'display_all_mailboxes')
actions = (SendAddressEmail(),) actions = (SendAddressEmail(),)
filter_by_account_fields = ('domain', 'mailboxes') filter_by_account_fields = ('domain', 'mailboxes')
filter_horizontal = ['mailboxes'] filter_horizontal = ['mailboxes']
@ -237,6 +237,16 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
return '<br>'.join(boxes) return '<br>'.join(boxes)
display_mailboxes.short_description = _("Mailboxes") display_mailboxes.short_description = _("Mailboxes")
display_mailboxes.allow_tags = True display_mailboxes.allow_tags = True
display_mailboxes.admin_order_field = 'mailboxes__count'
def display_all_mailboxes(self, address):
boxes = []
for mailbox in address.get_mailboxes():
url = change_url(mailbox)
boxes.append('<a href="%s">%s</a>' % (url, mailbox.name))
return '<br>'.join(boxes)
display_all_mailboxes.short_description = _("Mailboxes links")
display_all_mailboxes.allow_tags = True
def display_forward(self, address): def display_forward(self, address):
forward_mailboxes = {m.name: m for m in address.get_forward_mailboxes()} forward_mailboxes = {m.name: m for m in address.get_forward_mailboxes()}
@ -268,7 +278,8 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
def get_queryset(self, request): def get_queryset(self, request):
qs = super(AddressAdmin, self).get_queryset(request) qs = super(AddressAdmin, self).get_queryset(request)
return qs.annotate(computed_email=Concat(F('name'), V('@'), F('domain__name'))) qs = qs.annotate(computed_email=Concat(F('name'), V('@'), F('domain__name')))
return qs.annotate(Count('mailboxes'))
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None): def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
if not add: if not add:

View File

@ -151,13 +151,12 @@ class Address(models.Model):
def get_forward_mailboxes(self): def get_forward_mailboxes(self):
rm_local_domain = re.compile(r'@%s$' % settings.MAILBOXES_LOCAL_DOMAIN) rm_local_domain = re.compile(r'@%s$' % settings.MAILBOXES_LOCAL_DOMAIN)
mailboxes = []
for forward in self.forward.split(): for forward in self.forward.split():
forward = rm_local_domain.sub('', forward) forward = rm_local_domain.sub('', forward)
if '@' not in forward: if '@' not in forward:
try: mailboxes.append(forward)
yield Mailbox.objects.get(name=forward) return Mailbox.objects.filter(name__in=mailboxes)
except Mailbox.DoesNotExist:
pass
def get_mailboxes(self): def get_mailboxes(self):
for mailbox in self.mailboxes.all(): for mailbox in self.mailboxes.all():

View File

@ -12,7 +12,7 @@ from .models import Mailbox, Address
def delete_forwards(sender, *args, **kwargs): def delete_forwards(sender, *args, **kwargs):
# Cleanup related addresses # Cleanup related addresses
instance = kwargs['instance'] instance = kwargs['instance']
for address in Address.objects.filter(forward__regex=r'.*(^|\s)+%s($|\s)+.*' % instance.name): for address in instance.get_forwards():
forward = address.forward.split() forward = address.forward.split()
forward.remove(instance.name) forward.remove(instance.name)
address.forward = ' '.join(forward) address.forward = ' '.join(forward)

View File

@ -28,59 +28,60 @@ class UNIXUserController(ServiceController):
context = self.get_context(user) context = self.get_context(user)
if not context['user']: if not context['user']:
return return
groups = ','.join(self.get_groups(user))
context['groups_arg'] = '--groups %s' % groups if groups else ''
# TODO userd add will fail if %(user)s group already exists # TODO userd add will fail if %(user)s group already exists
self.append(textwrap.dedent(""" self.append(textwrap.dedent("""
# Update/create user state for %(user)s # Update/create user state for %(user)s
if id %(user)s ; then if id %(user)s ; then
usermod %(user)s --home %(home)s \\ usermod %(user)s --home '%(home)s' \\
--password '%(password)s' \\ --password '%(password)s' \\
--shell %(shell)s %(groups_arg)s --shell '%(shell)s' \\
--groups '%(groups)s'
else else
useradd_code=0 useradd_code=0
useradd %(user)s --home %(home)s \\ useradd %(user)s --home '%(home)s' \\
--password '%(password)s' \\ --password '%(password)s' \\
--shell %(shell)s %(groups_arg)s || useradd_code=$? --shell '%(shell)s' \\
--groups '%(groups)s' || useradd_code=$?
if [[ $useradd_code -eq 8 ]]; then if [[ $useradd_code -eq 8 ]]; then
# User is logged in, kill and retry # User is logged in, kill and retry
pkill -u %(user)s; sleep 2 pkill -u %(user)s; sleep 2
pkill -9 -u %(user)s; sleep 1 pkill -9 -u %(user)s; sleep 1
useradd %(user)s --home %(home)s \\ useradd %(user)s --home '%(home)s' \\
--password '%(password)s' \\ --password '%(password)s' \\
--shell %(shell)s %(groups_arg)s --shell '%(shell)s' \\
--groups '%(groups)s'
elif [[ $useradd_code -ne 0 ]]; then elif [[ $useradd_code -ne 0 ]]; then
exit $useradd_code exit $useradd_code
fi fi
fi fi
mkdir -p %(base_home)s mkdir -p '%(base_home)s'
chmod 750 %(base_home)s chmod 750 '%(base_home)s'
""") % context """) % context
) )
if context['home'] != context['base_home']: if context['home'] != context['base_home']:
self.append(textwrap.dedent(""" self.append(textwrap.dedent("""\
# Set extra permissions: %(user)s home is inside %(mainuser)s home # Set extra permissions: %(user)s home is inside %(mainuser)s home
if mount | grep "^$(df %(home)s|grep '^/'|cut -d' ' -f1)\s" | grep acl > /dev/null; then if mount | grep "^$(df %(home)s|grep '^/'|cut -d' ' -f1)\s" | grep acl > /dev/null; then
# Account group as the owner # Account group as the owner
chown %(mainuser)s:%(mainuser)s %(home)s chown %(mainuser)s:%(mainuser)s '%(home)s'
chmod g+s %(home)s chmod g+s '%(home)s'
# Home access # Home access
setfacl -m u:%(user)s:--x '%(mainuser_home)s' setfacl -m u:%(user)s:--x '%(mainuser_home)s'
# Grant perms to future files within the directory # Grant perms to future files within the directory
setfacl -m d:u:%(user)s:rwx %(home)s setfacl -m d:u:%(user)s:rwx '%(home)s'
# Grant access to main user # Grant access to main user
setfacl -m d:u:%(mainuser)s:rwx %(home)s setfacl -m d:u:%(mainuser)s:rwx '%(home)s'
else else
chmod g+rxw %(home)s chmod g+rxw %(home)s
fi""") % context fi""") % context
) )
else: else:
self.append(textwrap.dedent("""\ self.append(textwrap.dedent("""\
chown %(user)s:%(group)s %(home)s chown %(user)s:%(group)s '%(home)s'
ls -A /etc/skel/ | while read line; do ls -A /etc/skel/ | while read line; do
if [[ ! -e %(home)s/${line} ]]; then if [[ ! -e "%(home)s/${line}" ]]; then
cp -a /etc/skel/${line} %(home)s/${line} && \\ cp -a "/etc/skel/${line}" "%(home)s/${line}" && \\
chown -R %(user)s:%(group)s %(home)s/${line} chown -R %(user)s:%(group)s "%(home)s/${line}"
fi fi
done done
""") % context """) % context
@ -107,14 +108,14 @@ class UNIXUserController(ServiceController):
self.append(textwrap.dedent("""\ self.append(textwrap.dedent("""\
# Move home into SYSTEMUSERS_MOVE_ON_DELETE_PATH, nesting if exists. # Move home into SYSTEMUSERS_MOVE_ON_DELETE_PATH, nesting if exists.
deleted_home="%(deleted_home)s" deleted_home="%(deleted_home)s"
while [[ -e $deleted_home ]]; do while [[ -e "$deleted_home" ]]; do
deleted_home="${deleted_home}/$(basename ${deleted_home})" deleted_home="${deleted_home}/$(basename ${deleted_home})"
done done
mv %(base_home)s $deleted_home || exit_code=$? mv '%(base_home)s' "$deleted_home" || exit_code=$?
""") % context """) % context
) )
else: else:
self.append("rm -fr %(base_home)s" % context) self.append("rm -fr '%(base_home)s'" % context)
def grant_permissions(self, user, context): def grant_permissions(self, user, context):
context['perms'] = user.set_perm_perms context['perms'] = user.set_perm_perms
@ -206,8 +207,8 @@ class UNIXUserController(ServiceController):
self.append(textwrap.dedent("""\ self.append(textwrap.dedent("""\
# Create link # Create link
su %(user)s --shell /bin/bash << 'EOF' || exit_code=1 su %(user)s --shell /bin/bash << 'EOF' || exit_code=1
if [[ ! -e %(link_name)s ]]; then if [[ ! -e '%(link_name)s' ]]; then
ln -s %(link_target)s %(link_name)s ln -s '%(link_target)s' '%(link_name)s'
else else
echo "%(link_name)s already exists, doing nothing." >&2 echo "%(link_name)s already exists, doing nothing." >&2
exit 1 exit 1
@ -236,6 +237,7 @@ class UNIXUserController(ServiceController):
'object_id': user.pk, 'object_id': user.pk,
'user': user.username, 'user': user.username,
'group': user.username, 'group': user.username,
'groups': ','.join(self.get_groups(user)),
'password': user.password if user.active else '*%s' % user.password, 'password': user.password if user.active else '*%s' % user.password,
'shell': user.shell, 'shell': user.shell,
'mainuser': user.username if user.is_main else user.account.username, 'mainuser': user.username if user.is_main else user.account.username,