Skip to content

Commit

Permalink
Merge pull request #166 from screwdriver-cd/user-tokens
Browse files Browse the repository at this point in the history
feat: Get a user by token value
  • Loading branch information
ian-fox authored May 26, 2017
2 parents e8186e2 + c6813a4 commit da3d5e5
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 1 deletion.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ factory.create(config).then(model => {

#### Get
Get a user based on id. Can pass the generatedId for the user, or the username, and the id will be determined automatically.
Can also pass a Screwdriver access token, and will get the user associated with that token.
```js
factory.get(id).then(model => {
// do stuff with user model
Expand All @@ -425,12 +426,17 @@ factory.get(id).then(model => {
factory.get({ username }).then(model => {
// do stuff with user model
});

factory.get({ token }).then(model => {
// do stuff with user model
});
```

| Parameter | Type | Description |
| :------------- | :---- | :-------------|
| id | String | The unique ID for the build |
| config.username | String | User name |
| config.accessToken | String | A user access token value |

### User Model
```js
Expand Down
2 changes: 1 addition & 1 deletion lib/tokenFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class TokenFactory extends BaseFactory {
* @return {Promise}
*/
get(config) {
if (config && config.value) {
if (config.value) {
config.hash = generateToken.hashValue(config.value);
delete config.value;
}
Expand Down
32 changes: 32 additions & 0 deletions lib/userFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,38 @@ class UserFactory extends BaseFactory {
});
}

/**
* Get a user model by name, id, or personal access token
* @method get
* @param {Mixed} config
* @param {String} [config.username] Username of the user to look up
* @param {String} [config.accessToken] Access token of the user to look up
* @return {Promise}
*/
get(config) {
if (!config.accessToken) {
return super.get(config);
}

// Lazy load factory dependency to prevent circular dependency issues
// https://nodejs.org/api/modules.html#modules_cycles
/* eslint-disable global-require */
const TokenFactory = require('./tokenFactory');
/* eslint-enable global-require */
const tokenFactory = TokenFactory.getInstance();

return tokenFactory.get({ value: config.accessToken })
.then((token) => {
if (!token) {
return token;
}

token.lastUsed = (new Date()).toISOString();

return token.update().then(() => this.get(token.userId));
});
}

/**
* Get an instance of the UserFactory
* @method getInstance
Expand Down
61 changes: 61 additions & 0 deletions test/lib/userFactory.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const mockery = require('mockery');
const sinon = require('sinon');

sinon.assert.expose(assert, { prefix: '' });
require('sinon-as-promised');

describe('User Factory', () => {
const password = 'totallySecurePassword';
let UserFactory;
let datastore;
let hashaMock;
let ironMock;
let tokenFactoryMock;
let factory;
let User;

Expand All @@ -35,9 +37,15 @@ describe('User Factory', () => {
seal: sinon.stub(),
defaults: 'defaults'
};
tokenFactoryMock = {
get: sinon.stub()
};

mockery.registerMock('screwdriver-hashr', hashaMock);
mockery.registerMock('iron', ironMock);
mockery.registerMock('./tokenFactory', {
getInstance: sinon.stub().returns(tokenFactoryMock)
});

// eslint-disable-next-line global-require
User = require('../../lib/user');
Expand Down Expand Up @@ -96,6 +104,59 @@ describe('User Factory', () => {
});
});

describe('get a user by access token', () => {
const accessToken = 'an access token goes here';
const now = 1111;
const tokenMock = {
userId: 123,
lastUsed: null,
update: sinon.stub()
};
let sandbox;

beforeEach(() => {
sandbox = sinon.sandbox.create();
sandbox.useFakeTimers(now);
tokenFactoryMock.get.resolves(tokenMock);
tokenMock.update.resolves(tokenMock);
});

afterEach(() => {
sandbox.restore();
});

it('should return a user and update the last used field of the token', () => {
const expected = {
id: 123,
username: 'frodo'
};

datastore.get.resolves(expected);

return factory.get({ accessToken })
.then((user) => {
assert.isOk(user);
assert.calledWith(tokenFactoryMock.get, { value: accessToken });
assert.calledOnce(tokenMock.update);
assert.equal(tokenMock.lastUsed, (new Date(now)).toISOString());
});
});

it('should return null if the user doesn\'t exist', () => {
datastore.get.resolves(null);

return factory.get({ accessToken })
.then(user => assert.isNull(user));
});

it('should return null if the token doesn\'t exist', () => {
tokenFactoryMock.get.resolves(null);

return factory.get({ accessToken })
.then(user => assert.isNull(user));
});
});

describe('getInstance', () => {
let config;

Expand Down

0 comments on commit da3d5e5

Please sign in to comment.