diff --git a/orchestra/apps/mails/admin.py b/orchestra/apps/mails/admin.py index 6b165644..e92b71fb 100644 --- a/orchestra/apps/mails/admin.py +++ b/orchestra/apps/mails/admin.py @@ -1,3 +1,5 @@ +import copy + from django import forms from django.contrib import admin from django.core.urlresolvers import reverse @@ -24,15 +26,16 @@ class AutoresponseInline(admin.StackedInline): class MailboxAdmin(AccountAdminMixin, ExtendedModelAdmin): list_display = ( - 'name', 'account_link', 'use_custom_filtering', 'display_addresses' + 'name', 'account_link', 'uses_custom_filtering', 'display_addresses' ) - list_filter = ('use_custom_filtering', HasAddressListFilter) + list_filter = (HasAddressListFilter,) add_fieldsets = ( (None, { 'fields': ('account', 'name', 'password'), }), (_("Filtering"), { - 'fields': ('use_custom_filtering', 'custom_filtering'), + 'classes': ('collapse',), + 'fields': ('custom_filtering',), }), ) fieldsets = ( @@ -41,8 +44,8 @@ class MailboxAdmin(AccountAdminMixin, ExtendedModelAdmin): 'fields': ('account_link', 'name'), }), (_("Filtering"), { - 'classes': ('wide',), - 'fields': ('use_custom_filtering', 'custom_filtering'), + 'classes': ('collapse',), + 'fields': ('custom_filtering',), }), (_("Addresses"), { 'classes': ('wide',), @@ -60,6 +63,20 @@ class MailboxAdmin(AccountAdminMixin, ExtendedModelAdmin): display_addresses.short_description = _("Addresses") display_addresses.allow_tags = True + def uses_custom_filtering(self, mailbox): + return bool(mailbox.custom_filtering) + uses_custom_filtering.short_description = _("Custom filter") + uses_custom_filtering.boolean = True + uses_custom_filtering.admin_order_field = 'custom_filtering' + + def get_fieldsets(self, request, obj=None): + """ not collapsed filtering when exists """ + fieldsets = super(MailboxAdmin, self).get_fieldsets(request, obj=obj) + if obj and obj.custom_filtering: + fieldsets = copy.deepcopy(fieldsets) + fieldsets[1][1]['classes'] = fieldsets[0][1]['fields'] + ('open',) + return fieldsets + def addresses_field(self, mailbox): """ Address form field with "Add address" button """ account = mailbox.account diff --git a/orchestra/apps/mails/models.py b/orchestra/apps/mails/models.py index 12ba771a..58aa2561 100644 --- a/orchestra/apps/mails/models.py +++ b/orchestra/apps/mails/models.py @@ -16,11 +16,10 @@ class Mailbox(models.Model): password = models.CharField(_("password"), max_length=128) account = models.ForeignKey('accounts.Account', verbose_name=_("account"), related_name='mailboxes') - use_custom_filtering = models.BooleanField(_("Use custom filtering"), - default=False) custom_filtering = models.TextField(_("filtering"), blank=True, validators=[validators.validate_sieve], - help_text=_("Arbitrary email filtering in sieve language.")) + help_text=_("Arbitrary email filtering in sieve language. " + "This overrides any automatic junk email filtering")) is_active = models.BooleanField(_("is active"), default=True) # addresses = models.ManyToManyField('mails.Address', # verbose_name=_("addresses"), diff --git a/orchestra/apps/users/admin.py b/orchestra/apps/users/admin.py index 6f049fd5..74676dab 100644 --- a/orchestra/apps/users/admin.py +++ b/orchestra/apps/users/admin.py @@ -18,10 +18,7 @@ class UserAdmin(AccountAdminMixin, ExtendedModelAdmin): list_filter = ('is_active',) fieldsets = ( (None, { - 'fields': ('account', 'username', 'password', 'is_active') - }), - (_("Personal info"), { - 'fields': ('first_name', 'last_name', 'email') + 'fields': ('account', 'username', 'password', 'home', 'shell', 'groups', 'is_active') }), ) add_fieldsets = ( @@ -33,7 +30,8 @@ class UserAdmin(AccountAdminMixin, ExtendedModelAdmin): search_fields = ['username', 'account__username'] readonly_fields = ('display_is_main', 'account_link') change_readonly_fields = ('username',) - filter_horizontal = () + filter_horizontal = ('groups',) + filter_by_account_fields = ('groups',) add_form = UserCreationForm form = UserChangeForm roles = [] @@ -62,6 +60,7 @@ class UserAdmin(AccountAdminMixin, ExtendedModelAdmin): return new_urls + urls def get_fieldsets(self, request, obj=None): + # TODO implement on AccountAdminMixin fieldsets = super(UserAdmin, self).get_fieldsets(request, obj=obj) if obj and obj.account: fieldsets[0][1]['fields'] = ('account_link',) + fieldsets[0][1]['fields'][1:] diff --git a/orchestra/apps/users/models.py b/orchestra/apps/users/models.py index 6eea5e24..8c97431c 100644 --- a/orchestra/apps/users/models.py +++ b/orchestra/apps/users/models.py @@ -4,45 +4,38 @@ from django.core.mail import send_mail from django.db import models from django.utils.translation import ugettext_lazy as _ - from orchestra.core import services +from . import settings + class User(models.Model): + """ System users """ username = models.CharField(_("username"), max_length=64, unique=True, - help_text=_("Required. 30 characters or fewer. Letters, digits and " - "./-/_ only."), + help_text=_("Required. 30 characters or fewer. Letters, digits and ./-/_ only."), validators=[validators.RegexValidator(r'^[\w.-]+$', _("Enter a valid username."), 'invalid')]) password = models.CharField(_("password"), max_length=128) account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), related_name='users') - first_name = models.CharField(_("first name"), max_length=30, blank=True) - last_name = models.CharField(_("last name"), max_length=30, blank=True) - email = models.EmailField(_('email address'), blank=True) + home = models.CharField(_("home"), max_length=256, blank=True, + help_text=_("Home directory relative to account's ~primary_user")) + shell = models.CharField(_("shell"), max_length=32, + choices=settings.USERS_SHELLS, default=settings.USERS_DEFAULT_SHELL) + groups = models.ManyToManyField('users.User', blank=True, + help_text=_("A new group will be created for the user. " + "Which additional groups would you like them to be a member of?")) is_active = models.BooleanField(_("active"), default=True, help_text=_("Designates whether this account should be treated as active. " "Unselect this instead of deleting accounts.")) + def __unicode__(self): + return self.username + @property def is_main(self): return self.username == self.account.username - def get_full_name(self): - full_name = '%s %s' % (self.first_name, self.last_name) - return full_name.strip() or self.username - - def get_short_name(self): - """ Returns the short name for the user """ - return self.first_name - - def get_description(self): - return "{full_name}, {email}".format(full_name=self.get_full_name(), email=self.email) - - def email_user(self, subject, message, from_email=None, **kwargs): - """ Sends an email to this User """ - send_mail(subject, message, from_email, [self.email], **kwargs) - def set_password(self, raw_password): self.password = make_password(raw_password) @@ -54,6 +47,9 @@ class User(models.Model): def setter(raw_password): self.set_password(raw_password) self.save(update_fields=["password"]) + + def get_is_active(self): + return self.account.is_active and self.is_active services.register(User) diff --git a/orchestra/apps/users/settings.py b/orchestra/apps/users/settings.py index 012099a4..e9d8a7a7 100644 --- a/orchestra/apps/users/settings.py +++ b/orchestra/apps/users/settings.py @@ -1,6 +1,16 @@ from django.conf import settings +from django.utils.translation import ugettext, ugettext_lazy as _ + USERS_SYSTEMUSER_HOME = getattr(settings, 'USERES_SYSTEMUSER_HOME', '/home/%(username)s') USERS_FTP_LOG_PATH = getattr(settings, 'USERS_FTP_LOG_PATH', '/var/log/vsftpd.log') + +USERS_SHELLS = getattr(settings, 'USERS_SHELLS', ( + ('/bin/false', _("FTP/sFTP only")), + ('/bin/rsync', _("rsync shell")), + ('/bin/bash', "Bash"), +)) + +USERS_DEFAULT_SHELL = getattr(settings, 'USERS_DEFAULT_SHELL', '/bin/false') diff --git a/orchestra/templates/admin/base_site.html b/orchestra/templates/admin/base_site.html index ead258a6..6d4cd4e8 100644 --- a/orchestra/templates/admin/base_site.html +++ b/orchestra/templates/admin/base_site.html @@ -1,8 +1,14 @@ {% extends "admin/base.html" %} -{% load admin_tools_menu_tags utils %} +{% load admin_tools_menu_tags utils static %} {% block title %}{% if header_title %}{{ header_title }}{% else %}{{ title }}{% endif %} | {{ SITE_VERBOSE_NAME }} {% endblock %} +{% block blockbots %} +{{ block.super }} +{% comment %}This has to load after admin/js/collapse.js{% endcomment %} + +{% endblock %} + {% block extrastyle %} {{ block.super }} {% if user.is_active and user.is_staff %}