First round of mail view refactoring

This commit is contained in:
Johannes Zellner
2018-01-23 12:30:35 +01:00
parent 7166604fc0
commit 456577a166
3 changed files with 148 additions and 178 deletions

View File

@@ -188,7 +188,7 @@
<div class="content">
<div class="text-left">
<h1>Domains <button class="btn btn-primary btn-outline pull-right" ng-show="false" ng-click="domainConfigure.show()"><i class="fa fa-plus"></i> Add Domain</button></h1>
<h1>Domains <button class="btn btn-primary btn-outline pull-right" ng-show="true" ng-click="domainConfigure.show()"><i class="fa fa-plus"></i> Add Domain</button></h1>
</div>
<div class="card card-large">

View File

@@ -6,10 +6,10 @@
<div class="modal-header">
<h4 class="modal-title">Cloudron Email Server</h4>
</div>
<div class="modal-body" ng-show="dnsConfig.provider === 'noop' || dnsConfig.provider === 'manual'">
<div class="modal-body" ng-show="selectedDomain.provider === 'noop' || selectedDomain.provider === 'manual'">
No DNS provider is setup. Displayed DNS records will have to be setup manually.<br/>
</div>
<div class="modal-body" ng-hide="dnsConfig.provider === 'noop' || dnsConfig.provider === 'manual'">
<div class="modal-body" ng-hide="selectedDomain.provider === 'noop' || selectedDomain.provider === 'manual'">
Cloudron will setup Email related DNS records automatically.
If this domain is already configured to handle email with some other provider, it will <b>overwrite</b> those records.
<br/><br/>
@@ -57,9 +57,16 @@
</div>
</div>
<div class="content">
<div ng-show="!ready" class="loading-banner">
<h1><i class="fa fa-circle-o-notch fa-spin"></i></h1>
</div>
<div class="content" ng-show="ready">
<div class="text-left">
<h1>Email</h1>
<h1>
Email
<select class="form-control pull-right" style="display: inline-block; width: 200px;" ng-model="selectedDomain" ng-options="a.domain for a in domains" ng-change="refreshDomain()"></select>
</h1>
</div>
<div class="text-left">
@@ -73,7 +80,7 @@
Apps can send emails regardless of this setting.
</div>
</div>
<div class="row" ng-show="mailConfig.enabled">
<div class="row" ng-show="selectedDomain.mailConfig.enabled">
<br/>
<div class="col-md-12">
<a href="" data-toggle="collapse" data-parent="#accordion" data-target="#mail_settings">Mail server settings for email clients</a>
@@ -88,20 +95,20 @@
</div>
<br/>
<div class="row">
<div class="col-md-12" ng-show="dnsConfig.provider !== 'caas'">
<button class="pull-left" ng-class="mailConfig.enabled ? 'btn btn-danger' : 'btn btn-primary'" ng-click="email.toggle()" ng-enabled="mailConfig">{{ mailConfig.enabled ? "Disable Email" : "Enable Email" }}</button>
<div class="col-md-12" ng-show="selectedDomain.provider !== 'caas'">
<button class="pull-left" ng-class="selectedDomain.mailConfig.enabled ? 'btn btn-danger' : 'btn btn-primary'" ng-click="email.toggle()" ng-enabled="selectedDomain.mailConfig">{{ selectedDomain.mailConfig.enabled ? "Disable Email" : "Enable Email" }}</button>
</div>
<div class="col-md-12" ng-show="dnsConfig.provider === 'caas'">
<div class="col-md-12" ng-show="selectedDomain.provider === 'caas'">
<span class="text-danger text-bold">This feature requires the Cloudron to be on <a ng-href="{{ config.webServerOrigin + '/documentation/managed-hosting/#using-a-custom-domain' }}" target="_blank">custom domain</a>.</span>
</div>
</div>
</div>
<div class="text-left" ng-show="isPaying">
<div class="text-left">
<h3>Outbound Mail Relay</h3>
</div>
<div class="card" style="margin-bottom: 15px;" ng-show="isPaying">
<div class="card" style="margin-bottom: 15px;">
<div class="row">
<div class="col-md-12">
Select the mail server through which Cloudron will send outbound mails:
@@ -176,11 +183,11 @@
</div>
</div>
<div class="text-left" ng-show="mailConfig.enabled && isPaying">
<div class="text-left" ng-show="selectedDomain.mailConfig.enabled">
<h3>Catch-all</h3>
</div>
<div class="card" style="margin-bottom: 15px;" ng-show="mailConfig.enabled && isPaying">
<div class="card" style="margin-bottom: 15px;" ng-show="selectedDomain.mailConfig.enabled">
<div class="row">
<div class="col-md-12">
Emails sent to non existing addresses will be forwarded to the following accounts:
@@ -195,11 +202,11 @@
</div>
</div>
<div class="text-left" ng-show="dnsConfig.provider && dnsConfig.provider !== 'caas' && currentRelay.provider === 'cloudron-smtp'">
<div class="text-left" ng-show="selectedDomain.provider !== 'caas' && selectedDomain.mailConfig.relay.provider === 'cloudron-smtp'">
<h3>DNS Records</h3>
</div>
<div class="card" style="margin-bottom: 15px;" ng-show="dnsConfig.provider && dnsConfig.provider !== 'caas' && currentRelay.provider === 'cloudron-smtp'">
<div class="card" style="margin-bottom: 15px;" ng-show="selectedDomain.provider !== 'caas' && selectedDomain.mailConfig.relay.provider === 'cloudron-smtp'">
<div class="row">
<div class="col-md-12">
@@ -211,9 +218,9 @@
<div class="row" ng-if="expectedDnsRecords[record.value] && (mailConfig.enabled || (record.name !== 'DMARC' && record.name !== 'MX'))">
<div class="col-xs-12">
<p class="text-muted">
<i ng-hide="email.refreshBusy" ng-class="expectedDnsRecords[record.value].status ? 'fa fa-check-circle text-success' : 'fa fa-exclamation-triangle text-danger'"></i> &nbsp;
<i ng-hide="refreshBusy" ng-class="expectedDnsRecords[record.value].status ? 'fa fa-check-circle text-success' : 'fa fa-exclamation-triangle text-danger'"></i> &nbsp;
<a href="" data-toggle="collapse" data-parent="#accordion" data-target="#collapse_dns_{{ record.value }}">{{ record.name }} record</a>
<button class="btn btn-xs btn-default" ng-click="email.refresh()" ng-disabled="email.refreshBusy" ng-show="!expectedDnsRecords[record.value].status"><i class="fa fa-refresh" ng-class="{ 'fa-pulse': email.refreshBusy }"></i></button>
<button class="btn btn-xs btn-default" ng-click="email.refresh()" ng-disabled="refreshBusy" ng-show="!expectedDnsRecords[record.value].status"><i class="fa fa-refresh" ng-class="{ 'fa-pulse': refreshBusy }"></i></button>
</p>
<div id="collapse_dns_{{ record.value }}" class="panel-collapse collapse">
<div class="panel-body">
@@ -232,39 +239,39 @@
</div>
<div class="text-left" ng-show="dnsConfig.provider && dnsConfig.provider !== 'caas'">
<div class="text-left" ng-show="selectedDomain.provider !== 'caas'">
<h3>SMTP Status</h3>
</div>
<div class="card" style="margin-bottom: 15px;" ng-show="dnsConfig.provider && dnsConfig.provider !== 'caas'">
<div class="card" style="margin-bottom: 15px;" ng-show="selectedDomain.provider !== 'caas'">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-xs-12">
<p class="text-muted">
<i ng-hide="email.refreshBusy" ng-class="relay.status ? 'fa fa-check-circle text-success' : 'fa fa-exclamation-triangle text-danger'"></i> &nbsp;
<i ng-hide="refreshBusy" ng-class="selectedDomain.mailStatus.relay.status ? 'fa fa-check-circle text-success' : 'fa fa-exclamation-triangle text-danger'"></i> &nbsp;
<a href="" data-toggle="collapse" data-parent="#accordion" data-target="#collapse_outbound_smtp">
Outbound SMTP
</a>
<button class="btn btn-xs btn-default" ng-click="email.refresh()" ng-disabled="email.refreshBusy" ng-show="!relay.status"><i class="fa fa-refresh" ng-class="{ 'fa-pulse': email.refreshBusy }"></i></button>
<button class="btn btn-xs btn-default" ng-click="email.refresh()" ng-disabled="refreshBusy" ng-show="!selectedDomain.mailStatus.relay.status"><i class="fa fa-refresh" ng-class="{ 'fa-pulse': refreshBusy }"></i></button>
</p>
<div id="collapse_outbound_smtp" class="panel-collapse collapse">
<div class="panel-body">
<p><b> {{ relay.value }} </b> </p>
<p><b> {{ selectedDomain.mailStatus.relay.value }} </b> </p>
</div>
</div>
</div>
</div>
<div class="row" ng-show="currentRelay.provider === 'cloudron-smtp'">
<div class="row" ng-show="selectedDomain.mailConfig.relay.provider === 'cloudron-smtp'">
<div class="col-xs-12">
<p class="text-muted">
<i ng-hide="email.refreshBusy" ng-class="rbl.status ? 'fa fa-check-circle text-success' : 'fa fa-exclamation-triangle text-danger'"></i> &nbsp;
<i ng-hide="refreshBusy" ng-class="rbl.status ? 'fa fa-check-circle text-success' : 'fa fa-exclamation-triangle text-danger'"></i> &nbsp;
<a href="" data-toggle="collapse" data-parent="#accordion" data-target="#collapse_rbl">
IP Address Blacklist Check
</a>
<button class="btn btn-xs btn-default" ng-click="email.refresh()" ng-disabled="email.refreshBusy" ng-show="!rbl.status"><i class="fa fa-refresh" ng-class="{ 'fa-pulse': email.refreshBusy }"></i></button>
<button class="btn btn-xs btn-default" ng-click="email.refresh()" ng-disabled="refreshBusy" ng-show="!rbl.status"><i class="fa fa-refresh" ng-class="{ 'fa-pulse': refreshBusy }"></i></button>
</p>
<div id="collapse_rbl" class="panel-collapse collapse">
<div class="panel-body">

View File

@@ -1,14 +1,17 @@
'use strict';
angular.module('Application').controller('EmailController', ['$scope', '$location', '$rootScope', 'Client', 'AppStore', function ($scope, $location, $rootScope, Client, AppStore) {
angular.module('Application').controller('EmailController', ['$scope', '$location', '$timeout', '$rootScope', 'Client', 'AppStore', function ($scope, $location, $timeout, $rootScope, Client, AppStore) {
Client.onReady(function () { if (!Client.getUserInfo().admin) $location.path('/'); });
$scope.ready = false;
$scope.refreshBusy = true;
$scope.client = Client;
$scope.user = Client.getUserInfo();
$scope.config = Client.getConfig();
$scope.dnsConfig = {};
$scope.currentRelay = {};
$scope.relay = {};
$scope.domains = [];
$scope.selectedDomain = null;
$scope.rbl = null;
$scope.expectedDnsRecords = {
mx: { },
@@ -24,9 +27,7 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
{ name: 'DMARC', value: 'dmarc' },
{ name: 'PTR', value: 'ptr' }
];
$scope.mailConfig = null;
$scope.users = [];
$scope.isPaying = false;
$scope.showView = function (view) {
// wait for dialog to be fully closed to avoid modal behavior breakage when moving to a different view already
@@ -57,45 +58,31 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
}
};
$scope.email = {
refreshBusy: false,
toggle: function () {
if ($scope.mailConfig.enabled) return $scope.email.disable();
// show warning first
$('#enableEmailModal').modal('show');
},
enable: function () {
$('#enableEmailModal').modal('hide');
Client.setMailConfig({ enabled: true }, function (error) {
if (error) return console.error(error);
$scope.mailConfig.enabled = true;
});
},
disable: function () {
Client.setMailConfig({ enabled: false }, function (error) {
if (error) return console.error(error);
$scope.mailConfig.enabled = false;
});
},
refresh: function () {
$scope.email.refreshBusy = true;
collapseDnsRecords();
showExpectedDnsRecords(function (error) {
if (error) console.error(error);
$scope.email.refreshBusy = false;
});
$scope.toggleEmail = function () {
if ($scope.selectedDomain.mailConfig.enabled) {
$scope.email.disable();
$scope.refreshDomain();
return;
}
// show warning first
$('#enableEmailModal').modal('show');
};
$scope.enableEmail = function () {
$('#enableEmailModal').modal('hide');
Client.enableMailForDomain($scope.selectedDomain.domain, true , function (error) {
if (error) return console.error(error);
$scope.refreshDomain();
});
};
$scope.disableEmail = function () {
Client.enableMailForDomain($scope.selectedDomain.domain, false , function (error) {
if (error) return console.error(error);
$scope.refreshDomain();
});
};
$scope.mailRelayPresets = [
@@ -158,7 +145,7 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
data.password = $scope.mailRelay.relay.password;
}
Client.setMailRelay(data, function (error) {
Client.setMailRelay($scope.selectedDomain.domain, data, function (error) {
$scope.mailRelay.busy = false;
if (error) {
@@ -166,9 +153,12 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
return;
}
$scope.currentRelay = data;
$scope.selectedDomain.relay = data;
$scope.mailRelay.success = true;
$scope.email.refresh();
$scope.refreshDomain();
// clear success indicator after 3sec
$timeout(function () { $scope.mailRelay.success = false; }, 3000);
});
}
};
@@ -211,54 +201,6 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
}
};
function getMailConfig() {
Client.getMailConfig(function (error, mailConfig) {
if (error) return console.error(error);
$scope.mailConfig = mailConfig;
});
}
function getMailRelay() {
Client.getMailRelay(function (error, relay) {
if (error) return console.error(error);
$scope.mailRelay.relay.provider = relay.provider;
$scope.mailRelay.relay.host = relay.host;
$scope.mailRelay.relay.port = relay.port;
$scope.mailRelay.relay.username = '';
$scope.mailRelay.relay.password = '';
$scope.mailRelay.relay.serverApiToken = '';
$scope.currentRelay = relay;
if (relay.provider === 'postmark-smtp') {
$scope.mailRelay.relay.serverApiToken = relay.username;
} else if (relay.provider === 'sendgrid-smtp') {
$scope.mailRelay.relay.serverApiToken = relay.password;
} else {
$scope.mailRelay.relay.username = relay.username;
$scope.mailRelay.relay.password = relay.password;
}
for (var i = 0; i < $scope.mailRelayPresets.length; i++) {
if ($scope.mailRelayPresets[i].provider === relay.provider) {
$scope.mailRelay.preset = $scope.mailRelayPresets[i];
break;
}
}
});
}
// TODO this currently assumes the config.fqdn is the mail domain
function getDnsConfig() {
Client.getDomain($scope.config.fqdn, function (error, result) {
if (error) return console.error(error);
$scope.dnsConfig = result;
});
}
function collapseDnsRecords() {
$scope.expectedDnsRecordsTypes.forEach(function (record) {
var type = record.value;
@@ -269,45 +211,79 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
$('#collapse_rbl').collapse('hide');
}
function showExpectedDnsRecords(callback) {
callback = callback || function (error) { if (error) console.error(error); };
function showExpectedDnsRecords() {
// open the record details if they are not correct
$scope.expectedDnsRecordsTypes.forEach(function (record) {
var type = record.value;
$scope.expectedDnsRecords[type] = $scope.selectedDomain.mailStatus.dns[type] || {};
Client.getEmailStatus(function (error, result) {
if (error) return callback(error);
if (!$scope.expectedDnsRecords[type].status) {
$('#collapse_dns_' + type).collapse('show');
}
});
$scope.relay = result.relay;
$scope.rbl = result.rbl;
if (!$scope.selectedDomain.mailStatus.relay.status) {
$('#collapse_outbound_smtp').collapse('show');
}
// open the record details if they are not correct
$scope.expectedDnsRecordsTypes.forEach(function (record) {
var type = record.value;
$scope.expectedDnsRecords[type] = result.dns[type] || {};
if (!$scope.selectedDomain.mailStatus.rbl.status) {
$('#collapse_rbl').collapse('show');
}
}
if (!$scope.expectedDnsRecords[type].status) {
$('#collapse_dns_' + type).collapse('show');
$scope.refreshDomain = function () {
$scope.refreshBusy = true;
collapseDnsRecords();
Client.getMailConfigForDomain($scope.selectedDomain.domain, function (error, mailConfig) {
if (error) {
$scope.refreshBusy = false;
return console.error(error);
}
// pre-fill the form
$scope.mailRelay.relay.provider = mailConfig.relay.provider;
$scope.mailRelay.relay.host = mailConfig.relay.host;
$scope.mailRelay.relay.port = mailConfig.relay.port;
$scope.mailRelay.relay.username = '';
$scope.mailRelay.relay.password = '';
$scope.mailRelay.relay.serverApiToken = '';
if (mailConfig.relay.provider === 'postmark-smtp') {
$scope.mailRelay.relay.serverApiToken = mailConfig.relay.username;
} else if (mailConfig.relay.provider === 'sendgrid-smtp') {
$scope.mailRelay.relay.serverApiToken = mailConfig.relay.password;
} else {
$scope.mailRelay.relay.username = mailConfig.relay.username;
$scope.mailRelay.relay.password = mailConfig.relay.password;
}
for (var i = 0; i < $scope.mailRelayPresets.length; i++) {
if ($scope.mailRelayPresets[i].provider === mailConfig.relay.provider) {
$scope.mailRelay.preset = $scope.mailRelayPresets[i];
break;
}
}
Client.getMailStatusForDomain($scope.selectedDomain.domain, function (error, mailStatus) {
if (error) {
$scope.refreshBusy = false;
return console.error(error);
}
// amend to selected domain to be available for the UI
$scope.selectedDomain.mailConfig = mailConfig;
$scope.selectedDomain.mailStatus = mailStatus;
console.log($scope.selectedDomain);
showExpectedDnsRecords();
$scope.refreshBusy = false;
});
if (!$scope.relay.status) {
$('#collapse_outbound_smtp').collapse('show');
}
if (!$scope.rbl.status) {
$('#collapse_rbl').collapse('show');
}
callback(null);
});
}
function getUsers() {
Client.getUsers(function (error, result) {
if (error) return console.error('Unable to get user listing.', error);
// only allow users with a Cloudron email address
$scope.catchall.availableAddresses = result.filter(function (u) { return !!u.email; }).map(function (u) { return u.username; });
});
}
};
function getCatchallAddresses() {
Client.getCatchallAddresses(function (error, result) {
@@ -320,33 +296,20 @@ angular.module('Application').controller('EmailController', ['$scope', '$locatio
});
}
function getSubscription() {
if ($scope.config.provider === 'caas') {
$scope.isPaying = true;
return;
}
Client.getAppstoreConfig(function (error, result) {
if (error) return console.error(error);
if (!result.token) return;
AppStore.getSubscription(result, function (error, result) {
if (error) return console.error(error);
$scope.isPaying = result.plan.id !== 'free' && result.plan.id !== 'undecided';
});
});
}
Client.onReady(function () {
getMailConfig();
getMailRelay();
getDnsConfig();
getSubscription();
getUsers();
getCatchallAddresses();
$scope.email.refresh();
Client.getDomains(function (error, domains) {
if (error) return console.error('Unable to get domain listing.', error);
$scope.domains = domains;
$scope.selectedDomain = $scope.domains[0];
$scope.refreshDomain();
$scope.ready = true;
});
// only allow users with a Cloudron email address
// $scope.catchall.availableAddresses = result.filter(function (u) { return !!u.email; }).map(function (u) { return u.username; });
});
// setup all the dialog focus handling