* New "import data" feature (only supports mailboxes for now)

* Some javascript cleanup into the admin. application

see #191
This commit is contained in:
Antoine Nguyen
2011-12-09 14:38:56 +01:00
parent 767343640a
commit 4fcc5b7911
14 changed files with 226 additions and 86 deletions
+10
View File
@@ -199,3 +199,13 @@ class DomainAdminForm(forms.Form):
forms.ChoiceField(label=_("User"), required=True,
choices=[("", _("Empty"))],
help_text=_("Select a user in the list"))
class ImportDataForm(forms.Form):
sourcefile = forms.FileField(label=_("Select a file"))
sepcar = forms.CharField(label=_("Separator"), max_length=1, required=False)
def clean_sepcar(self):
if self.cleaned_data["sepcar"] == "":
return ";"
return self.cleaned_data["sepcar"]
+20
View File
@@ -319,6 +319,26 @@ class Mailbox(DatesAware):
self.quota = self.domain.quota
super(Mailbox, self).save()
def create_from_csv(self, line):
"""Create a new mailbox from a CSV file entry
The expected order is the following::
[loginname, password, first name, last name, address]
:param line: a list containing the expected information
"""
if len(line) < 5:
raise AdminError(_("Invalid line"))
mailbox, domname = split_mailbox(line[4])
self.address = mailbox
try:
self.domain = Domain.objects.get(name=domname)
except Domain.DoesNotExist:
raise AdminError(_("Cannot import this mailbox because the associated domain does not exist"))
self.name = "%s %s" % (line[2], line[3])
self.save(password=line[1], enabled=True)
def delete(self, *args, **kwargs):
keepdir = False
if kwargs.has_key("keepdir"):
+17 -2
View File
@@ -93,7 +93,13 @@ def domains_menu(selection, user, domid):
else:
disabled = False
entries += [{"name" : "new",
entries += [
{"name" : "actions",
"label" : _("Actions"),
"img" : static_url("pics/tools.png"),
"class" : "menubardropdown",
"menu" : [
{"name" : "new",
"label" : _("New"),
"img" : static_url("pics/add.png"),
"disabled" : disabled},
@@ -101,7 +107,16 @@ def domains_menu(selection, user, domid):
"label" : _("Remove"),
"img" : static_url("pics/remove.png"),
"disabled" : disabled
}]
},
{"name" : "import",
"label" : _("Import data"),
"img" : static_url("pics/import.png"),
"class" : "boxed",
"rel" : "{handler:'iframe',size:{x:370,y:250}}",
"url" : reverse(admin.views.importdata)}
]
},
]
entries += [{"separator" : True}]
if user.has_perm("admin.view_domains"):
+1 -3
View File
@@ -6,6 +6,7 @@ urlpatterns = patterns('modoboa.admin.views',
(r'^domains/new/', 'newdomain'),
(r'^domains/(?P<dom_id>\d+)/edit/$', 'editdomain'),
(r'^domains/delete/$', 'deldomain'),
(r'^domains/import/$', 'importdata'),
(r'^domaliases/$', "domaliases"),
(r'^domaliases/new/', 'newdomalias'),
@@ -25,9 +26,6 @@ urlpatterns = patterns('modoboa.admin.views',
(r'^domains/(?P<dom_id>\d+)/rawmboxes/$', 'mailboxes_raw'),
#url(r'^domains/(?P<dom_id>\d+)/aliases/$', "aliases", name="full-aliases"),
#url(r'^domains/(?P<dom_id>\d+)/aliases/(?P<mbox_id>\d+)/$', "aliases", name="mbox-aliases"),
(r'^settings/$', 'viewparameters'),
(r'^settings/parameters/$', 'viewparameters'),
(r'^settings/parameters/save/$', 'saveparameters'),
+34
View File
@@ -608,3 +608,37 @@ def saveextensions(request):
ext.save()
messages.info(request, _("Modifications applied."), fail_silently=True)
return HttpResponseRedirect(reverse(admin.views.viewextensions))
@login_required
@user_passes_test(lambda u: u.is_superuser)
def importdata(request, tplname="admin/import.html"):
if request.method == "POST":
error = None
form = ImportDataForm(request.POST, request.FILES)
if form.is_valid():
import csv
reader = csv.reader(request.FILES['sourcefile'],
delimiter=form.cleaned_data['sepcar'])
cpt = 0
try:
for row in reader:
mb = Mailbox()
mb.create_from_csv(row)
cpt += 1
except AdminError, e:
error = str(e)
else:
messages.info(request, _("%d mailboxes imported successfully" % cpt))
return _render(request, "admin/import_done.html", {
"status" : "ok", "msg" : ""
})
return _render(request, "admin/import_done.html", {
"status" : "ko", "msg" : error
})
form = ImportDataForm()
ctx = dict(title=_("Import data"), action="", formid="importform",
enctype="multipart/form-data", form=form, submit_label=_("Import"))
return _render(request, tplname, ctx)
+1 -1
View File
@@ -142,7 +142,7 @@ div#footer {
}
#logo img {
height: 90px;
height: 70px;
}
#test {
+63 -38
View File
@@ -1,41 +1,66 @@
window.addEvent('domready', function() {
var handlers = new Array();
if ($defined($("subcontent"))) {
SqueezeBox.assign($("subcontent").getElements('a[class=boxed]'), {
parse: 'rel'
var Domains = new Class({
initialize: function(rooturl, deloptions) {
this.rooturl = rooturl;
if (deloptions != undefined) {
this.deloptions = deloptions;
} else {
this.deloptions = new Array();
}
if ($("subcontent") != undefined) {
SqueezeBox.assign($("subcontent").getElements('a[class=boxed]'), {
parse: 'rel'
});
}
setDivHeight("content", 20, 0);
this.objtable = new HtmlTable($("objects_table"), {
selectable: true
});
$$("a[name=new]").addEvent("click", this.new_clickcb.bind(this));
$$("a[name=remove]").addEvent("click", this.remove_clickcb.bind(this));
},
new_clickcb: function(evt) {
var type = $("objects").get("name");
var sizes = $("objects").get("rel").split(" ");
evt.stop();
SqueezeBox.open(this.rooturl + type + "/new/", {
size: {x: parseInt(sizes[0]), y: parseInt(sizes[1])},
handler: 'iframe'
});
},
remove_clickcb: function(evt) {
evt.stop();
if (this.objtable._selectedRows.length == 0) {
return;
}
var type = $("objects").get("name");
var selection = "";
this.objtable._selectedRows.each(function(item) {
var options = JSON.decode(item.get("rel"));
if (options != undefined && options.ui_disabled != undefined &&
options.ui_disabled == "True") {
return;
}
if (selection != "") {
selection += ",";
}
selection += item.get("id");
});
if (selection == "") {
return;
}
new Confirmation(
this.rooturl + type + "/delete/",
"selection=" + selection,
gettext('Remove this selection?'), {
checkboxes: this.deloptions
}
);
}
$(document.body).addEvent('click', function(event) {
var target = event.target;
if (target.get('tag') == 'a') {
var name = target.get('name');
if (name == 'undefined')
return;
if (typeof(handlers[name]) != 'undefined') {
if (!handlers[name](target, target.get('href'))) {
new Event(event).stop();
}
}
}
});
$(document.body).addEvent('submit', function(event) {
target = event.target;
if (target.get('tag') == 'form') {
name = target.get('name');
if (name == 'undefined')
return;
if (typeof(handlers[name]) != 'undefined') {
new Event(event).stop();
handlers[name](target);
}
}
});
setDivHeight("content", 20, 0);
objtable = new HtmlTable($("objects_table"), {
selectable: true
});
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

+2 -1
View File
@@ -5,7 +5,8 @@
{% block content %}
<div class="title"><h1>{{ title }}</h1></div>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
<form action="{{ action }}" method="POST" id="{{ formid }}" name="{{ formid }}">
<form action="{{ action }}" enctype="{{ enctype }}"
method="POST" id="{{ formid }}" name="{{ formid }}">
{% include "common/genericform.html" %}
{% block extrafields %}{% endblock %}
<div class="spacer"></div>
+2 -41
View File
@@ -1,50 +1,11 @@
{% extends "nlayout.html" %}
{% load i18n admin_extras libextras %}
{% block html_head %}
<script src="{{ MEDIA_URL }}js/domains.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}js/confirmation.js" type="text/javascript"></script>
<script src="{{ MEDIA_URL }}js/domains.js" type="text/javascript"></script>
<script type="text/javascript">
window.addEvent("domready", function() {
var rooturl = "{% url index %}";
$$("a[name=new]").addEvent("click", function(evt) {
var type = $("objects").get("name");
var sizes = $("objects").get("rel").split(" ");
evt.stop();
SqueezeBox.open(rooturl + type + "/new/", {
size: {x: parseInt(sizes[0]), y: parseInt(sizes[1])},
handler: 'iframe'
});
});
$$("a[name=remove]").addEvent("click", function(evt) {
evt.stop();
if (objtable._selectedRows.length == 0) {
return;
}
var type = $("objects").get("name");
var selection = "";
objtable._selectedRows.each(function(item) {
var options = JSON.decode(item.get("rel"));
if ($defined(options) && $defined(options.ui_disabled) && options.ui_disabled == "True") {
return;
}
if (selection != "") {
selection += ",";
}
selection += item.get("id");
});
if (selection == "") {
return;
}
new Confirmation(rooturl + type + "/delete/", "selection=" + selection,
"{% trans 'Remove this selection?' %}", {
{% if deloptions %}checkboxes: { {% join deloptions %} }{% endif %}
});
});
new Domains("{% url index %}"{% if deloptions %}, { {% join deloptions %} } {% endif %});
});
</script>
{% endblock %}
+65
View File
@@ -0,0 +1,65 @@
{% extends "layout_simple.html" %}
{% load i18n %}
{% block html_head %}
{{ block.super }}
<style>
#id_sepcar {
width: 10px;
}
#import_result, #import_status {
width: 100%;
text-align: center;
}
#import_result {
color: green;
font-weight: bold;
}
</style>
<script type="text/javascript">
function import_cb(status, msg) {
$("import_status").setStyle("display", "none");
$("submit").set("disabled", false);
if (status == "ok") {
parent.location.reload();
parent.SqueezeBox.close();
} else {
$("import_result").set("html", "");
$("error").set("html", msg);
}
}
window.addEvent("domready", function() {
$("importform").addEvent("submit", function(evt) {
if ($("id_sourcefile").value == "") {
evt.stop();
return;
}
$("import_status").setStyle("display", "block");
$("submit").set("disabled", true);
});
});
</script>
{% endblock %}
{% block content %}
<div class="title"><h1>{% trans "Import data" %}</h1></div>
<div id="error" class="error">{{ error }}</div>
<form action="{% url admin.views.importdata %}" enctype="multipart/form-data"
target="import_target"
method="POST" id="importform" name="importform">
{% include "common/genericform.html" %}
<div class="spacer"></div>
<div class="lastrow" align="center">
<input type="submit" id="submit" name="submit" value="{% trans 'Import' %}" />
</div>
</form>
<iframe id="import_target" name="import_target" src="#"
style="width:0;height:0;border:0px solid #fff;"></iframe>
<div id="import_status" style="display:none">
<img src="{{MEDIA_URL}}css/spinner.gif" /> {% trans "Importing..." %}
</div>
<div id="import_result"></div>
{% endblock %}
+11
View File
@@ -0,0 +1,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://www.w3.org/2005/10/profile">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
parent.import_cb("{{ status }}", "{{ msg }}");
</script>
</head>
<body></body>
</html>