Merge branch 'standalone-improvements' into 'develop'
Standalone: add external accounts, refresh on logout See merge request soapbox-pub/soapbox-fe!700
This commit is contained in:
commit
402a45b495
|
@ -18,6 +18,7 @@ import { createApp } from 'soapbox/actions/apps';
|
|||
import { obtainOAuthToken, revokeOAuthToken } from 'soapbox/actions/oauth';
|
||||
import sourceCode from 'soapbox/utils/code';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
export const SWITCH_ACCOUNT = 'SWITCH_ACCOUNT';
|
||||
|
||||
|
@ -177,6 +178,7 @@ export function logOut(intl) {
|
|||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const account = getLoggedInAccount(state);
|
||||
const standalone = isStandalone(state);
|
||||
|
||||
const params = {
|
||||
client_id: state.getIn(['auth', 'app', 'client_id']),
|
||||
|
@ -185,7 +187,7 @@ export function logOut(intl) {
|
|||
};
|
||||
|
||||
return dispatch(revokeOAuthToken(params)).finally(() => {
|
||||
dispatch({ type: AUTH_LOGGED_OUT, account });
|
||||
dispatch({ type: AUTH_LOGGED_OUT, account, standalone });
|
||||
dispatch(snackbar.success(intl.formatMessage(messages.loggedOut)));
|
||||
});
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import { baseClient } from '../api';
|
||||
import { createApp } from 'soapbox/actions/apps';
|
||||
import { obtainOAuthToken } from 'soapbox/actions/oauth';
|
||||
import { authLoggedIn, verifyCredentials } from 'soapbox/actions/auth';
|
||||
import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
|
||||
import { parseBaseURL } from 'soapbox/utils/auth';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import sourceCode from 'soapbox/utils/code';
|
||||
|
@ -73,6 +73,7 @@ export function loginWithCode(code) {
|
|||
return dispatch(obtainOAuthToken(params, baseURL))
|
||||
.then(token => dispatch(authLoggedIn(token)))
|
||||
.then(({ access_token }) => dispatch(verifyCredentials(access_token, baseURL)))
|
||||
.then(account => dispatch(switchAccount(account.id)))
|
||||
.then(() => window.location.href = '/');
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,129 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<LoginPage /> renders correctly on load 1`] = `
|
||||
<form
|
||||
className="simple_form new_user"
|
||||
method="post"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<fieldset
|
||||
disabled={false}
|
||||
>
|
||||
<div
|
||||
className="fields-group"
|
||||
>
|
||||
<div
|
||||
className="input email user_email"
|
||||
>
|
||||
<input
|
||||
aria-label="Username"
|
||||
autoComplete="off"
|
||||
className="string email"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
required={true}
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="input password user_password"
|
||||
>
|
||||
<input
|
||||
aria-label="Password"
|
||||
autoComplete="off"
|
||||
className="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
required={true}
|
||||
type="password"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
className="hint subtle-hint"
|
||||
>
|
||||
<a
|
||||
href="/auth/reset_password"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Trouble logging in?
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div
|
||||
className="actions"
|
||||
>
|
||||
<button
|
||||
className="btn button button-primary"
|
||||
name="button"
|
||||
type="submit"
|
||||
>
|
||||
Log in
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
exports[`<LoginPage /> renders correctly on load 1`] = `null`;
|
||||
|
||||
exports[`<LoginPage /> renders correctly on load 2`] = `
|
||||
<form
|
||||
className="simple_form new_user"
|
||||
method="post"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<fieldset
|
||||
disabled={false}
|
||||
>
|
||||
<div
|
||||
className="fields-group"
|
||||
>
|
||||
<div
|
||||
className="input email user_email"
|
||||
>
|
||||
<input
|
||||
aria-label="Username"
|
||||
autoComplete="off"
|
||||
className="string email"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
required={true}
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="input password user_password"
|
||||
>
|
||||
<input
|
||||
aria-label="Password"
|
||||
autoComplete="off"
|
||||
className="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
required={true}
|
||||
type="password"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
className="hint subtle-hint"
|
||||
>
|
||||
<a
|
||||
href="/auth/reset_password"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Trouble logging in?
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div
|
||||
className="actions"
|
||||
>
|
||||
<button
|
||||
className="btn button button-primary"
|
||||
name="button"
|
||||
type="submit"
|
||||
>
|
||||
Log in
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
exports[`<LoginPage /> renders correctly on load 2`] = `null`;
|
||||
|
|
|
@ -6,10 +6,12 @@ import { injectIntl } from 'react-intl';
|
|||
import LoginForm from './login_form';
|
||||
import OtpAuthForm from './otp_auth_form';
|
||||
import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
me: state.get('me'),
|
||||
isLoading: false,
|
||||
standalone: isStandalone(state),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
|
@ -55,8 +57,11 @@ class LoginPage extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { standalone } = this.props;
|
||||
const { isLoading, mfa_auth_needed, mfa_token, shouldRedirect } = this.state;
|
||||
|
||||
if (standalone) return <Redirect to='/auth/external' />;
|
||||
|
||||
if (shouldRedirect) return <Redirect to='/' />;
|
||||
|
||||
if (mfa_auth_needed) return <OtpAuthForm mfa_token={mfa_token} />;
|
||||
|
|
|
@ -9,19 +9,7 @@ import Footer from './components/footer';
|
|||
import LandingPage from '../landing_page';
|
||||
import AboutPage from '../about';
|
||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import { isPrerendered } from 'soapbox/precheck';
|
||||
|
||||
const validInstance = state => {
|
||||
const v = state.getIn(['instance', 'version']);
|
||||
return v && typeof v === 'string' && v !== '0.0.0';
|
||||
};
|
||||
|
||||
const isStandalone = state => {
|
||||
const hasInstance = validInstance(state);
|
||||
const instanceFetchFailed = state.getIn(['meta', 'instance_fetch_failed']);
|
||||
|
||||
return !isPrerendered && !hasInstance && instanceFetchFailed;
|
||||
};
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
soapbox: getSoapboxConfig(state),
|
||||
|
|
|
@ -261,7 +261,10 @@ const userSwitched = (oldState, state) => {
|
|||
};
|
||||
|
||||
const maybeReload = (oldState, state, action) => {
|
||||
if (userSwitched(oldState, state)) {
|
||||
const loggedOutStandalone = action.type === AUTH_LOGGED_OUT && action.standalone;
|
||||
const switched = userSwitched(oldState, state);
|
||||
|
||||
if (switched || loggedOutStandalone) {
|
||||
reload(state);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
/**
|
||||
* State: general Redux state utility functions.
|
||||
* @module soapbox/utils/state
|
||||
*/
|
||||
|
||||
import { getSoapboxConfig } from'soapbox/actions/soapbox';
|
||||
import { createSelector } from 'reselect';
|
||||
import { isPrerendered } from 'soapbox/precheck';
|
||||
import { isURL } from 'soapbox/utils/auth';
|
||||
import { BACKEND_URL } from 'soapbox/build_config';
|
||||
|
||||
export const displayFqn = state => {
|
||||
const soapbox = getSoapboxConfig(state);
|
||||
|
@ -8,3 +17,15 @@ export const displayFqn = state => {
|
|||
export const federationRestrictionsDisclosed = state => {
|
||||
return state.hasIn(['instance', 'pleroma', 'metadata', 'federation', 'mrf_policies']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine whether Soapbox FE is running in standalone mode.
|
||||
* Standalone mode runs separately from any backend and can login anywhere.
|
||||
* @param {object} state
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isStandalone = state => createSelector([
|
||||
state => state.getIn(['meta', 'instance_fetch_failed'], false),
|
||||
], instanceFetchFailed => {
|
||||
return isURL(BACKEND_URL) ? false : (!isPrerendered && instanceFetchFailed);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue