diff --git a/src/js/client.js b/src/js/client.js
index a791a4eb1..01151fd51 100644
--- a/src/js/client.js
+++ b/src/js/client.js
@@ -1721,6 +1721,15 @@ angular.module('Application').service('Client', ['$http', '$interval', '$timeout
});
};
+ Client.prototype.getDNSRecords = function (domain, subdomain, type, callback) {
+ get('/api/v1/domains/' + domain + '/dns?subdomain=' + subdomain + '&type=' + type, null, function (error, data, status) {
+ if (error) return callback(error);
+ if (status !== 200) return callback(new ClientError(status, data));
+
+ callback(null, data.values);
+ });
+ };
+
Client.prototype.addMailDomain = function (domain, callback) {
post('/api/v1/mail', { domain: domain }, null, function (error, data, status) {
if (error) return callback(error);
diff --git a/src/views/app.html b/src/views/app.html
index 21f416f47..b4d0238d5 100644
--- a/src/views/app.html
+++ b/src/views/app.html
@@ -81,6 +81,28 @@
+
+
+
+
+
+
+
By default Cloudron does not overwrite DNS records which exist outside of Cloudron.
+
The following domains already exist outside of Cloudron:
+
+ - {{ domain.subdomain + '.' + domain.domain }}
+
+
+
+
+
+
+
diff --git a/src/views/app.js b/src/views/app.js
index 9eb3e2b15..87f10449d 100644
--- a/src/views/app.js
+++ b/src/views/app.js
@@ -3,6 +3,7 @@
/* global angular */
/* global $ */
/* global asyncSeries */
+/* global asyncForEach */
// TODO use this once we enable custom SSL certificate ui again
@@ -156,7 +157,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
$scope.location = {
busy: false,
error: {},
- success: false,
+ domainCollisions: [],
domain: null,
location: '',
@@ -182,6 +183,7 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
var app = $scope.app;
$scope.location.error = {};
+ $scope.location.domainCollisions = [];
$scope.location.location = app.location;
$scope.location.domain = $scope.domains.filter(function (d) { return d.domain === app.domain; })[0];
$scope.location.portBindingsInfo = angular.extend({}, app.manifest.tcpPorts, app.manifest.udpPorts); // Portbinding map only for information
@@ -199,9 +201,12 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
}
},
- submit: function () {
+ submit: function (overwriteDns) {
+ $('#domainCollisionsModal').modal('hide');
+
$scope.location.busy = true;
$scope.location.error = {};
+ $scope.location.domainCollisions = [];
// only use enabled ports from portBindings
var portBindings = {};
@@ -212,30 +217,62 @@ angular.module('Application').controller('AppController', ['$scope', '$location'
}
var data = {
+ overwriteDns: !!overwriteDns,
location: $scope.location.location,
domain: $scope.location.domain.domain,
portBindings: portBindings,
alternateDomains: $scope.location.alternateDomains.map(function (a) { return { subdomain: a.subdomain, domain: a.domain.domain };})
};
- Client.configureApp($scope.app.id, 'location', data, function (error) {
- if (error && (error.statusCode === 409 || error.statusCode === 400)) {
- if ((error.location && error.domain) || error.field === 'location') {
- $scope.location.error.location = error.message;
- $scope.locationForm.$setPristine();
- } else {
- $scope.location.error.alternateDomains = error.message;
- }
+ // pre-flight only for changed domains
+ var domains = [];
+ if ($scope.app.domain !== data.domain || $scope.app.location !== data.location) domains.push({ subdomain: data.location, domain: data.domain });
+ data.alternateDomains.forEach(function (a) {
+ if ($scope.app.alternateDomains.some(function (d) { return d.domain === a.domain && d.subdomain === a.subdomain; })) return;
+ domains.push({ subdomain: a.subdomain, domain: a.domain });
+ });
+ asyncForEach(domains, function (domain, callback) {
+ if (overwriteDns) return callback();
+
+ Client.getDNSRecords(domain.domain, domain.subdomain, 'A', function (error, result) {
+ // TODO handle credential errors
+ if (error) return callback(error);
+
+ if (result.length) $scope.location.domainCollisions.push(domain);
+
+ callback();
+ });
+ }, function (error) {
+ if (error) {
$scope.location.busy = false;
- return;
+ return Client.error(error);
}
- if (error) return Client.error(error);
- $scope.location.success = true;
- $scope.location.busy = false;
+ if ($scope.location.domainCollisions.length) {
+ $scope.location.busy = false;
+ return $('#domainCollisionsModal').modal('show');
+ }
- refreshApp();
+ Client.configureApp($scope.app.id, 'location', data, function (error) {
+ if (error && (error.statusCode === 409 || error.statusCode === 400)) {
+ if ((error.location && error.domain) || error.field === 'location') {
+ $scope.location.error.location = error.message;
+ $scope.locationForm.$setPristine();
+ } else {
+ $scope.location.error.alternateDomains = error.message;
+ }
+
+ $scope.location.busy = false;
+ return;
+ }
+ if (error) return Client.error(error);
+
+ $scope.locationForm.$setPristine();
+ $scope.location.busy = false;
+
+ refreshApp();
+ });
});
}
};