Skip to content

Commit

Permalink
Merge 85fde1c into 3157280
Browse files Browse the repository at this point in the history
  • Loading branch information
robgietema committed Mar 12, 2018
2 parents 3157280 + 85fde1c commit d62242c
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 27 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Expand Up @@ -23,6 +23,7 @@
],
"arrow-parens": "off", // Keep compatible with prettier
"no-confusing-arrow": 0, // Keep compatible with prettier
"no-mixed-operators": 0, // Keep compatible with prettier
"indent": 0, // Keep compatible with prettier
"prettier/prettier": [
"error",
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -28,6 +28,7 @@
* Added tags @robgietema
* Upgrade to React 16 @sneridagh
* Upgrade to Webpack 4 @sneridagh
* Renew login token when almost expired @robgietema

## 0.4.0 (2017-05-03)

Expand Down
2 changes: 1 addition & 1 deletion src/actions/index.js
Expand Up @@ -39,5 +39,5 @@ export {
editPassword,
setInitialPassword,
} from './users/users';
export { login, logout } from './userSession/userSession';
export { login, loginRenew, logout } from './userSession/userSession';
export { getWorkflow, transitionWorkflow } from './workflow/workflow';
14 changes: 13 additions & 1 deletion src/actions/userSession/userSession.js
Expand Up @@ -3,7 +3,7 @@
* @module actions/search/search
*/

import { LOGIN, LOGOUT } from '../../constants/ActionTypes';
import { LOGIN, LOGIN_RENEW, LOGOUT } from '../../constants/ActionTypes';

/**
* Login function.
Expand All @@ -19,6 +19,18 @@ export function login(username, password) {
};
}

/**
* Login renew function.
* @function loginRenew
* @returns {Object} Login renew action.
*/
export function loginRenew() {
return {
type: LOGIN_RENEW,
promise: api => api.post('@login-renew'),
};
}

/**
* Logout function.
* @function logout
Expand Down
19 changes: 17 additions & 2 deletions src/actions/userSession/userSession.test.js
@@ -1,5 +1,5 @@
import { login, logout } from './userSession';
import { LOGIN, LOGOUT } from '../../constants/ActionTypes';
import { login, loginRenew, logout } from './userSession';
import { LOGIN, LOGIN_RENEW, LOGOUT } from '../../constants/ActionTypes';

describe('User session action', () => {
describe('login', () => {
Expand All @@ -21,6 +21,21 @@ describe('User session action', () => {
});
});

describe('loginRenew', () => {
it('should create an action to renew the login', () => {
const action = loginRenew();

expect(action.type).toEqual(LOGIN_RENEW);

const apiMock = {
post: jest.fn(),
};
action.promise(apiMock);

expect(apiMock.post).toBeCalledWith('@login-renew');
});
});

describe('logout', () => {
it('should create an action to logout', () => {
const action = logout();
Expand Down
18 changes: 16 additions & 2 deletions src/components/theme/Logout/Logout.jsx
Expand Up @@ -13,7 +13,9 @@ import { Login } from '../../../components';
import { logout, purgeMessages } from '../../../actions';

@connect(
() => ({}),
(state, props) => ({
query: props.location.query,
}),
dispatch => bindActionCreators({ logout, purgeMessages }, dispatch),
)
/**
Expand All @@ -30,6 +32,18 @@ export class LogoutComponent extends Component {
static propTypes = {
logout: PropTypes.func.isRequired,
purgeMessages: PropTypes.func.isRequired,
query: PropTypes.shape({
return_url: PropTypes.string,
}),
};

/**
* Default properties.
* @property {Object} defaultProps Default properties.
* @static
*/
static defaultProps = {
query: null,
};

/**
Expand All @@ -48,7 +62,7 @@ export class LogoutComponent extends Component {
* @returns {string} Markup for the component.
*/
render() {
return <Login location={{ query: {} }} />;
return <Login location={{ query: this.props.location.query }} />;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/theme/Logout/Logout.test.jsx
Expand Up @@ -14,7 +14,7 @@ describe('Logout', () => {
const store = mockStore();
const component = renderer.create(
<Provider store={store}>
<Logout />
<Logout location={{}} />
</Provider>,
);
const json = component.toJSON();
Expand Down
1 change: 1 addition & 0 deletions src/constants/ActionTypes.js
Expand Up @@ -37,6 +37,7 @@ export const GET_VOCABULARY = 'GET_VOCABULARY';
export const GET_WORKFLOW = 'GET_WORKFLOW';
export const GET_WORKFLOW_MULTIPLE = 'GET_WORKFLOW_MULTIPLE';
export const LOGIN = 'LOGIN';
export const LOGIN_RENEW = 'LOGIN_RENEW';
export const LOGOUT = 'LOGOUT';
export const ORDER_CONTENT = 'ORDER_CONTENT';
export const MOVE_CONTENT = 'MOVE_CONTENT';
Expand Down
30 changes: 25 additions & 5 deletions src/helpers/AuthToken/AuthToken.js
Expand Up @@ -5,6 +5,9 @@

import cookie from 'react-cookie';
import jwtDecode from 'jwt-decode';
import { browserHistory } from 'react-router';

import { loginRenew } from '../../actions';

/**
* Get auth token method.
Expand All @@ -27,25 +30,42 @@ export function persistAuthToken(store) {
/**
* handleChange method.
* @method handleChange
* @param {bool} initial Initial call.
* @returns {undefined}
*/
function handleChange() {
function handleChange(initial) {
const previousValue = currentValue;
const state = store.getState();
currentValue = state.userSession.token;

if (previousValue !== currentValue) {
if (currentValue === null) {
if (previousValue !== currentValue || initial) {
if (!currentValue) {
cookie.remove('auth_token', { path: '/' });
} else {
cookie.save('auth_token', currentValue, {
path: '/',
expires: new Date(jwtDecode(currentValue).exp * 1000),
});
setTimeout(() => {
if (store.getState().userSession.token) {
if (
jwtDecode(store.getState().userSession.token).exp * 1000 >
new Date().getTime()
) {
store.dispatch(loginRenew());
} else {
// Logout
browserHistory.push(
`/logout?return_url=${
store.getState().routing.locationBeforeTransitions.pathname
}`,
);
}
}
}, (jwtDecode(store.getState().userSession.token).exp * 1000 - new Date().getTime()) * 0.9);
}
}
}

store.subscribe(handleChange);
handleChange();
handleChange(true);
}
14 changes: 0 additions & 14 deletions src/helpers/AuthToken/AuthToken.test.js
Expand Up @@ -19,20 +19,6 @@ describe('AuthToken', () => {
});

describe('persistAuthToken', () => {
it('can set the same auth token', () => {
const store = {
subscribe: jest.fn(),
getState: jest.fn(() => ({
userSession: {
token: jwt.sign({ exp: 1 }, 'secret'),
},
})),
};

persistAuthToken(store);
expect(cookie.save).toHaveBeenCalledTimes(0);
});

it('can set a new auth token', () => {
const store = {
subscribe: jest.fn(),
Expand Down
4 changes: 3 additions & 1 deletion src/reducers/userSession/userSession.js
Expand Up @@ -3,7 +3,7 @@
* @module reducers/userSession
*/

import { LOGIN, LOGOUT } from '../../constants/ActionTypes';
import { LOGIN, LOGIN_RENEW, LOGOUT } from '../../constants/ActionTypes';

const initialState = {
token: null,
Expand Down Expand Up @@ -34,6 +34,7 @@ export default function userSession(state = initialState, action = {}) {
},
};
case `${LOGIN}_SUCCESS`:
case `${LOGIN_RENEW}_SUCCESS`:
return {
...state,
token: action.result.token,
Expand All @@ -44,6 +45,7 @@ export default function userSession(state = initialState, action = {}) {
},
};
case `${LOGIN}_FAIL`:
case `${LOGIN_RENEW}_FAIL`:
return {
...state,
token: null,
Expand Down

0 comments on commit d62242c

Please sign in to comment.