2020-03-23 15:35:58 +01:00
|
|
|
/*
|
|
|
|
|
* MIT License
|
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
* copies or substantial portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-08-03 17:41:40 +02:00
|
|
|
import { Link, Me } from "@scm-manager/ui-types";
|
2019-10-20 18:02:52 +02:00
|
|
|
import * as types from "./types";
|
2018-07-05 16:48:56 +02:00
|
|
|
|
2019-10-20 18:02:52 +02:00
|
|
|
import { apiClient, UnauthorizedError } from "@scm-manager/ui-components";
|
|
|
|
|
import { isPending } from "./pending";
|
|
|
|
|
import { getFailure } from "./failure";
|
2018-10-15 13:46:42 +02:00
|
|
|
import {
|
|
|
|
|
callFetchIndexResources,
|
2018-10-29 13:42:56 +01:00
|
|
|
fetchIndexResources,
|
|
|
|
|
fetchIndexResourcesPending,
|
2020-08-11 10:34:29 +02:00
|
|
|
fetchIndexResourcesSuccess,
|
|
|
|
|
getLoginLink
|
2019-10-20 18:02:52 +02:00
|
|
|
} from "./indexResource";
|
2020-08-03 17:41:40 +02:00
|
|
|
import { AnyAction } from "redux";
|
2018-07-10 16:52:23 +02:00
|
|
|
|
2018-07-13 10:57:11 +02:00
|
|
|
// Action
|
|
|
|
|
|
2019-10-20 18:02:52 +02:00
|
|
|
export const LOGIN = "scm/auth/LOGIN";
|
2018-07-30 15:29:23 +02:00
|
|
|
export const LOGIN_PENDING = `${LOGIN}_${types.PENDING_SUFFIX}`;
|
|
|
|
|
export const LOGIN_SUCCESS = `${LOGIN}_${types.SUCCESS_SUFFIX}`;
|
|
|
|
|
export const LOGIN_FAILURE = `${LOGIN}_${types.FAILURE_SUFFIX}`;
|
2018-07-13 10:57:11 +02:00
|
|
|
|
2019-10-20 18:02:52 +02:00
|
|
|
export const FETCH_ME = "scm/auth/FETCH_ME";
|
2018-07-30 15:29:23 +02:00
|
|
|
export const FETCH_ME_PENDING = `${FETCH_ME}_${types.PENDING_SUFFIX}`;
|
|
|
|
|
export const FETCH_ME_SUCCESS = `${FETCH_ME}_${types.SUCCESS_SUFFIX}`;
|
|
|
|
|
export const FETCH_ME_FAILURE = `${FETCH_ME}_${types.FAILURE_SUFFIX}`;
|
|
|
|
|
export const FETCH_ME_UNAUTHORIZED = `${FETCH_ME}_UNAUTHORIZED`;
|
2018-07-13 10:57:11 +02:00
|
|
|
|
2019-10-20 18:02:52 +02:00
|
|
|
export const LOGOUT = "scm/auth/LOGOUT";
|
2018-07-30 15:29:23 +02:00
|
|
|
export const LOGOUT_PENDING = `${LOGOUT}_${types.PENDING_SUFFIX}`;
|
|
|
|
|
export const LOGOUT_SUCCESS = `${LOGOUT}_${types.SUCCESS_SUFFIX}`;
|
|
|
|
|
export const LOGOUT_FAILURE = `${LOGOUT}_${types.FAILURE_SUFFIX}`;
|
2019-04-17 11:45:44 +02:00
|
|
|
export const LOGOUT_REDIRECT = `${LOGOUT}_REDIRECT`;
|
2019-04-12 11:42:19 +02:00
|
|
|
|
2018-07-13 10:57:11 +02:00
|
|
|
// Reducer
|
|
|
|
|
|
2018-07-30 15:29:23 +02:00
|
|
|
const initialState = {};
|
2018-07-13 10:57:11 +02:00
|
|
|
|
2018-07-30 15:51:45 +02:00
|
|
|
export default function reducer(
|
2019-10-19 16:38:07 +02:00
|
|
|
state: object = initialState,
|
2020-08-03 17:41:40 +02:00
|
|
|
action: AnyAction = {
|
2019-10-20 18:02:52 +02:00
|
|
|
type: "UNKNOWN"
|
|
|
|
|
}
|
2018-07-30 15:51:45 +02:00
|
|
|
) {
|
2018-07-13 10:57:11 +02:00
|
|
|
switch (action.type) {
|
|
|
|
|
case LOGIN_SUCCESS:
|
|
|
|
|
case FETCH_ME_SUCCESS:
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
2019-10-20 18:02:52 +02:00
|
|
|
me: action.payload
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
case FETCH_ME_UNAUTHORIZED:
|
|
|
|
|
return {
|
2019-10-20 18:02:52 +02:00
|
|
|
me: {}
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
case LOGOUT_SUCCESS:
|
|
|
|
|
return initialState;
|
2018-07-30 15:29:23 +02:00
|
|
|
|
2019-04-17 11:45:44 +02:00
|
|
|
case LOGOUT_REDIRECT: {
|
|
|
|
|
// we keep the current state until we are redirected to the new page
|
|
|
|
|
return {
|
|
|
|
|
...state,
|
2019-10-20 18:02:52 +02:00
|
|
|
redirecting: true
|
2019-04-17 11:45:44 +02:00
|
|
|
};
|
|
|
|
|
}
|
2018-07-13 10:57:11 +02:00
|
|
|
default:
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Action Creators
|
|
|
|
|
|
2018-07-30 15:29:23 +02:00
|
|
|
export const loginPending = () => {
|
2018-07-13 10:57:11 +02:00
|
|
|
return {
|
2019-10-20 18:02:52 +02:00
|
|
|
type: LOGIN_PENDING
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2018-07-30 15:29:23 +02:00
|
|
|
export const loginSuccess = (me: Me) => {
|
2018-07-13 10:57:11 +02:00
|
|
|
return {
|
2018-07-30 15:29:23 +02:00
|
|
|
type: LOGIN_SUCCESS,
|
2019-10-20 18:02:52 +02:00
|
|
|
payload: me
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const loginFailure = (error: Error) => {
|
|
|
|
|
return {
|
|
|
|
|
type: LOGIN_FAILURE,
|
2019-10-20 18:02:52 +02:00
|
|
|
payload: error
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2018-07-30 15:29:23 +02:00
|
|
|
export const logoutPending = () => {
|
2018-07-13 10:57:11 +02:00
|
|
|
return {
|
2019-10-20 18:02:52 +02:00
|
|
|
type: LOGOUT_PENDING
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const logoutSuccess = () => {
|
|
|
|
|
return {
|
2019-10-20 18:02:52 +02:00
|
|
|
type: LOGOUT_SUCCESS
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-17 11:45:44 +02:00
|
|
|
export const redirectAfterLogout = () => {
|
|
|
|
|
return {
|
2019-10-20 18:02:52 +02:00
|
|
|
type: LOGOUT_REDIRECT
|
2019-04-17 18:59:58 +02:00
|
|
|
};
|
2019-04-17 11:45:44 +02:00
|
|
|
};
|
|
|
|
|
|
2018-07-13 10:57:11 +02:00
|
|
|
export const logoutFailure = (error: Error) => {
|
|
|
|
|
return {
|
|
|
|
|
type: LOGOUT_FAILURE,
|
2019-10-20 18:02:52 +02:00
|
|
|
payload: error
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2018-07-30 15:29:23 +02:00
|
|
|
export const fetchMePending = () => {
|
2018-07-13 10:57:11 +02:00
|
|
|
return {
|
2019-10-20 18:02:52 +02:00
|
|
|
type: FETCH_ME_PENDING
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const fetchMeSuccess = (me: Me) => {
|
|
|
|
|
return {
|
|
|
|
|
type: FETCH_ME_SUCCESS,
|
2019-10-20 18:02:52 +02:00
|
|
|
payload: me
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const fetchMeUnauthenticated = () => {
|
|
|
|
|
return {
|
2018-07-30 15:29:23 +02:00
|
|
|
type: FETCH_ME_UNAUTHORIZED,
|
2019-10-20 18:02:52 +02:00
|
|
|
resetPending: true
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const fetchMeFailure = (error: Error) => {
|
|
|
|
|
return {
|
|
|
|
|
type: FETCH_ME_FAILURE,
|
2019-10-20 18:02:52 +02:00
|
|
|
payload: error
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// side effects
|
2018-07-12 11:33:41 +02:00
|
|
|
|
2018-10-11 09:54:12 +02:00
|
|
|
const callFetchMe = (link: string): Promise<Me> => {
|
2019-04-12 11:42:19 +02:00
|
|
|
return apiClient.get(link).then(response => {
|
|
|
|
|
return response.json();
|
|
|
|
|
});
|
2018-07-30 15:29:23 +02:00
|
|
|
};
|
|
|
|
|
|
2019-10-21 10:57:56 +02:00
|
|
|
export const login = (loginLink: string, username: string, password: string) => {
|
2020-08-03 17:41:40 +02:00
|
|
|
const loginData = {
|
2018-07-11 21:01:29 +02:00
|
|
|
cookie: true,
|
2020-08-11 10:34:29 +02:00
|
|
|
grant_type: "password",
|
2018-07-11 21:01:29 +02:00
|
|
|
username,
|
2019-10-20 18:02:52 +02:00
|
|
|
password
|
2018-07-09 11:38:13 +02:00
|
|
|
};
|
2018-07-13 10:57:11 +02:00
|
|
|
return function(dispatch: any) {
|
2018-07-30 15:29:23 +02:00
|
|
|
dispatch(loginPending());
|
2018-07-10 16:52:23 +02:00
|
|
|
return apiClient
|
2020-08-03 17:41:40 +02:00
|
|
|
.post(loginLink, loginData)
|
2018-11-15 21:39:08 +01:00
|
|
|
.then(() => {
|
2018-10-29 13:42:56 +01:00
|
|
|
dispatch(fetchIndexResourcesPending());
|
2018-10-11 10:26:54 +02:00
|
|
|
return callFetchIndexResources();
|
2018-10-11 09:54:12 +02:00
|
|
|
})
|
|
|
|
|
.then(response => {
|
2018-10-15 13:46:42 +02:00
|
|
|
dispatch(fetchIndexResourcesSuccess(response));
|
2020-08-03 17:41:40 +02:00
|
|
|
const meLink = (response._links.me as Link).href;
|
2018-10-11 10:26:54 +02:00
|
|
|
return callFetchMe(meLink);
|
2018-07-30 15:29:23 +02:00
|
|
|
})
|
|
|
|
|
.then(me => {
|
|
|
|
|
dispatch(loginSuccess(me));
|
2018-07-11 12:02:53 +02:00
|
|
|
})
|
2018-07-11 21:01:29 +02:00
|
|
|
.catch(err => {
|
2018-07-13 10:57:11 +02:00
|
|
|
dispatch(loginFailure(err));
|
2018-07-09 11:38:13 +02:00
|
|
|
});
|
|
|
|
|
};
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
2018-07-05 16:48:56 +02:00
|
|
|
|
2018-10-11 09:54:12 +02:00
|
|
|
export const fetchMe = (link: string) => {
|
2018-07-13 10:57:11 +02:00
|
|
|
return function(dispatch: any) {
|
2018-07-30 15:29:23 +02:00
|
|
|
dispatch(fetchMePending());
|
2018-10-11 09:54:12 +02:00
|
|
|
return callFetchMe(link)
|
2018-07-13 10:57:11 +02:00
|
|
|
.then(me => {
|
2018-07-30 15:29:23 +02:00
|
|
|
dispatch(fetchMeSuccess(me));
|
2018-07-13 10:57:11 +02:00
|
|
|
})
|
|
|
|
|
.catch((error: Error) => {
|
2018-11-15 21:39:08 +01:00
|
|
|
if (error instanceof UnauthorizedError) {
|
2018-07-13 10:57:11 +02:00
|
|
|
dispatch(fetchMeUnauthenticated());
|
|
|
|
|
} else {
|
|
|
|
|
dispatch(fetchMeFailure(error));
|
|
|
|
|
}
|
|
|
|
|
});
|
2018-07-05 16:48:56 +02:00
|
|
|
};
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
2018-07-05 16:48:56 +02:00
|
|
|
|
2020-08-11 10:34:29 +02:00
|
|
|
export const logout = (link: string, callback: () => void) => {
|
2018-07-12 11:33:41 +02:00
|
|
|
return function(dispatch: any) {
|
2018-07-30 15:29:23 +02:00
|
|
|
dispatch(logoutPending());
|
2018-07-12 11:33:41 +02:00
|
|
|
return apiClient
|
2018-10-11 08:27:24 +02:00
|
|
|
.delete(link)
|
2019-04-12 11:42:19 +02:00
|
|
|
.then(response => {
|
|
|
|
|
return response.status === 200
|
|
|
|
|
? response.json()
|
|
|
|
|
: new Promise(function(resolve) {
|
2019-04-17 11:45:44 +02:00
|
|
|
resolve();
|
2019-04-12 11:42:19 +02:00
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
.then(json => {
|
2019-04-17 11:45:44 +02:00
|
|
|
let fetchIndex = true;
|
2019-04-12 11:42:19 +02:00
|
|
|
if (json && json.logoutRedirect) {
|
2019-04-17 11:45:44 +02:00
|
|
|
dispatch(redirectAfterLogout());
|
2019-04-12 14:32:17 +02:00
|
|
|
window.location.assign(json.logoutRedirect);
|
2019-04-17 11:45:44 +02:00
|
|
|
fetchIndex = false;
|
|
|
|
|
} else {
|
|
|
|
|
dispatch(logoutSuccess());
|
2019-04-12 11:42:19 +02:00
|
|
|
}
|
2019-04-17 11:45:44 +02:00
|
|
|
return fetchIndex;
|
2018-07-12 11:33:41 +02:00
|
|
|
})
|
2019-04-17 11:45:44 +02:00
|
|
|
.then((fetchIndex: boolean) => {
|
|
|
|
|
if (fetchIndex) {
|
|
|
|
|
dispatch(fetchIndexResources());
|
|
|
|
|
}
|
2018-10-11 12:15:18 +02:00
|
|
|
})
|
2020-08-11 10:34:29 +02:00
|
|
|
.then(callback)
|
2018-07-12 11:33:41 +02:00
|
|
|
.catch(error => {
|
2018-07-13 10:57:11 +02:00
|
|
|
dispatch(logoutFailure(error));
|
2018-07-12 11:33:41 +02:00
|
|
|
});
|
|
|
|
|
};
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
2018-07-12 11:33:41 +02:00
|
|
|
|
2018-07-13 10:57:11 +02:00
|
|
|
// selectors
|
2018-07-12 11:33:41 +02:00
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
const stateAuth = (state: object): object => {
|
2020-08-03 17:41:40 +02:00
|
|
|
// @ts-ignore Right types for redux not available
|
2018-07-30 15:29:23 +02:00
|
|
|
return state.auth || {};
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const isAuthenticated = (state: object) => {
|
2020-08-03 17:41:40 +02:00
|
|
|
// @ts-ignore Right types for redux not available
|
|
|
|
|
return !!((state.auth.me && !getLoginLink(state)) || isAnonymous(state.auth.me));
|
2018-07-30 15:29:23 +02:00
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const getMe = (state: object): Me => {
|
2020-08-03 17:41:40 +02:00
|
|
|
// @ts-ignore Right types for redux not available
|
2018-07-30 15:29:23 +02:00
|
|
|
return stateAuth(state).me;
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const isFetchMePending = (state: object) => {
|
2018-07-30 15:29:23 +02:00
|
|
|
return isPending(state, FETCH_ME);
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const getFetchMeFailure = (state: object) => {
|
2018-07-30 15:29:23 +02:00
|
|
|
return getFailure(state, FETCH_ME);
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const isLoginPending = (state: object) => {
|
2018-07-30 15:29:23 +02:00
|
|
|
return isPending(state, LOGIN);
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const getLoginFailure = (state: object) => {
|
2018-07-30 15:29:23 +02:00
|
|
|
return getFailure(state, LOGIN);
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const isLogoutPending = (state: object) => {
|
2018-07-30 15:29:23 +02:00
|
|
|
return isPending(state, LOGOUT);
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const getLogoutFailure = (state: object) => {
|
2018-07-30 15:29:23 +02:00
|
|
|
return getFailure(state, LOGOUT);
|
2018-07-13 10:57:11 +02:00
|
|
|
};
|
2019-04-17 11:45:44 +02:00
|
|
|
|
2019-10-19 16:38:07 +02:00
|
|
|
export const isRedirecting = (state: object) => {
|
2020-08-03 17:41:40 +02:00
|
|
|
// @ts-ignore Right types for redux not available
|
2019-04-17 11:45:44 +02:00
|
|
|
return !!stateAuth(state).redirecting;
|
|
|
|
|
};
|
2020-08-03 17:41:40 +02:00
|
|
|
|
|
|
|
|
// Helper methods
|
|
|
|
|
|
|
|
|
|
export const isAnonymous = (me: Me) => {
|
|
|
|
|
return me?.name === "_anonymous";
|
|
|
|
|
};
|