Add JSON import and export of mailboxes

This commit is contained in:
Johannes Zellner
2022-01-23 22:26:23 +01:00
parent 7b8c721a8a
commit 963af4334d
2 changed files with 148 additions and 1 deletions
+43 -1
View File
@@ -199,6 +199,45 @@
</div>
</div>
<!-- Modal import mailboxes -->
<div class="modal fade" id="mailboxImportModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Import Users</h4>
</div>
<div class="modal-body">
<div ng-show="!mailboxImport.done">
<div ng-show="!mailboxImport.busy">
<p>The import requires a specific schema for JSON. The detailed schema is described in our <a href="" target="_blank">documentation</a></p>
<input type="file" style="display: none;" id="mailboxImportFileInput" accept="application/json"/>
<button class="btn btn-primary" ng-click="mailboxImport.openFileInput()">Select JSON file</button>
<br/>
<br/>
<p class="text-danger" ng-show="mailboxImport.error.file">{{ mailboxImport.error.file }}</p>
<p ng-show="mailboxImport.mailboxes.length">Found {{ mailboxImport.mailboxes.length }} mailboxes to import</p>
</div>
<div ng-show="mailboxImport.busy" class="progress progress-striped active">
<div class="progress-bar progress-bar-success" role="progressbar" style="width: {{ mailboxImport.percent }}%"></div>
</div>
</div>
<div ng-show="mailboxImport.done">
<p>{{ mailboxImport.success }} mailboxes successfully imported.</p>
<div ng-show="mailboxImport.error.import.length">
<p class="text-danger">The following mailboxes were not imported:</p>
<div ng-repeat="tmp in mailboxImport.error.import"><b>{{ tmp.mailbox.name }}@{{ tmp.mailbox.domain }}:</b> {{ tmp.error.message }}</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'main.dialog.close' | tr }}</button>
<button type="button" class="btn btn-primary" ng-click="mailboxImport.import()" ng-show="!mailboxImport.done" ng-disabled="mailboxImport.busy || !mailboxImport.mailboxes.length"><i class="fa fa-circle-notch fa-spin" ng-show="mailboxImport.busy"></i> Import</button>
</div>
</div>
</div>
</div>
<!-- Modal add mailinglist -->
<div class="modal fade" id="mailinglistAddModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
@@ -368,7 +407,10 @@
<div class="text-left">
<h3 style="margin-bottom: 15px;">{{ 'email.incoming.mailboxes.title' | tr }}
<button class="btn btn-primary btn-outline pull-right" ng-click="mailboxes.add.show()" ng-disabled="!domain.mailConfig.enabled" tooltip-enable="!domain.mailConfig.enabled" uib-tooltip="{{ 'email.incoming.mailboxes.disabledTooltip' | tr }}"><i class="fa fa-inbox"></i> {{ 'email.incoming.mailboxes.addAction' | tr }}</button>
<div class="btn-group pull-right" style="margin-left: 5px;">
<button class="btn btn-primary" ng-click="mailboxImport.show()" uib-tooltip="Import Mailboxes" tooltip-append-to-body="true"><i class="fa fa-file-import"></i></button>
<button class="btn btn-primary" ng-click="mailboxExport()" uib-tooltip="Export Mailboxes" tooltip-append-to-body="true"><i class="fa fa-file-export"></i></button>
</div>
<input class="form-control pull-right" style="width: 200px;" placeholder="{{ 'main.searchPlaceholder' | tr }}" type="text" ng-model="mailboxes.search" ng-model-options="{ debounce: 1000 }" ng-change="mailboxes.updateFilter()" />
</h3>
</div>
+105
View File
@@ -353,6 +353,111 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
}
};
$scope.mailboxImport = {
busy: false,
done: false,
error: null,
percent: 0,
success: 0,
mailboxes: [],
reset: function () {
$scope.mailboxImport.busy = false;
$scope.mailboxImport.error = null;
$scope.mailboxImport.mailboxes = [];
$scope.mailboxImport.percent = 0;
$scope.mailboxImport.success = 0;
$scope.mailboxImport.done = false;
},
handleFileChanged: function () {
$scope.mailboxImport.reset();
var fileInput = document.getElementById('mailboxImportFileInput');
if (!fileInput.files || !fileInput.files[0]) return;
var file = fileInput.files[0];
if (file.type !== 'application/json') return console.log('Unsupported file type.');
const reader = new FileReader();
reader.addEventListener('load', function () {
$scope.$apply(function () {
try {
$scope.mailboxImport.mailboxes = JSON.parse(reader.result);
} catch (e) {
console.error('Failed to parse mailboxes.', e);
$scope.mailboxImport.error = { file: 'Imported file is not valid JSON' };
}
// TODO check for validity and minium requirements for the mailboxes from JSON
// currently supported and required fields are:
// domain
// name
// ownerId
// ownerType
});
}, false);
reader.readAsText(file);
},
show: function () {
$scope.mailboxImport.reset();
// named so no duplactes
document.getElementById('mailboxImportFileInput').addEventListener('change', $scope.mailboxImport.handleFileChanged);
$('#mailboxImportModal').modal('show');
},
openFileInput: function () {
$('#mailboxImportFileInput').click();
},
import: function () {
$scope.mailboxImport.percent = 0;
$scope.mailboxImport.success = 0;
$scope.mailboxImport.done = false;
$scope.mailboxImport.error = { import: [] };
$scope.mailboxImport.busy = true;
var processed = 0;
async.eachSeries($scope.mailboxImport.mailboxes, function (mailbox, callback) {
Client.addMailbox(mailbox.domain, mailbox.name, mailbox.ownerId, mailbox.ownerType, function (error) {
if (error) $scope.mailboxImport.error.import.push({ error: error, mailbox: mailbox });
else ++$scope.mailboxImport.success;
++processed;
$scope.mailboxImport.percent = 100 * processed / $scope.mailboxImport.mailboxes.length;
callback();
});
}, function (error) {
if (error) return console.error(error);
$scope.mailboxImport.busy = false;
$scope.mailboxImport.done = true;
});
}
};
$scope.mailboxExport = function () {
// FIXME only does first 10k mailboxes
Client.listMailboxes($scope.domain.domain, '', 1, 10000, function (error, result) {
if (error) {
Client.error('Failed to list mailboxes. Full error in the webinspector.');
return console.error('Failed to list mailboxes.', error);
}
var file = new Blob([ JSON.stringify(result, null, 2) ], { type: 'application/json' });
var a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = $scope.domain.domain.replaceAll('.','_') + '-mailboxes.json';
document.body.appendChild(a);
a.click();
});
};
$scope.mailboxes = {
mailboxes: [],
search: '',