Skip to content

Commit

Permalink
feat: CMS-2574 signup
Browse files Browse the repository at this point in the history
  • Loading branch information
simon-scherzinger committed Feb 2, 2017
1 parent 1751292 commit 0b9a2fb
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 15 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -26,6 +26,7 @@
"ec.cookie-mock": "^1.0.0",
"halfred": "^1.0.0",
"jwt-decode": "^2.1.0",
"superagent": "^3.4.1",
"traverson": "^5.0.0",
"traverson-hal": "^5.0.0"
},
Expand Down
33 changes: 32 additions & 1 deletion src/Accounts.js
@@ -1,5 +1,5 @@
import Core from './Core';
import { get, post, getUrl, optionsToQuery } from './helper';
import { get, post, getUrl, superagentFormPost, optionsToQuery } from './helper';
import AccountList from './resources/AccountList';
import AccountResource from './resources/AccountResource';
import TokenStoreFactory from './TokenStore';
Expand Down Expand Up @@ -178,4 +178,35 @@ export default class Accounts extends Core {
return get(this.environment, request)
.then(([a]) => a.available);
}

/**
* Signup a new account.
*
*
* @param {string} email email for the new account
* @param {string} password password for the new account
* @param {string?} invite optional invite. signup can be declined without invite.
* @returns {Promise<string>} Promise resolving the newly created {@link AccountResource}
*/
signup(email, password, invite) {
if (!email) {
throw new Error('email must be defined');
}

if (!password) {
throw new Error('password must be defined');
}

const request = this.newRequest().follow('ec:auth/register').withTemplateParameters({
clientID: this.clientID,
invite,
});

return getUrl(this.environment, request)
.then((url) => superagentFormPost(url, { email, password }))
.then((token) => {
this.tokenStore.set(token.token);
return Promise.resolve(token.token);
});
}
}
26 changes: 25 additions & 1 deletion src/helper.js
@@ -1,3 +1,5 @@
import superagent from 'superagent';

import Problem from './Problem';
import events from './EventEmitter';
import { stores } from './TokenStore';
Expand Down Expand Up @@ -99,7 +101,7 @@ export function get(environment, t) {
*
* @param {string} environment environment from which a token should be used
* @param {object} t request builder
* @returns {Promise.string} resolves to the url.
* @returns {Promise} resolves to the url.
*/
export function getUrl(environment, t) {
return traversonWrapper('getUrl', environment, t);
Expand Down Expand Up @@ -164,6 +166,28 @@ export function del(environment, t) {
return traversonWrapper('delete', environment, t);
}

/**
* Superagent Wrapper for posting forms.
*
* @param {string} url the url to post to
* @param {object} form the form to post as object
* @returns {Promise} Promise resolving to response body.
*/
export function superagentFormPost(url, form) {
return superagent.post(url)
.type('form')
.send(form)
.then(res => Promise.resolve(res.body ? res.body : {}))
.catch((err) => {
let problem;
if ({}.hasOwnProperty.call(err, 'status')) {
problem = new Problem(err.response.body);
}
events.emit('error', problem || err);
throw problem || err;
});
}

/**
* Modifier for filter object to query convertion.
*
Expand Down
30 changes: 29 additions & 1 deletion test/Account.test.js
Expand Up @@ -118,7 +118,7 @@ describe('Accounts class', () => {
});
it('should logout successfully', () => {
const accounts = new Accounts();
accounts.setToken('eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNjaGVyemluZ2VyQGVudHJlY29kZS5kZSIsImp0aSI6IjEwODRlMGRmLTg1NzktNGRmMC1hNjc4LTk5M2QwMDNkY2QyNSIsImlhdCI6MTQ4MjUwNTcxMywiZXhwIjoxNDg1MDk3NzEzLCJpc3MiOiJlbnRyZWNvZGUiLCJzdWIiOiJkZGQyOWZkMS03NDE3LTQ4OTQtYTU0Ni01YzEyYjExYzAxODYifQ.Z2UA2EkFUMPvj5AZX5Ox5-pHiQsfw1Jjvq7sqXDT4OfdOFdGMHvKDLsJm1aVWWga5PMLSpKPucYYk_MrDTjYFp1HJhn97B1VwO62psP-Z6BMFgIPpQNB0f-_Mgth4OGucpLajoGgw9PemmHGWvyStC1Gzg9QBdKCch4VNjKvgg33puyZ5DA9YvldjUTQVhl02rHQspf4dfAz7DQHCJJN_tFhXXLpYzg_pQOu6L-yowsEFlLhl9SZoidz9v8T4PMio04g9wauilu0-ZXGRMRHKk2RYqlRaSc4QLSRZnyefdjp1_Xk7q9dG0Fn71YWxClXYlf2hycuzO2bg1-JBElxzQ');
accounts.setToken('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJlbnRyZWNvZGVUZXN0IiwiaWF0IjoxNDg1NzgzNTg4LCJleHAiOjQ2NDE0NTcxODgsImF1ZCI6IlRlc3QiLCJzdWIiOiJ0ZXN0QGVudHJlY29kZS5kZSJ9.Vhrq5GR2hNz-RoAhdlnIIWHelPciBPCemEa74s7cXn8');
const stub = sinon.stub(helper, 'post');
stub.returns(Promise.resolve());

Expand All @@ -142,6 +142,34 @@ describe('Accounts class', () => {
const throws = () => new Accounts().emailAvailable();
throws.should.throw(Error);
});
it('should signup new account', () => {
const accounts = new Accounts();
accounts.setClientID('rest');
const url = sinon.stub(helper, 'getUrl');
url.returns(Promise.resolve('https://accounts.entrecode.de/auth/signup?clientID=rest'));
const token = sinon.stub(helper, 'superagentFormPost');
token.returns(Promise.resolve({ token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJlbnRyZWNvZGVUZXN0IiwiaWF0IjoxNDg1NzgzNTg4LCJleHAiOjQ2NDE0NTcxODgsImF1ZCI6IlRlc3QiLCJzdWIiOiJ0ZXN0QGVudHJlY29kZS5kZSJ9.Vhrq5GR2hNz-RoAhdlnIIWHelPciBPCemEa74s7cXn8' }));

return accounts.signup('someone@example.com', 'suchsecurewow')
.then((tokenResponse) => {
tokenResponse.should.be.equal('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJlbnRyZWNvZGVUZXN0IiwiaWF0IjoxNDg1NzgzNTg4LCJleHAiOjQ2NDE0NTcxODgsImF1ZCI6IlRlc3QiLCJzdWIiOiJ0ZXN0QGVudHJlY29kZS5kZSJ9.Vhrq5GR2hNz-RoAhdlnIIWHelPciBPCemEa74s7cXn8');
token.restore();
url.restore();
})
.catch((err) => {
token.restore();
url.restore();
throw err;
});
});
it('should throw on undefined email', () => {
const throws = () => new Accounts().signup(null, 'supersecure');
throws.should.throw(Error);
});
it('should throw on undefined password', () => {
const throws = () => new Accounts().signup('someone@example.com', null);
throws.should.throw(Error);
});
});

describe('Account ListResource', () => {
Expand Down
45 changes: 34 additions & 11 deletions test/Core.test.js
@@ -1,3 +1,5 @@
/*eslint no-unused-expressions:0*/

const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const nock = require('nock');
Expand Down Expand Up @@ -55,12 +57,15 @@ describe('Core', () => {
});
});

describe('Traverson Helper', () => {
describe('Network Helper', () => {
let dmList;
let mock;
let traversal;
let store;
let spy;
before((done) => {
spy = sinon.spy();
emitter.on('error', spy);
fs.readFile(`${__dirname}/mocks/dm-list.json`, 'utf8', (err, res) => {
if (err) {
return done(err);
Expand All @@ -70,6 +75,7 @@ describe('Traverson Helper', () => {
});
});
beforeEach(() => {
spy.reset();
nock.disableNetConnect();
store = TokenStore.default('test');
mock = nock('https://datamanager.entrecode.de');
Expand Down Expand Up @@ -116,8 +122,6 @@ describe('Traverson Helper', () => {
});
it('should fire error event', () => {
mock.get('/').replyWithError('mocked error');
const spy = sinon.spy();
emitter.on('error', spy);

return helper.get('live', traversal).catch((err) => {
err.should.be.defined;
Expand All @@ -137,8 +141,6 @@ describe('Traverson Helper', () => {
});
it('should fire error event', () => {
mock.get('/').replyWithError('mocked error');
const spy = sinon.spy();
emitter.on('error', spy);

return helper.getUrl('live', traversal.follow('ec:dm-stats')).catch((err) => {
err.should.be.defined;
Expand All @@ -162,8 +164,6 @@ describe('Traverson Helper', () => {
});
it('should fire error event', () => {
mock.post('/').replyWithError('mocked error');
const spy = sinon.spy();
emitter.on('error', spy);

return helper.post('live', traversal).catch((err) => {
err.should.be.defined;
Expand All @@ -187,8 +187,6 @@ describe('Traverson Helper', () => {
});
it('should fire error event', () => {
mock.put('/').replyWithError('mocked error');
const spy = sinon.spy();
emitter.on('error', spy);

return helper.put('live', traversal).catch((err) => {
err.should.be.defined;
Expand All @@ -212,15 +210,40 @@ describe('Traverson Helper', () => {
});
it('should fire error event', () => {
mock.delete('/').replyWithError('mocked error');
const spy = sinon.spy();
emitter.on('error', spy);

return helper.del('live', traversal).catch((err) => {
err.should.be.defined;
spy.should.be.called.once;
});
});
});
describe('superagentFormPost', () => {
it('should be resolved', () => {
mock.post('/').reply(200, { token: 'token' });
return helper.superagentFormPost('https://datamanager.entrecode.de', {}).should.be.eventually.fulfilled;
});
it('should be rejected', () => {
mock.post('/').reply(404, {
title: 'not found',
code: 2102,
status: 404,
detail: 'title',
});
return helper.superagentFormPost('https://datamanager.entrecode.de', {}).should.be.eventually.rejectedWith(Problem);
});
it('should fire error event', () => {
mock.post('/').replyWithError('mocked error');

return helper.superagentFormPost('https://datamanager.entrecode.de', {})
.then(() => {
throw new Error('unexpectedly resolved');
})
.catch((err) => {
err.should.be.defined;
spy.should.be.called.once;
});
});
});
});

describe('optionsToQuery', () => {
Expand Down
2 changes: 1 addition & 1 deletion test/mocks/login-token.json
@@ -1,3 +1,3 @@
{
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InNpbW9uLnNjaGVyemluZ2VyK2J1ZmZhbG8xQGdtYWlsLmNvbSIsImp0aSI6IjAyNzQxYjE3LWM1MDUtNGY5OC04NjU3LWViM2RiMDI2OGIxMCIsImlhdCI6MTQ4NTI3NjQzNywiZXhwIjoxNDg3ODY4NDM3LCJpc3MiOiJlbnRyZWNvZGUiLCJzdWIiOiI4NmE1MTZmMS1hY2FkLTQ1NWYtOTc2Ni04MjJjYjhkYTc4OGIifQ.Eakrl28cuXfkBREjoorjKdUCjRsG12aDTaecqhawDpVq4MAs8iRaeFLEJK90abqYtbDS1ntXNFfg2zWB5sGJMn-w0sf0rxKSnXOy5V7UBHQpWeRffGAixilXdV_wCkKPE628ufcJgOmFnIXwYnbG-cunyc2zZ-j5aQptin2qO8WDIwAcMhYZetR-qhO9C5S-6cgW6IkYFG7C9nDwbgP51FUj_OfwQH4T2R24WEnpBaP72JtRN_n7V5w60gfcW89Aya-9bwV0YKiRkPyKoxM0f9tq97TzpMgMGADbUTbIIZmuuhqqKWOpGrOpoP3wLm7eYq-46nBC3ggVOWJZswizEA"
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJlbnRyZWNvZGVUZXN0IiwiaWF0IjoxNDg1NzgzNTg4LCJleHAiOjQ2NDE0NTcxODgsImF1ZCI6IlRlc3QiLCJzdWIiOiJ0ZXN0QGVudHJlY29kZS5kZSJ9.Vhrq5GR2hNz-RoAhdlnIIWHelPciBPCemEa74s7cXn8"
}

0 comments on commit 0b9a2fb

Please sign in to comment.