Adding support for import/export of objects.

see #491
This commit is contained in:
Antoine Nguyen
2013-10-30 16:21:12 +01:00
parent 0a27cf725b
commit 971c535f18
12 changed files with 116 additions and 15 deletions
-1
View File
@@ -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
+3
View File
@@ -37,6 +37,9 @@ admin_events = [
"ExtraAccountForm",
"CheckExtraAccountForm",
"FillAccountInstances",
"ExtraDomainImportHelp",
"ImportObject"
]
+1
View File
@@ -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
@@ -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)
@@ -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);
+1 -1
View File
@@ -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)
+1
View File
@@ -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
)
+3 -5
View File
@@ -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"])
+15 -5
View File
@@ -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):
<ul>
<li><em>domain; name; quota; enabled</em></li>
<li><em>domainalias; name; targeted domain; enabled</em></li>
%s
</ul>
<p>The first element of each line is mandatory and must be equal to one of the previous values.</p>
<p>You can use a different character as separator.</p>
""")
""" % ''.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", {
@@ -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("""
<li><em>relaydomain; name; target host; service; enabled; verify recipients</em></li>
<li><em>relaydomainalias; name; target; enabled</em></li>
""")]
@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 []
@@ -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)
@@ -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)