Merge branch 'lookup-401' into 'develop'
Redirect to /login if viewing an account 401's See merge request soapbox-pub/soapbox-fe!1509
This commit is contained in:
commit
bd95c9f7e8
|
@ -148,34 +148,24 @@ describe('fetchAccountByUsername()', () => {
|
||||||
const username = 'tiger';
|
const username = 'tiger';
|
||||||
let state, account;
|
let state, account;
|
||||||
|
|
||||||
describe('when the account has already been cached in redux', () => {
|
beforeEach(() => {
|
||||||
beforeEach(() => {
|
account = normalizeAccount({
|
||||||
account = normalizeAccount({
|
id,
|
||||||
id,
|
acct: username,
|
||||||
acct: username,
|
display_name: 'Tiger',
|
||||||
display_name: 'Tiger',
|
avatar: 'test.jpg',
|
||||||
avatar: 'test.jpg',
|
birthday: undefined,
|
||||||
birthday: undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
state = rootReducer(undefined, {})
|
|
||||||
.set('accounts', ImmutableMap({
|
|
||||||
[id]: account,
|
|
||||||
}));
|
|
||||||
|
|
||||||
store = mockStore(state);
|
|
||||||
|
|
||||||
__stub((mock) => {
|
|
||||||
mock.onGet(`/api/v1/accounts/${id}`).reply(200, account);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null', async() => {
|
state = rootReducer(undefined, {})
|
||||||
const result = await store.dispatch(fetchAccountByUsername(username));
|
.set('accounts', ImmutableMap({
|
||||||
const actions = store.getActions();
|
[id]: account,
|
||||||
|
}));
|
||||||
|
|
||||||
expect(actions).toEqual([]);
|
store = mockStore(state);
|
||||||
expect(result).toBeNull();
|
|
||||||
|
__stub((mock) => {
|
||||||
|
mock.onGet(`/api/v1/accounts/${id}`).reply(200, account);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,13 @@ export const BIRTHDAY_REMINDERS_FETCH_REQUEST = 'BIRTHDAY_REMINDERS_FETCH_REQUES
|
||||||
export const BIRTHDAY_REMINDERS_FETCH_SUCCESS = 'BIRTHDAY_REMINDERS_FETCH_SUCCESS';
|
export const BIRTHDAY_REMINDERS_FETCH_SUCCESS = 'BIRTHDAY_REMINDERS_FETCH_SUCCESS';
|
||||||
export const BIRTHDAY_REMINDERS_FETCH_FAIL = 'BIRTHDAY_REMINDERS_FETCH_FAIL';
|
export const BIRTHDAY_REMINDERS_FETCH_FAIL = 'BIRTHDAY_REMINDERS_FETCH_FAIL';
|
||||||
|
|
||||||
|
const maybeRedirectLogin = (error, history) => {
|
||||||
|
// The client is unauthorized - redirect to login.
|
||||||
|
if (history && error?.response?.status === 401) {
|
||||||
|
history.push('/login');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export function createAccount(params) {
|
export function createAccount(params) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch({ type: ACCOUNT_CREATE_REQUEST, params });
|
dispatch({ type: ACCOUNT_CREATE_REQUEST, params });
|
||||||
|
@ -153,19 +160,10 @@ export function fetchAccount(id) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchAccountByUsername(username) {
|
export function fetchAccountByUsername(username, history) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const { instance, me } = getState();
|
||||||
const account = state.get('accounts').find(account => account.get('acct') === username);
|
|
||||||
|
|
||||||
if (account) {
|
|
||||||
dispatch(fetchAccount(account.get('id')));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const instance = state.get('instance');
|
|
||||||
const features = getFeatures(instance);
|
const features = getFeatures(instance);
|
||||||
const me = state.get('me');
|
|
||||||
|
|
||||||
if (features.accountByUsername && (me || !features.accountLookup)) {
|
if (features.accountByUsername && (me || !features.accountLookup)) {
|
||||||
return api(getState).get(`/api/v1/accounts/${username}`).then(response => {
|
return api(getState).get(`/api/v1/accounts/${username}`).then(response => {
|
||||||
|
@ -182,6 +180,7 @@ export function fetchAccountByUsername(username) {
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchAccountFail(null, error));
|
dispatch(fetchAccountFail(null, error));
|
||||||
dispatch(importErrorWhileFetchingAccountByUsername(username));
|
dispatch(importErrorWhileFetchingAccountByUsername(username));
|
||||||
|
maybeRedirectLogin(error, history);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return dispatch(accountSearch({
|
return dispatch(accountSearch({
|
||||||
|
|
|
@ -5,8 +5,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import { fetchAccount, fetchAccountByUsername } from 'soapbox/actions/accounts';
|
import { fetchAccountByUsername } from 'soapbox/actions/accounts';
|
||||||
import { fetchPatronAccount } from 'soapbox/actions/patron';
|
import { fetchPatronAccount } from 'soapbox/actions/patron';
|
||||||
import { getSettings } from 'soapbox/actions/settings';
|
import { getSettings } from 'soapbox/actions/settings';
|
||||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||||
|
@ -67,6 +68,7 @@ const makeMapStateToProps = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export default @connect(makeMapStateToProps)
|
export default @connect(makeMapStateToProps)
|
||||||
|
@withRouter
|
||||||
class AccountTimeline extends ImmutablePureComponent {
|
class AccountTimeline extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -82,11 +84,11 @@ class AccountTimeline extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { params: { username }, accountId, accountApId, withReplies, patronEnabled } = this.props;
|
const { params: { username }, accountId, accountApId, withReplies, patronEnabled, history } = this.props;
|
||||||
|
|
||||||
|
this.props.dispatch(fetchAccountByUsername(username, history));
|
||||||
|
|
||||||
if (accountId && accountId !== -1) {
|
if (accountId && accountId !== -1) {
|
||||||
this.props.dispatch(fetchAccount(accountId));
|
|
||||||
|
|
||||||
if (!withReplies) {
|
if (!withReplies) {
|
||||||
this.props.dispatch(expandAccountFeaturedTimeline(accountId));
|
this.props.dispatch(expandAccountFeaturedTimeline(accountId));
|
||||||
}
|
}
|
||||||
|
@ -96,17 +98,17 @@ class AccountTimeline extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
|
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
|
||||||
} else {
|
|
||||||
this.props.dispatch(fetchAccountByUsername(username));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const { params: { username }, accountId, withReplies, accountApId, patronEnabled } = this.props;
|
const { params: { username }, accountId, withReplies, accountApId, patronEnabled, history } = this.props;
|
||||||
|
|
||||||
|
if (username && (username !== prevProps.params.username)) {
|
||||||
|
this.props.dispatch(fetchAccountByUsername(username, history));
|
||||||
|
}
|
||||||
|
|
||||||
if (accountId && (accountId !== -1) && (accountId !== prevProps.accountId) || withReplies !== prevProps.withReplies) {
|
if (accountId && (accountId !== -1) && (accountId !== prevProps.accountId) || withReplies !== prevProps.withReplies) {
|
||||||
this.props.dispatch(fetchAccount(accountId));
|
|
||||||
|
|
||||||
if (!withReplies) {
|
if (!withReplies) {
|
||||||
this.props.dispatch(expandAccountFeaturedTimeline(accountId));
|
this.props.dispatch(expandAccountFeaturedTimeline(accountId));
|
||||||
}
|
}
|
||||||
|
@ -116,8 +118,6 @@ class AccountTimeline extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
|
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
|
||||||
} else if (username && (username !== prevProps.params.username)) {
|
|
||||||
this.props.dispatch(fetchAccountByUsername(username));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,12 @@ const isRememberFailType = (type: string): boolean => type.endsWith('_REMEMBER_F
|
||||||
/** Whether the error contains an Axios response. */
|
/** Whether the error contains an Axios response. */
|
||||||
const hasResponse = (error: any): boolean => Boolean(error && error.response);
|
const hasResponse = (error: any): boolean => Boolean(error && error.response);
|
||||||
|
|
||||||
|
/** Don't show 401's. */
|
||||||
|
const authorized = (error: any): boolean => error?.response?.status !== 401;
|
||||||
|
|
||||||
/** Whether the error should be shown to the user. */
|
/** Whether the error should be shown to the user. */
|
||||||
const shouldShowError = ({ type, skipAlert, error }: AnyAction): boolean => {
|
const shouldShowError = ({ type, skipAlert, error }: AnyAction): boolean => {
|
||||||
return !skipAlert && hasResponse(error) && isFailType(type) && !isRememberFailType(type);
|
return !skipAlert && hasResponse(error) && authorized(error) && isFailType(type) && !isRememberFailType(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Middleware to display Redux errors to the user. */
|
/** Middleware to display Redux errors to the user. */
|
||||||
|
|
Loading…
Reference in New Issue