#125: make activation page available for all guests and innactive users

This commit is contained in:
SleepWalker 2016-06-05 15:06:14 +03:00
parent 446bfbaa29
commit 2737c6502b
6 changed files with 38 additions and 33 deletions

View File

@ -28,7 +28,7 @@ export default class User {
lang: '',
goal: null, // the goal with wich user entered site
isGuest: true,
isActive: true,
isActive: false,
shouldChangePassword: false, // TODO: нужно ещё пробросить причину необходимости смены
passwordChangedAt: null,
hasMojangUsernameCollision: false,

View File

@ -5,6 +5,7 @@ import LoginState from './LoginState';
import OAuthState from './OAuthState';
import ForgotPasswordState from './ForgotPasswordState';
import RecoverPasswordState from './RecoverPasswordState';
import ActivationState from './ActivationState';
import ResendActivationState from './ResendActivationState';
// TODO: a way to unload service (when we are on account page)
@ -70,12 +71,13 @@ export default class AuthFlow {
throw new Error('State is required');
}
// if (this.state instanceof state.constructor) {
// // already in this state
// return;
// }
if (this.state instanceof state.constructor) {
// already in this state
return;
}
this.state && this.state.leave(this);
this.prevState = this.state;
this.state = state;
const resp = this.state.enter(this);
@ -129,7 +131,6 @@ export default class AuthFlow {
case '/':
case '/login':
case '/password':
case '/activation':
case '/change-password':
case '/oauth/permissions':
case '/oauth/finish':
@ -138,6 +139,9 @@ export default class AuthFlow {
default:
switch (path.replace(/(.)\/.+/, '$1')) { // use only first part of an url
case '/activation':
this.setState(new ActivationState());
break;
case '/recover-password':
this.setState(new RecoverPasswordState());
break;

View File

@ -7,7 +7,7 @@ export default class ResendActivationState extends AbstractState {
enter(context) {
const {user} = context.getState();
if (user.isActive && !user.isGuest) {
if (user.isActive) {
context.setState(new CompleteState());
} else {
context.navigate('/resend-activation');
@ -16,13 +16,11 @@ export default class ResendActivationState extends AbstractState {
resolve(context, payload) {
context.run('resendActivation', payload)
.then(() => context.setState(new CompleteState()));
.then(() => context.setState(new ActivationState()));
}
goBack(context) {
const {user} = context.getState();
if (user.isGuest) {
if (context.prevState instanceof RegisterState) {
context.setState(new RegisterState());
} else {
context.setState(new ActivationState());

View File

@ -25,7 +25,6 @@ describe('ActivationState', () => {
it('should navigate to /activation', () => {
context.getState.returns({
user: {
isGuest: false,
isActive: false
}
});
@ -38,7 +37,6 @@ describe('ActivationState', () => {
it('should transition to complete state if account activated', () => {
context.getState.returns({
user: {
isGuest: false,
isActive: true
}
});

View File

@ -5,6 +5,7 @@ import OAuthState from 'services/authFlow/OAuthState';
import RegisterState from 'services/authFlow/RegisterState';
import RecoverPasswordState from 'services/authFlow/RecoverPasswordState';
import ForgotPasswordState from 'services/authFlow/ForgotPasswordState';
import ActivationState from 'services/authFlow/ActivationState';
import ResendActivationState from 'services/authFlow/ResendActivationState';
import LoginState from 'services/authFlow/LoginState';
@ -49,8 +50,11 @@ describe('AuthFlow', () => {
});
it('should call `leave` on previous state if any', () => {
const state1 = new AbstractState();
const state2 = new AbstractState();
class State1 extends AbstractState {}
class State2 extends AbstractState {}
const state1 = new State1();
const state2 = new State2();
const spy1 = sinon.spy(state1, 'leave');
const spy2 = sinon.spy(state2, 'leave');
@ -62,6 +66,20 @@ describe('AuthFlow', () => {
sinon.assert.notCalled(spy2);
});
it('should not change state, if current state is of same type', () => {
const state1 = new AbstractState();
const state2 = new AbstractState();
const spy1 = sinon.spy(state1, 'enter');
const spy2 = sinon.spy(state2, 'enter');
flow.setState(state1);
flow.setState(state2);
sinon.assert.calledWith(spy1, flow);
sinon.assert.calledOnce(spy1);
sinon.assert.notCalled(spy2);
});
it('should return promise, if #enter returns it', () => {
const state = new AbstractState();
const expected = Promise.resolve();
@ -169,7 +187,6 @@ describe('AuthFlow', () => {
'/': LoginState,
'/login': LoginState,
'/password': LoginState,
'/activation': LoginState,
'/change-password': LoginState,
'/oauth/permissions': LoginState,
'/oauth/finish': LoginState,
@ -178,6 +195,7 @@ describe('AuthFlow', () => {
'/recover-password': RecoverPasswordState,
'/recover-password/key123': RecoverPasswordState,
'/forgot-password': ForgotPasswordState,
'/activation': ActivationState,
'/resend-activation': ResendActivationState
}).forEach(([path, type]) => {
it(`should transition to ${type.name} if ${path}`, () => {

View File

@ -26,7 +26,6 @@ describe('ResendActivationState', () => {
it('should navigate to /resend-activation', () => {
context.getState.returns({
user: {
isGuest: false,
isActive: false
}
});
@ -40,7 +39,7 @@ describe('ResendActivationState', () => {
context.getState.returns({
user: {
isGuest: true,
isActive: true
isActive: false
}
});
@ -52,7 +51,6 @@ describe('ResendActivationState', () => {
it('should transition to complete state if account activated', () => {
context.getState.returns({
user: {
isGuest: false,
isActive: true
}
});
@ -80,7 +78,7 @@ describe('ResendActivationState', () => {
const promise = Promise.resolve();
mock.expects('run').returns(promise);
expectState(mock, CompleteState);
expectState(mock, ActivationState);
state.resolve(context);
@ -101,26 +99,15 @@ describe('ResendActivationState', () => {
describe('#goBack', () => {
it('should transition to activation', () => {
context.getState.returns({
user: {
isGuest: false
}
});
expectState(mock, ActivationState);
state.goBack(context);
});
it('should transition to register if guest', () => {
context.getState.returns({
user: {
isGuest: true
}
});
it('should transition to register if it was active previousely', () => {
expectState(mock, RegisterState);
context.prevState = new RegisterState();
state.goBack(context);
});
});