diff --git a/core/server/api/users.js b/core/server/api/users.js index 23f6e5612a..8d5ae3bb6b 100644 --- a/core/server/api/users.js +++ b/core/server/api/users.js @@ -290,7 +290,12 @@ users = { return users.read(_.merge(options, { status: 'all'})).then(function (result) { return dataProvider.Base.transaction(function (t) { options.transacting = t; - dataProvider.Post.destroyByAuthor(options).then(function () { + + Promise.all([ + dataProvider.Accesstoken.destroyByUser(options), + dataProvider.Refreshtoken.destroyByUser(options), + dataProvider.Post.destroyByAuthor(options) + ]).then(function () { return dataProvider.User.destroy(options); }).then(function () { t.commit(); diff --git a/core/server/models/basetoken.js b/core/server/models/basetoken.js index a949ca8257..b0efbcce60 100644 --- a/core/server/models/basetoken.js +++ b/core/server/models/basetoken.js @@ -1,4 +1,6 @@ -var ghostBookshelf = require('./base'), +var Promise = require('bluebird'), + ghostBookshelf = require('./base'), + errors = require('../errors'), Basetoken; @@ -31,11 +33,32 @@ Basetoken = ghostBookshelf.Model.extend({ options = this.filterOptions(options, 'destroyAll'); return ghostBookshelf.Collection.forge([], {model: this}) .query('where', 'expires', '<', Date.now()) - .fetch() + .fetch(options) .then(function (collection) { collection.invokeThen('destroy', options); }); + }, + /** + * ### destroyByUser + * @param {[type]} options has context and id. Context is the user doing the destroy, id is the user to destroy + */ + destroyByUser: function (options) { + var userId = options.id; + + options = this.filterOptions(options, 'destroyByUser'); + + if (userId) { + return ghostBookshelf.Collection.forge([], {model: this}) + .query('where', 'user_id', '=', userId) + .fetch(options) + .then(function (collection) { + collection.invokeThen('destroy', options); + }); + } + + return Promise.reject(new errors.NotFoundError('No user found')); } + }); module.exports = Basetoken; \ No newline at end of file diff --git a/core/test/integration/api/api_users_spec.js b/core/test/integration/api/api_users_spec.js index df51b5d60a..671a3fc2ac 100644 --- a/core/test/integration/api/api_users_spec.js +++ b/core/test/integration/api/api_users_spec.js @@ -20,7 +20,7 @@ describe('Users API', function () { // Keep the DB clean before(testUtils.teardown); - beforeEach(testUtils.setup('users:roles', 'users', 'perms:user', 'perms:role', 'perms:setting', 'perms:init')); + beforeEach(testUtils.setup('users:roles', 'users', 'user:token', 'perms:user', 'perms:role', 'perms:setting', 'perms:init')); afterEach(testUtils.teardown); it('dateTime fields are returned as Date objects', function (done) { @@ -85,7 +85,6 @@ describe('Users API', function () { }).catch(done); }); - it('Can browse invited/invited-pending (admin)', function (done) { testUtils.fixtures.createInvitedUsers().then(function () { UserAPI.browse(_.extend(testUtils.context.admin, { status: 'invited' })).then(function (response) { diff --git a/core/test/utils/fixtures/data-generator.js b/core/test/utils/fixtures/data-generator.js index 01db8c76cb..1ba98c8954 100644 --- a/core/test/utils/fixtures/data-generator.js +++ b/core/test/utils/fixtures/data-generator.js @@ -1,5 +1,6 @@ -var _ = require('lodash'), - uuid = require('node-uuid'), +var _ = require('lodash'), + uuid = require('node-uuid'), + globalUtils = require('../../../server/utils'), DataGenerator = {}; DataGenerator.Content = { @@ -232,7 +233,8 @@ DataGenerator.forKnex = (function () { app_fields, roles, users, - roles_users; + roles_users, + clients; function createBasic(overrides) { return _.defaults(overrides, { @@ -327,6 +329,14 @@ DataGenerator.forKnex = (function () { }); } + function createToken(overrides) { + return _.defaults(overrides, { + token: uuid.v4(), + client_id: 1, + expires:Date.now() + globalUtils.ONE_DAY_MS + }); + } + posts = [ createPost(DataGenerator.Content.posts[0]), createPost(DataGenerator.Content.posts[1]), @@ -349,14 +359,18 @@ DataGenerator.forKnex = (function () { createBasic(DataGenerator.Content.roles[0]), createBasic(DataGenerator.Content.roles[1]), createBasic(DataGenerator.Content.roles[2]), - createBasic(DataGenerator.Content.roles[3]), + createBasic(DataGenerator.Content.roles[3]) ]; users = [ createUser(DataGenerator.Content.users[0]), createUser(DataGenerator.Content.users[1]), createUser(DataGenerator.Content.users[2]), - createUser(DataGenerator.Content.users[3]), + createUser(DataGenerator.Content.users[3]) + ]; + + clients = [ + createBasic({name: 'Ghost Admin', slug: 'ghost-admin', secret: 'not_available'}) ]; roles_users = [ @@ -399,6 +413,7 @@ DataGenerator.forKnex = (function () { createApp: createBasic, createAppField: createAppField, createAppSetting: createAppSetting, + createToken: createToken, posts: posts, tags: tags, @@ -407,7 +422,8 @@ DataGenerator.forKnex = (function () { app_fields: app_fields, roles: roles, users: users, - roles_users: roles_users + roles_users: roles_users, + clients: clients }; }()); diff --git a/core/test/utils/index.js b/core/test/utils/index.js index 24801709df..3c72638661 100644 --- a/core/test/utils/index.js +++ b/core/test/utils/index.js @@ -231,6 +231,16 @@ fixtures = { }); }, + // Creates a client, and access and refresh tokens for user 3 (author) + createTokensForUser: function createTokensForUser() { + var knex = config.database.knex; + return knex('clients').insert(DataGenerator.forKnex.clients).then(function () { + return knex('accesstokens').insert(DataGenerator.forKnex.createToken({user_id: 3})); + }).then(function () { + return knex('refreshtokens').insert(DataGenerator.forKnex.createToken({user_id: 3})); + }); + }, + createInvitedUsers: function createInvitedUser() { var knex = config.database.knex, // grab 3 more users @@ -361,6 +371,7 @@ toDoList = { }, 'users:roles': function createUsersWithRoles() { return fixtures.createUsersWithRoles(); }, 'users': function createExtraUsers() { return fixtures.createExtraUsers(); }, + 'user:token': function createTokensForUser() { return fixtures.createTokensForUser(); }, 'owner': function insertOwnerUser() { return fixtures.insertOwnerUser(); }, 'owner:pre': function initOwnerUser() { return fixtures.initOwnerUser(); }, 'owner:post': function overrideOwnerUser() { return fixtures.overrideOwnerUser(); },