diff --git a/modoboa/core/views/admin.py b/modoboa/core/views/admin.py index 678c41caf..071e1091a 100644 --- a/modoboa/core/views/admin.py +++ b/modoboa/core/views/admin.py @@ -25,7 +25,6 @@ def viewsettings(request, tplname='core/settings_header.html'): @user_passes_test(lambda u: u.is_superuser) def viewparameters(request, tplname='core/parameters.html'): return render_to_json_response({ - "status": "ok", "left_selection": "parameters", "content": _render_to_string(request, tplname, { "forms": parameters.get_admin_forms diff --git a/modoboa/extensions/admin/__init__.py b/modoboa/extensions/admin/__init__.py index 7cfd3d63a..281fac420 100644 --- a/modoboa/extensions/admin/__init__.py +++ b/modoboa/extensions/admin/__init__.py @@ -37,6 +37,9 @@ admin_events = [ "ExtraAccountForm", "CheckExtraAccountForm", "FillAccountInstances", + + "ExtraDomainImportHelp", + "ImportObject" ] diff --git a/modoboa/extensions/admin/lib.py b/modoboa/extensions/admin/lib.py index 896956c35..d84a998d4 100644 --- a/modoboa/extensions/admin/lib.py +++ b/modoboa/extensions/admin/lib.py @@ -4,6 +4,7 @@ from itertools import chain from django.db.models import Q from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.contrib.contenttypes.models import ContentType +from django.utils.translation import ugettext as _ from modoboa.core.models import User from modoboa.lib import parameters, events from modoboa.lib.exceptions import PermDeniedException diff --git a/modoboa/extensions/admin/models/domain.py b/modoboa/extensions/admin/models/domain.py index 7a0b909df..b0a2c474e 100644 --- a/modoboa/extensions/admin/models/domain.py +++ b/modoboa/extensions/admin/models/domain.py @@ -134,5 +134,7 @@ class Domain(AdminObject): def to_csv(self, csvwriter): csvwriter.writerow(["domain", self.name, self.quota, self.enabled]) + for dalias in self.domainalias_set.all(): + dalias.to_csv(csvwriter) reversion.register(Domain) diff --git a/modoboa/extensions/admin/static/admin/js/admin.js b/modoboa/extensions/admin/static/admin/js/admin.js index 313bc332e..57f27f9be 100644 --- a/modoboa/extensions/admin/static/admin/js/admin.js +++ b/modoboa/extensions/admin/static/admin/js/admin.js @@ -125,7 +125,7 @@ Admin.prototype = { $("#import_status").css("display", "none"); if (status == "ok") { $("#modalbox").modal('hide'); - this.reload_listing({respmsg: msg}); + this.reload_listing(msg); } else { $("#import_result").addClass("alert alert-error"); $("#import_result").html(msg); diff --git a/modoboa/extensions/admin/tests/account.py b/modoboa/extensions/admin/tests/account.py index 6f316eb17..547e170ab 100644 --- a/modoboa/extensions/admin/tests/account.py +++ b/modoboa/extensions/admin/tests/account.py @@ -70,7 +70,7 @@ class AccountTestCase(ModoTestCase): def test_set_nul_quota_as_domainadmin(self): self.clt.logout() self.assertTrue(self.clt.login(username="admin@test.com", password="toto")) - self._set_quota("user@test.com", 0, 424) + self._set_quota("user@test.com", 0, 400) self.clt.logout() self.assertTrue(self.clt.login(username="admin@test2.com", password="toto")) self._set_quota("user@test2.com", 0) diff --git a/modoboa/extensions/admin/views/domain.py b/modoboa/extensions/admin/views/domain.py index 38cd61f10..2dd635c65 100644 --- a/modoboa/extensions/admin/views/domain.py +++ b/modoboa/extensions/admin/views/domain.py @@ -40,6 +40,7 @@ def _domains(request): for flt in ['domfilter', 'searchquery'] + events.raiseQueryEvent('ExtraDomainFilters') ) + request.session['domains_filters'] = filters domainlist = get_domains( request.user, **filters ) diff --git a/modoboa/extensions/admin/views/export.py b/modoboa/extensions/admin/views/export.py index 681a54bda..2c38e778f 100644 --- a/modoboa/extensions/admin/views/export.py +++ b/modoboa/extensions/admin/views/export.py @@ -8,8 +8,7 @@ from django.utils.translation import ugettext as _ from django.contrib.auth.decorators import ( login_required, permission_required, user_passes_test ) -from modoboa.extensions.admin.lib import get_identities -from modoboa.extensions.admin.models import Domain +from modoboa.extensions.admin.lib import get_domains, get_identities from modoboa.extensions.admin.forms import ( ExportIdentitiesForm, ExportDomainsForm ) @@ -73,10 +72,9 @@ def export_domains(request): form.is_valid() fp = cStringIO.StringIO() csvwriter = csv.writer(fp, delimiter=form.cleaned_data["sepchar"]) - for dom in Domain.objects.get_for_admin(request.user): + for dom in get_domains(request.user, + **request.session['domains_filters']): dom.to_csv(csvwriter) - for da in dom.domainalias_set.all(): - da.to_csv(csvwriter) content = fp.getvalue() fp.close() return _export(content, form.cleaned_data["filename"]) diff --git a/modoboa/extensions/admin/views/import.py b/modoboa/extensions/admin/views/import.py index ea1cb857f..52497d051 100644 --- a/modoboa/extensions/admin/views/import.py +++ b/modoboa/extensions/admin/views/import.py @@ -6,6 +6,7 @@ from django.db import transaction, IntegrityError from django.contrib.auth.decorators import ( login_required, permission_required, user_passes_test ) +from modoboa.lib import events from modoboa.lib.exceptions import ModoboaException, Conflict from modoboa.core.models import User from modoboa.extensions.admin.models import ( @@ -39,10 +40,11 @@ def import_domains(request):

The first element of each line is mandatory and must be equal to one of the previous values.

You can use a different character as separator.

-""") +""" % ''.join([unicode(hlp) for hlp in events.raiseQueryEvent('ExtraDomainImportHelp')])) ctx = dict( title=_("Import domains"), @@ -100,8 +102,8 @@ def importdata(request, formclass=ImportDataForm): try: reader = csv.reader(request.FILES['sourcefile'], delimiter=form.cleaned_data['sepchar']) - except csv.Error, e: - error = str(e) + except csv.Error as inst: + error = str(inst) if error is None: try: @@ -112,13 +114,21 @@ def importdata(request, formclass=ImportDataForm): try: fct = globals()["import_%s" % row[0].strip()] except KeyError: - continue + fct = events.raiseQueryEvent( + 'ImportObject', row[0].strip() + ) + if not fct: + continue + fct = fct[0] try: fct(request.user, row, form.cleaned_data) except IntegrityError, e: if form.cleaned_data["continue_if_exists"]: continue - raise Conflict(_("Object already exists: %s" % row)) + raise Conflict( + _("Object already exists: %s" + % form.cleaned_data['sepchar'].join(row[:2])) + ) cpt += 1 msg = _("%d objects imported successfully" % cpt) return render(request, "admin/import_done.html", { diff --git a/modoboa/extensions/postfix_relay_domains/__init__.py b/modoboa/extensions/postfix_relay_domains/__init__.py index 151462236..647615e24 100644 --- a/modoboa/extensions/postfix_relay_domains/__init__.py +++ b/modoboa/extensions/postfix_relay_domains/__init__.py @@ -201,3 +201,22 @@ def extra_parameters(app, level): widget=forms.widgets.TextInput(attrs={"class": "span1"}) ) } + + +@events.observe('ExtraDomainImportHelp') +def extra_domain_import_help(): + return [ugettext_lazy(""" +
  • relaydomain; name; target host; service; enabled; verify recipients
  • +
  • relaydomainalias; name; target; enabled
  • +""")] + + +@events.observe('ImportObject') +def get_import_func(objtype): + from .lib import import_relaydomain, import_relaydomainalias + + if objtype == 'relaydomain': + return [import_relaydomain] + if objtype == 'relaydomainalias': + return [import_relaydomainalias] + return [] diff --git a/modoboa/extensions/postfix_relay_domains/lib.py b/modoboa/extensions/postfix_relay_domains/lib.py new file mode 100644 index 000000000..a5c4764ec --- /dev/null +++ b/modoboa/extensions/postfix_relay_domains/lib.py @@ -0,0 +1,14 @@ +from django.db import transaction +from .models import RelayDomain, RelayDomainAlias + + +@transaction.commit_on_success +def import_relaydomain(user, row, formopts): + """Specific code for relay domains import""" + RelayDomain().from_csv(user, row) + + +@transaction.commit_on_success +def import_relaydomainalias(user, row, formopts): + """Specific code for relay domain aliases import""" + RelayDomainAlias().from_csv(user, row) diff --git a/modoboa/extensions/postfix_relay_domains/models.py b/modoboa/extensions/postfix_relay_domains/models.py index 2900b5c35..560dfb0c5 100644 --- a/modoboa/extensions/postfix_relay_domains/models.py +++ b/modoboa/extensions/postfix_relay_domains/models.py @@ -4,8 +4,8 @@ from django.db.models.manager import Manager from django.contrib.contenttypes import generic from django.utils.translation import ugettext as _, ugettext_lazy from modoboa.core.models import ObjectAccess -from modoboa.lib import events, parameters -from modoboa.lib.permissions import ungrant_access_to_object +from modoboa.lib import parameters +from modoboa.lib.exceptions import BadRequest, NotFound from modoboa.extensions.admin.models import AdminObject @@ -52,6 +52,8 @@ class ServiceManager(Manager): class Service(models.Model): + """Postfix service. + """ name = models.CharField( ugettext_lazy('name'), max_length=100, unique=True, help_text=ugettext_lazy('The service name') @@ -106,6 +108,33 @@ class RelayDomain(AdminObject): def __str__(self): return self.name + def to_csv(self, csvwriter): + """Export this relay domain to CSV. + + :param csvwriter: + """ + csvwriter.writerow( + ["relaydomain", self.name, self.target_host, + self.service.name, self.enabled, self.verify_recipients] + ) + for rdalias in self.relaydomainalias_set.all(): + rdalias.to_csv(csvwriter) + + def from_csv(self, user, row): + """Import a relay domain from CSV. + + :param user: user importing the relay domain + :param str row: relay domain definition + """ + if len(row) != 6: + raise BadRequest(_("Invalid line")) + self.name = row[1].strip() + self.target_host = row[2].strip() + self.service, created = Service.objects.get_or_create(name=row[3].strip()) + self.enabled = (row[4].strip() == 'True') + self.verify_recipients = (row[5].strip() == 'True') + self.save(creator=user) + reversion.register(RelayDomain) @@ -126,4 +155,29 @@ class RelayDomainAlias(AdminObject): def __str__(self): return self.name + def to_csv(self, csvwriter): + """Export this relay domain alias to CSV. + + :param csvwriter: + """ + csvwriter.writerow( + ['relaydomainalias', self.name, self.target.name, self.enabled] + ) + + def from_csv(self, user, row): + """Import a relay domain alias from CSV. + + :param user: user importing the relay domain alias + :param str row: relay domain alias definition + """ + if len(row) != 4: + raise BadRequest(_("Invalid line")) + self.name = row[1].strip() + try: + self.target = RelayDomain.objects.get(name=row[2].strip()) + except RelayDomain.DoesNotExist: + raise NotFound(_("Relay domain %s does not exist" % row[2].strip())) + self.enabled = (row[3].strip() == 'True') + self.save(creator=user) + reversion.register(RelayDomainAlias)