mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-11-08 07:21:03 +08:00
fixes sign out action on settings page, clean the redux store, handles redirect to sign in page if session is terminated [fixes SCI-1567]
This commit is contained in:
parent
fcea55c2a1
commit
524e8bffbf
13 changed files with 101 additions and 27 deletions
1
.babelrc
1
.babelrc
|
|
@ -17,6 +17,7 @@
|
|||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
"syntax-dynamic-import",
|
||||
"transform-react-jsx-source",
|
||||
[
|
||||
"transform-class-properties",
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,16 @@ module ClientApi
|
|||
module Users
|
||||
class UsersController < ApplicationController
|
||||
|
||||
def sign_out_user
|
||||
respond_to do |format|
|
||||
if sign_out current_user
|
||||
format.json { render json: {}, status: :ok }
|
||||
else
|
||||
format.json { render json: {}, status: :unauthorized }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def preferences_info
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
|
|
|
|||
|
|
@ -1,22 +1,33 @@
|
|||
import React, { Component } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { func, shape, string, number } from "prop-types";
|
||||
import { NavDropdown, MenuItem, Image } from "react-bootstrap";
|
||||
import styled from "styled-components";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { SIGN_IN_PATH } from "../../../config/routes";
|
||||
|
||||
import { getCurrentUser } from "../../actions/UsersActions";
|
||||
import { getCurrentUser, destroyState } from "../../actions/UsersActions";
|
||||
import { signOutUser } from "../../../services/api/users_api";
|
||||
|
||||
const StyledNavDropdown = styled(NavDropdown)`
|
||||
& #user-account-dropdown {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
& #user-account-dropdown {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
`;
|
||||
|
||||
class UserAccountDropdown extends Component {
|
||||
componentDidMount() {
|
||||
this.props.getCurrentUser();
|
||||
this.signOut = this.signOut.bind(this);
|
||||
}
|
||||
|
||||
signOut() {
|
||||
document.querySelector('meta[name="csrf-token"]').remove();
|
||||
signOutUser().then(() => {
|
||||
this.props.destroyState();
|
||||
window.location = SIGN_IN_PATH;
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
@ -43,7 +54,7 @@ class UserAccountDropdown extends Component {
|
|||
<FormattedMessage id="user_account_dropdown.settings" />
|
||||
</MenuItem>
|
||||
<MenuItem divider />
|
||||
<MenuItem href="/users/sign_out">
|
||||
<MenuItem onClick={this.signOut}>
|
||||
<FormattedMessage id="user_account_dropdown.log_out" />
|
||||
</MenuItem>
|
||||
</StyledNavDropdown>
|
||||
|
|
@ -52,24 +63,18 @@ class UserAccountDropdown extends Component {
|
|||
}
|
||||
|
||||
UserAccountDropdown.propTypes = {
|
||||
getCurrentUser: PropTypes.func.isRequired,
|
||||
current_user: PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
fullName: PropTypes.string.isRequired,
|
||||
avatarPath: PropTypes.string.isRequired
|
||||
getCurrentUser: func.isRequired,
|
||||
destroyState: func.isRequired,
|
||||
current_user: shape({
|
||||
id: number.isRequired,
|
||||
fullName: string.isRequired,
|
||||
avatarPath: string.isRequired
|
||||
}).isRequired
|
||||
};
|
||||
|
||||
// Map the states from store to component
|
||||
const mapStateToProps = ({ current_user }) => ({ current_user });
|
||||
|
||||
// Map the fetch activity action to component
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
getCurrentUser() {
|
||||
dispatch(getCurrentUser());
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(
|
||||
export default connect(mapStateToProps, { destroyState, getCurrentUser })(
|
||||
UserAccountDropdown
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import {
|
|||
} from "../../config/api_endpoints";
|
||||
|
||||
import {
|
||||
USER_LOGOUT,
|
||||
SET_CURRENT_USER,
|
||||
CHANGE_CURRENT_USER_FULL_NAME,
|
||||
CHANGE_CURRENT_USER_INITIALS,
|
||||
|
|
@ -29,6 +30,10 @@ import {
|
|||
CHANGE_SYSTEM_MESSAGE_NOTIFICATION_EMAIL
|
||||
} from "../../config/action_types";
|
||||
|
||||
export function destroyState() {
|
||||
return { type: USER_LOGOUT };
|
||||
}
|
||||
|
||||
function addCurrentUser(data) {
|
||||
return {
|
||||
type: SET_CURRENT_USER,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export const GLOBAL_ACTIVITIES_DATA = "GLOBAL_ACTIVITIES_DATA";
|
|||
export const DESTROY_GLOBAL_ACTIVITIES_DATA = "DESTROY_GLOBAL_ACTIVITIES_DATA";
|
||||
|
||||
// users
|
||||
export const USER_LOGOUT = "USER_LOGOUT";
|
||||
export const SET_CURRENT_USER = "SET_CURRENT_USER";
|
||||
export const CHANGE_CURRENT_USER_FULL_NAME = "CHANGE_CURRENT_USER_FULL_NAME";
|
||||
export const CHANGE_CURRENT_USER_INITIALS = "CHANGE_CURRENT_USER_INITIALS";
|
||||
|
|
@ -39,4 +40,4 @@ export const SPINNER_OFF = "SPINNER_OFF";
|
|||
// alerts
|
||||
export const ADD_ALERT = "ADD_ALERT";
|
||||
export const CLEAR_ALERT = "CLEAR_ALERT";
|
||||
export const CLEAR_ALL_ALERTS = "CLEAR_ALL_ALERTS";
|
||||
export const CLEAR_ALL_ALERTS = "CLEAR_ALL_ALERTS";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,19 @@
|
|||
// @TODO remove this file ASAP the preferences/profile refactoring is merged
|
||||
import axios from "axios";
|
||||
import store from "./store";
|
||||
import { SIGN_IN_PATH } from "./routes";
|
||||
import { destroyState } from "../components/actions/UsersActions";
|
||||
|
||||
export default axios.create({
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
validateStatus(status) {
|
||||
if (status === 401) {
|
||||
store.dispatch(destroyState);
|
||||
window.location = SIGN_IN_PATH;
|
||||
}
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import { combineReducers } from "redux";
|
||||
import { USER_LOGOUT } from "./action_types";
|
||||
import {
|
||||
setCurrentTeam,
|
||||
getListOfTeams,
|
||||
showLeaveTeamModal,
|
||||
showLeaveTeamModal
|
||||
} from "../components/reducers/TeamReducers";
|
||||
import { globalActivities } from "../components/reducers/ActivitiesReducers";
|
||||
import { currentUser } from "../components/reducers/UsersReducer";
|
||||
import { alerts } from "../components/reducers/AlertsReducers";
|
||||
|
||||
export default combineReducers({
|
||||
const appReducer = combineReducers({
|
||||
current_team: setCurrentTeam,
|
||||
all_teams: getListOfTeams,
|
||||
global_activities: globalActivities,
|
||||
|
|
@ -16,3 +17,12 @@ export default combineReducers({
|
|||
showLeaveTeamModal,
|
||||
alerts
|
||||
});
|
||||
|
||||
const rootReducer = (state, action) => {
|
||||
if (action.type === USER_LOGOUT) {
|
||||
state = undefined;
|
||||
}
|
||||
return appReducer(state, action);
|
||||
};
|
||||
|
||||
export default rootReducer;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
export const ROOT_PATH = "/";
|
||||
|
||||
export const SIGN_IN_PATH = "/users/sign_in";
|
||||
|
||||
// Settings page
|
||||
export const SETTINGS_TEAMS_ROUTE = "/settings/teams";
|
||||
export const SETTINGS_TEAM_ROUTE = "/settings/teams/:id";
|
||||
export const SETTINGS_NEW_TEAM_ROUTE = "/settings/teams/new";
|
||||
export const SETTINGS_ACCOUNT_PROFILE = "/settings/account/profile";
|
||||
export const SETTINGS_ACCOUNT_PREFERENCES = "/settings/account/preferences";
|
||||
export const SETTINGS_ACCOUNT_PREFERENCES = "/settings/account/preferences";
|
||||
|
|
|
|||
21
app/javascript/src/services/api/config.js
Normal file
21
app/javascript/src/services/api/config.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import axios from "axios";
|
||||
// import { dispatch } from "redux";
|
||||
import store from "../../config/store";
|
||||
import { SIGN_IN_PATH } from "../../config/routes";
|
||||
import { destroyState } from "../../components/actions/UsersActions";
|
||||
|
||||
export const axiosInstance = axios.create({
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
"X-CSRF-TOKEN": document.querySelector('meta[name="csrf-token"]').content
|
||||
},
|
||||
validateStatus(status) {
|
||||
if (status === 401) {
|
||||
setTimeout(() => {
|
||||
store.dispatch(destroyState)
|
||||
window.location = SIGN_IN_PATH;
|
||||
}, 500);
|
||||
}
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
});
|
||||
1
app/javascript/src/services/api/endpoints.js
Normal file
1
app/javascript/src/services/api/endpoints.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
export const SIGN_OUT_PATH = "/client_api/users/sign_out_user"
|
||||
6
app/javascript/src/services/api/users_api.js
Normal file
6
app/javascript/src/services/api/users_api.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { axiosInstance } from "./config";
|
||||
import { SIGN_OUT_PATH } from "./endpoints";
|
||||
|
||||
export function signOutUser() {
|
||||
return axiosInstance.get(SIGN_OUT_PATH);
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ Rails.application.routes.draw do
|
|||
get '/current_user_info', to: 'users/users#current_user_info'
|
||||
|
||||
namespace :users do
|
||||
get '/sign_out_user', to: 'users#sign_out_user'
|
||||
delete '/remove_user', to: 'user_teams#remove_user'
|
||||
delete '/leave_team', to: 'user_teams#leave_team'
|
||||
put '/update_role', to: 'user_teams#update_role'
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-plugin-transform-react-jsx-source": "^6.22.0",
|
||||
"eslint": "^3.7.1",
|
||||
"eslint-config-airbnb": "^15.1.0",
|
||||
"eslint-config-google": "^0.5.0",
|
||||
|
|
@ -68,8 +69,6 @@
|
|||
"react-bootstrap-table": "^4.0.0",
|
||||
"react-bootstrap-timezone-picker": "^1.0.11",
|
||||
"react-data-grid": "^2.0.2",
|
||||
"react-tagsinput": "^3.17.0",
|
||||
"react-transition-group": "^2.2.0",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-intl": "^2.3.0",
|
||||
"react-intl-redux": "^0.6.0",
|
||||
|
|
@ -78,7 +77,9 @@
|
|||
"react-router-bootstrap": "^0.24.2",
|
||||
"react-router-dom": "^4.1.2",
|
||||
"react-router-prop-types": "^0.0.1",
|
||||
"react-tagsinput": "^3.17.0",
|
||||
"react-timezone": "^0.2.0",
|
||||
"react-transition-group": "^2.2.0",
|
||||
"redux": "^3.7.2",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"resolve-url-loader": "^2.1.0",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue