Primitive account deletion via DELETE /account

This commit is contained in:
Ben Gotow 2016-07-11 16:56:18 -07:00
parent 8e0cd92bad
commit 492ac21bb6
7 changed files with 64 additions and 16 deletions

View file

@ -1,4 +1,5 @@
const Serialization = require('../serialization'); const Serialization = require('../serialization');
const {DatabaseConnector} = require('nylas-core');
module.exports = (server) => { module.exports = (server) => {
server.route({ server.route({
@ -21,4 +22,28 @@ module.exports = (server) => {
reply(Serialization.jsonStringify(account)); reply(Serialization.jsonStringify(account));
}, },
}); });
server.route({
method: 'DELETE',
path: '/account',
config: {
description: 'Deletes the current account and all data from the Nylas Cloud.',
notes: 'Notes go here',
tags: ['accounts'],
validate: {
params: {
},
},
},
handler: (request, reply) => {
const account = request.auth.credentials;
account.destroy().then((saved) =>
DatabaseConnector.destroyAccountDatabase(saved.id).then(() =>
reply(Serialization.jsonStringify({status: 'success'}))
)
).catch((err) => {
reply(err).code(500);
})
},
});
}; };

View file

@ -79,11 +79,7 @@ class DatabaseConnector {
const dbname = `a-${accountId}`; const dbname = `a-${accountId}`;
if (process.env.DB_HOSTNAME) { if (process.env.DB_HOSTNAME) {
const sequelize = new Sequelize(null, process.env.DB_USERNAME, process.env.DB_PASSWORD, { const sequelize = this._sequelizePoolForDatabase(null);
host: process.env.DB_HOSTNAME,
dialect: "mysql",
logging: false,
})
return sequelize.authenticate().then(() => return sequelize.authenticate().then(() =>
sequelize.query(`CREATE DATABASE \`${dbname}\``) sequelize.query(`CREATE DATABASE \`${dbname}\``)
); );
@ -91,6 +87,18 @@ class DatabaseConnector {
return Promise.resolve() return Promise.resolve()
} }
destroyAccountDatabase(accountId) {
const dbname = `a-${accountId}`;
if (process.env.DB_HOSTNAME) {
const sequelize = this._sequelizePoolForDatabase(null);
return sequelize.authenticate().then(() =>
sequelize.query(`CREATE DATABASE \`${dbname}\``)
);
}
fs.removeFileSync(path.join(STORAGE_DIR, `${dbname}.sqlite`));
return Promise.resolve()
}
_sequelizeForShared() { _sequelizeForShared() {
const sequelize = this._sequelizePoolForDatabase(`shared`); const sequelize = this._sequelizePoolForDatabase(`shared`);
const modelsPath = path.join(__dirname, 'models/shared'); const modelsPath = path.join(__dirname, 'models/shared');

View file

@ -17,7 +17,11 @@ module.exports = (db, sequelize) => {
}); });
} }
}) })
// TODO delete account from redis sequelize.addHook("afterDestroy", ({dataValues, $modelOptions}) => {
// sequelize.addHook("afterDelete", ({dataValues, $modelOptions}) => { if ($modelOptions.name.singular === 'account') {
// }) PubsubConnector.notifyAccount(dataValues.id, {
type: MessageTypes.ACCOUNT_DELETED,
});
}
})
} }

View file

@ -270,9 +270,11 @@ class IMAPConnection extends EventEmitter {
} }
end() { end() {
if (this._imap) {
this._imap.end();
this._imap = null;
}
this._queue = []; this._queue = [];
this._imap.end();
this._imap = null;
this._connectPromise = null; this._connectPromise = null;
} }

View file

@ -1,5 +1,6 @@
module.exports = { module.exports = {
ACCOUNT_CREATED: "ACCOUNT_CREATED", ACCOUNT_CREATED: "ACCOUNT_CREATED",
ACCOUNT_UPDATED: "ACCOUNT_UPDATED", ACCOUNT_UPDATED: "ACCOUNT_UPDATED",
ACCOUNT_DELETED: "ACCOUNT_DELETED",
SYNCBACK_REQUESTED: "SYNCBACK_REQUESTED", SYNCBACK_REQUESTED: "SYNCBACK_REQUESTED",
} }

View file

@ -178,6 +178,7 @@ class SyncProcessManager {
return; return;
} }
this._logger.info({account_id: accountId}, `ProcessManager: Starting worker for Account`) this._logger.info({account_id: accountId}, `ProcessManager: Starting worker for Account`)
this._workers[account.id] = new SyncWorker(account, db, () => { this._workers[account.id] = new SyncWorker(account, db, () => {
this.removeWorkerForAccountId(accountId) this.removeWorkerForAccountId(accountId)
}); });

View file

@ -27,7 +27,6 @@ class SyncWorker {
this._logger = global.Logger.forAccount(account) this._logger = global.Logger.forAccount(account)
this._syncTimer = null; this._syncTimer = null;
this._expirationTimer = null;
this._destroyed = false; this._destroyed = false;
this.syncNow({reason: 'Initial'}); this.syncNow({reason: 'Initial'});
@ -37,6 +36,8 @@ class SyncWorker {
} }
cleanup() { cleanup() {
clearTimeout(this._syncTimer);
this._syncTimer = null;
this._destroyed = true; this._destroyed = true;
this._listener.dispose(); this._listener.dispose();
this.closeConnection() this.closeConnection()
@ -51,13 +52,19 @@ class SyncWorker {
_onMessage(msg) { _onMessage(msg) {
const {type} = JSON.parse(msg); const {type} = JSON.parse(msg);
switch (type) { switch (type) {
case MessageTypes.ACCOUNT_UPDATED:
this._onAccountUpdated(); break;
case MessageTypes.SYNCBACK_REQUESTED:
this.syncNow({reason: 'Syncback Action Queued'}); break;
case MessageTypes.ACCOUNT_CREATED: case MessageTypes.ACCOUNT_CREATED:
// No other processing currently required for account creation // No other processing currently required for account creation
break; break;
case MessageTypes.ACCOUNT_UPDATED:
this._onAccountUpdated();
break;
case MessageTypes.ACCOUNT_DELETED:
this.cleanup();
this._onExpired();
break;
case MessageTypes.SYNCBACK_REQUESTED:
this.syncNow({reason: 'Syncback Action Queued'});
break;
default: default:
this._logger.error({message: msg}, 'SyncWorker: Invalid message') this._logger.error({message: msg}, 'SyncWorker: Invalid message')
} }
@ -208,7 +215,7 @@ class SyncWorker {
const now = Date.now(); const now = Date.now();
const syncGraphTimeLength = 60 * 30; // 30 minutes, should be the same as SyncGraph.config.timeLength const syncGraphTimeLength = 60 * 30; // 30 minutes, should be the same as SyncGraph.config.timeLength
let lastSyncCompletions = [...this._account.lastSyncCompletions] let lastSyncCompletions = [].concat(this._account.lastSyncCompletions)
lastSyncCompletions = [now, ...lastSyncCompletions] lastSyncCompletions = [now, ...lastSyncCompletions]
while (now - lastSyncCompletions[lastSyncCompletions.length - 1] > 1000 * syncGraphTimeLength) { while (now - lastSyncCompletions[lastSyncCompletions.length - 1] > 1000 * syncGraphTimeLength) {
lastSyncCompletions.pop(); lastSyncCompletions.pop();