Compare commits

...

7 Commits
v7.4.2 ... 4.0

Author SHA1 Message Date
Johannes Zellner
51a69cce41 Ensure notifications are sorted by time descending
(cherry picked from commit 63310c44c0)
2019-05-14 09:49:26 -07:00
Johannes Zellner
8686832bd1 4.0.3 changes 2019-05-14 16:57:45 +02:00
Girish Ramakrishnan
c93c06ba88 gcs: fix crash
(cherry picked from commit 05d3f8a667)
2019-05-12 18:14:17 -07:00
Girish Ramakrishnan
36d64b3566 4.0.2 changes
(cherry picked from commit 3fa45ea728)
2019-05-12 14:04:26 -07:00
Girish Ramakrishnan
e0c531564c Add option to skip backup before update
(cherry picked from commit a7d2098f09)
2019-05-12 13:59:07 -07:00
Girish Ramakrishnan
1e0ec75f0a gcdns: fix crash
(cherry picked from commit e1ecb49d59)
2019-05-12 12:57:06 -07:00
Girish Ramakrishnan
36ac02d29f Fix crash because params was undefined
(cherry picked from commit 800e25a7a7)
2019-05-10 13:08:26 -07:00
10 changed files with 49 additions and 29 deletions

View File

@@ -1593,3 +1593,10 @@
* Make it easier to import email
* Give SFTP access only to admins
[4.0.2]
* Fix GCDNS crash
* Add option to update without backing up
[4.0.3]
* Fix dashboard issue for non-admins

View File

@@ -204,7 +204,7 @@ function boxAutoupdatePatternChanged(pattern) {
var updateInfo = updateChecker.getUpdateInfo();
if (updateInfo.box) {
debug('Starting autoupdate to %j', updateInfo.box);
updater.updateToLatest(auditSource.CRON, NOOP_CALLBACK);
updater.updateToLatest({ skipBackup: false }, auditSource.CRON, NOOP_CALLBACK);
} else {
debug('No box auto updates available');
}

View File

@@ -15,7 +15,7 @@ var assert = require('assert'),
dns = require('../native-dns.js'),
domains = require('../domains.js'),
DomainsError = require('../domains.js').DomainsError,
GCDNS = require('@google-cloud/dns'),
GCDNS = require('@google-cloud/dns').DNS,
util = require('util'),
waitForDns = require('./waitfordns.js'),
_ = require('underscore');
@@ -46,7 +46,7 @@ function getZoneByName(dnsConfig, zoneName, callback) {
assert.strictEqual(typeof zoneName, 'string');
assert.strictEqual(typeof callback, 'function');
var gcdns = GCDNS(getDnsCredentials(dnsConfig));
var gcdns = new GCDNS(getDnsCredentials(dnsConfig));
gcdns.getZones(function (error, zones) {
if (error && error.message === 'invalid_grant') return callback(new DomainsError(DomainsError.ACCESS_DENIED, 'The key was probably revoked'));

View File

@@ -112,7 +112,7 @@ function listByUserIdPaged(userId, page, perPage, callback) {
var data = [ userId ];
var query = 'SELECT ' + NOTIFICATION_FIELDS + ' FROM notifications WHERE userId=?';
query += ' ORDER BY creationTime, title DESC LIMIT ?,?';
query += ' ORDER BY creationTime DESC LIMIT ?,?';
data.push((page-1)*perPage);
data.push(perPage);

View File

@@ -57,8 +57,10 @@ function getDisks(req, res, next) {
}
function update(req, res, next) {
if ('skipBackup' in req.body && typeof req.body.skipBackup !== 'boolean') return next(new HttpError(400, 'skipBackup must be a boolean'));
// this only initiates the update, progress can be checked via the progress route
updater.updateToLatest(auditSource.fromRequest(req), function (error, taskId) {
updater.updateToLatest(req.body, auditSource.fromRequest(req), function (error, taskId) {
if (error && error.reason === UpdaterError.ALREADY_UPTODATE) return next(new HttpError(422, error.message));
if (error && error.reason === UpdaterError.BAD_STATE) return next(new HttpError(409, error.message));
if (error) return next(new HttpError(500, error));

View File

@@ -38,7 +38,7 @@ function update(req, res, next) {
debug('triggering update');
// this only initiates the update, progress can be checked via the progress route
updater.updateToLatest(auditSource.SYSADMIN, function (error, taskId) {
updater.updateToLatest({ skipBackup: false }, auditSource.SYSADMIN, function (error, taskId) {
if (error && error.reason === UpdaterError.ALREADY_UPTODATE) return next(new HttpError(422, error.message));
if (error && error.reason === UpdaterError.BAD_STATE) return next(new HttpError(409, error.message));
if (error) return next(new HttpError(500, error));

View File

@@ -25,7 +25,7 @@ var assert = require('assert'),
BackupsError = require('../backups.js').BackupsError,
debug = require('debug')('box:storage/gcs'),
EventEmitter = require('events'),
GCS = require('@google-cloud/storage'),
GCS = require('@google-cloud/storage').Storage,
PassThrough = require('stream').PassThrough,
path = require('path');
@@ -53,7 +53,7 @@ function getBucket(apiConfig) {
}
};
return GCS(gcsConfig).bucket(apiConfig.bucket);
return new GCS(gcsConfig).bucket(apiConfig.bucket);
}
// storage api

View File

@@ -263,7 +263,7 @@ function copy(apiConfig, oldFilePath, newFilePath) {
endBytes = startBytes + chunkSize;
if (endBytes > size) endBytes = size;
var params = {
var partCopyParams = {
Bucket: apiConfig.bucket,
Key: path.join(newFilePath, relativePath),
CopySource: encodeCopySource(apiConfig.bucket, entry.fullPath), // See aws-sdk-js/issues/1302
@@ -272,12 +272,12 @@ function copy(apiConfig, oldFilePath, newFilePath) {
UploadId: uploadId
};
events.emit('progress', `Copying part ${params.PartNumber} - ${params.CopySource} ${params.CopySourceRange}`);
events.emit('progress', `Copying part ${partCopyParams.PartNumber} - ${partCopyParams.CopySource} ${partCopyParams.CopySourceRange}`);
s3.uploadPartCopy(params, function (error, result) {
s3.uploadPartCopy(partCopyParams, function (error, result) {
if (error) return done(error);
events.emit('progress', `Uploaded part ${params.PartNumber} - Etag: ${result.CopyPartResult.ETag}`);
events.emit('progress', `Uploaded part ${partCopyParams.PartNumber} - Etag: ${result.CopyPartResult.ETag}`);
uploadedParts.push({ ETag: result.CopyPartResult.ETag, PartNumber: partNumber });
@@ -287,16 +287,16 @@ function copy(apiConfig, oldFilePath, newFilePath) {
return copyNextChunk();
}
var params = {
var completeMultipartParams = {
Bucket: apiConfig.bucket,
Key: path.join(newFilePath, relativePath),
MultipartUpload: { Parts: uploadedParts },
UploadId: uploadId
};
events.emit('progress', `Finishing multipart copy - ${params.Key}`);
events.emit('progress', `Finishing multipart copy - ${completeMultipartParams.Key}`);
s3.completeMultipartUpload(params, done);
s3.completeMultipartUpload(completeMultipartParams, done);
}).on('retry', function (response) {
++retryCount;
events.emit('progress', `Retrying (${response.retryCount+1}) multipart copy of ${relativePath || oldFilePath}. Error: ${response.error} ${response.httpResponse.statusCode}`);

View File

@@ -11,7 +11,6 @@ var async = require('async'),
users = require('../users.js'),
userdb = require('../userdb.js'),
eventlogdb = require('../eventlogdb.js'),
notificationdb = require('../notificationdb.js'),
notifications = require('../notifications.js'),
NotificationsError = notifications.NotificationsError,
expect = require('expect.js');
@@ -152,20 +151,24 @@ describe('Notifications', function () {
});
});
it('getAllPaged succeeds for second page', function (done) {
async.timesSeries(20, function (n, callback) {
notifications._add(USER_0.id, EVENT_0.id, 'title' + n, 'some message', callback);
it('getAllPaged succeeds for second page (takes 5 seconds to add)', function (done) {
async.timesSeries(5, function (n, callback) {
// timeout is for database TIMESTAMP resolution
setTimeout(function () {
notifications._add(USER_0.id, EVENT_0.id, 'title' + n, 'some message', callback);
}, 1000);
}, function (error) {
expect(error).to.eql(null);
notifications.getAllPaged(USER_0.id, null /* ack */, 2, 10, function (error, results) {
notifications.getAllPaged(USER_0.id, null /* ack */, 2, 3, function (error, results) {
expect(error).to.eql(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(10);
expect(results.length).to.be(3);
// we cannot compare the title because ordering is by time which is stored in mysql with seconds
// precision. making the ordering random...
// expect(results[0].title).to.equal('title9');
expect(results[0].title).to.equal('title1');
expect(results[1].title).to.equal('title0');
// the previous tests already add one notification with 'title'
expect(results[2].title).to.equal('title');
done();
});

View File

@@ -154,8 +154,9 @@ function downloadAndVerifyRelease(updateInfo, callback) {
});
}
function update(boxUpdateInfo, progressCallback, callback) {
function update(boxUpdateInfo, options, progressCallback, callback) {
assert(boxUpdateInfo && typeof boxUpdateInfo === 'object');
assert(options && typeof options === 'object');
assert.strictEqual(typeof progressCallback, 'function');
assert.strictEqual(typeof callback, 'function');
@@ -164,9 +165,15 @@ function update(boxUpdateInfo, progressCallback, callback) {
downloadAndVerifyRelease(boxUpdateInfo, function (error, packageInfo) {
if (error) return callback(error);
progressCallback({ percent: 10, message: 'Backing up' });
function maybeBackup(next) {
if (options.skipBackup) return next();
backups.backupBoxAndApps((progress) => progressCallback({ percent: 10+progress.percent*70/100, message: progress.message }), function (error) {
progressCallback({ percent: 10, message: 'Backing up' });
backups.backupBoxAndApps((progress) => progressCallback({ percent: 10+progress.percent*70/100, message: progress.message }), next);
}
maybeBackup(function (error) {
if (error) return callback(error);
debug('updating box %s', boxUpdateInfo.sourceTarballUrl);
@@ -201,7 +208,8 @@ function canUpdate(boxUpdateInfo, callback) {
});
}
function updateToLatest(auditSource, callback) {
function updateToLatest(options, auditSource, callback) {
assert.strictEqual(typeof options, 'object');
assert.strictEqual(typeof auditSource, 'object');
assert.strictEqual(typeof callback, 'function');
@@ -215,7 +223,7 @@ function updateToLatest(auditSource, callback) {
error = locker.lock(locker.OP_BOX_UPDATE);
if (error) return callback(new UpdaterError(UpdaterError.BAD_STATE, `Cannot update now: ${error.message}`));
let task = tasks.startTask(tasks.TASK_UPDATE, [ boxUpdateInfo ]);
let task = tasks.startTask(tasks.TASK_UPDATE, [ boxUpdateInfo, options ]);
task.on('error', (error) => callback(new UpdaterError(UpdaterError.INTERNAL_ERROR, error)));
task.on('start', (taskId) => {
eventlog.add(eventlog.ACTION_UPDATE, auditSource, { taskId, boxUpdateInfo });