mirror of
https://github.com/strapi/strapi.git
synced 2025-07-31 04:45:54 +00:00
Remove willSecure and didGetSecured data hooks
This commit is contained in:
parent
76560a1c9c
commit
b3bc4a0941
@ -81,37 +81,39 @@ export class Admin extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
/* istanbul ignore next */
|
||||
// const { getHook } = this.props;
|
||||
// getHook('didGetSecuredData');
|
||||
// Retrieve the main settings of the application
|
||||
this.props.getInitData();
|
||||
// this.props.getInitData();
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
admin: { didGetSecuredData, isLoading, isSecured },
|
||||
getHook,
|
||||
getSecuredData,
|
||||
location: { pathname },
|
||||
} = this.props;
|
||||
// componentDidUpdate(prevProps) {
|
||||
// const {
|
||||
// admin: { didGetSecuredData, isLoading, isSecured },
|
||||
// getHook,
|
||||
// getSecuredData,
|
||||
// location: { pathname },
|
||||
// } = this.props;
|
||||
|
||||
if (!isLoading && this.state.shouldSecureAfterAllPluginsAreMounted) {
|
||||
if (!this.hasApluginNotReady(this.props)) {
|
||||
getHook('willSecure');
|
||||
}
|
||||
}
|
||||
// if (!isLoading && this.state.shouldSecureAfterAllPluginsAreMounted) {
|
||||
// if (!this.hasApluginNotReady(this.props)) {
|
||||
// getHook('willSecure');
|
||||
// }
|
||||
// }
|
||||
|
||||
if (prevProps.location.pathname !== pathname) {
|
||||
getHook('willSecure');
|
||||
}
|
||||
// if (prevProps.location.pathname !== pathname) {
|
||||
// getHook('willSecure');
|
||||
// }
|
||||
|
||||
if (prevProps.admin.isSecured !== isSecured && isSecured) {
|
||||
getSecuredData();
|
||||
}
|
||||
// if (prevProps.admin.isSecured !== isSecured && isSecured) {
|
||||
// getSecuredData();
|
||||
// }
|
||||
|
||||
if (prevProps.admin.didGetSecuredData !== didGetSecuredData) {
|
||||
getHook('didGetSecuredData');
|
||||
}
|
||||
}
|
||||
// if (prevProps.admin.didGetSecuredData !== didGetSecuredData) {
|
||||
// getHook('didGetSecuredData');
|
||||
// }
|
||||
// }
|
||||
|
||||
/* istanbul ignore next */
|
||||
componentDidCatch(error, info) {
|
||||
@ -129,13 +131,7 @@ export class Admin extends React.Component {
|
||||
|
||||
// TODO remove
|
||||
getContentWrapperStyle = () => {
|
||||
const {
|
||||
admin: { showMenu },
|
||||
} = this.props;
|
||||
|
||||
return showMenu
|
||||
? { main: {}, sub: styles.content }
|
||||
: { main: { width: '100%' }, sub: styles.wrapper };
|
||||
return { main: {}, sub: styles.content };
|
||||
};
|
||||
|
||||
hasApluginNotReady = props => {
|
||||
@ -195,7 +191,6 @@ export class Admin extends React.Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
admin: { isLoading, showLogoutComponent, showMenu },
|
||||
global: {
|
||||
blockApp,
|
||||
overlayBlockerData,
|
||||
@ -205,10 +200,6 @@ export class Admin extends React.Component {
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingIndicatorPage />;
|
||||
}
|
||||
|
||||
// We need the admin data in order to make the initializers work
|
||||
if (this.showLoader()) {
|
||||
return (
|
||||
@ -221,17 +212,17 @@ export class Admin extends React.Component {
|
||||
|
||||
return (
|
||||
<div className={styles.adminPage}>
|
||||
{showMenu && <LeftMenu version={strapiVersion} plugins={plugins} />}
|
||||
<LeftMenu version={strapiVersion} plugins={plugins} />
|
||||
<NavTopRightWrapper>
|
||||
{/* Injection zone not ready yet */}
|
||||
{showLogoutComponent && <Logout />}
|
||||
<Logout />
|
||||
<LocaleToggle isLogged />
|
||||
</NavTopRightWrapper>
|
||||
<div
|
||||
className={styles.adminPageRightWrapper}
|
||||
style={this.getContentWrapperStyle().main}
|
||||
>
|
||||
{showMenu ? <Header /> : ''}
|
||||
<Header />
|
||||
<div className={this.getContentWrapperStyle().sub}>
|
||||
<Switch>
|
||||
<Route
|
||||
@ -266,7 +257,7 @@ export class Admin extends React.Component {
|
||||
isOpen={blockApp && showGlobalAppBlocker}
|
||||
{...overlayBlockerData}
|
||||
/>
|
||||
{showLogoutComponent && SHOW_TUTORIALS && <Onboarding />}
|
||||
{SHOW_TUTORIALS && <Onboarding />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -21,15 +21,10 @@ const initialState = fromJS({
|
||||
autoReload: false,
|
||||
appError: false,
|
||||
currentEnvironment: 'development',
|
||||
didGetSecuredData: false,
|
||||
isLoading: true,
|
||||
isSecured: false,
|
||||
layout: Map({}),
|
||||
// NOTE: This should be the models and our stuffs
|
||||
// Since this api is not implemented yet I just set this vague key ATM
|
||||
securedData: {},
|
||||
showMenu: true,
|
||||
showLogoutComponent: false,
|
||||
strapiVersion: '3',
|
||||
uuid: false,
|
||||
});
|
||||
|
@ -19,11 +19,11 @@ import { bindActionCreators, compose } from 'redux';
|
||||
import { LoadingIndicatorPage, request } from 'strapi-helper-plugin';
|
||||
|
||||
import Admin from '../Admin';
|
||||
import AppLoader from '../AppLoader';
|
||||
import AuthPage from '../AuthPage';
|
||||
import NotFoundPage from '../NotFoundPage';
|
||||
import NotificationProvider from '../NotificationProvider';
|
||||
import AppLoader from '../AppLoader';
|
||||
import styles from './styles.scss';
|
||||
import AuthPage from '../AuthPage';
|
||||
import PrivateRoute from '../PrivateRoute';
|
||||
|
||||
import { getDataSucceeded } from './actions';
|
||||
|
||||
@ -58,7 +58,7 @@ function App(props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div style={{ display: 'block' }}>
|
||||
<Switch>
|
||||
<Route
|
||||
path="/auth/:authType"
|
||||
@ -71,10 +71,7 @@ function App(props) {
|
||||
)}
|
||||
exact
|
||||
/>
|
||||
<Route
|
||||
path="/"
|
||||
render={router => <Admin {...props} {...router} />}
|
||||
/>
|
||||
<PrivateRoute {...props} path="/" component={Admin} />
|
||||
<Route path="" component={NotFoundPage} />
|
||||
</Switch>
|
||||
</div>
|
||||
|
@ -1,11 +0,0 @@
|
||||
/**
|
||||
* styles.css
|
||||
*
|
||||
* App container styles
|
||||
*/
|
||||
|
||||
@import "../../styles/variables/variables";
|
||||
|
||||
.container {
|
||||
display: block;
|
||||
}
|
@ -4,6 +4,7 @@ import { Route } from 'react-router-dom';
|
||||
|
||||
import AppLoader from '../../AppLoader';
|
||||
import { App } from '../../App';
|
||||
import PrivateRoute from '../../PrivateRoute';
|
||||
|
||||
describe('<App />', () => {
|
||||
it('should render the <AppLoader />', () => {
|
||||
@ -17,7 +18,8 @@ describe('<App />', () => {
|
||||
topComp.find(AppLoader).prop('children')({ shouldLoad: false })
|
||||
);
|
||||
|
||||
expect(insideAppLoaderNotLoading.find(Route).length).toBe(3);
|
||||
expect(insideAppLoaderNotLoading.find(Route).length).toBe(2);
|
||||
expect(insideAppLoaderNotLoading.find(PrivateRoute)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should not render the <Switch /> if the app is loading', () => {
|
||||
|
@ -23,7 +23,6 @@ import formatErrorFromRequest from './utils/formatErrorFromRequest';
|
||||
|
||||
const AuthPage = ({
|
||||
hasAdminUser,
|
||||
history: { push },
|
||||
location: { search },
|
||||
match: {
|
||||
params: { authType },
|
||||
@ -31,6 +30,9 @@ const AuthPage = ({
|
||||
}) => {
|
||||
const [reducerState, dispatch] = useReducer(reducer, initialState);
|
||||
const codeRef = useRef();
|
||||
const aborController = new AbortController();
|
||||
|
||||
const { signal } = aborController;
|
||||
codeRef.current = getQueryParameters(search, 'code');
|
||||
useEffect(() => {
|
||||
// Set the reset code provided by the url
|
||||
@ -47,7 +49,10 @@ const AuthPage = ({
|
||||
});
|
||||
}
|
||||
|
||||
return () => {};
|
||||
return () => {
|
||||
aborController.abort();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [authType, codeRef]);
|
||||
const {
|
||||
didCheckErrors,
|
||||
@ -77,6 +82,7 @@ const AuthPage = ({
|
||||
await request('https://analytics.strapi.io/register', {
|
||||
method: 'POST',
|
||||
body: omit(modifiedData, ['password', 'confirmPassword']),
|
||||
signal,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
@ -95,6 +101,7 @@ const AuthPage = ({
|
||||
const { jwt, user, ok } = await request(requestURL, {
|
||||
method: 'POST',
|
||||
body,
|
||||
signal,
|
||||
});
|
||||
|
||||
if (authType === 'forgot-password' && ok === true) {
|
||||
@ -105,7 +112,6 @@ const AuthPage = ({
|
||||
} else {
|
||||
auth.setToken(jwt, modifiedData.rememberMe);
|
||||
auth.setUserInfo(user, modifiedData.rememberMe);
|
||||
push('/');
|
||||
}
|
||||
} catch (err) {
|
||||
const formattedError = formatErrorFromRequest(err);
|
||||
@ -259,9 +265,6 @@ const AuthPage = ({
|
||||
|
||||
AuthPage.propTypes = {
|
||||
hasAdminUser: PropTypes.bool.isRequired,
|
||||
history: PropTypes.shape({
|
||||
push: PropTypes.func.isRequired,
|
||||
}),
|
||||
location: PropTypes.shape({
|
||||
search: PropTypes.string.isRequired,
|
||||
}),
|
||||
|
@ -4,25 +4,46 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { memo, useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { request } from 'strapi-helper-plugin';
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
class Initializer extends React.PureComponent {
|
||||
// eslint-disable-line react/prefer-stateless-function
|
||||
componentDidMount() {
|
||||
// Emit the event 'pluginReady'
|
||||
this.props.updatePlugin(pluginId, 'isReady', true);
|
||||
}
|
||||
const Initializer = ({ updatePlugin }) => {
|
||||
const ref = useRef();
|
||||
ref.current = updatePlugin;
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
const getData = async () => {
|
||||
const requestURL = `/${pluginId}/content-types`;
|
||||
|
||||
try {
|
||||
const { data } = await request(requestURL, { method: 'GET' });
|
||||
|
||||
const menu = [
|
||||
{
|
||||
name: 'Content Types',
|
||||
links: data,
|
||||
},
|
||||
];
|
||||
|
||||
ref.current(pluginId, 'leftMenuSections', menu);
|
||||
} catch (err) {
|
||||
strapi.notification.error('content-manager.error.model.fetch');
|
||||
}
|
||||
};
|
||||
|
||||
getData();
|
||||
ref.current(pluginId, 'isReady', true);
|
||||
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
Initializer.propTypes = {
|
||||
updatePlugin: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default Initializer;
|
||||
export default memo(Initializer);
|
||||
|
@ -8,14 +8,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import didGetSecuredData from './lifecycles/didGetSecuredData';
|
||||
|
||||
function lifecycles() {
|
||||
// Set hooks for the AdminPage container.
|
||||
// Note: we don't need to specify the first argument because we already know what "willSecure" refers to.
|
||||
this.setHooks({
|
||||
didGetSecuredData,
|
||||
});
|
||||
// this.setHooks({
|
||||
// didGetSecuredData,
|
||||
// });
|
||||
}
|
||||
|
||||
export default lifecycles;
|
||||
|
@ -1,26 +0,0 @@
|
||||
import { request } from 'strapi-helper-plugin';
|
||||
import pluginId from '../pluginId';
|
||||
|
||||
// TODO: update needs to be updated when the models are retrieved from the admin.
|
||||
|
||||
async function didGetSecuredData() {
|
||||
const { updatePlugin } = this.props;
|
||||
const requestURL = `/${pluginId}/content-types`;
|
||||
|
||||
try {
|
||||
const { data } = await request(requestURL, { method: 'GET' });
|
||||
|
||||
const menu = [
|
||||
{
|
||||
name: 'Content Types',
|
||||
links: data,
|
||||
},
|
||||
];
|
||||
|
||||
updatePlugin(pluginId, 'leftMenuSections', menu);
|
||||
} catch (err) {
|
||||
strapi.notification.error('content-manager.error.model.fetch');
|
||||
}
|
||||
}
|
||||
|
||||
export default didGetSecuredData;
|
@ -10,8 +10,6 @@ import PropTypes from 'prop-types';
|
||||
import { Switch, Route } from 'react-router-dom';
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
// Containers
|
||||
import AuthPage from '../AuthPage';
|
||||
import EditPage from '../EditPage';
|
||||
import HomePage from '../HomePage';
|
||||
import NotFoundPage from '../NotFoundPage';
|
||||
@ -23,17 +21,10 @@ class App extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
renderRoute = props => <AuthPage {...this.props} {...props} />;
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className={pluginId}>
|
||||
<Switch>
|
||||
<Route
|
||||
path={`/plugins/${pluginId}/auth/:authType/:id?`}
|
||||
render={this.renderRoute}
|
||||
exact
|
||||
/>
|
||||
<Route
|
||||
path={`/plugins/${pluginId}/:settingType/:actionType/:id?`}
|
||||
component={EditPage}
|
||||
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* AuthPage actions
|
||||
*
|
||||
*/
|
||||
|
||||
import {
|
||||
HIDE_LOGIN_ERRORS_INPUT,
|
||||
ON_CHANGE_INPUT,
|
||||
SET_ERRORS,
|
||||
SET_FORM,
|
||||
SUBMIT,
|
||||
SUBMIT_ERROR,
|
||||
SUBMIT_SUCCEEDED,
|
||||
} from './constants';
|
||||
|
||||
export function hideLoginErrorsInput(value) {
|
||||
return {
|
||||
type: HIDE_LOGIN_ERRORS_INPUT,
|
||||
value,
|
||||
};
|
||||
}
|
||||
|
||||
export function onChangeInput({ target }) {
|
||||
return {
|
||||
type: ON_CHANGE_INPUT,
|
||||
key: target.name,
|
||||
value: target.value,
|
||||
};
|
||||
}
|
||||
|
||||
export function setErrors(formErrors) {
|
||||
return {
|
||||
type: SET_ERRORS,
|
||||
formErrors,
|
||||
};
|
||||
}
|
||||
|
||||
export function setForm(formType, email) {
|
||||
let data;
|
||||
|
||||
switch (formType) {
|
||||
case 'forgot-password':
|
||||
data = {
|
||||
email: '',
|
||||
};
|
||||
|
||||
break;
|
||||
case 'login':
|
||||
data = {
|
||||
identifier: '',
|
||||
password: '',
|
||||
rememberMe: true,
|
||||
};
|
||||
|
||||
break;
|
||||
case 'register':
|
||||
data = {
|
||||
username: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
email: '',
|
||||
news: false,
|
||||
};
|
||||
break;
|
||||
case 'register-success':
|
||||
data = {
|
||||
email,
|
||||
};
|
||||
break;
|
||||
case 'reset-password':
|
||||
data = {
|
||||
password: '',
|
||||
passwordConfirmation: '',
|
||||
code: email,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
data = {};
|
||||
}
|
||||
|
||||
return {
|
||||
type: SET_FORM,
|
||||
data,
|
||||
formType,
|
||||
};
|
||||
}
|
||||
|
||||
export function submit(context) {
|
||||
return {
|
||||
type: SUBMIT,
|
||||
context,
|
||||
};
|
||||
}
|
||||
|
||||
export function submitError(formErrors) {
|
||||
return {
|
||||
type: SUBMIT_ERROR,
|
||||
formErrors,
|
||||
};
|
||||
}
|
||||
|
||||
export function submitSucceeded() {
|
||||
return {
|
||||
type: SUBMIT_SUCCEEDED,
|
||||
};
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* AuthPage constants
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
export const HIDE_LOGIN_ERRORS_INPUT = 'UsersPermissions/AuthPage/HIDE_LOGIN_ERRORS_INPUT';
|
||||
export const ON_CHANGE_INPUT = 'UsersPermissions/AuthPage/ON_CHANGE_INPUT';
|
||||
export const SET_ERRORS = 'UsersPermissions/AuthPage/SET_ERRORS';
|
||||
export const SET_FORM = 'UsersPermissions/AuthPage/SET_FORM';
|
||||
export const SUBMIT = 'UsersPermissions/AuthPage/SUBMIT';
|
||||
export const SUBMIT_ERROR = 'UsersPermissions/AuthPage/SUBMIT_ERROR';
|
||||
export const SUBMIT_SUCCEEDED = 'UsersPermissions/AuthPage/SUBMIT_SUCCEEDED';
|
@ -1,116 +0,0 @@
|
||||
{
|
||||
"form": {
|
||||
"forgot-password": [
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.forgot-password.email.label"
|
||||
},
|
||||
"name": "email",
|
||||
"type": "email",
|
||||
"placeholder": "users-permissions.Auth.form.forgot-password.email.placeholder"
|
||||
}
|
||||
],
|
||||
"login": [
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.login.username.label"
|
||||
},
|
||||
"name": "identifier",
|
||||
"type": "text",
|
||||
"placeholder": "users-permissions.Auth.form.login.username.placeholder"
|
||||
},
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.login.password.label"
|
||||
},
|
||||
"name": "password",
|
||||
"type": "password"
|
||||
},
|
||||
{
|
||||
"customBootstrapClass": "col-md-6",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.login.rememberMe.label"
|
||||
},
|
||||
"name": "rememberMe",
|
||||
"type": "checkbox"
|
||||
}
|
||||
],
|
||||
"register": [
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register.username.label"
|
||||
},
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"placeholder": "users-permissions.Auth.form.register.username.placeholder"
|
||||
},
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register.password.label"
|
||||
},
|
||||
"name": "password",
|
||||
"type": "password"
|
||||
},
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register.confirmPassword.label"
|
||||
},
|
||||
"name": "confirmPassword",
|
||||
"type": "password"
|
||||
},
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register.email.label"
|
||||
},
|
||||
"name": "email",
|
||||
"placeholder": "users-permissions.Auth.form.register.email.placeholder",
|
||||
"type": "email"
|
||||
},
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register.news.label"
|
||||
},
|
||||
"name": "news",
|
||||
"type": "checkbox",
|
||||
"value": false
|
||||
}
|
||||
],
|
||||
"register-success": [
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"name": "email",
|
||||
"type": "email",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register-success.email.label"
|
||||
},
|
||||
"placeholder": "users-permissions.Auth.form.register-success.email.placeholder"
|
||||
}
|
||||
],
|
||||
"reset-password": [
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"name": "password",
|
||||
"type": "password",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register.password.label"
|
||||
}
|
||||
},
|
||||
{
|
||||
"customBootstrapClass": "col-md-12",
|
||||
"name": "passwordConfirmation",
|
||||
"type": "password",
|
||||
"label": {
|
||||
"id": "users-permissions.Auth.form.register.confirmPassword.label"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -1,452 +0,0 @@
|
||||
/**
|
||||
*
|
||||
* AuthPage
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators, compose } from 'redux';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { findIndex, get, isBoolean, isEmpty, map, replace } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Design
|
||||
import { auth, Button, InputsIndex as Input } from 'strapi-helper-plugin';
|
||||
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
// Logo
|
||||
import LogoStrapi from '../../assets/images/logo_strapi.png';
|
||||
|
||||
import {
|
||||
hideLoginErrorsInput,
|
||||
onChangeInput,
|
||||
setErrors,
|
||||
setForm,
|
||||
submit,
|
||||
} from './actions';
|
||||
import form from './form.json';
|
||||
import reducer from './reducer';
|
||||
import saga from './saga';
|
||||
import makeSelectAuthPage from './selectors';
|
||||
|
||||
import styles from './styles.scss';
|
||||
|
||||
export class AuthPage extends React.Component {
|
||||
// eslint-disable-line react/prefer-stateless-function
|
||||
componentDidMount() {
|
||||
auth.clearAppStorage();
|
||||
this.setForm();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
hideLoginErrorsInput,
|
||||
match: {
|
||||
params: { authType },
|
||||
},
|
||||
submitSuccess,
|
||||
} = this.props;
|
||||
|
||||
if (authType !== prevProps.match.params.authType) {
|
||||
this.setForm();
|
||||
hideLoginErrorsInput(false);
|
||||
}
|
||||
|
||||
if (submitSuccess) {
|
||||
switch (authType) {
|
||||
case 'login':
|
||||
case 'reset-password':
|
||||
// Check if we have token to handle redirection to login or admin.
|
||||
// Done to prevent redirection to admin after reset password if user should
|
||||
// not have access.
|
||||
auth.getToken()
|
||||
? this.redirect('/')
|
||||
: this.redirect('/plugins/users-permissions/auth/login');
|
||||
break;
|
||||
case 'register':
|
||||
this.redirect('/');
|
||||
// NOTE: prepare for comfirm email;
|
||||
// this.redirect(`/plugins/users-permissions/auth/register-success/${this.props.modifiedData.email}`);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get form Errors shortcut.
|
||||
getFormErrors = () => {
|
||||
const { formErrors } = this.props;
|
||||
return get(formErrors, ['0', 'errors', '0', 'id']);
|
||||
};
|
||||
|
||||
getLogo = () => {
|
||||
const {
|
||||
assets: { loginLogo },
|
||||
} = this.props;
|
||||
|
||||
return loginLogo || LogoStrapi;
|
||||
};
|
||||
|
||||
setForm = () => {
|
||||
const {
|
||||
location: { search },
|
||||
match: {
|
||||
params: { authType, id },
|
||||
},
|
||||
setForm,
|
||||
} = this.props;
|
||||
const params = search ? replace(search, '?code=', '') : id;
|
||||
|
||||
setForm(authType, params);
|
||||
};
|
||||
|
||||
isAuthType = type => {
|
||||
const {
|
||||
match: {
|
||||
params: { authType },
|
||||
},
|
||||
} = this.props;
|
||||
return authType === type;
|
||||
};
|
||||
|
||||
handleSubmit = e => {
|
||||
const { modifiedData, setErrors, submit } = this.props;
|
||||
e.preventDefault();
|
||||
const formErrors = Object.keys(modifiedData).reduce((acc, key) => {
|
||||
if (
|
||||
isEmpty(get(modifiedData, key)) &&
|
||||
!isBoolean(get(modifiedData, key))
|
||||
) {
|
||||
acc.push({
|
||||
name: key,
|
||||
errors: [{ id: 'components.Input.error.validation.required' }],
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
!isEmpty(get(modifiedData, 'password')) &&
|
||||
!isEmpty(get(modifiedData, 'confirmPassword')) &&
|
||||
findIndex(acc, ['name', 'confirmPassword']) === -1
|
||||
) {
|
||||
if (modifiedData.password.length < 6) {
|
||||
acc.push({
|
||||
name: 'password',
|
||||
errors: [
|
||||
{
|
||||
id: 'users-permissions.components.Input.error.password.length',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
get(modifiedData, 'password') !== get(modifiedData, 'confirmPassword')
|
||||
) {
|
||||
acc.push({
|
||||
name: 'confirmPassword',
|
||||
errors: [
|
||||
{
|
||||
id: 'users-permissions.components.Input.error.password.noMatch',
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
setErrors(formErrors);
|
||||
|
||||
if (isEmpty(formErrors)) {
|
||||
submit(this.context);
|
||||
}
|
||||
};
|
||||
|
||||
redirect = path => this.props.history.push(path);
|
||||
|
||||
renderButton = () => {
|
||||
const {
|
||||
match: {
|
||||
params: { authType },
|
||||
},
|
||||
submitSuccess,
|
||||
} = this.props;
|
||||
|
||||
if (this.isAuthType('login')) {
|
||||
return (
|
||||
<div className={cn('col-md-6', styles.loginButton)}>
|
||||
<Button
|
||||
primary
|
||||
label="users-permissions.Auth.form.button.login"
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const isEmailForgotSent =
|
||||
this.isAuthType('forgot-password') && submitSuccess;
|
||||
const label = isEmailForgotSent
|
||||
? 'users-permissions.Auth.form.button.forgot-password.success'
|
||||
: `users-permissions.Auth.form.button.${authType}`;
|
||||
|
||||
return (
|
||||
<div className={cn('col-md-12', styles.buttonContainer)}>
|
||||
<Button
|
||||
className={cn(isEmailForgotSent && styles.buttonForgotSuccess)}
|
||||
label={label}
|
||||
style={{ width: '100%' }}
|
||||
primary={!isEmailForgotSent}
|
||||
type="submit"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
renderLogo = () =>
|
||||
this.isAuthType('register') && (
|
||||
<div className={styles.logoContainer}>
|
||||
<img src={this.getLogo()} alt="logo" />
|
||||
</div>
|
||||
);
|
||||
|
||||
renderLink = () => {
|
||||
if (this.isAuthType('login')) {
|
||||
return (
|
||||
<Link to="/plugins/users-permissions/auth/forgot-password">
|
||||
<FormattedMessage id="users-permissions.Auth.link.forgot-password" />
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.isAuthType('forgot-password') ||
|
||||
this.isAuthType('register-success')
|
||||
) {
|
||||
return (
|
||||
<Link to="/plugins/users-permissions/auth/login">
|
||||
<FormattedMessage id="users-permissions.Auth.link.ready" />
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
return <div />;
|
||||
};
|
||||
|
||||
renderInputs = () => {
|
||||
const {
|
||||
didCheckErrors,
|
||||
formErrors,
|
||||
match: {
|
||||
params: { authType },
|
||||
},
|
||||
modifiedData,
|
||||
noErrorsDescription,
|
||||
onChangeInput,
|
||||
submitSuccess,
|
||||
} = this.props;
|
||||
|
||||
const inputs = get(form, ['form', authType]);
|
||||
const isForgotEmailSent =
|
||||
this.isAuthType('forgot-password') && submitSuccess;
|
||||
return map(inputs, (input, key) => {
|
||||
let label = isForgotEmailSent
|
||||
? {
|
||||
id:
|
||||
'users-permissions.Auth.form.forgot-password.email.label.success',
|
||||
}
|
||||
: get(input, 'label');
|
||||
|
||||
if (input.name === 'news') {
|
||||
const handleClick = (e, to) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const win = window.open(`https://strapi.io/${to}`, '_blank');
|
||||
win.focus();
|
||||
};
|
||||
|
||||
const terms = (
|
||||
<FormattedMessage
|
||||
id={`${pluginId}.Auth.privacy-policy-agreement.terms`}
|
||||
>
|
||||
{content => (
|
||||
<span
|
||||
style={{ color: '#0097f7', cursor: 'pointer' }}
|
||||
onClick={e => handleClick(e, 'terms')}
|
||||
>
|
||||
{content}
|
||||
</span>
|
||||
)}
|
||||
</FormattedMessage>
|
||||
);
|
||||
const policy = (
|
||||
<FormattedMessage
|
||||
id={`${pluginId}.Auth.privacy-policy-agreement.policy`}
|
||||
>
|
||||
{content => (
|
||||
<span
|
||||
style={{ color: '#0097f7', cursor: 'pointer' }}
|
||||
onClick={e => handleClick(e, 'policy')}
|
||||
>
|
||||
{content}
|
||||
</span>
|
||||
)}
|
||||
</FormattedMessage>
|
||||
);
|
||||
|
||||
label = () => (
|
||||
<FormattedMessage id={input.label.id} values={{ terms, policy }} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Input
|
||||
autoFocus={key === 0}
|
||||
customBootstrapClass={get(input, 'customBootstrapClass')}
|
||||
didCheckErrors={didCheckErrors}
|
||||
errors={get(formErrors, [
|
||||
findIndex(formErrors, ['name', input.name]),
|
||||
'errors',
|
||||
])}
|
||||
key={get(input, 'name')}
|
||||
label={label}
|
||||
name={get(input, 'name')}
|
||||
onChange={onChangeInput}
|
||||
placeholder={get(input, 'placeholder')}
|
||||
type={get(input, 'type')}
|
||||
validations={{ required: true }}
|
||||
value={get(modifiedData, get(input, 'name'), get(input, 'value'))}
|
||||
noErrorsDescription={noErrorsDescription}
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { modifiedData, noErrorsDescription, submitSuccess } = this.props;
|
||||
|
||||
let divStyle = this.isAuthType('register')
|
||||
? { marginTop: '3.2rem' }
|
||||
: { marginTop: '.9rem' };
|
||||
|
||||
if (this.isAuthType('forgot-password') && submitSuccess) {
|
||||
divStyle = { marginTop: '.9rem', minHeight: '18.2rem' };
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.authPage}>
|
||||
<div className={styles.wrapper}>
|
||||
<div className={styles.headerContainer}>
|
||||
{this.isAuthType('register') ? (
|
||||
<FormattedMessage id="users-permissions.Auth.form.header.register" />
|
||||
) : (
|
||||
<img src={this.getLogo()} alt="logo" />
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.headerDescription}>
|
||||
{this.isAuthType('register') && (
|
||||
<FormattedMessage id="users-permissions.Auth.header.register.description" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
styles.formContainer,
|
||||
this.isAuthType('forgot-password') && submitSuccess
|
||||
? styles.borderedSuccess
|
||||
: styles.bordered
|
||||
)}
|
||||
style={divStyle}
|
||||
>
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<div className="container-fluid">
|
||||
{noErrorsDescription && !isEmpty(this.getFormErrors()) ? (
|
||||
<div className={styles.errorsContainer}>
|
||||
<FormattedMessage id={this.getFormErrors()} />
|
||||
</div>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
<div className="row" style={{ textAlign: 'start' }}>
|
||||
{!submitSuccess && this.renderInputs()}
|
||||
{this.isAuthType('forgot-password') && submitSuccess && (
|
||||
<div className={styles.forgotSuccess}>
|
||||
<FormattedMessage id="users-permissions.Auth.form.forgot-password.email.label.success" />
|
||||
<br />
|
||||
<p>{get(modifiedData, 'email', '')}</p>
|
||||
</div>
|
||||
)}
|
||||
{this.renderButton()}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div className={styles.linkContainer}>{this.renderLink()}</div>
|
||||
</div>
|
||||
{this.renderLogo()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AuthPage.contextTypes = {
|
||||
updatePlugin: PropTypes.func,
|
||||
};
|
||||
|
||||
AuthPage.defaultProps = {
|
||||
assets: { loginLogo: null },
|
||||
};
|
||||
|
||||
AuthPage.propTypes = {
|
||||
assets: PropTypes.object,
|
||||
didCheckErrors: PropTypes.bool.isRequired,
|
||||
formErrors: PropTypes.array.isRequired,
|
||||
hideLoginErrorsInput: PropTypes.func.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
location: PropTypes.object.isRequired,
|
||||
match: PropTypes.object.isRequired,
|
||||
modifiedData: PropTypes.object.isRequired,
|
||||
noErrorsDescription: PropTypes.bool.isRequired,
|
||||
onChangeInput: PropTypes.func.isRequired,
|
||||
setErrors: PropTypes.func.isRequired,
|
||||
setForm: PropTypes.func.isRequired,
|
||||
submit: PropTypes.func.isRequired,
|
||||
submitSuccess: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = makeSelectAuthPage();
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return bindActionCreators(
|
||||
{
|
||||
hideLoginErrorsInput,
|
||||
onChangeInput,
|
||||
setErrors,
|
||||
setForm,
|
||||
submit,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
}
|
||||
|
||||
const withConnect = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
);
|
||||
const withReducer = window.strapi.injectReducer({
|
||||
key: 'authPage',
|
||||
reducer,
|
||||
pluginId,
|
||||
});
|
||||
const withSaga = window.strapi.injectSaga({ key: 'authPage', saga, pluginId });
|
||||
|
||||
export default compose(
|
||||
withReducer,
|
||||
withSaga,
|
||||
withConnect
|
||||
)(AuthPage);
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* AuthPage reducer
|
||||
*
|
||||
*/
|
||||
|
||||
import { fromJS, List, Map } from 'immutable';
|
||||
import {
|
||||
HIDE_LOGIN_ERRORS_INPUT,
|
||||
ON_CHANGE_INPUT,
|
||||
SET_ERRORS,
|
||||
SET_FORM,
|
||||
SUBMIT_ERROR,
|
||||
SUBMIT_SUCCEEDED,
|
||||
} from './constants';
|
||||
|
||||
const initialState = fromJS({
|
||||
didCheckErrors: false,
|
||||
formErrors: List([]),
|
||||
formType: 'login',
|
||||
noErrorsDescription: false,
|
||||
modifiedData: Map({}),
|
||||
submitSuccess: false,
|
||||
});
|
||||
|
||||
function authPageReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case HIDE_LOGIN_ERRORS_INPUT:
|
||||
return state.set('noErrorsDescription', action.value);
|
||||
case ON_CHANGE_INPUT:
|
||||
return state
|
||||
.updateIn(['modifiedData', action.key], () => action.value);
|
||||
case SET_ERRORS:
|
||||
case SUBMIT_ERROR:
|
||||
return state
|
||||
.set('didCheckErrors', !state.get('didCheckErrors'))
|
||||
.set('formErrors', List(action.formErrors));
|
||||
case SET_FORM:
|
||||
return state
|
||||
.set('formErrors', List([]))
|
||||
.set('noErrorsDescription', false)
|
||||
.set('formType', action.formType)
|
||||
.set('submitSuccess', false)
|
||||
.set('modifiedData', Map(action.data));
|
||||
case SUBMIT_SUCCEEDED:
|
||||
return state
|
||||
.set('noErrorsDescription', false)
|
||||
.set('submitSuccess', true);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default authPageReducer;
|
@ -1,133 +0,0 @@
|
||||
import { get, includes, isArray, omit, set } from 'lodash';
|
||||
import { call, fork, put, select, takeLatest } from 'redux-saga/effects';
|
||||
import { auth, request } from 'strapi-helper-plugin';
|
||||
|
||||
import { updateHasAdmin } from '../Initializer/actions';
|
||||
|
||||
import { hideLoginErrorsInput, submitError, submitSucceeded } from './actions';
|
||||
import { SUBMIT } from './constants';
|
||||
import { makeSelectFormType, makeSelectModifiedData } from './selectors';
|
||||
|
||||
export function* submitForm(action) {
|
||||
try {
|
||||
const body = yield select(makeSelectModifiedData());
|
||||
const formType = yield select(makeSelectFormType());
|
||||
const isRegister = formType === 'register';
|
||||
|
||||
let requestURL;
|
||||
|
||||
switch (formType) {
|
||||
case 'login':
|
||||
requestURL = '/admin/auth/local';
|
||||
break;
|
||||
case 'register':
|
||||
requestURL = '/admin/auth/local/register';
|
||||
break;
|
||||
case 'reset-password':
|
||||
requestURL = '/admin/auth/reset-password';
|
||||
break;
|
||||
case 'forgot-password':
|
||||
requestURL = '/admin/auth/forgot-password';
|
||||
set(
|
||||
body,
|
||||
'url',
|
||||
`${
|
||||
strapi.backendURL
|
||||
}/admin/plugins/users-permissions/auth/reset-password`,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
const response = yield call(request, requestURL, {
|
||||
method: 'POST',
|
||||
body: omit(body, 'news'),
|
||||
});
|
||||
|
||||
if (
|
||||
get(response, 'user.role.name', '') === 'Administrator' ||
|
||||
isRegister ||
|
||||
get(response, 'user.isAdmin', false)
|
||||
) {
|
||||
yield call(auth.setToken, response.jwt, body.rememberMe);
|
||||
yield call(auth.setUserInfo, response.user, body.rememberMe);
|
||||
}
|
||||
|
||||
if (isRegister) {
|
||||
action.context.updatePlugin('users-permissions', 'hasAdminUser', true);
|
||||
yield put(updateHasAdmin(true));
|
||||
|
||||
if (body.news) {
|
||||
try {
|
||||
yield call(request, 'https://analytics.strapi.io/register', {
|
||||
method: 'POST',
|
||||
body: omit(body, ['password', 'confirmPassword']),
|
||||
});
|
||||
} catch (e) {
|
||||
// Silent.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield put(submitSucceeded());
|
||||
} catch (error) {
|
||||
const formType = yield select(makeSelectFormType());
|
||||
|
||||
if (isArray(get(error, ['response', 'payload', 'message']))) {
|
||||
const errors = error.response.payload.message.reduce((acc, key) => {
|
||||
const err = key.messages.reduce(
|
||||
(acc, key) => {
|
||||
acc.id = `users-permissions.${key.id}`;
|
||||
|
||||
return acc;
|
||||
},
|
||||
{ id: '' },
|
||||
);
|
||||
|
||||
acc.push(err);
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
let formErrors;
|
||||
|
||||
switch (formType) {
|
||||
case 'forgot-password':
|
||||
formErrors = [{ name: 'email', errors }];
|
||||
break;
|
||||
case 'login':
|
||||
formErrors = [
|
||||
{ name: 'identifier', errors },
|
||||
{ name: 'password', errors },
|
||||
];
|
||||
yield put(hideLoginErrorsInput(true));
|
||||
break;
|
||||
case 'reset-password':
|
||||
if (
|
||||
errors[0].id === 'users-permissions.Auth.form.error.code.provide'
|
||||
) {
|
||||
strapi.notification.error(errors[0].id);
|
||||
} else {
|
||||
formErrors = [{ name: 'password', errors }];
|
||||
}
|
||||
break;
|
||||
case 'register': {
|
||||
const target = includes(get(errors, ['0', 'id']), 'username')
|
||||
? 'username'
|
||||
: 'email';
|
||||
formErrors = [{ name: target, errors }];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
yield put(submitError(formErrors));
|
||||
} else {
|
||||
strapi.notification.error('notification.error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function* defaultSaga() {
|
||||
yield fork(takeLatest, SUBMIT, submitForm);
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
/**
|
||||
* Direct selector to the authPage state domain
|
||||
*/
|
||||
const selectAuthPageDomain = () => (state) => state.get(`${pluginId}_authPage`);
|
||||
|
||||
/**
|
||||
* Default selector used by AuthPage
|
||||
*/
|
||||
|
||||
const makeSelectAuthPage = () => createSelector(
|
||||
selectAuthPageDomain(),
|
||||
(substate) => substate.toJS()
|
||||
);
|
||||
|
||||
/**
|
||||
* Other specific selectors
|
||||
*/
|
||||
|
||||
const makeSelectFormType = () => createSelector(
|
||||
selectAuthPageDomain(),
|
||||
(substate) => substate.get('formType'),
|
||||
);
|
||||
|
||||
const makeSelectModifiedData = () => createSelector(
|
||||
selectAuthPageDomain(),
|
||||
(substate) => substate.get('modifiedData').toJS(),
|
||||
);
|
||||
|
||||
export default makeSelectAuthPage;
|
||||
export {
|
||||
makeSelectFormType,
|
||||
makeSelectModifiedData,
|
||||
selectAuthPageDomain,
|
||||
};
|
@ -1,118 +0,0 @@
|
||||
.authPage {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
text-align: center;
|
||||
padding: 6.2rem 0;
|
||||
background: #FAFAFB;
|
||||
height: 100vh;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
height: 22.1rem;
|
||||
width: 685px;
|
||||
text-align: center;
|
||||
background-image: url('../../assets/images/background_empty.svg');
|
||||
background-position-x: center;
|
||||
font-size: 1.4rem;
|
||||
font-family: Lato;
|
||||
|
||||
}
|
||||
.errorsContainer {
|
||||
margin-top: -21px;
|
||||
margin-bottom: 18px;
|
||||
color: #ff203c;
|
||||
}
|
||||
.headerContainer {
|
||||
> span {
|
||||
line-height: 36px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
> img {
|
||||
margin-top: 1px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
}
|
||||
.headerDescription {
|
||||
width: 41.6rem;
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
padding: 13px 30px 0 30px;
|
||||
line-height: 18px;
|
||||
color: #333740;
|
||||
}
|
||||
|
||||
.formContainer {
|
||||
min-height: 20rem;
|
||||
width: 41.6rem;
|
||||
margin: 1.4rem auto;
|
||||
margin-bottom: 0;
|
||||
padding: 3.9rem 1.5rem 1.5rem 1.5rem;
|
||||
border-radius: 2px;
|
||||
background-color: #FFFFFF;
|
||||
box-shadow: 0 2px 4px 0 #E3E9F3;
|
||||
}
|
||||
|
||||
.loginButton {
|
||||
margin-top: -6px;
|
||||
padding-right: 0;
|
||||
text-align: right;
|
||||
|
||||
> button {
|
||||
margin-right: 1.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.linkContainer {
|
||||
padding-top: 1.8rem;
|
||||
> a {
|
||||
color: #262931;
|
||||
font-size: 13px;
|
||||
&:hover, &:active, &:focus {
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bordered {
|
||||
border-top: 2px solid #1C5DE7;
|
||||
}
|
||||
|
||||
.borderedSuccess {
|
||||
border-top: 2px solid #5A9E06;
|
||||
}
|
||||
|
||||
.logoContainer {
|
||||
position: absolute;
|
||||
left: 30px; bottom: 30px;
|
||||
|
||||
> img {
|
||||
height: 34px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonForgotSuccess {
|
||||
border: 1px solid #5A9E06;
|
||||
color: #5A9E06;
|
||||
}
|
||||
|
||||
.forgotSuccess {
|
||||
width: 100%;
|
||||
// margin-top: -2px;
|
||||
text-align: center;
|
||||
color: #5A9E06;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
> p {
|
||||
margin-top: 17px;
|
||||
margin-bottom: 18px;
|
||||
color: #333740;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Initializer actions
|
||||
*
|
||||
*/
|
||||
|
||||
import {
|
||||
INITIALIZE,
|
||||
INITIALIZE_SUCCEEDED,
|
||||
UPDATE_HAS_ADMIN,
|
||||
} from './constants';
|
||||
|
||||
export function initialize() {
|
||||
return {
|
||||
type: INITIALIZE,
|
||||
};
|
||||
}
|
||||
|
||||
export function initializeSucceeded(data) {
|
||||
return {
|
||||
type: INITIALIZE_SUCCEEDED,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateHasAdmin(value) {
|
||||
return {
|
||||
type: UPDATE_HAS_ADMIN,
|
||||
value,
|
||||
};
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Initializer constants
|
||||
*
|
||||
*/
|
||||
|
||||
export const INITIALIZE = 'UsersPermissions/Initializer/INITIALIZE';
|
||||
export const INITIALIZE_SUCCEEDED =
|
||||
'UsersPermissions/Initializer/INITIALIZE_SUCCEEDED';
|
||||
export const UPDATE_HAS_ADMIN = 'UsersPermissions/Initializer/UPDATE_HAS_ADMIN';
|
@ -4,76 +4,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { memo, useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators, compose } from 'redux';
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
import { initialize } from './actions';
|
||||
const Initializer = ({ updatePlugin }) => {
|
||||
const ref = useRef();
|
||||
ref.current = updatePlugin;
|
||||
|
||||
import makeSelectInitializer from './selectors';
|
||||
import reducer from './reducer';
|
||||
import saga from './saga';
|
||||
useEffect(() => {
|
||||
ref.current(pluginId, 'isReady', true);
|
||||
}, []);
|
||||
|
||||
class Initializer extends React.Component {
|
||||
// eslint-disable-line react/prefer-stateless-function
|
||||
componentDidMount() {
|
||||
this.props.initialize();
|
||||
this.props.unsetAppSecured();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { shouldUpdate, updatePlugin } = this.props;
|
||||
|
||||
if (prevProps.shouldUpdate !== shouldUpdate) {
|
||||
// Emit the event 'pluginReady' so the app can start
|
||||
updatePlugin('users-permissions', 'isReady', true);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Initializer.propTypes = {
|
||||
initialize: PropTypes.func.isRequired,
|
||||
shouldUpdate: PropTypes.bool.isRequired,
|
||||
unsetAppSecured: PropTypes.func.isRequired,
|
||||
updatePlugin: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
const mapStateToProps = makeSelectInitializer();
|
||||
|
||||
export function mapDispatchToProps(dispatch) {
|
||||
return bindActionCreators(
|
||||
{
|
||||
initialize,
|
||||
},
|
||||
dispatch,
|
||||
);
|
||||
}
|
||||
|
||||
const withConnect = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
);
|
||||
|
||||
/* Remove this line if the container doesn't have a route and
|
||||
* check the documentation to see how to create the container's store
|
||||
*/
|
||||
|
||||
const withReducer = strapi.injectReducer({ key: 'initializer', reducer, pluginId });
|
||||
|
||||
/* Remove the line below the container doesn't have a route and
|
||||
* check the documentation to see how to create the container's store
|
||||
*/
|
||||
const withSaga = strapi.injectSaga({ key: 'initializer', saga, pluginId });
|
||||
|
||||
export default memo(Initializer);
|
||||
export { Initializer };
|
||||
export default compose(
|
||||
withReducer,
|
||||
withSaga,
|
||||
withConnect,
|
||||
)(Initializer);
|
||||
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Initializer reducer
|
||||
*
|
||||
*/
|
||||
|
||||
import { fromJS } from 'immutable';
|
||||
import { INITIALIZE_SUCCEEDED, UPDATE_HAS_ADMIN } from './constants';
|
||||
|
||||
const initialState = fromJS({
|
||||
hasAdminUser: false,
|
||||
shouldUpdate: false,
|
||||
});
|
||||
|
||||
function initializerReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case INITIALIZE_SUCCEEDED:
|
||||
return state
|
||||
.updateIn(['hasAdminUser'], () => action.data)
|
||||
.update('shouldUpdate', v => !v);
|
||||
case UPDATE_HAS_ADMIN:
|
||||
return state.update('hasAdminUser', () => action.value);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default initializerReducer;
|
@ -1,24 +0,0 @@
|
||||
import { fork, takeLatest, call, put } from 'redux-saga/effects';
|
||||
|
||||
import { request } from 'strapi-helper-plugin';
|
||||
|
||||
import { INITIALIZE } from './constants';
|
||||
import { initializeSucceeded } from './actions';
|
||||
|
||||
export function* initialize() {
|
||||
try {
|
||||
const requestURL = '/users-permissions/init';
|
||||
|
||||
const { hasAdmin } = yield call(request, requestURL, { method: 'GET' });
|
||||
|
||||
yield put(initializeSucceeded(hasAdmin));
|
||||
} catch (err) {
|
||||
strapi.notification.error('notification.error');
|
||||
}
|
||||
}
|
||||
|
||||
// Individual exports for testing
|
||||
export default function* defaultSaga() {
|
||||
// See example in containers/HomePage/saga.js
|
||||
yield fork(takeLatest, INITIALIZE, initialize);
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import pluginId from '../../pluginId';
|
||||
|
||||
/**
|
||||
* Direct selector to the initializer state domain
|
||||
*/
|
||||
const selectInitializerDomain = () => state => state.get(`${pluginId}_initializer`);
|
||||
|
||||
/**
|
||||
* Other specific selectors
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default selector used by Initializer
|
||||
*/
|
||||
|
||||
const makeSelectInitializer = () =>
|
||||
createSelector(
|
||||
selectInitializerDomain(),
|
||||
substate => substate.toJS(),
|
||||
);
|
||||
|
||||
export default makeSelectInitializer;
|
||||
export { selectInitializerDomain };
|
@ -1,33 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`initialize Saga should call the strapi.notification action if the response errors 1`] = `
|
||||
Object {
|
||||
"@@redux-saga/IO": true,
|
||||
"CALL": Object {
|
||||
"args": Array [
|
||||
"/users-permissions/init",
|
||||
Object {
|
||||
"method": "GET",
|
||||
},
|
||||
],
|
||||
"context": null,
|
||||
"fn": [Function],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`initialize Saga should dispatch the initializeSucceeded action if it requests the data successfully 1`] = `
|
||||
Object {
|
||||
"@@redux-saga/IO": true,
|
||||
"CALL": Object {
|
||||
"args": Array [
|
||||
"/users-permissions/init",
|
||||
Object {
|
||||
"method": "GET",
|
||||
},
|
||||
],
|
||||
"context": null,
|
||||
"fn": [Function],
|
||||
},
|
||||
}
|
||||
`;
|
@ -1,24 +0,0 @@
|
||||
import { initialize, initializeSucceeded } from '../actions';
|
||||
import { INITIALIZE, INITIALIZE_SUCCEEDED } from '../constants';
|
||||
|
||||
describe('Initializer actions', () => {
|
||||
describe('Initialize Action', () => {
|
||||
it('has a type of INITIALIZE', () => {
|
||||
const expected = {
|
||||
type: INITIALIZE,
|
||||
};
|
||||
expect(initialize()).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('InitializeSucceeded Action', () => {
|
||||
it('has a type of INITIALIZE_SUCCEEDED and returns the given data', () => {
|
||||
const data = { hasAdmin: true };
|
||||
const expected = {
|
||||
type: INITIALIZE_SUCCEEDED,
|
||||
data,
|
||||
};
|
||||
expect(initializeSucceeded(data)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,73 +1,21 @@
|
||||
import React from 'react';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
|
||||
import { Initializer, mapDispatchToProps } from '../index';
|
||||
import { initialize } from '../actions';
|
||||
import { Initializer } from '../index';
|
||||
|
||||
describe('<Initializer />', () => {
|
||||
let defaultProps;
|
||||
|
||||
beforeEach(() => {
|
||||
defaultProps = {
|
||||
initialize: jest.fn(),
|
||||
shouldUpdate: false,
|
||||
unsetAppSecured: jest.fn(),
|
||||
updatePlugin: jest.fn(),
|
||||
};
|
||||
it('should not crash', () => {
|
||||
shallow(<Initializer updatePlugin={jest.fn()} />);
|
||||
});
|
||||
|
||||
it('Should not crash', () => {
|
||||
shallow(<Initializer {...defaultProps} />);
|
||||
});
|
||||
it('should call the updatePlugin props on mount', () => {
|
||||
const props = { updatePlugin: jest.fn() };
|
||||
mount(<Initializer {...props} />);
|
||||
|
||||
it('should call the initialize prop on mount', () => {
|
||||
mount(<Initializer {...defaultProps} />);
|
||||
|
||||
expect(defaultProps.initialize).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call the unsetAppSecured prop on mount', () => {
|
||||
mount(<Initializer {...defaultProps} />);
|
||||
|
||||
expect(defaultProps.unsetAppSecured).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call the updatePlugin prop when the shouldUpdate prop has changed', () => {
|
||||
const renderedComponent = mount(<Initializer {...defaultProps} />);
|
||||
|
||||
renderedComponent.setProps({ shouldUpdate: true });
|
||||
|
||||
expect(renderedComponent.instance().props.updatePlugin).toHaveBeenCalledWith(
|
||||
expect(props.updatePlugin).toHaveBeenCalledWith(
|
||||
'users-permissions',
|
||||
'isReady',
|
||||
true,
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
it('should not call the updatePlugin prop when the shouldUpdate prop has changed', () => {
|
||||
const renderedComponent = mount(<Initializer {...defaultProps} />);
|
||||
|
||||
renderedComponent.setProps({ shouldUpdate: false });
|
||||
|
||||
expect(renderedComponent.instance().props.updatePlugin).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('<Initializer />, mapDispatchToProps', () => {
|
||||
describe('initialize', () => {
|
||||
it('should be injected', () => {
|
||||
const dispatch = jest.fn();
|
||||
const result = mapDispatchToProps(dispatch);
|
||||
|
||||
expect(result.initialize).toBeDefined();
|
||||
});
|
||||
|
||||
it('should dispatch the initialize action when called', () => {
|
||||
const dispatch = jest.fn();
|
||||
const result = mapDispatchToProps(dispatch);
|
||||
result.initialize();
|
||||
|
||||
expect(dispatch).toHaveBeenCalledWith(initialize());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,27 +0,0 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import { initializeSucceeded } from '../actions';
|
||||
|
||||
import initializerReducer from '../reducer';
|
||||
|
||||
describe('initializerReducer', () => {
|
||||
let state;
|
||||
|
||||
beforeEach(() => {
|
||||
state = fromJS({
|
||||
hasAdminUser: false,
|
||||
shouldUpdate: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the initial state', () => {
|
||||
const expected = state;
|
||||
|
||||
expect(initializerReducer(undefined, {})).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should handle the initializeSucceeded action correctly', () => {
|
||||
const expected = state.set('hasAdminUser', true).set('shouldUpdate', true);
|
||||
|
||||
expect(initializerReducer(state, initializeSucceeded(true))).toEqual(expected);
|
||||
});
|
||||
});
|
@ -1,47 +0,0 @@
|
||||
/**
|
||||
* Test sagas
|
||||
*/
|
||||
|
||||
/* eslint-disable redux-saga/yield-effects */
|
||||
/* eslint-disable redux-saga/no-unhandled-errors */
|
||||
|
||||
import { fork, put, takeLatest } from 'redux-saga/effects';
|
||||
import defaultSaga, { initialize } from '../saga';
|
||||
import { initializeSucceeded } from '../actions';
|
||||
import { INITIALIZE } from '../constants';
|
||||
|
||||
describe('initialize Saga', () => {
|
||||
let initializeGenerator;
|
||||
|
||||
beforeEach(() => {
|
||||
initializeGenerator = initialize();
|
||||
const data = { hasAdmin: true };
|
||||
|
||||
const callDescriptor = initializeGenerator.next(data).value;
|
||||
|
||||
expect(callDescriptor).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should dispatch the initializeSucceeded action if it requests the data successfully', () => {
|
||||
const response = { hasAdmin: true };
|
||||
|
||||
const putDescriptor = initializeGenerator.next(response).value;
|
||||
expect(putDescriptor).toEqual(put(initializeSucceeded(response.hasAdmin)));
|
||||
});
|
||||
|
||||
it('should call the strapi.notification action if the response errors', () => {
|
||||
const response = new Error('Some error');
|
||||
initializeGenerator.throw(response).value;
|
||||
|
||||
expect(strapi.notification.error).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('defaultSaga Saga', () => {
|
||||
const defaultSagaSaga = defaultSaga();
|
||||
|
||||
it('should start task to watch for INITIALIZE action', () => {
|
||||
const forkDescriptor = defaultSagaSaga.next().value;
|
||||
expect(forkDescriptor).toEqual(fork(takeLatest, INITIALIZE, initialize));
|
||||
});
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
import { fromJS } from 'immutable';
|
||||
import makeSelectInitializerDomain, { selectInitializerDomain } from '../selectors';
|
||||
import pluginId from '../../../pluginId';
|
||||
|
||||
describe('<Initializer /> selectors', () => {
|
||||
describe('selectInitializerDomain', () => {
|
||||
it('should select the global state', () => {
|
||||
const initializerState = fromJS({});
|
||||
const mockedState = fromJS({
|
||||
[`${pluginId}_initializer`]: initializerState,
|
||||
});
|
||||
|
||||
expect(selectInitializerDomain()(mockedState)).toEqual(initializerState);
|
||||
});
|
||||
});
|
||||
|
||||
describe('makeSelectInitiazerDomain', () => {
|
||||
it('should select the global state (.toJS())', () => {
|
||||
const initializerState = fromJS({});
|
||||
const mockedState = fromJS({
|
||||
[`${pluginId}_initializer`]: initializerState,
|
||||
});
|
||||
|
||||
expect(makeSelectInitializerDomain()(mockedState)).toEqual(initializerState.toJS());
|
||||
});
|
||||
});
|
||||
});
|
@ -8,9 +8,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// import didGetSecuredData from './lifecycles/didGetSecuredData';
|
||||
import willSecure from './lifecycles/willSecure';
|
||||
|
||||
function lifecycles() {
|
||||
// TODO: Make it work and remove it when the split-admin PR has been merged
|
||||
// const componentsToAdd = [
|
||||
@ -23,10 +20,6 @@ function lifecycles() {
|
||||
// this.setComponents(componentsToAdd);
|
||||
// Set hooks for the AdminPage container.
|
||||
// Note: we don't need to specify the first argument because we already know what "willSecure" refers to.
|
||||
this.setHooks({
|
||||
// didGetSecuredData,
|
||||
willSecure,
|
||||
});
|
||||
// Set hooks for the App container of the Content Manager.
|
||||
// Note: we have to specify the first argument to select a specific container which is located in a plugin, or not.
|
||||
// this.setHooks('content-manager.App', {
|
||||
|
@ -1,24 +0,0 @@
|
||||
// const pluginId = require('../pluginId');
|
||||
import pluginId from '../pluginId';
|
||||
|
||||
function didGetSecuredData() {
|
||||
const {
|
||||
props: { updatePlugin },
|
||||
} = this;
|
||||
const leftMenuSections = [
|
||||
{
|
||||
links: [
|
||||
{
|
||||
label: 'Users',
|
||||
destination: 'user',
|
||||
plugin: 'content-manager',
|
||||
},
|
||||
],
|
||||
name: 'Content Types',
|
||||
},
|
||||
];
|
||||
|
||||
updatePlugin(pluginId, 'leftMenuSections', leftMenuSections);
|
||||
}
|
||||
|
||||
export default didGetSecuredData;
|
@ -1,83 +0,0 @@
|
||||
import { auth } from 'strapi-helper-plugin';
|
||||
|
||||
function willSecure() {
|
||||
const {
|
||||
props: {
|
||||
hideLeftMenu,
|
||||
hideLogout,
|
||||
history,
|
||||
location: { pathname },
|
||||
resetLocaleDefaultClassName,
|
||||
setAppSecured,
|
||||
setLocaleCustomClassName,
|
||||
showLeftMenu,
|
||||
showLogout,
|
||||
store,
|
||||
unsetAppSecured,
|
||||
},
|
||||
} = this;
|
||||
|
||||
const cb = () =>
|
||||
this.setState({
|
||||
shouldSecureAfterAllPluginsAreMounted: false,
|
||||
});
|
||||
|
||||
const initializerReducer = store
|
||||
.getState()
|
||||
.getIn(['users-permissions_initializer']);
|
||||
|
||||
const nonProtectedURLs = '/plugins/users-permissions/auth';
|
||||
const redirectEndPoint = initializerReducer.get('hasAdminUser')
|
||||
? '/plugins/users-permissions/auth/login'
|
||||
: '/plugins/users-permissions/auth/register';
|
||||
|
||||
if (auth.getToken()) {
|
||||
resetLocaleDefaultClassName(); // NOTE: Temporary should be removed when we switch to administrators
|
||||
setAppSecured();
|
||||
showLeftMenu();
|
||||
showLogout();
|
||||
|
||||
return cb();
|
||||
}
|
||||
|
||||
if (!pathname.includes(nonProtectedURLs)) {
|
||||
hideLeftMenu();
|
||||
hideLogout();
|
||||
setLocaleCustomClassName('localeDropdownMenuNotLogged'); // NOTE: Temporary should be removed when we switch to administrators
|
||||
unsetAppSecured();
|
||||
history.push(redirectEndPoint);
|
||||
|
||||
return cb();
|
||||
}
|
||||
|
||||
if (
|
||||
pathname === '/plugins/users-permissions/auth/login' ||
|
||||
pathname === '/plugins/users-permissions/auth/register'
|
||||
) {
|
||||
hideLeftMenu();
|
||||
hideLogout();
|
||||
setLocaleCustomClassName('localeDropdownMenuNotLogged'); // NOTE: Temporary should be removed when we switch to administrators
|
||||
unsetAppSecured();
|
||||
history.push(redirectEndPoint);
|
||||
|
||||
return cb();
|
||||
}
|
||||
|
||||
if (pathname.includes(nonProtectedURLs)) {
|
||||
hideLeftMenu();
|
||||
hideLogout();
|
||||
setLocaleCustomClassName('localeDropdownMenuNotLogged'); // NOTE: Temporary should be removed when we switch to administrators
|
||||
unsetAppSecured();
|
||||
|
||||
return cb();
|
||||
}
|
||||
|
||||
resetLocaleDefaultClassName(); // NOTE: Temporary should be removed when we switch to administrators
|
||||
showLeftMenu();
|
||||
showLogout();
|
||||
setAppSecured();
|
||||
|
||||
return cb();
|
||||
}
|
||||
|
||||
export default willSecure;
|
Loading…
x
Reference in New Issue
Block a user