Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 61f7c1af48 | |||
| 00786dda05 | |||
| 8b9f44addc | |||
| 56c7dbb6e4 | |||
| c47f878203 | |||
| 8a2107e6eb | |||
| cd9f0f69d8 | |||
| 1da91b64f6 | |||
| a87dd65c1d | |||
| 7c63d9e758 | |||
| 329bf596ac |
@@ -982,3 +982,12 @@
|
||||
* Add webterminal to shell into apps from the admin UI
|
||||
* Update Haraka for a few crash fixes
|
||||
|
||||
[1.6.3]
|
||||
* Fixes selection issue while clicking on empty flexbox space
|
||||
* Indicate directories can be downloaded in the web terminal
|
||||
* Do not show app update indicator for normal users
|
||||
* Display email notice when using Cloudflare DNS
|
||||
* Set MX records correctly when using Cloudflare DNS
|
||||
* Fix bug where webterminal can incorrectly appear in main view
|
||||
* Do not crash if DNS credentials are invalid
|
||||
|
||||
|
||||
@@ -82,7 +82,6 @@ BackupsError.INTERNAL_ERROR = 'internal error';
|
||||
BackupsError.BAD_STATE = 'bad state';
|
||||
BackupsError.BAD_FIELD = 'bad field';
|
||||
BackupsError.NOT_FOUND = 'not found';
|
||||
BackupsError.MISSING_CREDENTIALS = 'missing credentials';
|
||||
|
||||
// choose which storage backend we use for test purpose we use s3
|
||||
function api(provider) {
|
||||
|
||||
@@ -109,10 +109,18 @@ function upsert(dnsConfig, zoneName, subdomain, type, values, callback) {
|
||||
var i = 0;
|
||||
|
||||
async.eachSeries(values, function (value, callback) {
|
||||
var priority = null;
|
||||
|
||||
if (type === 'MX') {
|
||||
priority = value.split(' ')[0];
|
||||
value = value.split(' ')[1];
|
||||
}
|
||||
|
||||
var data = {
|
||||
type: type,
|
||||
name: fqdn,
|
||||
content: value,
|
||||
priority: priority,
|
||||
ttl: 120 // 1 means "automatic" (meaning 300ms) and 120 is the lowest supported
|
||||
};
|
||||
|
||||
|
||||
+3
-1
@@ -329,7 +329,9 @@ function startMail(callback) {
|
||||
|
||||
async.mapSeries(records, function (record, iteratorCallback) {
|
||||
subdomains.upsert(record.subdomain, record.type, record.values, iteratorCallback);
|
||||
}, callback);
|
||||
}, NOOP_CALLBACK); // do not crash if DNS creds do not work in startup sequence
|
||||
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -184,6 +184,10 @@ function getConfig(req, res, next) {
|
||||
cloudron.getConfig(function (error, cloudronConfig) {
|
||||
if (error) return next(new HttpError(500, error));
|
||||
|
||||
if (!req.user.admin) {
|
||||
cloudronConfig = _.pick(cloudronConfig, 'apiServerOrigin', 'webServerOrigin', 'fqdn', 'version', 'progress', 'isCustomDomain', 'isDemo', 'cloudronName', 'provider');
|
||||
}
|
||||
|
||||
next(new HttpSuccess(200, cloudronConfig));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,12 +16,14 @@ var async = require('async'),
|
||||
superagent = require('superagent'),
|
||||
server = require('../../server.js'),
|
||||
settings = require('../../settings.js'),
|
||||
shell = require('../../shell.js');
|
||||
shell = require('../../shell.js'),
|
||||
tokendb = require('../../tokendb.js');
|
||||
|
||||
var SERVER_URL = 'http://localhost:' + config.get('port');
|
||||
|
||||
var USERNAME = 'superadmin', PASSWORD = 'Foobar?1337', EMAIL ='silly@me.com';
|
||||
var token = null; // authentication token
|
||||
var USERNAME_1 = 'userTheFirst', EMAIL_1 = 'taO@zen.mac', userId_1, token_1;
|
||||
|
||||
var server;
|
||||
function setup(done) {
|
||||
@@ -204,6 +206,22 @@ describe('Cloudron', function () {
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
function (callback) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users')
|
||||
.query({ access_token: token })
|
||||
.send({ username: USERNAME_1, email: EMAIL_1, invite: false })
|
||||
.end(function (error, result) {
|
||||
expect(result).to.be.ok();
|
||||
expect(result.statusCode).to.eql(201);
|
||||
|
||||
token_1 = tokendb.generateToken();
|
||||
userId_1 = result.body.id;
|
||||
|
||||
// HACK to get a token for second user (passwords are generated and the user should have gotten a password setup link...)
|
||||
tokendb.add(token_1, userId_1, 'test-client-id', Date.now() + 100000, '*', callback);
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
|
||||
@@ -239,7 +257,7 @@ describe('Cloudron', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds', function (done) {
|
||||
it('succeeds (admin)', function (done) {
|
||||
var scope = nock(config.apiServerOrigin())
|
||||
.get('/api/v1/boxes/localhost?token=' + config.token())
|
||||
.reply(200, { box: { region: 'sfo', size: '1gb' }, user: { }});
|
||||
@@ -260,6 +278,7 @@ describe('Cloudron', function () {
|
||||
expect(result.body.region).to.eql('sfo');
|
||||
expect(result.body.memory).to.eql(os.totalmem());
|
||||
expect(result.body.cloudronName).to.be.a('string');
|
||||
expect(result.body.provider).to.be.a('string');
|
||||
|
||||
expect(scope.isDone()).to.be.ok();
|
||||
|
||||
@@ -267,6 +286,31 @@ describe('Cloudron', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds (non-admin)', function (done) {
|
||||
superagent.get(SERVER_URL + '/api/v1/cloudron/config')
|
||||
.query({ access_token: token_1 })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
console.dir(result.body);
|
||||
|
||||
expect(result.body.apiServerOrigin).to.eql('http://localhost:6060');
|
||||
expect(result.body.webServerOrigin).to.eql(null);
|
||||
expect(result.body.fqdn).to.eql(config.fqdn());
|
||||
expect(result.body.isCustomDomain).to.eql(true);
|
||||
expect(result.body.progress).to.be.an('object');
|
||||
expect(result.body.version).to.eql(config.version());
|
||||
expect(result.body.cloudronName).to.be.a('string');
|
||||
expect(result.body.provider).to.be.a('string');
|
||||
|
||||
expect(result.body.update).to.be(undefined);
|
||||
expect(result.body.size).to.be(undefined);
|
||||
expect(result.body.region).to.be(undefined);
|
||||
expect(result.body.memory).to.be(undefined);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
xdescribe('migrate', function () {
|
||||
|
||||
@@ -40,7 +40,6 @@ SubdomainError.NOT_FOUND = 'No such domain';
|
||||
SubdomainError.EXTERNAL_ERROR = 'External error';
|
||||
SubdomainError.BAD_FIELD = 'Bad Field';
|
||||
SubdomainError.STILL_BUSY = 'Still busy';
|
||||
SubdomainError.MISSING_CREDENTIALS = 'Missing credentials';
|
||||
SubdomainError.INTERNAL_ERROR = 'Internal error';
|
||||
SubdomainError.ACCESS_DENIED = 'Access denied';
|
||||
SubdomainError.INVALID_PROVIDER = 'provider must be route53, digitalocean, cloudflare, noop, manual or caas';
|
||||
|
||||
@@ -518,7 +518,7 @@ h1, h2, h3 {
|
||||
|
||||
.grid-item-top .progress {
|
||||
border-radius: 0;
|
||||
box-shadown: none;
|
||||
box-shadow: none;
|
||||
margin-top: 10px;
|
||||
width: inherit;
|
||||
height: 10px;
|
||||
@@ -526,7 +526,7 @@ h1, h2, h3 {
|
||||
|
||||
.grid-item-top .progress-bar {
|
||||
border-radius: 0;
|
||||
box-shadown: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.app-icon {
|
||||
|
||||
@@ -362,6 +362,9 @@
|
||||
|
||||
<div class="content content-large">
|
||||
|
||||
<!-- Workaround for select-all issue, see commit message -->
|
||||
<div style="font-size: 1px;"> </div>
|
||||
|
||||
<div class="animateMeOpacity ng-hide" ng-show="installedApps.length === 0 && user.admin">
|
||||
<div class="col-md-12" style="text-align: center;">
|
||||
<br/><br/><br/><br/>
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">Download a file from {{ selected.name }}</h4>
|
||||
<h4 class="modal-title">Download from {{ selected.name }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form name="downloadFileForm" ng-submit="downloadFile.submit()">
|
||||
<div class="form-group" ng-class="{ 'has-error': downloadFileForm.filePath.$dirty && downloadFile.error }">
|
||||
<label class="control-label" for="inputDownloadFilePath">Path to file or directory</label>
|
||||
<div class="control-label" ng-show="{ 'has-error': downloadFileForm.filePath.$dirty && downloadFile.error }">
|
||||
<small>{{ downloadFile.error }}</small>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="filePath" ng-model="downloadFile.filePath" required autofocus>
|
||||
</div>
|
||||
<input class="ng-hide" type="submit" ng-disabled="!downloadFile.filePath"/>
|
||||
<input id="inputDownloadFilePath" class="ng-hide" type="submit" ng-disabled="!downloadFile.filePath"/>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
@@ -239,7 +239,9 @@ angular.module('Application').controller('DebugController', ['$scope', '$locatio
|
||||
|
||||
$scope.terminalSocket.onclose = function () {
|
||||
// retry in one second only if terminal view is still selected
|
||||
setTimeout(function () {
|
||||
$scope.terminalReconnectTimeout = setTimeout(function () {
|
||||
// if the scope was already destroyed, do not reconnect
|
||||
if ($scope.$$destroyed) return;
|
||||
if ($scope.terminalVisible) $scope.showTerminal(true);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<div class="modal-body" ng-show="dnsConfig.provider === 'noop' || dnsConfig.provider === 'manual'">
|
||||
No DNS provider is setup. Displayed DNS records will have to be setup manually.<br/>
|
||||
</div>
|
||||
<div class="modal-body" ng-show="dnsConfig.provider === 'route53' || dnsConfig.provider === 'digitalocean'">
|
||||
The Cloudron will setup Email related DNS records automatically.
|
||||
<div class="modal-body" ng-show="dnsConfig.provider === 'route53' || dnsConfig.provider === 'digitalocean' || dnsConfig.provider === 'cloudflare'">
|
||||
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/>
|
||||
Disabling Cloudron Email later will <b>not</b> put the old records back.
|
||||
<br/><br/>
|
||||
Status of DNS Records will show an error when DNS is propagating (~5 minutes).
|
||||
Status of DNS Records will show an error while DNS is propagating (~5 minutes).
|
||||
<br/>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@@ -200,4 +200,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -54,33 +54,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal enable email -->
|
||||
<div class="modal fade" id="enableEmailModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<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'">
|
||||
No DNS provider is setup. Displayed DNS records will have to be setup manually.<br/>
|
||||
</div>
|
||||
<div class="modal-body" ng-show="dnsConfig.provider === 'route53' || dnsConfig.provider === 'digitalocean'">
|
||||
The 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/>
|
||||
Disabling Cloudron Email later will <b>not</b> put the old records back.
|
||||
<br/><br/>
|
||||
Status of DNS Records will show an error when DNS is propagating (~5 minutes).
|
||||
<br/>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" ng-click="email.enable()">I understand, enable</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal backup failed -->
|
||||
<div class="modal fade" id="createBackupFailedModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
|
||||
Reference in New Issue
Block a user