diff --git a/migrations/20180511222705-apps-add-owner-id.js b/migrations/20180511222705-apps-add-owner-id.js new file mode 100644 index 000000000..fc062ec34 --- /dev/null +++ b/migrations/20180511222705-apps-add-owner-id.js @@ -0,0 +1,28 @@ +'use strict'; + +var async = require('async'); + +exports.up = function(db, callback) { + async.series([ + db.runSql.bind(db, 'START TRANSACTION;'), + db.runSql.bind(db, 'ALTER TABLE apps ADD COLUMN ownerId VARCHAR(128)'), + function (next) { + db.all('SELECT id FROM users ORDER BY createdAt LIMIT 1', [ ], function (error, results) { + if (error || results.length === 0) return next(error); + + var ownerId = results[0].id; + db.runSql('UPDATE apps SET ownerId=?', [ ownerId ], next); + }); + }, + db.runSql.bind(db, 'ALTER TABLE apps MODIFY ownerId VARCHAR(128) NOT NULL'), + db.runSql.bind(db, 'ALTER TABLE apps ADD CONSTRAINT apps_owner_constraint FOREIGN KEY(ownerId) REFERENCES users(id)'), + db.runSql.bind(db, 'COMMIT'), + ], callback); +}; + +exports.down = function(db, callback) { + db.runSql('ALTER TABLE apps DROP COLUMN ownerId', function (error) { + if (error) console.error(error); + callback(error); + }); +}; diff --git a/migrations/schema.sql b/migrations/schema.sql index bba875ad1..3db00393d 100644 --- a/migrations/schema.sql +++ b/migrations/schema.sql @@ -86,6 +86,9 @@ CREATE TABLE IF NOT EXISTS apps( oldConfigJson TEXT, // used to pass old config to apptask (configure, restore) updateConfigJson TEXT, // used to pass new config to apptask (update) + ownerId VARCHAR(128), + + FOREIGN KEY(ownerId) REFERENCES users(id), FOREIGN KEY(domain) REFERENCES domains(domain), PRIMARY KEY(id)); @@ -143,6 +146,10 @@ CREATE TABLE IF NOT EXISTS domains( configJson TEXT, /* JSON containing the dns backend provider config */ tlsConfigJson TEXT, /* JSON containing the tls provider config */ + ownerId VARCHAR(128), + + FOREIGN KEY(ownerId) REFERENCES users(id), + PRIMARY KEY (domain)) /* the default db collation is utf8mb4_unicode_ci but for the app table domain constraint we have to use the old one */ diff --git a/src/appdb.js b/src/appdb.js index 2773f822f..331faff25 100644 --- a/src/appdb.js +++ b/src/appdb.js @@ -62,7 +62,7 @@ var APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationSta 'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.httpPort', 'apps.location', 'apps.domain', 'apps.dnsRecordId', 'apps.accessRestrictionJson', 'apps.restoreConfigJson', 'apps.oldConfigJson', 'apps.updateConfigJson', 'apps.memoryLimit', 'apps.xFrameOptions', 'apps.sso', 'apps.debugModeJson', 'apps.robotsTxt', 'apps.enableBackup', - 'apps.creationTime', 'apps.updateTime', 'apps.ts' ].join(','); + 'apps.creationTime', 'apps.updateTime', 'apps.ownerId', 'apps.ts' ].join(','); var PORT_BINDINGS_FIELDS = [ 'hostPort', 'environmentVariable', 'appId' ].join(','); @@ -178,13 +178,14 @@ function getAll(callback) { }); } -function add(id, appStoreId, manifest, location, domain, portBindings, data, callback) { +function add(id, appStoreId, manifest, location, domain, ownerId, portBindings, data, callback) { assert.strictEqual(typeof id, 'string'); assert.strictEqual(typeof appStoreId, 'string'); assert(manifest && typeof manifest === 'object'); assert.strictEqual(typeof manifest.version, 'string'); assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domain, 'string'); + assert.strictEqual(typeof ownerId, 'string'); assert.strictEqual(typeof portBindings, 'object'); assert(data && typeof data === 'object'); assert.strictEqual(typeof callback, 'function'); @@ -205,9 +206,9 @@ function add(id, appStoreId, manifest, location, domain, portBindings, data, cal var queries = []; queries.push({ - query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, location, domain, accessRestrictionJson, memoryLimit, xFrameOptions, restoreConfigJson, sso, debugModeJson, robotsTxt) ' + - ' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', - args: [ id, appStoreId, manifestJson, installationState, location, domain, accessRestrictionJson, memoryLimit, xFrameOptions, restoreConfigJson, sso, debugModeJson, robotsTxt ] + query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, location, domain, accessRestrictionJson, memoryLimit, xFrameOptions, restoreConfigJson, sso, debugModeJson, robotsTxt, ownerId) ' + + ' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', + args: [ id, appStoreId, manifestJson, installationState, location, domain, accessRestrictionJson, memoryLimit, xFrameOptions, restoreConfigJson, sso, debugModeJson, robotsTxt, ownerId ] }); Object.keys(portBindings).forEach(function (env) { diff --git a/src/apps.js b/src/apps.js index 6d17d17b2..faa21c9a3 100644 --- a/src/apps.js +++ b/src/apps.js @@ -509,7 +509,8 @@ function install(data, auditSource, callback) { robotsTxt = data.robotsTxt || null, enableBackup = 'enableBackup' in data ? data.enableBackup : true, backupId = data.backupId || null, - backupFormat = data.backupFormat || 'tgz'; + backupFormat = data.backupFormat || 'tgz', + ownerId = data.ownerId; assert(data.appStoreId || data.manifest); // atleast one of them is required @@ -585,7 +586,7 @@ function install(data, auditSource, callback) { robotsTxt: robotsTxt }; - appdb.add(appId, appStoreId, manifest, location, domain, portBindings, data, function (error) { + appdb.add(appId, appStoreId, manifest, location, domain, ownerId, portBindings, data, function (error) { if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(getDuplicateErrorDetails(location, portBindings, error)); if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new AppsError(AppsError.NOT_FOUND, error.message)); if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error)); @@ -924,12 +925,14 @@ function clone(appId, data, auditSource, callback) { var location = data.location.toLowerCase(), domain = data.domain.toLowerCase(), portBindings = data.portBindings || null, - backupId = data.backupId; + backupId = data.backupId, + ownerId = data.ownerId; assert.strictEqual(typeof backupId, 'string'); assert.strictEqual(typeof location, 'string'); assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof portBindings, 'object'); + assert(ownerId === null || typeof ownerId === 'string'); get(appId, function (error, app) { if (error) return callback(error); @@ -969,7 +972,7 @@ function clone(appId, data, auditSource, callback) { robotsTxt: app.robotsTxt }; - appdb.add(newAppId, app.appStoreId, manifest, location, domain, portBindings, data, function (error) { + appdb.add(newAppId, app.appStoreId, manifest, location, domain, ownerId, portBindings, data, function (error) { if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(getDuplicateErrorDetails(location, portBindings, error)); if (error) return callback(new AppsError(AppsError.INTERNAL_ERROR, error)); diff --git a/src/routes/apps.js b/src/routes/apps.js index 6e48b6837..deecab5eb 100644 --- a/src/routes/apps.js +++ b/src/routes/apps.js @@ -79,6 +79,7 @@ function installApp(req, res, next) { assert.strictEqual(typeof req.body, 'object'); var data = req.body; + data.ownerId = req.user.id; // atleast one if ('manifest' in data && typeof data.manifest !== 'object') return next(new HttpError(400, 'manifest must be an object')); @@ -202,6 +203,7 @@ function cloneApp(req, res, next) { assert.strictEqual(typeof req.params.id, 'string'); var data = req.body; + data.ownerId = req.user.id; debug('Clone app id:%s', req.params.id); diff --git a/src/routes/test/backups-test.js b/src/routes/test/backups-test.js index 8fcf895ba..9ab6d2e8f 100644 --- a/src/routes/test/backups-test.js +++ b/src/routes/test/backups-test.js @@ -29,7 +29,7 @@ const DOMAIN_0 = { tlsConfig: { provider: 'fallback' } }; -var token = null; +var token = null, ownerId = null; function setup(done) { nock.cleanAll(); @@ -49,6 +49,7 @@ function setup(done) { expect(result.statusCode).to.eql(201); // stash token for further use + ownerId = result.body.userId; token = result.body.token; callback(); @@ -57,7 +58,7 @@ function setup(done) { function addApp(callback) { var manifest = { version: '0.0.1', manifestVersion: 1, dockerImage: 'foo', healthCheckPath: '/', httpPort: 3, title: 'ok', addons: { } }; - appdb.add('appid', 'appStoreId', manifest, 'location', DOMAIN_0.domain, [ ] /* portBindings */, { }, callback); + appdb.add('appid', 'appStoreId', manifest, 'location', DOMAIN_0.domain, ownerId, [ ] /* portBindings */, { }, callback); }, function createSettings(callback) { diff --git a/src/routes/test/caas-test.js b/src/routes/test/caas-test.js index 6065e41f0..111e00d3d 100644 --- a/src/routes/test/caas-test.js +++ b/src/routes/test/caas-test.js @@ -35,7 +35,7 @@ const DOMAIN_0 = { tlsConfig: { provider: 'fallback' } }; -var token = null; +var token = null, ownerId = null; var gSudoOriginal = null; function injectShellMock() { gSudoOriginal = shell.sudo; @@ -74,6 +74,7 @@ function setup(done) { expect(scope2.isDone()).to.be.ok(); // stash token for further use + ownerId = result.body.userId; token = result.body.token; callback(); @@ -82,7 +83,7 @@ function setup(done) { function addApp(callback) { var manifest = { version: '0.0.1', manifestVersion: 1, dockerImage: 'foo', healthCheckPath: '/', httpPort: 3, title: 'ok', addons: { } }; - appdb.add('appid', 'appStoreId', manifest, 'location', DOMAIN_0.domain, [ ] /* portBindings */, { }, callback); + appdb.add('appid', 'appStoreId', manifest, 'location', DOMAIN_0.domain, ownerId, [ ] /* portBindings */, { }, callback); }, function createSettings(callback) { diff --git a/src/routes/test/oauth2-test.js b/src/routes/test/oauth2-test.js index 0dc40a3bd..b3a8c5e7e 100644 --- a/src/routes/test/oauth2-test.js +++ b/src/routes/test/oauth2-test.js @@ -62,7 +62,8 @@ describe('OAuth2', function () { domain: DOMAIN_0.domain, portBindings: {}, accessRestriction: null, - memoryLimit: 0 + memoryLimit: 0, + ownerId: USER_0.id }; var APP_1 = { @@ -73,7 +74,8 @@ describe('OAuth2', function () { domain: DOMAIN_0.domain, portBindings: {}, accessRestriction: { users: [ 'foobar' ] }, - memoryLimit: 0 + memoryLimit: 0, + ownerId: USER_0.id }; var APP_2 = { @@ -84,7 +86,8 @@ describe('OAuth2', function () { domain: DOMAIN_0.domain, portBindings: {}, accessRestriction: { users: [ USER_0.id ] }, - memoryLimit: 0 + memoryLimit: 0, + ownerId: USER_0.id }; var APP_3 = { @@ -95,7 +98,8 @@ describe('OAuth2', function () { domain: DOMAIN_0.domain, portBindings: {}, accessRestriction: { groups: [ 'someothergroup', 'admin', 'anothergroup' ] }, - memoryLimit: 0 + memoryLimit: 0, + ownerId: USER_0.id }; // unknown app @@ -214,19 +218,22 @@ describe('OAuth2', function () { clientdb.add.bind(null, CLIENT_6.id, CLIENT_6.appId, CLIENT_6.type, CLIENT_6.clientSecret, CLIENT_6.redirectURI, CLIENT_6.scope), clientdb.add.bind(null, CLIENT_7.id, CLIENT_7.appId, CLIENT_7.type, CLIENT_7.clientSecret, CLIENT_7.redirectURI, CLIENT_7.scope), clientdb.add.bind(null, CLIENT_9.id, CLIENT_9.appId, CLIENT_9.type, CLIENT_9.clientSecret, CLIENT_9.redirectURI, CLIENT_9.scope), - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0), - appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, APP_1.portBindings, APP_1), - appdb.add.bind(null, APP_2.id, APP_2.appStoreId, APP_2.manifest, APP_2.location, APP_2.domain, APP_2.portBindings, APP_2), - appdb.add.bind(null, APP_3.id, APP_3.appStoreId, APP_3.manifest, APP_3.location, APP_3.domain, APP_3.portBindings, APP_3), function (callback) { users.create(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, { }, null /* source */, function (error, userObject) { expect(error).to.not.be.ok(); // update the global objects to reflect the new user id - USER_0.id = userObject.id; + USER_0.id = APP_0.ownerId = APP_1.ownerId = APP_2.ownerId = APP_3.ownerId = userObject.id; APP_2.accessRestriction = { users: [ 'foobar', userObject.id ] }; - appdb.update(APP_2.id, APP_2, callback); + async.series([ + appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0), + appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, APP_1.ownerId, APP_1.portBindings, APP_1), + appdb.add.bind(null, APP_2.id, APP_2.appStoreId, APP_2.manifest, APP_2.location, APP_2.domain, APP_2.ownerId, APP_2.portBindings, APP_2), + appdb.add.bind(null, APP_3.id, APP_3.appStoreId, APP_3.manifest, APP_3.location, APP_3.domain, APP_3.ownerId, APP_3.portBindings, APP_3), + + appdb.update.bind(null, APP_2.id, APP_2) + ], callback); }); }, ], done); diff --git a/src/routes/test/sysadmin-test.js b/src/routes/test/sysadmin-test.js index 6c490c779..d976c6e15 100644 --- a/src/routes/test/sysadmin-test.js +++ b/src/routes/test/sysadmin-test.js @@ -38,6 +38,8 @@ const DOMAIN_0 = { tlsConfig: { provider: 'fallback' } }; +var ownerId = null; + function setup(done) { config._reset(); config.setFqdn(DOMAIN_0.domain); @@ -56,13 +58,15 @@ function setup(done) { expect(result).to.be.ok(); expect(result.statusCode).to.eql(201); + ownerId = result.body.userId; + callback(); }); }, function addApp(callback) { var manifest = { version: '0.0.1', manifestVersion: 1, dockerImage: 'foo', healthCheckPath: '/', httpPort: 3, title: 'ok', addons: { } }; - appdb.add('appid', 'appStoreId', manifest, 'location', DOMAIN_0.domain, [ ] /* portBindings */, { }, callback); + appdb.add('appid', 'appStoreId', manifest, 'location', DOMAIN_0.domain, ownerId, [ ] /* portBindings */, { }, callback); }, function createSettings(callback) { diff --git a/src/setup.js b/src/setup.js index ea1b504b7..f671555a7 100644 --- a/src/setup.js +++ b/src/setup.js @@ -251,7 +251,7 @@ function activate(username, password, email, displayName, ip, auditSource, callb eventlog.add(eventlog.ACTION_ACTIVATE, auditSource, { }); - callback(null, { token: result.accessToken, expires: result.expires }); + callback(null, { userId: userObject.id, token: result.accessToken, expires: result.expires }); setTimeout(cloudron.onActivated, 3000); // hack for now to not block the above http response }); diff --git a/src/test/apps-test.js b/src/test/apps-test.js index 013265720..e66ecfdc7 100644 --- a/src/test/apps-test.js +++ b/src/test/apps-test.js @@ -104,7 +104,8 @@ describe('Apps', function () { accessRestriction: null, memoryLimit: 0, robotsTxt: null, - sso: false + sso: false, + ownerId: USER_0.id }; var APP_1 = { @@ -118,7 +119,8 @@ describe('Apps', function () { }, portBindings: {}, accessRestriction: { users: [ 'someuser' ], groups: [ GROUP_0.id ] }, - memoryLimit: 0 + memoryLimit: 0, + ownerId: USER_0.id }; var APP_2 = { @@ -134,7 +136,8 @@ describe('Apps', function () { accessRestriction: { users: [ 'someuser', USER_0.id ], groups: [ GROUP_1.id ] }, memoryLimit: 0, robotsTxt: null, - sso: false + sso: false, + ownerId: USER_0.id }; before(function (done) { @@ -156,9 +159,9 @@ describe('Apps', function () { groupdb.add.bind(null, GROUP_1.id, GROUP_1.name, [ /* roles */ ]), groups.addMember.bind(null, constants.ADMIN_GROUP_ID, ADMIN_0.id), groups.addMember.bind(null, GROUP_0.id, USER_1.id), - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0), - appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, APP_1.portBindings, APP_1), - appdb.add.bind(null, APP_2.id, APP_2.appStoreId, APP_2.manifest, APP_2.location, APP_2.domain, APP_2.portBindings, APP_2), + appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0), + appdb.add.bind(null, APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, APP_1.ownerId, APP_1.portBindings, APP_1), + appdb.add.bind(null, APP_2.id, APP_2.appStoreId, APP_2.manifest, APP_2.location, APP_2.domain, APP_2.ownerId, APP_2.portBindings, APP_2), settingsdb.set.bind(null, settings.BACKUP_CONFIG_KEY, JSON.stringify({ provider: 'caas', token: 'BACKUP_TOKEN', bucket: 'Bucket', prefix: 'Prefix' })) ], done); }); diff --git a/src/test/apptask-test.js b/src/test/apptask-test.js index 9140b4a60..ddf9afe2f 100644 --- a/src/test/apptask-test.js +++ b/src/test/apptask-test.js @@ -19,6 +19,7 @@ var addons = require('../addons.js'), nock = require('nock'), paths = require('../paths.js'), settings = require('../settings.js'), + userdb = require('../userdb.js'), _ = require('underscore'); var MANIFEST = { @@ -61,6 +62,19 @@ const DOMAIN_0 = { tlsConfig: { provider: 'caas' } }; +var ADMIN = { + id: 'admin123', + username: 'admin123', + password: 'secret', + email: 'admin@me.com', + fallbackEmail: 'admin@me.com', + salt: 'morton', + createdAt: 'sometime back', + modifiedAt: 'now', + resetToken: '', + displayName: '' +}; + var APP = { id: 'appid', appStoreId: 'appStoreId', @@ -75,7 +89,8 @@ var APP = { portBindings: null, accessRestriction: null, dnsRecordId: 'someDnsRecordId', - memoryLimit: 0 + memoryLimit: 0, + ownerId: ADMIN.id }; var awsHostedZones; @@ -105,7 +120,8 @@ describe('apptask', function () { database.initialize, database._clear, domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0.zoneName, DOMAIN_0.provider, DOMAIN_0.config, null, DOMAIN_0.tlsConfig), - appdb.add.bind(null, APP.id, APP.appStoreId, APP.manifest, APP.location, APP.domain, APP.portBindings, APP), + userdb.add.bind(null, ADMIN.id, ADMIN), + appdb.add.bind(null, APP.id, APP.appStoreId, APP.manifest, APP.location, APP.domain, APP.ownerId, APP.portBindings, APP), settings.initialize ], done); }); diff --git a/src/test/database-test.js b/src/test/database-test.js index 7fa9157e6..b22815b98 100644 --- a/src/test/database-test.js +++ b/src/test/database-test.js @@ -116,6 +116,14 @@ describe('database', function () { }); describe('domains', function () { + before(function (done) { + userdb.add(USER_0.id, USER_0, done); + }); + + after(function (done) { + database._clear(done); + }); + it('can add domain', function (done) { domaindb.add(DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }, done); }); @@ -223,11 +231,12 @@ describe('database', function () { sso: true, debugMode: null, robotsTxt: null, - enableBackup: true + enableBackup: true, + ownerId: USER_0.id }; it('cannot delete referenced domain', function (done) { - appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0, function (error) { + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0, function (error) { expect(error).to.be(null); domaindb.del(DOMAIN_0.domain, function (error) { @@ -713,7 +722,7 @@ describe('database', function () { }); }); - describe('app', function () { + describe('apps', function () { var APP_0 = { id: 'appid-0', appStoreId: 'appStoreId-0', @@ -737,7 +746,8 @@ describe('database', function () { sso: true, debugMode: null, robotsTxt: null, - enableBackup: true + enableBackup: true, + ownerId: USER_0.id }; var APP_1 = { @@ -763,11 +773,15 @@ describe('database', function () { sso: true, debugMode: null, robotsTxt: null, - enableBackup: true + enableBackup: true, + ownerId: USER_0.id }; before(function (done) { - domaindb.add(DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }, done); + async.series([ + userdb.add.bind(null, USER_0.id, USER_0), + domaindb.add.bind(null, DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }) + ], done); }); after(function (done) { @@ -788,7 +802,7 @@ describe('database', function () { }); it('add succeeds', function (done) { - appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0, function (error) { + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0, function (error) { expect(error).to.be(null); done(); }); @@ -812,7 +826,7 @@ describe('database', function () { }); it('add of same app fails', function (done) { - appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, [], APP_0, function (error) { + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, [], APP_0, function (error) { expect(error).to.be.a(DatabaseError); expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS); done(); @@ -884,7 +898,7 @@ describe('database', function () { }); it('add second app succeeds', function (done) { - appdb.add(APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, [], APP_1, function (error) { + appdb.add(APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, APP_0.ownerId, [], APP_1, function (error) { expect(error).to.be(null); done(); }); diff --git a/src/test/ldap-test.js b/src/test/ldap-test.js index b08015507..415234aed 100644 --- a/src/test/ldap-test.js +++ b/src/test/ldap-test.js @@ -78,7 +78,8 @@ var APP_0 = { accessRestriction: null, restoreConfig: null, oldConfig: null, - memoryLimit: 4294967296 + memoryLimit: 4294967296, + ownerId: null }; var dockerProxy; @@ -99,21 +100,20 @@ function setup(done) { ldapServer.start.bind(null), domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0.zoneName, DOMAIN_0.provider, DOMAIN_0.config, DOMAIN_0.fallbackCertificate, DOMAIN_0.tlsConfig), maildb.add.bind(null, DOMAIN_0.domain), - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0), + function (callback) { + users.createOwner(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE, function (error, result) { + if (error) return callback(error); + + USER_0.id = APP_0.ownerId = result.id; + + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0, callback); + }); + }, appdb.update.bind(null, APP_0.id, { containerId: APP_0.containerId }), appdb.setAddonConfig.bind(null, APP_0.id, 'sendmail', [{ name: 'MAIL_SMTP_PASSWORD', value : 'sendmailpassword' }]), appdb.setAddonConfig.bind(null, APP_0.id, 'recvmail', [{ name: 'MAIL_IMAP_PASSWORD', value : 'recvmailpassword' }]), mailboxdb.addMailbox.bind(null, APP_0.location + '.app', APP_0.domain, APP_0.id, mailboxdb.OWNER_TYPE_APP), - function (callback) { - users.createOwner(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE, function (error, result) { - if (error) return callback(error); - - USER_0.id = result.id; - - callback(null); - }); - }, function (callback) { users.create(USER_1.username, USER_1.password, USER_1.email, USER_0.displayName, { invitor: USER_0 }, AUDIT_SOURCE, function (error, result) { if (error) return callback(error); diff --git a/src/test/updatechecker-test.js b/src/test/updatechecker-test.js index 00dfc98b8..2c1b40cb2 100644 --- a/src/test/updatechecker-test.js +++ b/src/test/updatechecker-test.js @@ -278,7 +278,8 @@ describe('updatechecker - app - manual (email)', function () { portBindings: { PORT: 5678 }, healthy: null, accessRestriction: null, - memoryLimit: 0 + memoryLimit: 0, + ownerId: null }; before(function (done) { @@ -294,8 +295,14 @@ describe('updatechecker - app - manual (email)', function () { domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0.zoneName, DOMAIN_0.provider, DOMAIN_0.config, DOMAIN_0.fallbackCertificate, DOMAIN_0.tlsConfig), mail.addDomain.bind(null, DOMAIN_0.domain), mailer._clearMailQueue, - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0), - users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE), + function (next) { + users.createOwner(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE, function (error, userObject) { + if (error) return next(error); + + APP_0.ownerId = userObject.id; + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0, next); + }); + }, settings.setAppAutoupdatePattern.bind(null, constants.AUTOUPDATE_PATTERN_NEVER), settingsdb.set.bind(null, settings.APPSTORE_CONFIG_KEY, JSON.stringify({ userId: 'uid', cloudronId: 'cid', token: 'token' })) ], done); @@ -394,7 +401,8 @@ describe('updatechecker - app - automatic (no email)', function () { portBindings: { PORT: 5678 }, healthy: null, accessRestriction: null, - memoryLimit: 0 + memoryLimit: 0, + ownerId: null }; before(function (done) { @@ -410,8 +418,14 @@ describe('updatechecker - app - automatic (no email)', function () { domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0.zoneName, DOMAIN_0.provider, DOMAIN_0.config, DOMAIN_0.fallbackCertificate, DOMAIN_0.tlsConfig), mail.addDomain.bind(null, DOMAIN_0.domain), mailer._clearMailQueue, - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0), - users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE), + function (next) { + users.createOwner(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE, function (error, userObject) { + if (error) return next(error); + + APP_0.ownerId = userObject.id; + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0, next); + }); + }, settings.setAppAutoupdatePattern.bind(null, '00 00 1,3,5,23 * * *'), settingsdb.set.bind(null, settings.APPSTORE_CONFIG_KEY, JSON.stringify({ userId: 'uid', cloudronId: 'cid', token: 'token' })) ], done); @@ -460,7 +474,8 @@ describe('updatechecker - app - automatic free (email)', function () { portBindings: { PORT: 5678 }, healthy: null, accessRestriction: null, - memoryLimit: 0 + memoryLimit: 0, + ownerId: null }; before(function (done) { @@ -476,8 +491,14 @@ describe('updatechecker - app - automatic free (email)', function () { domains.add.bind(null, DOMAIN_0.domain, DOMAIN_0.zoneName, DOMAIN_0.provider, DOMAIN_0.config, DOMAIN_0.fallbackCertificate, DOMAIN_0.tlsConfig), mail.addDomain.bind(null, DOMAIN_0.domain), mailer._clearMailQueue, - appdb.add.bind(null, APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0), - users.createOwner.bind(null, USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE), + function (next) { + users.createOwner(USER_0.username, USER_0.password, USER_0.email, USER_0.displayName, AUDIT_SOURCE, function (error, userObject) { + if (error) return next(error); + + APP_0.ownerId = userObject.id; + appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.ownerId, APP_0.portBindings, APP_0, next); + }); + }, settings.setAppAutoupdatePattern.bind(null, '00 00 1,3,5,23 * * *'), settingsdb.set.bind(null, settings.APPSTORE_CONFIG_KEY, JSON.stringify({ userId: 'uid', cloudronId: 'cid', token: 'token' })) ], done); diff --git a/src/userdb.js b/src/userdb.js index 36c37b114..999f129ce 100644 --- a/src/userdb.js +++ b/src/userdb.js @@ -147,6 +147,7 @@ function add(userId, user, callback) { database.query(query, args, function (error) { if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_email') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'email already exists')); if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_username') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'username already exists')); + if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('PRIMARY') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'id already exists')); if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); callback(null);