Merge pull request #227 from ONLYOFFICE/feature/oauth2.0
Feature/oauth2.0
@ -90,6 +90,11 @@ server {
|
|||||||
root $public_root;
|
root $public_root;
|
||||||
try_files /offline/$basename /index.html =404;
|
try_files /offline/$basename /index.html =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location ~* /thirdparty/ {
|
||||||
|
root $public_root;
|
||||||
|
try_files /thirdparty/third-party.html /index.html =404;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
location /login {
|
location /login {
|
||||||
|
@ -197,6 +197,29 @@ export function updateUserType(type, userIds) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function linkOAuth(serializedProfile) {
|
||||||
|
return request({
|
||||||
|
method: "put",
|
||||||
|
url: "people/thirdparty/linkaccount.json",
|
||||||
|
data: { serializedProfile },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function signupOAuth(signupAccount) {
|
||||||
|
return request({
|
||||||
|
method: "post",
|
||||||
|
url: "people/thirdparty/signup.json",
|
||||||
|
data: signupAccount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unlinkOAuth(provider) {
|
||||||
|
return request({
|
||||||
|
method: "delete",
|
||||||
|
url: `people/thirdparty/unlinkaccount.json?provider=${provider}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function sendInstructionsToDelete() {
|
export function sendInstructionsToDelete() {
|
||||||
return request({
|
return request({
|
||||||
method: "put",
|
method: "put",
|
||||||
|
@ -233,6 +233,13 @@ export function getConsumersList() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAuthProviders() {
|
||||||
|
return request({
|
||||||
|
method: "get",
|
||||||
|
url: `/settings/authproviders`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function updateConsumerProps(newProps) {
|
export function updateConsumerProps(newProps) {
|
||||||
const options = {
|
const options = {
|
||||||
method: "post",
|
method: "post",
|
||||||
|
@ -13,6 +13,14 @@ export function login(userName, passwordHash) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function thirdPartyLogin(SerializedProfile) {
|
||||||
|
return request({
|
||||||
|
method: "post",
|
||||||
|
url: "authentication.json",
|
||||||
|
data: { SerializedProfile },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
return request({
|
return request({
|
||||||
method: "post",
|
method: "post",
|
||||||
|
@ -108,7 +108,25 @@ export const ConflictResolveType = Object.freeze({
|
|||||||
Overwrite: 1,
|
Overwrite: 1,
|
||||||
Duplicate: 2,
|
Duplicate: 2,
|
||||||
});
|
});
|
||||||
|
export const providersData = Object.freeze({
|
||||||
|
Google: {
|
||||||
|
label: "SignInWithGoogle",
|
||||||
|
icon: "/static/images/share.google.react.svg",
|
||||||
|
},
|
||||||
|
Facebook: {
|
||||||
|
label: "SignInWithFacebook",
|
||||||
|
icon: "/static/images/share.facebook.react.svg",
|
||||||
|
},
|
||||||
|
Twitter: {
|
||||||
|
label: "SignInWithTwitter",
|
||||||
|
icon: "/static/images/share.twitter.react.svg",
|
||||||
|
iconOptions: { color: "#2AA3EF" },
|
||||||
|
},
|
||||||
|
LinkedIn: {
|
||||||
|
label: "SignInWithLinkedIn",
|
||||||
|
icon: "/static/images/share.linkedin.react.svg",
|
||||||
|
},
|
||||||
|
});
|
||||||
export const i18nBaseSettings = {
|
export const i18nBaseSettings = {
|
||||||
lng: localStorage.getItem(LANGUAGE) || "en",
|
lng: localStorage.getItem(LANGUAGE) || "en",
|
||||||
supportedLngs: ["en", "ru"],
|
supportedLngs: ["en", "ru"],
|
||||||
|
@ -20,6 +20,8 @@ class AuthStore {
|
|||||||
isAuthenticated = false;
|
isAuthenticated = false;
|
||||||
version = null;
|
version = null;
|
||||||
|
|
||||||
|
providers = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.userStore = new UserStore();
|
this.userStore = new UserStore();
|
||||||
this.moduleStore = new ModuleStore();
|
this.moduleStore = new ModuleStore();
|
||||||
@ -154,6 +156,22 @@ class AuthStore {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
thirdPartyLogin = async (SerializedProfile) => {
|
||||||
|
try {
|
||||||
|
const response = await api.user.thirdPartyLogin(SerializedProfile);
|
||||||
|
|
||||||
|
if (!response || !response.token) throw "Empty API response";
|
||||||
|
|
||||||
|
setWithCredentialsStatus(true);
|
||||||
|
|
||||||
|
await this.init();
|
||||||
|
|
||||||
|
return Promise.resolve(true);
|
||||||
|
} catch (e) {
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
reset = () => {
|
reset = () => {
|
||||||
this.userStore = new UserStore();
|
this.userStore = new UserStore();
|
||||||
this.moduleStore = new ModuleStore();
|
this.moduleStore = new ModuleStore();
|
||||||
@ -250,6 +268,10 @@ class AuthStore {
|
|||||||
setProductVersion = (version) => {
|
setProductVersion = (version) => {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setProviders = (providers) => {
|
||||||
|
this.providers = providers;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new AuthStore();
|
export default new AuthStore();
|
||||||
|
@ -183,6 +183,33 @@ class SettingsStore {
|
|||||||
this.updateEncryptionKeys(encryptionKeys);
|
this.updateEncryptionKeys(encryptionKeys);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getOAuthToken = (tokenGetterWin) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
localStorage.removeItem("code");
|
||||||
|
let interval = null;
|
||||||
|
interval = setInterval(() => {
|
||||||
|
try {
|
||||||
|
const code = localStorage.getItem("code");
|
||||||
|
|
||||||
|
if (code) {
|
||||||
|
localStorage.removeItem("code");
|
||||||
|
clearInterval(interval);
|
||||||
|
resolve(code);
|
||||||
|
} else if (tokenGetterWin && tokenGetterWin.closed) {
|
||||||
|
clearInterval(interval);
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getLoginLink = (token, code) => {
|
||||||
|
return combineUrl(proxyURL, `/login.ashx?p=${token}&code=${code}`);
|
||||||
|
};
|
||||||
|
|
||||||
setModuleInfo = (homepage, productId) => {
|
setModuleInfo = (homepage, productId) => {
|
||||||
if (this.homepage == homepage) return;
|
if (this.homepage == homepage) return;
|
||||||
this.homepage = homepage;
|
this.homepage = homepage;
|
||||||
|
48
packages/asc-web-components/facebook-button/index.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import equal from "fast-deep-equal/react";
|
||||||
|
|
||||||
|
import Text from "../text";
|
||||||
|
import StyledFacebookButton from "./styled-facebook-button";
|
||||||
|
import { ReactSVG } from "react-svg";
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
|
||||||
|
class FacebookButton extends React.Component {
|
||||||
|
shouldComponentUpdate(nextProps) {
|
||||||
|
return !equal(this.props, nextProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { label, iconName, ...otherProps } = this.props;
|
||||||
|
return (
|
||||||
|
<StyledFacebookButton {...otherProps}>
|
||||||
|
<ReactSVG className="iconWrapper" src={iconName} />
|
||||||
|
{label && (
|
||||||
|
<Text as="span" className="social_button_text">
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</StyledFacebookButton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FacebookButton.propTypes = {
|
||||||
|
label: PropTypes.string,
|
||||||
|
iconName: PropTypes.string,
|
||||||
|
tabIndex: PropTypes.number,
|
||||||
|
isDisabled: PropTypes.bool,
|
||||||
|
className: PropTypes.string,
|
||||||
|
id: PropTypes.string,
|
||||||
|
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
$iconOptions: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
FacebookButton.defaultProps = {
|
||||||
|
tabIndex: -1,
|
||||||
|
isDisabled: false,
|
||||||
|
$iconOptions: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FacebookButton;
|
@ -0,0 +1,77 @@
|
|||||||
|
import React from "react";
|
||||||
|
import styled, { css } from "styled-components";
|
||||||
|
import Base from "../themes/base";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const ButtonWrapper = ({ label, iconName, isDisabled, noHover, ...props }) => (
|
||||||
|
<button type="button" {...props}></button>
|
||||||
|
);
|
||||||
|
|
||||||
|
ButtonWrapper.propTypes = {
|
||||||
|
label: PropTypes.string,
|
||||||
|
iconName: PropTypes.string,
|
||||||
|
tabIndex: PropTypes.number,
|
||||||
|
isDisabled: PropTypes.bool,
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
$iconOptions: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledFacebookButton = styled(ButtonWrapper).attrs((props) => ({
|
||||||
|
disabled: props.isDisabled ? "disabled" : "",
|
||||||
|
tabIndex: props.tabIndex,
|
||||||
|
}))`
|
||||||
|
border: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #1877f2;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 100%;
|
||||||
|
${(props) => !props.noHover && "cursor: pointer;"}
|
||||||
|
padding: 0;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
touch-callout: none;
|
||||||
|
-o-touch-callout: none;
|
||||||
|
-moz-touch-callout: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
margin: 11px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
min-width: 18px;
|
||||||
|
min-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
${(props) =>
|
||||||
|
props.$iconOptions &&
|
||||||
|
props.$iconOptions.color &&
|
||||||
|
css`
|
||||||
|
svg {
|
||||||
|
path {
|
||||||
|
fill: ${props.$iconOptions.color};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
|
||||||
|
.iconWrapper {
|
||||||
|
display: flex;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social_button_text {
|
||||||
|
pointer-events: none;
|
||||||
|
font-family: Roboto, "Open Sans", sans-serif, Arial;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 14px;
|
||||||
|
color: #1877f2;
|
||||||
|
margin: 0 11px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
StyledFacebookButton.defaultProps = { theme: Base };
|
||||||
|
|
||||||
|
export default StyledFacebookButton;
|
@ -13,10 +13,10 @@ class SocialButton extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { label, iconName } = this.props;
|
const { label, iconName, ...otherProps } = this.props;
|
||||||
return (
|
return (
|
||||||
<StyledSocialButton {...this.props}>
|
<StyledSocialButton {...otherProps}>
|
||||||
<ReactSVG src={iconName} />
|
<ReactSVG className="iconWrapper" src={iconName} />
|
||||||
{label && (
|
{label && (
|
||||||
<Text as="span" className="social_button_text">
|
<Text as="span" className="social_button_text">
|
||||||
{label}
|
{label}
|
||||||
@ -42,6 +42,8 @@ SocialButton.propTypes = {
|
|||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
/** Accepts css style */
|
/** Accepts css style */
|
||||||
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
$iconOptions: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
SocialButton.defaultProps = {
|
SocialButton.defaultProps = {
|
||||||
@ -49,6 +51,7 @@ SocialButton.defaultProps = {
|
|||||||
iconName: "SocialButtonGoogleIcon",
|
iconName: "SocialButtonGoogleIcon",
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
|
$iconOptions: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SocialButton;
|
export default SocialButton;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
import React from "react";
|
||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
import Base from "../themes/base";
|
import Base from "../themes/base";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
const ButtonWrapper = ({ label, iconName, isDisabled, ...props }) => (
|
const ButtonWrapper = ({ label, iconName, isDisabled, noHover, ...props }) => (
|
||||||
<button type="button" {...props}></button>
|
<button type="button" {...props}></button>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ ButtonWrapper.propTypes = {
|
|||||||
tabIndex: PropTypes.number,
|
tabIndex: PropTypes.number,
|
||||||
isDisabled: PropTypes.bool,
|
isDisabled: PropTypes.bool,
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
|
$iconOptions: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledSocialButton = styled(ButtonWrapper).attrs((props) => ({
|
const StyledSocialButton = styled(ButtonWrapper).attrs((props) => ({
|
||||||
@ -20,7 +22,8 @@ const StyledSocialButton = styled(ButtonWrapper).attrs((props) => ({
|
|||||||
}))`
|
}))`
|
||||||
font-family: ${(props) => props.theme.fontFamily};
|
font-family: ${(props) => props.theme.fontFamily};
|
||||||
border: none;
|
border: none;
|
||||||
display: inline-block;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
font-weight: ${(props) => props.theme.socialButton.fontWeight};
|
font-weight: ${(props) => props.theme.socialButton.fontWeight};
|
||||||
text-decoration: ${(props) => props.theme.socialButton.textDecoration};
|
text-decoration: ${(props) => props.theme.socialButton.textDecoration};
|
||||||
@ -42,6 +45,15 @@ const StyledSocialButton = styled(ButtonWrapper).attrs((props) => ({
|
|||||||
outline: ${(props) => props.theme.socialButton.outline};
|
outline: ${(props) => props.theme.socialButton.outline};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
${(props) =>
|
||||||
|
props.$iconOptions &&
|
||||||
|
props.$iconOptions.color &&
|
||||||
|
css`
|
||||||
|
svg path {
|
||||||
|
fill: ${props.$iconOptions.color};
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
|
||||||
${(props) =>
|
${(props) =>
|
||||||
!props.isDisabled
|
!props.isDisabled
|
||||||
? css`
|
? css`
|
||||||
@ -49,20 +61,27 @@ const StyledSocialButton = styled(ButtonWrapper).attrs((props) => ({
|
|||||||
box-shadow: ${(props) => props.theme.socialButton.boxShadow};
|
box-shadow: ${(props) => props.theme.socialButton.boxShadow};
|
||||||
color: ${(props) => props.theme.socialButton.color};
|
color: ${(props) => props.theme.socialButton.color};
|
||||||
|
|
||||||
|
${(props) =>
|
||||||
|
!props.noHover &&
|
||||||
|
css`
|
||||||
:hover,
|
:hover,
|
||||||
:active {
|
:active {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: ${(props) => props.theme.socialButton.hoverBoxShadow};
|
box-shadow: ${(props) =>
|
||||||
|
props.theme.socialButton.hoverBoxShadow};
|
||||||
}
|
}
|
||||||
|
|
||||||
:hover {
|
:hover {
|
||||||
background: ${(props) => props.theme.socialButton.hoverBackground};
|
background: ${(props) =>
|
||||||
|
props.theme.socialButton.hoverBackground};
|
||||||
}
|
}
|
||||||
|
|
||||||
:active {
|
:active {
|
||||||
background: ${(props) => props.theme.socialButton.activeBackground};
|
background: ${(props) =>
|
||||||
|
props.theme.socialButton.activeBackground};
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
`}
|
||||||
`
|
`
|
||||||
: css`
|
: css`
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -75,8 +94,14 @@ const StyledSocialButton = styled(ButtonWrapper).attrs((props) => ({
|
|||||||
}
|
}
|
||||||
`};
|
`};
|
||||||
|
|
||||||
|
.iconWrapper {
|
||||||
|
display: flex;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.social_button_text {
|
.social_button_text {
|
||||||
position: absolute;
|
position: relative;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
width: ${(props) => props.theme.socialButton.text.width};
|
width: ${(props) => props.theme.socialButton.text.width};
|
||||||
height: ${(props) => props.theme.socialButton.text.height};
|
height: ${(props) => props.theme.socialButton.text.height};
|
||||||
|
@ -213,14 +213,13 @@ const Base = {
|
|||||||
socialButton: {
|
socialButton: {
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
margin: "20px 0 0 20px",
|
|
||||||
padding: "0",
|
padding: "0",
|
||||||
borderRadius: "2px",
|
borderRadius: "2px",
|
||||||
width: "201px",
|
|
||||||
height: "40px",
|
height: "40px",
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
stroke: " none",
|
stroke: " none",
|
||||||
outline: "none",
|
outline: "none",
|
||||||
|
width: "100%",
|
||||||
|
|
||||||
background: white,
|
background: white,
|
||||||
disableBackgroundColor: "rgba(0, 0, 0, 0.08)",
|
disableBackgroundColor: "rgba(0, 0, 0, 0.08)",
|
||||||
@ -236,16 +235,17 @@ const Base = {
|
|||||||
disableColor: "rgba(0, 0, 0, 0.4)",
|
disableColor: "rgba(0, 0, 0, 0.4)",
|
||||||
|
|
||||||
text: {
|
text: {
|
||||||
width: "142px",
|
width: "100%",
|
||||||
height: "16px",
|
height: "16px",
|
||||||
margin: "12px 9px 12px 10px",
|
margin: "0 11px",
|
||||||
fontWeight: "500",
|
fontWeight: "600",
|
||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
lineHeight: "16px",
|
lineHeight: "14px",
|
||||||
letterSpacing: "0.21875px",
|
letterSpacing: "0.21875px",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
|
color: "#757575",
|
||||||
},
|
},
|
||||||
|
|
||||||
svg: {
|
svg: {
|
||||||
|
@ -129,6 +129,7 @@ const PureThirdPartyListContainer = ({
|
|||||||
openConnectWindow(data.title, authModal).then((modal) => {
|
openConnectWindow(data.title, authModal).then((modal) => {
|
||||||
redirectAction();
|
redirectAction();
|
||||||
getOAuthToken(modal).then((token) => {
|
getOAuthToken(modal).then((token) => {
|
||||||
|
authModal.close();
|
||||||
const serviceData = {
|
const serviceData = {
|
||||||
title: data.title,
|
title: data.title,
|
||||||
provider_key: data.title,
|
provider_key: data.title,
|
||||||
@ -216,6 +217,7 @@ const ThirdPartyList = withTranslation("Article")(
|
|||||||
export default inject(
|
export default inject(
|
||||||
({
|
({
|
||||||
filesStore,
|
filesStore,
|
||||||
|
auth,
|
||||||
settingsStore,
|
settingsStore,
|
||||||
treeFoldersStore,
|
treeFoldersStore,
|
||||||
selectedFolderStore,
|
selectedFolderStore,
|
||||||
@ -231,16 +233,16 @@ export default inject(
|
|||||||
oneDriveConnectItem,
|
oneDriveConnectItem,
|
||||||
nextCloudConnectItem,
|
nextCloudConnectItem,
|
||||||
webDavConnectItem,
|
webDavConnectItem,
|
||||||
getOAuthToken,
|
|
||||||
openConnectWindow,
|
openConnectWindow,
|
||||||
} = settingsStore.thirdPartyStore;
|
} = settingsStore.thirdPartyStore;
|
||||||
|
|
||||||
|
const { getOAuthToken } = auth.settingsStore;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setConnectItem,
|
setConnectItem,
|
||||||
setConnectDialogVisible,
|
setConnectDialogVisible,
|
||||||
setThirdPartyDialogVisible,
|
setThirdPartyDialogVisible,
|
||||||
} = dialogsStore;
|
} = dialogsStore;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
googleConnectItem,
|
googleConnectItem,
|
||||||
boxConnectItem,
|
boxConnectItem,
|
||||||
|
@ -185,7 +185,10 @@ const PureConnectDialogContainer = (props) => {
|
|||||||
const onReconnect = () => {
|
const onReconnect = () => {
|
||||||
let authModal = window.open("", "Authorization", "height=600, width=1020");
|
let authModal = window.open("", "Authorization", "height=600, width=1020");
|
||||||
openConnectWindow(title, authModal).then((modal) =>
|
openConnectWindow(title, authModal).then((modal) =>
|
||||||
getOAuthToken(modal).then((token) => setToken(token))
|
getOAuthToken(modal).then((token) => {
|
||||||
|
authModal.close();
|
||||||
|
setToken(token);
|
||||||
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -321,6 +324,7 @@ const ConnectDialog = withTranslation("ConnectDialog")(
|
|||||||
|
|
||||||
export default inject(
|
export default inject(
|
||||||
({
|
({
|
||||||
|
auth,
|
||||||
filesStore,
|
filesStore,
|
||||||
settingsStore,
|
settingsStore,
|
||||||
treeFoldersStore,
|
treeFoldersStore,
|
||||||
@ -329,12 +333,12 @@ export default inject(
|
|||||||
}) => {
|
}) => {
|
||||||
const {
|
const {
|
||||||
providers,
|
providers,
|
||||||
getOAuthToken,
|
|
||||||
saveThirdParty,
|
saveThirdParty,
|
||||||
openConnectWindow,
|
openConnectWindow,
|
||||||
fetchThirdPartyProviders,
|
fetchThirdPartyProviders,
|
||||||
} = settingsStore.thirdPartyStore;
|
} = settingsStore.thirdPartyStore;
|
||||||
const { fetchFiles } = filesStore;
|
const { fetchFiles } = filesStore;
|
||||||
|
const { getOAuthToken } = auth.settingsStore;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
treeFolders,
|
treeFolders,
|
||||||
|
@ -105,11 +105,13 @@ const ThirdPartyDialog = (props) => {
|
|||||||
);
|
);
|
||||||
openConnectWindow(item.title, authModal).then((modal) =>
|
openConnectWindow(item.title, authModal).then((modal) =>
|
||||||
getOAuthToken(modal).then((token) => {
|
getOAuthToken(modal).then((token) => {
|
||||||
|
authModal.close();
|
||||||
showOAuthModal(token, item);
|
showOAuthModal(token, item);
|
||||||
setConnectItem(item);
|
|
||||||
setConnectDialogVisible(true);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
setConnectItem(item);
|
||||||
|
setConnectDialogVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
setThirdPartyDialogVisible(false);
|
setThirdPartyDialogVisible(false);
|
||||||
@ -242,7 +244,6 @@ export default inject(({ auth, settingsStore, dialogsStore }) => {
|
|||||||
ownCloudConnectItem,
|
ownCloudConnectItem,
|
||||||
webDavConnectItem,
|
webDavConnectItem,
|
||||||
sharePointConnectItem,
|
sharePointConnectItem,
|
||||||
getOAuthToken,
|
|
||||||
openConnectWindow,
|
openConnectWindow,
|
||||||
} = settingsStore.thirdPartyStore;
|
} = settingsStore.thirdPartyStore;
|
||||||
const {
|
const {
|
||||||
@ -251,6 +252,7 @@ export default inject(({ auth, settingsStore, dialogsStore }) => {
|
|||||||
setConnectDialogVisible,
|
setConnectDialogVisible,
|
||||||
setConnectItem,
|
setConnectItem,
|
||||||
} = dialogsStore;
|
} = dialogsStore;
|
||||||
|
const { getOAuthToken } = auth.settingsStore;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
visible,
|
visible,
|
||||||
|
@ -25,7 +25,6 @@ class ThirdPartyStore {
|
|||||||
setThirdPartyCapabilities: action,
|
setThirdPartyCapabilities: action,
|
||||||
fetchThirdPartyProviders: action,
|
fetchThirdPartyProviders: action,
|
||||||
deleteThirdParty: action,
|
deleteThirdParty: action,
|
||||||
getOAuthToken: action,
|
|
||||||
openConnectWindow: action,
|
openConnectWindow: action,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -66,25 +65,6 @@ class ThirdPartyStore {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
getOAuthToken = () => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
localStorage.removeItem("code");
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
try {
|
|
||||||
const code = localStorage.getItem("code");
|
|
||||||
|
|
||||||
if (code) {
|
|
||||||
localStorage.removeItem("code");
|
|
||||||
clearInterval(interval);
|
|
||||||
resolve(code);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
convertServiceName = (serviceName) => {
|
convertServiceName = (serviceName) => {
|
||||||
//Docusign, OneDrive, Wordpress
|
//Docusign, OneDrive, Wordpress
|
||||||
switch (serviceName) {
|
switch (serviceName) {
|
||||||
|
@ -1,3 +1,22 @@
|
|||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<?xml version="1.0" standalone="no"?>
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 0H2C0.897 0 0 0.897 0 2V14C0 15.103 0.897 16 2 16H8V10.1848H5.81641V8H8V5.90666C8 4.24966 9.343 2.90666 11 2.90666H13.0877V5.09417H11.912C11.36 5.09417 10.912 5.26478 10.912 5.81678V8H13.5L12.5 10.1848H10.912V16H14C15.103 16 16 15.103 16 14V2C16 0.897 15.103 0 14 0Z" fill="#333333"/>
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
<metadata>
|
||||||
|
Created by potrace 1.16, written by Peter Selinger 2001-2019
|
||||||
|
</metadata>
|
||||||
|
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M2255 5108 c-105 -12 -298 -51 -409 -83 -994 -288 -1724 -1155 -1835
|
||||||
|
-2177 -14 -125 -14 -451 0 -576 99 -919 703 -1723 1562 -2081 170 -71 487
|
||||||
|
-161 566 -161 l21 0 0 895 0 895 -325 0 -325 0 0 370 0 370 325 0 325 0 0 359
|
||||||
|
c0 397 6 462 61 617 107 305 331 497 659 564 94 20 128 21 325 17 184 -4 433
|
||||||
|
-26 483 -42 9 -3 12 -76 12 -318 l0 -314 -212 -6 c-263 -7 -317 -20 -402 -98
|
||||||
|
-108 -99 -126 -176 -126 -556 l0 -223 355 0 c312 0 355 -2 355 -15 0 -17 -96
|
||||||
|
-652 -106 -698 l-6 -27 -299 0 -299 0 0 -895 0 -895 21 0 c79 0 396 90 566
|
||||||
|
161 859 358 1463 1162 1562 2081 14 125 14 451 0 576 -128 1181 -1080 2133
|
||||||
|
-2261 2261 -115 13 -479 12 -593 -1z"/>
|
||||||
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,6 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.64 9.20419C17.64 8.56601 17.5827 7.95237 17.4764 7.36328H9V10.8446H13.8436C13.635 11.9696 13.0009 12.9228 12.0477 13.561V15.8192H14.9564C16.6582 14.2524 17.64 11.9451 17.64 9.20419Z" fill="#4285F4"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 18.0009C11.43 18.0009 13.4673 17.195 14.9564 15.8205L12.0477 13.5623C11.2418 14.1023 10.2109 14.4214 9 14.4214C6.65591 14.4214 4.67182 12.8382 3.96409 10.7109H0.957275V13.0428C2.43818 15.9841 5.48182 18.0009 9 18.0009Z" fill="#34A853"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.96409 10.7088C3.78409 10.1688 3.68182 9.59203 3.68182 8.99885C3.68182 8.40567 3.78409 7.82885 3.96409 7.28885V4.95703H0.957273C0.347727 6.17203 0 7.54658 0 8.99885C0 10.4511 0.347727 11.8257 0.957273 13.0407L3.96409 10.7088Z" fill="#FBBC05"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9 3.57955C10.3214 3.57955 11.5077 4.03364 12.4405 4.92545L15.0218 2.34409C13.4632 0.891818 11.4259 0 9 0C5.48182 0 2.43818 2.01682 0.957275 4.95818L3.96409 7.29C4.67182 5.16273 6.65591 3.57955 9 3.57955Z" fill="#EA4335"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.75036 8.05344C9.74586 8.06301 9.73967 8.07201 9.73292 8.08044H9.75036V8.05344Z" fill="#1276B3"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.25 0C1.00736 0 0 1.00736 0 2.25V15.75C0 16.9926 1.00736 18 2.25 18H15.75C16.9926 18 18 16.9926 18 15.75V2.25C18 1.00736 16.9926 0 15.75 0H2.25ZM2.89855 6.91044H5.5828V14.9846H2.89855V6.91044ZM4.25755 3.01794C5.17611 3.01794 5.74142 3.62094 5.7583 4.41407C5.7583 5.18751 5.17611 5.80851 4.24011 5.80851H4.22267C3.32211 5.80851 2.73992 5.18751 2.73992 4.41407C2.73992 3.62094 3.34011 3.01794 4.25755 3.01794ZM12.1697 6.72144C13.9354 6.72144 15.26 7.87513 15.26 10.3546L15.2595 14.9846H12.5758V10.6646C12.5758 9.57782 12.1882 8.83869 11.2157 8.83869C10.4754 8.83869 10.0333 9.34044 9.83867 9.82082C9.7678 9.99463 9.75036 10.2314 9.75036 10.4756V14.9846H7.06723C7.06723 14.9846 7.10155 7.66757 7.06723 6.91044H9.75036V8.05344C10.1087 7.50388 10.746 6.72144 12.1697 6.72144Z" fill="#1276B3"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.0 KiB |
@ -48,5 +48,16 @@
|
|||||||
"selectNewPhotoLabel": "Select new photo",
|
"selectNewPhotoLabel": "Select new photo",
|
||||||
"orDropFileHereLabel": "or drop file here",
|
"orDropFileHereLabel": "or drop file here",
|
||||||
"maxSizeFileError": "Maximum file size exceeded",
|
"maxSizeFileError": "Maximum file size exceeded",
|
||||||
"editAvatar": "Edit"
|
"editAvatar": "Edit",
|
||||||
|
|
||||||
|
"LoginSettings": "Login settings",
|
||||||
|
"SignInWithGoogle": "Sign in with Google",
|
||||||
|
"SignInWithFacebook": "Sign in with Facebook",
|
||||||
|
"SignInWithTwitter": "Sign in with Twitter",
|
||||||
|
"SignInWithLinkedIn": "Sign in with LinkedIn",
|
||||||
|
"Connect": "Connect",
|
||||||
|
"Disconnect": "Disconnect",
|
||||||
|
|
||||||
|
"ProviderSuccessfullyConnected": "Provider successfully connected",
|
||||||
|
"ProviderSuccessfullyDisconnected": "Provider successfully disconnected"
|
||||||
}
|
}
|
||||||
|
@ -48,5 +48,16 @@
|
|||||||
"selectNewPhotoLabel": "Выбрать новое фото",
|
"selectNewPhotoLabel": "Выбрать новое фото",
|
||||||
"orDropFileHereLabel": "или перетащите файл сюда",
|
"orDropFileHereLabel": "или перетащите файл сюда",
|
||||||
"maxSizeFileError": "Превышен максимальный размер файла",
|
"maxSizeFileError": "Превышен максимальный размер файла",
|
||||||
"editAvatar": "Изменить"
|
"editAvatar": "Изменить",
|
||||||
|
|
||||||
|
"LoginSettings": "Вход через социальные сети",
|
||||||
|
"SignInWithGoogle": "Вход через Google",
|
||||||
|
"SignInWithFacebook": "Вход через Facebook",
|
||||||
|
"SignInWithTwitter": "Вход через Twitter",
|
||||||
|
"SignInWithLinkedIn": "Вход через LinkedIn",
|
||||||
|
"Connect": "Подключить",
|
||||||
|
"Disconnect": "Отключить",
|
||||||
|
|
||||||
|
"ProviderSuccessfullyConnected": "Провайдер успешно подключен",
|
||||||
|
"ProviderSuccessfullyDisconnected": "Провайдер успешно отключен"
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@ import Avatar from "@appserver/components/avatar";
|
|||||||
import Button from "@appserver/components/button";
|
import Button from "@appserver/components/button";
|
||||||
import IconButton from "@appserver/components/icon-button";
|
import IconButton from "@appserver/components/icon-button";
|
||||||
import Text from "@appserver/components/text";
|
import Text from "@appserver/components/text";
|
||||||
|
import SocialButton from "@appserver/components/social-button";
|
||||||
|
import FacebookButton from "@appserver/components/facebook-button";
|
||||||
import ToggleContent from "@appserver/components/toggle-content";
|
import ToggleContent from "@appserver/components/toggle-content";
|
||||||
import Link from "@appserver/components/link";
|
import Link from "@appserver/components/link";
|
||||||
import ProfileInfo from "./ProfileInfo/ProfileInfo";
|
import ProfileInfo from "./ProfileInfo/ProfileInfo";
|
||||||
|
import toastr from "studio/toastr";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { combineUrl, isMe } from "@appserver/common/utils";
|
import { combineUrl, isMe } from "@appserver/common/utils";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
@ -17,7 +20,9 @@ import {
|
|||||||
getUserRole,
|
getUserRole,
|
||||||
} from "../../../../helpers/people-helpers";
|
} from "../../../../helpers/people-helpers";
|
||||||
import config from "../../../../../package.json";
|
import config from "../../../../../package.json";
|
||||||
import { AppServerConfig } from "@appserver/common/constants";
|
import { AppServerConfig, providersData } from "@appserver/common/constants";
|
||||||
|
import { unlinkOAuth, linkOAuth } from "@appserver/common/api/people";
|
||||||
|
import { getAuthProviders } from "@appserver/common/api/settings";
|
||||||
|
|
||||||
const ProfileWrapper = styled.div`
|
const ProfileWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -59,6 +64,13 @@ const ContactWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const ProviderButtonsWrapper = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-gap: 16px 22px;
|
||||||
|
`;
|
||||||
|
|
||||||
const createContacts = (contacts) => {
|
const createContacts = (contacts) => {
|
||||||
const styledContacts = contacts.map((contact, index) => {
|
const styledContacts = contacts.map((contact, index) => {
|
||||||
let url = null;
|
let url = null;
|
||||||
@ -88,12 +100,30 @@ const stringFormat = (string, data) =>
|
|||||||
string.replace(/\{(\d+)\}/g, (m, n) => data[n] || m);
|
string.replace(/\{(\d+)\}/g, (m, n) => data[n] || m);
|
||||||
|
|
||||||
class SectionBodyContent extends React.PureComponent {
|
class SectionBodyContent extends React.PureComponent {
|
||||||
componentDidMount() {
|
async componentDidMount() {
|
||||||
const { cultures, getPortalCultures, profile, viewer, isSelf } = this.props;
|
const {
|
||||||
|
cultures,
|
||||||
|
getPortalCultures,
|
||||||
|
profile,
|
||||||
|
viewer,
|
||||||
|
isSelf,
|
||||||
|
setProviders,
|
||||||
|
} = this.props;
|
||||||
//const isSelf = isMe(viewer, profile.userName);
|
//const isSelf = isMe(viewer, profile.userName);
|
||||||
if (isSelf && !cultures.length) {
|
if (isSelf && !cultures.length) {
|
||||||
getPortalCultures();
|
getPortalCultures();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isSelf) return;
|
||||||
|
try {
|
||||||
|
await getAuthProviders().then((providers) => {
|
||||||
|
setProviders(providers);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.loginCallback = this.loginCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
onEditSubscriptionsClick = () => console.log("Edit subscriptions onClick()");
|
onEditSubscriptionsClick = () => console.log("Edit subscriptions onClick()");
|
||||||
@ -110,6 +140,113 @@ class SectionBodyContent extends React.PureComponent {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
loginCallback = (profile) => {
|
||||||
|
const { setProviders, t } = this.props;
|
||||||
|
linkOAuth(profile.Serialized).then((resp) => {
|
||||||
|
getAuthProviders().then((providers) => {
|
||||||
|
setProviders(providers);
|
||||||
|
toastr.success(t("ProviderSuccessfullyConnected"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
unlinkAccount = (providerName) => {
|
||||||
|
const { setProviders, t } = this.props;
|
||||||
|
unlinkOAuth(providerName).then(() => {
|
||||||
|
getAuthProviders().then((providers) => {
|
||||||
|
setProviders(providers);
|
||||||
|
toastr.success(t("ProviderSuccessfullyDisconnected"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
linkAccount = (providerName, link, e) => {
|
||||||
|
const { getOAuthToken, getLoginLink } = this.props;
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tokenGetterWin = window.open(
|
||||||
|
link,
|
||||||
|
"login",
|
||||||
|
"width=800,height=500,status=no,toolbar=no,menubar=no,resizable=yes,scrollbars=no"
|
||||||
|
);
|
||||||
|
|
||||||
|
getOAuthToken(tokenGetterWin).then((code) => {
|
||||||
|
const token = window.btoa(
|
||||||
|
JSON.stringify({
|
||||||
|
auth: providerName,
|
||||||
|
mode: "popup",
|
||||||
|
callback: "loginCallback",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
tokenGetterWin.location.href = getLoginLink(token, code);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
providerButtons = () => {
|
||||||
|
const { t, providers } = this.props;
|
||||||
|
|
||||||
|
const providerButtons =
|
||||||
|
providers &&
|
||||||
|
providers.map((item) => {
|
||||||
|
const { icon, label, iconOptions } = providersData[item.provider];
|
||||||
|
|
||||||
|
if (!icon || !label) return <React.Fragment></React.Fragment>;
|
||||||
|
return (
|
||||||
|
<React.Fragment key={`${item.provider}ProviderItem`}>
|
||||||
|
<div>
|
||||||
|
{item.provider === "Facebook" ? (
|
||||||
|
<FacebookButton
|
||||||
|
noHover={true}
|
||||||
|
iconName={icon}
|
||||||
|
label={t(label)}
|
||||||
|
className="socialButton"
|
||||||
|
$iconOptions={iconOptions}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<SocialButton
|
||||||
|
noHover={true}
|
||||||
|
iconName={icon}
|
||||||
|
label={t(label)}
|
||||||
|
className="socialButton"
|
||||||
|
$iconOptions={iconOptions}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{item.linked ? (
|
||||||
|
<div>
|
||||||
|
<Link
|
||||||
|
type="action"
|
||||||
|
color="A3A9AE"
|
||||||
|
onClick={(e) => this.unlinkAccount(item.provider, e)}
|
||||||
|
isHovered={true}
|
||||||
|
>
|
||||||
|
{t("Disconnect")}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<Link
|
||||||
|
type="action"
|
||||||
|
color="A3A9AE"
|
||||||
|
onClick={(e) => this.linkAccount(item.provider, item.url, e)}
|
||||||
|
isHovered={true}
|
||||||
|
>
|
||||||
|
{t("Connect")}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return providerButtons;
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
profile,
|
profile,
|
||||||
@ -119,6 +256,7 @@ class SectionBodyContent extends React.PureComponent {
|
|||||||
viewer,
|
viewer,
|
||||||
t,
|
t,
|
||||||
isSelf,
|
isSelf,
|
||||||
|
providers,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const contacts = profile.contacts && getUserContacts(profile.contacts);
|
const contacts = profile.contacts && getUserContacts(profile.contacts);
|
||||||
@ -161,6 +299,16 @@ class SectionBodyContent extends React.PureComponent {
|
|||||||
cultures={cultures}
|
cultures={cultures}
|
||||||
culture={culture}
|
culture={culture}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{isSelf && providers && providers.length > 0 && (
|
||||||
|
<ToggleWrapper>
|
||||||
|
<ToggleContent label={t("LoginSettings")} isOpen={true}>
|
||||||
|
<ProviderButtonsWrapper>
|
||||||
|
{this.providerButtons()}
|
||||||
|
</ProviderButtonsWrapper>
|
||||||
|
</ToggleContent>
|
||||||
|
</ToggleWrapper>
|
||||||
|
)}
|
||||||
{isSelf && false && (
|
{isSelf && false && (
|
||||||
<ToggleWrapper isSelf={true}>
|
<ToggleWrapper isSelf={true}>
|
||||||
<ToggleContent label={t("Subscriptions")} isOpen={true}>
|
<ToggleContent label={t("Subscriptions")} isOpen={true}>
|
||||||
@ -213,5 +361,9 @@ export default withRouter(
|
|||||||
isSelf: peopleStore.targetUserStore.isMe,
|
isSelf: peopleStore.targetUserStore.isMe,
|
||||||
avatarMax: peopleStore.avatarEditorStore.avatarMax,
|
avatarMax: peopleStore.avatarEditorStore.avatarMax,
|
||||||
setAvatarMax: peopleStore.avatarEditorStore.setAvatarMax,
|
setAvatarMax: peopleStore.avatarEditorStore.setAvatarMax,
|
||||||
|
providers: peopleStore.usersStore.providers,
|
||||||
|
setProviders: peopleStore.usersStore.setProviders,
|
||||||
|
getOAuthToken: auth.settingsStore.getOAuthToken,
|
||||||
|
getLoginLink: auth.settingsStore.getLoginLink,
|
||||||
}))(observer(withTranslation("Profile")(SectionBodyContent)))
|
}))(observer(withTranslation("Profile")(SectionBodyContent)))
|
||||||
);
|
);
|
||||||
|
@ -927,5 +927,6 @@ export default withRouter(
|
|||||||
updateProfile: peopleStore.targetUserStore.updateProfile,
|
updateProfile: peopleStore.targetUserStore.updateProfile,
|
||||||
getUserPhoto: peopleStore.targetUserStore.getUserPhoto,
|
getUserPhoto: peopleStore.targetUserStore.getUserPhoto,
|
||||||
disableProfileType: peopleStore.targetUserStore.getDisableProfileType,
|
disableProfileType: peopleStore.targetUserStore.getDisableProfileType,
|
||||||
|
isSelf: peopleStore.targetUserStore.isMe,
|
||||||
}))(observer(withTranslation("ProfileAction")(UpdateUserForm)))
|
}))(observer(withTranslation("ProfileAction")(UpdateUserForm)))
|
||||||
);
|
);
|
||||||
|
@ -2,6 +2,9 @@ import React from "react";
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import PageLayout from "@appserver/common/components/PageLayout";
|
import PageLayout from "@appserver/common/components/PageLayout";
|
||||||
import Loaders from "@appserver/common/components/Loaders";
|
import Loaders from "@appserver/common/components/Loaders";
|
||||||
|
import toastr from "studio/toastr";
|
||||||
|
import { linkOAuth } from "@appserver/common/api/people";
|
||||||
|
import { getAuthProviders } from "@appserver/common/api/settings";
|
||||||
import {
|
import {
|
||||||
ArticleHeaderContent,
|
ArticleHeaderContent,
|
||||||
ArticleMainButtonContent,
|
ArticleMainButtonContent,
|
||||||
@ -118,6 +121,7 @@ ProfileAction.propTypes = {
|
|||||||
|
|
||||||
export default withRouter(
|
export default withRouter(
|
||||||
inject(({ auth, peopleStore }) => ({
|
inject(({ auth, peopleStore }) => ({
|
||||||
|
setProviders: peopleStore.usersStore.setProviders,
|
||||||
setDocumentTitle: auth.setDocumentTitle,
|
setDocumentTitle: auth.setDocumentTitle,
|
||||||
isEdit: peopleStore.editingFormStore.isEdit,
|
isEdit: peopleStore.editingFormStore.isEdit,
|
||||||
setIsEditingForm: peopleStore.editingFormStore.setIsEditingForm,
|
setIsEditingForm: peopleStore.editingFormStore.setIsEditingForm,
|
||||||
|
@ -10,13 +10,16 @@ import store from "studio/store";
|
|||||||
const { auth: authStore } = store;
|
const { auth: authStore } = store;
|
||||||
class UsersStore {
|
class UsersStore {
|
||||||
users = [];
|
users = [];
|
||||||
|
providers = [];
|
||||||
|
|
||||||
constructor(peopleStore) {
|
constructor(peopleStore) {
|
||||||
this.peopleStore = peopleStore;
|
this.peopleStore = peopleStore;
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
users: observable,
|
users: observable,
|
||||||
|
providers: observable,
|
||||||
getUsersList: action,
|
getUsersList: action,
|
||||||
setUsers: action,
|
setUsers: action,
|
||||||
|
setProviders: action,
|
||||||
createUser: action,
|
createUser: action,
|
||||||
removeUser: action,
|
removeUser: action,
|
||||||
updateUserStatus: action,
|
updateUserStatus: action,
|
||||||
@ -52,6 +55,10 @@ class UsersStore {
|
|||||||
this.users = users;
|
this.users = users;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
setProviders = (providers) => {
|
||||||
|
this.providers = providers;
|
||||||
|
};
|
||||||
|
|
||||||
employeeWrapperToMemberModel = (profile) => {
|
employeeWrapperToMemberModel = (profile) => {
|
||||||
const comment = profile.notes;
|
const comment = profile.notes;
|
||||||
const department = profile.groups
|
const department = profile.groups
|
||||||
|
@ -1528,17 +1528,17 @@ namespace ASC.Employee.Core.Controllers
|
|||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Create("thirdparty/signup")]
|
[Create("thirdparty/signup")]
|
||||||
public void SignupAccountFromBody([FromBody] LinkAccountModel model)
|
public void SignupAccountFromBody([FromBody] SignupAccountModel model)
|
||||||
{
|
{
|
||||||
LinkAccount(model);
|
SignupAccount(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
[Update("thirdparty/linkaccount")]
|
[Create("thirdparty/signup")]
|
||||||
[Consumes("application/x-www-form-urlencoded")]
|
[Consumes("application/x-www-form-urlencoded")]
|
||||||
public void SignupAccountFromForm([FromForm] LinkAccountModel model)
|
public void SignupAccountFromForm([FromForm] SignupAccountModel model)
|
||||||
{
|
{
|
||||||
LinkAccount(model);
|
SignupAccount(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SignupAccount(SignupAccountModel model)
|
public void SignupAccount(SignupAccountModel model)
|
||||||
@ -1554,18 +1554,41 @@ namespace ASC.Employee.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
var thirdPartyProfile = new LoginProfile(Signature, InstanceCrypto, model.SerializedProfile);
|
var thirdPartyProfile = new LoginProfile(Signature, InstanceCrypto, model.SerializedProfile);
|
||||||
|
if (!string.IsNullOrEmpty(thirdPartyProfile.AuthorizationError))
|
||||||
|
{
|
||||||
|
// ignore cancellation
|
||||||
|
if (thirdPartyProfile.AuthorizationError != "Canceled at provider")
|
||||||
|
throw new Exception(thirdPartyProfile.AuthorizationError);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(thirdPartyProfile.EMail))
|
||||||
|
{
|
||||||
|
throw new Exception(Resource.ErrorNotCorrectEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
var userID = Guid.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);
|
||||||
var newUser = CreateNewUser(GetFirstName(model, thirdPartyProfile), GetLastName(model, thirdPartyProfile), GetEmailAddress(model, thirdPartyProfile), passwordHash, employeeType, false);
|
var newUser = CreateNewUser(GetFirstName(model, thirdPartyProfile), GetLastName(model, thirdPartyProfile), GetEmailAddress(model, thirdPartyProfile), passwordHash, employeeType, false);
|
||||||
|
|
||||||
var messageAction = employeeType == EmployeeType.User ? MessageAction.UserCreatedViaInvite : MessageAction.GuestCreatedViaInvite;
|
var messageAction = employeeType == EmployeeType.User ? MessageAction.UserCreatedViaInvite : MessageAction.GuestCreatedViaInvite;
|
||||||
MessageService.Send(MessageInitiator.System, messageAction, MessageTarget.Create(newUser.ID), newUser.DisplayUserName(false, DisplayUserSettingsHelper));
|
MessageService.Send(MessageInitiator.System, messageAction, MessageTarget.Create(newUser.ID), newUser.DisplayUserName(false, DisplayUserSettingsHelper));
|
||||||
|
|
||||||
var userID = newUser.ID;
|
userID = newUser.ID;
|
||||||
if (!string.IsNullOrEmpty(thirdPartyProfile.Avatar))
|
if (!string.IsNullOrEmpty(thirdPartyProfile.Avatar))
|
||||||
{
|
{
|
||||||
SaveContactImage(userID, thirdPartyProfile.Avatar);
|
SaveContactImage(userID, thirdPartyProfile.Avatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetLinker().AddLink(userID.ToString(), thirdPartyProfile);
|
GetLinker().AddLink(userID.ToString(), thirdPartyProfile);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SecurityContext.Logout();
|
||||||
|
}
|
||||||
|
|
||||||
var user = UserManager.GetUsers(userID);
|
var user = UserManager.GetUsers(userID);
|
||||||
var cookiesKey = SecurityContext.AuthenticateMe(user.Email, passwordHash);
|
var cookiesKey = SecurityContext.AuthenticateMe(user.Email, passwordHash);
|
||||||
@ -1581,6 +1604,7 @@ namespace ASC.Employee.Core.Controllers
|
|||||||
UserHelpTourHelper.IsNewUser = true;
|
UserHelpTourHelper.IsNewUser = true;
|
||||||
if (CoreBaseSettings.Personal)
|
if (CoreBaseSettings.Personal)
|
||||||
PersonalSettingsHelper.IsNewUser = true;
|
PersonalSettingsHelper.IsNewUser = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Create("phone")]
|
[Create("phone")]
|
||||||
|
BIN
public/images/clouds.png
Normal file
After Width: | Height: | Size: 21 KiB |
4
public/images/share.facebook.react.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9 0C6.61305 0 4.32387 0.948211 2.63604 2.63604C0.948211 4.32387 0 6.61305 0 9C0 11.3869 0.948211 13.6761 2.63604 15.364C4.32387 17.0518 6.61305 18 9 18C11.3869 18 13.6761 17.0518 15.364 15.364C17.0518 13.6761 18 11.3869 18 9C18 6.61305 17.0518 4.32387 15.364 2.63604C13.6761 0.948211 11.3869 0 9 0Z" fill="#1877F2"/>
|
||||||
|
<path d="M10.1047 11.5264H12.5862L12.9758 9.21077H10.1042V7.94516C10.1042 6.98321 10.4464 6.1302 11.4259 6.1302H13V4.10941C12.7234 4.0751 12.1385 4 11.0333 4C8.72546 4 7.37245 5.11957 7.37245 7.67025V9.21077H5V11.5264H7.37245V17.8911C7.84229 17.956 8.31819 18 8.80671 18C9.2483 18 9.67928 17.9629 10.1047 17.9101V11.5264Z" fill="white"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 768 B |
3
public/images/share.twitter.react.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.4 0H1.6C0.72 0 0 0.72 0 1.6V14.4C0 15.28 0.72 16 1.6 16H14.4C15.28 16 16 15.28 16 14.4V1.6C16 0.72 15.28 0 14.4 0ZM12.56 5.84C12.48 9.52 10.16 12.08 6.64 12.24C5.2 12.32 4.16 11.84 3.2 11.28C4.24 11.44 5.6 11.04 6.32 10.4C5.28 10.32 4.64 9.76 4.32 8.88C4.64 8.96 4.96 8.88 5.2 8.88C4.24 8.56 3.6 8 3.52 6.72C3.76 6.88 4.08 6.96 4.4 6.96C3.68 6.56 3.2 5.04 3.76 4.08C4.8 5.2 6.08 6.16 8.16 6.32C7.6 4.08 10.64 2.88 11.84 4.4C12.4 4.32 12.8 4.08 13.2 3.92C13.04 4.48 12.72 4.8 12.32 5.12C12.72 5.04 13.12 4.96 13.44 4.8C13.36 5.2 12.96 5.52 12.56 5.84Z" fill="#333333"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 725 B |
85
public/thirdparty/third-party.html
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="favicon.ico" />
|
||||||
|
|
||||||
|
<title>Third party</title>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
#third-party-body {
|
||||||
|
cursor: default;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 36px 36px 0 36px;
|
||||||
|
border: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-family: "Open Sans", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
position: relative;
|
||||||
|
margin: 12px 0 60px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
max-width: 560px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
function getObjectByLocation(location) {
|
||||||
|
if (!location.search || !location.search.length) return null;
|
||||||
|
|
||||||
|
const searchUrl = location.search.substring(1);
|
||||||
|
const object = JSON.parse(
|
||||||
|
'{"' +
|
||||||
|
decodeURIComponent(searchUrl)
|
||||||
|
.replace(/"/g, '\\"')
|
||||||
|
.replace(/&/g, '","')
|
||||||
|
.replace(/=/g, '":"') +
|
||||||
|
'"}'
|
||||||
|
);
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderError(error) {
|
||||||
|
var container = document.getElementById("container");
|
||||||
|
container.innerHTML = `<img src="/static/images/clouds.png" /><p class="text">${error}</p>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlParams = getObjectByLocation(window.location);
|
||||||
|
const code = urlParams ? urlParams.code || null : null;
|
||||||
|
const error = urlParams ? urlParams.error || null : null;
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="third-party-body">
|
||||||
|
<div id="container"></div>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
if (code) {
|
||||||
|
localStorage.setItem("code", code);
|
||||||
|
} else if (error) {
|
||||||
|
renderError(error);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</html>
|
@ -26,5 +26,12 @@
|
|||||||
"ConfirmOwnerPortalTitle": "Please confirm that you want to change portal owner to {{newOwner}}",
|
"ConfirmOwnerPortalTitle": "Please confirm that you want to change portal owner to {{newOwner}}",
|
||||||
"SaveButton": "Save",
|
"SaveButton": "Save",
|
||||||
"CancelButton": "Cancel",
|
"CancelButton": "Cancel",
|
||||||
"ConfirmOwnerPortalSuccessMessage": "Portal owner has been successfully changed. {0}In 10 seconds you will be redirected {1}here{2}"
|
"ConfirmOwnerPortalSuccessMessage": "Portal owner has been successfully changed. {0}In 10 seconds you will be redirected {1}here{2}",
|
||||||
|
|
||||||
|
"SignInWithGoogle": "Sign in with Google",
|
||||||
|
"SignInWithFacebook": "Sign in with Facebook",
|
||||||
|
"SignInWithTwitter": "Sign in with Twitter",
|
||||||
|
"SignInWithLinkedIn": "Sign in with LinkedIn",
|
||||||
|
"ProviderLoginError": "Authorization error",
|
||||||
|
"ProviderNotConnected": "Provider is not connected to your account"
|
||||||
}
|
}
|
||||||
|
@ -21,5 +21,12 @@
|
|||||||
"ConfirmOwnerPortalTitle": "Пожалуйста, подтвердите, что Вы хотите изменить владельца портала на {{newOwner}}",
|
"ConfirmOwnerPortalTitle": "Пожалуйста, подтвердите, что Вы хотите изменить владельца портала на {{newOwner}}",
|
||||||
"SaveButton": "Сохранить",
|
"SaveButton": "Сохранить",
|
||||||
"CancelButton": "Отмена",
|
"CancelButton": "Отмена",
|
||||||
"ConfirmOwnerPortalSuccessMessage": "Portal owner has been successfully changed. {0}In 10 seconds you will be redirected {1}here{2}"
|
"ConfirmOwnerPortalSuccessMessage": "Portal owner has been successfully changed. {0}In 10 seconds you will be redirected {1}here{2}",
|
||||||
|
|
||||||
|
"SignInWithGoogle": "Вход через Google",
|
||||||
|
"SignInWithFacebook": "Вход через Facebook",
|
||||||
|
"SignInWithTwitter": "Вход через Twitter",
|
||||||
|
"SignInWithLinkedIn": "Вход через LinkedIn",
|
||||||
|
"ProviderLoginError": "Ошибка авторизации",
|
||||||
|
"ProviderNotConnected": "Провайдер не подключен к вашему аккаунту"
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,6 @@ const COMING_SOON_URLS = [
|
|||||||
//combineUrl(PROXY_HOMEPAGE_URL, "/products/calendar"),
|
//combineUrl(PROXY_HOMEPAGE_URL, "/products/calendar"),
|
||||||
//combineUrl(PROXY_HOMEPAGE_URL, "/products/talk/"),
|
//combineUrl(PROXY_HOMEPAGE_URL, "/products/talk/"),
|
||||||
];
|
];
|
||||||
const THIRD_PARTY_RESPONSE_URL = combineUrl(
|
|
||||||
PROXY_HOMEPAGE_URL,
|
|
||||||
"/thirdparty/:provider"
|
|
||||||
);
|
|
||||||
const PAYMENTS_URL = combineUrl(PROXY_HOMEPAGE_URL, "/payments");
|
const PAYMENTS_URL = combineUrl(PROXY_HOMEPAGE_URL, "/payments");
|
||||||
const SETTINGS_URL = combineUrl(PROXY_HOMEPAGE_URL, "/settings");
|
const SETTINGS_URL = combineUrl(PROXY_HOMEPAGE_URL, "/settings");
|
||||||
const ERROR_401_URL = combineUrl(PROXY_HOMEPAGE_URL, "/error401");
|
const ERROR_401_URL = combineUrl(PROXY_HOMEPAGE_URL, "/error401");
|
||||||
@ -66,9 +62,6 @@ const About = React.lazy(() => import("./components/pages/About"));
|
|||||||
const Wizard = React.lazy(() => import("./components/pages/Wizard"));
|
const Wizard = React.lazy(() => import("./components/pages/Wizard"));
|
||||||
const Settings = React.lazy(() => import("./components/pages/Settings"));
|
const Settings = React.lazy(() => import("./components/pages/Settings"));
|
||||||
const ComingSoon = React.lazy(() => import("./components/pages/ComingSoon"));
|
const ComingSoon = React.lazy(() => import("./components/pages/ComingSoon"));
|
||||||
const ThirdPartyResponse = React.lazy(() =>
|
|
||||||
import("./components/pages/ThirdParty")
|
|
||||||
);
|
|
||||||
const Confirm = React.lazy(() => import("./components/pages/Confirm"));
|
const Confirm = React.lazy(() => import("./components/pages/Confirm"));
|
||||||
|
|
||||||
const SettingsRoute = (props) => (
|
const SettingsRoute = (props) => (
|
||||||
@ -149,14 +142,6 @@ const ComingSoonRoute = (props) => (
|
|||||||
</React.Suspense>
|
</React.Suspense>
|
||||||
);
|
);
|
||||||
|
|
||||||
const ThirdPartyResponseRoute = (props) => (
|
|
||||||
<React.Suspense fallback={<AppLoader />}>
|
|
||||||
<ErrorBoundary>
|
|
||||||
<ThirdPartyResponse {...props} />
|
|
||||||
</ErrorBoundary>
|
|
||||||
</React.Suspense>
|
|
||||||
);
|
|
||||||
|
|
||||||
const Shell = ({ items = [], page = "home", ...rest }) => {
|
const Shell = ({ items = [], page = "home", ...rest }) => {
|
||||||
const { isLoaded, loadBaseInfo, modules } = rest;
|
const { isLoaded, loadBaseInfo, modules } = rest;
|
||||||
|
|
||||||
@ -174,7 +159,6 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
|
|||||||
LOGIN_URLS,
|
LOGIN_URLS,
|
||||||
CONFIRM_URL,
|
CONFIRM_URL,
|
||||||
COMING_SOON_URLS,
|
COMING_SOON_URLS,
|
||||||
THIRD_PARTY_RESPONSE_URL,
|
|
||||||
PAYMENTS_URL,
|
PAYMENTS_URL,
|
||||||
SETTINGS_URL,
|
SETTINGS_URL,
|
||||||
ERROR_401_URL,
|
ERROR_401_URL,
|
||||||
@ -251,10 +235,6 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
|
|||||||
path={COMING_SOON_URLS}
|
path={COMING_SOON_URLS}
|
||||||
component={ComingSoonRoute}
|
component={ComingSoonRoute}
|
||||||
/>
|
/>
|
||||||
<PrivateRoute
|
|
||||||
path={THIRD_PARTY_RESPONSE_URL}
|
|
||||||
component={ThirdPartyResponseRoute}
|
|
||||||
/>
|
|
||||||
<PrivateRoute path={PAYMENTS_URL} component={PaymentsRoute} />
|
<PrivateRoute path={PAYMENTS_URL} component={PaymentsRoute} />
|
||||||
<PrivateRoute
|
<PrivateRoute
|
||||||
restricted
|
restricted
|
||||||
|
@ -4,28 +4,44 @@ import { withTranslation } from "react-i18next";
|
|||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { createUser } from "@appserver/common/api/people";
|
import { createUser, signupOAuth } from "@appserver/common/api/people";
|
||||||
import { inject, observer } from "mobx-react";
|
import { inject, observer } from "mobx-react";
|
||||||
import Button from "@appserver/components/button";
|
import Button from "@appserver/components/button";
|
||||||
import TextInput from "@appserver/components/text-input";
|
import TextInput from "@appserver/components/text-input";
|
||||||
|
import Box from "@appserver/components/box";
|
||||||
import Text from "@appserver/components/text";
|
import Text from "@appserver/components/text";
|
||||||
import PasswordInput from "@appserver/components/password-input";
|
import PasswordInput from "@appserver/components/password-input";
|
||||||
import toastr from "@appserver/components/toast/toastr";
|
import toastr from "@appserver/components/toast/toastr";
|
||||||
import Loader from "@appserver/components/loader";
|
import Loader from "@appserver/components/loader";
|
||||||
|
import SocialButton from "@appserver/components/social-button";
|
||||||
|
import FacebookButton from "@appserver/components/facebook-button";
|
||||||
import EmailInput from "@appserver/components/email-input";
|
import EmailInput from "@appserver/components/email-input";
|
||||||
|
import { getAuthProviders } from "@appserver/common/api/settings";
|
||||||
import PageLayout from "@appserver/common/components/PageLayout";
|
import PageLayout from "@appserver/common/components/PageLayout";
|
||||||
import { combineUrl, createPasswordHash } from "@appserver/common/utils";
|
import { combineUrl, createPasswordHash } from "@appserver/common/utils";
|
||||||
import { AppServerConfig } from "@appserver/common/constants";
|
import { AppServerConfig, providersData } from "@appserver/common/constants";
|
||||||
import { isMobile } from "react-device-detect";
|
import { isMobile } from "react-device-detect";
|
||||||
|
|
||||||
const inputWidth = "400px";
|
const inputWidth = "400px";
|
||||||
|
|
||||||
|
const ButtonsWrapper = styled.div`
|
||||||
|
display: table;
|
||||||
|
margin: -6px;
|
||||||
|
margin-top: 17px;
|
||||||
|
margin-right: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
const ConfirmContainer = styled.div`
|
const ConfirmContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 200px;
|
margin-left: 200px;
|
||||||
|
|
||||||
|
.buttonWrapper {
|
||||||
|
margin: 6px;
|
||||||
|
min-width: 225px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 830px) {
|
@media (max-width: 830px) {
|
||||||
margin-left: 40px;
|
margin-left: 40px;
|
||||||
}
|
}
|
||||||
@ -150,6 +166,99 @@ class Confirm extends React.PureComponent {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
addFacebookToStart = (facebookIndex, providerButtons) => {
|
||||||
|
const { providers, t } = this.props;
|
||||||
|
const faceBookData = providers[facebookIndex];
|
||||||
|
const { icon, label, iconOptions } = providersData[faceBookData.provider];
|
||||||
|
providerButtons.unshift(
|
||||||
|
<div
|
||||||
|
className="buttonWrapper"
|
||||||
|
key={`${faceBookData.provider}ProviderItem`}
|
||||||
|
>
|
||||||
|
<FacebookButton
|
||||||
|
iconName={icon}
|
||||||
|
label={t(label)}
|
||||||
|
className="socialButton"
|
||||||
|
$iconOptions={iconOptions}
|
||||||
|
data-url={faceBookData.url}
|
||||||
|
data-providername={faceBookData.provider}
|
||||||
|
onClick={this.onSocialButtonClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
providerButtons = () => {
|
||||||
|
const { providers, t } = this.props;
|
||||||
|
|
||||||
|
let facebookIndex = null;
|
||||||
|
const providerButtons =
|
||||||
|
providers &&
|
||||||
|
providers.map((item, index) => {
|
||||||
|
const { icon, label, iconOptions, className } = providersData[
|
||||||
|
item.provider
|
||||||
|
];
|
||||||
|
if (!icon) return;
|
||||||
|
if (item.provider === "Facebook") {
|
||||||
|
facebookIndex = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="buttonWrapper" key={`${item.provider}ProviderItem`}>
|
||||||
|
<SocialButton
|
||||||
|
iconName={icon}
|
||||||
|
label={t(label)}
|
||||||
|
className={`socialButton ${className ? className : ""}`}
|
||||||
|
$iconOptions={iconOptions}
|
||||||
|
data-url={item.url}
|
||||||
|
data-providername={item.provider}
|
||||||
|
onClick={this.onSocialButtonClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (facebookIndex) this.addFacebookToStart(facebookIndex, providerButtons);
|
||||||
|
|
||||||
|
return providerButtons;
|
||||||
|
};
|
||||||
|
|
||||||
|
authCallback = (profile) => {
|
||||||
|
const { t, defaultPage } = this.props;
|
||||||
|
const { FirstName, LastName, EMail, Serialized } = profile;
|
||||||
|
|
||||||
|
console.log(profile);
|
||||||
|
|
||||||
|
const signupAccount = {
|
||||||
|
EmployeeType: null,
|
||||||
|
FirstName: FirstName,
|
||||||
|
LastName: LastName,
|
||||||
|
Email: EMail,
|
||||||
|
PasswordHash: "",
|
||||||
|
SerializedProfile: Serialized,
|
||||||
|
};
|
||||||
|
|
||||||
|
signupOAuth(signupAccount)
|
||||||
|
.then(() => {
|
||||||
|
window.location.replace(defaultPage);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
toastr.error(e);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
setProviders = async () => {
|
||||||
|
const { setProviders } = this.props;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await getAuthProviders().then((providers) => {
|
||||||
|
setProviders(providers);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
createConfirmUser = async (registerData, loginData, key) => {
|
createConfirmUser = async (registerData, loginData, key) => {
|
||||||
const data = Object.assign(
|
const data = Object.assign(
|
||||||
{ fromInviteLink: true },
|
{ fromInviteLink: true },
|
||||||
@ -171,6 +280,35 @@ class Confirm extends React.PureComponent {
|
|||||||
return user;
|
return user;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onSocialButtonClick = (e) => {
|
||||||
|
const providerName = e.target.dataset.providername;
|
||||||
|
const url = e.target.dataset.url;
|
||||||
|
|
||||||
|
const { getOAuthToken, getLoginLink } = this.props;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tokenGetterWin = window.open(
|
||||||
|
url,
|
||||||
|
"login",
|
||||||
|
"width=800,height=500,status=no,toolbar=no,menubar=no,resizable=yes,scrollbars=no"
|
||||||
|
);
|
||||||
|
|
||||||
|
getOAuthToken(tokenGetterWin).then((code) => {
|
||||||
|
const token = window.btoa(
|
||||||
|
JSON.stringify({
|
||||||
|
auth: providerName,
|
||||||
|
mode: "popup",
|
||||||
|
callback: "authCallback",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
tokenGetterWin.location.href = getLoginLink(token, code);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onKeyPress = (event) => {
|
onKeyPress = (event) => {
|
||||||
if (event.key === "Enter") {
|
if (event.key === "Enter") {
|
||||||
this.onSubmit();
|
this.onSubmit();
|
||||||
@ -191,6 +329,9 @@ class Confirm extends React.PureComponent {
|
|||||||
history.push(combineUrl(AppServerConfig.proxyURL, `/login/error=${e}`));
|
history.push(combineUrl(AppServerConfig.proxyURL, `/login/error=${e}`));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.setProviders();
|
||||||
|
window.authCallback = this.authCallback;
|
||||||
|
|
||||||
window.addEventListener("keydown", this.onKeyPress);
|
window.addEventListener("keydown", this.onKeyPress);
|
||||||
window.addEventListener("keyup", this.onKeyPress);
|
window.addEventListener("keyup", this.onKeyPress);
|
||||||
}
|
}
|
||||||
@ -230,7 +371,7 @@ class Confirm extends React.PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { settings, t, greetingTitle } = this.props;
|
const { settings, t, greetingTitle, providers } = this.props;
|
||||||
|
|
||||||
//console.log("createUser render");
|
//console.log("createUser render");
|
||||||
|
|
||||||
@ -352,6 +493,11 @@ class Confirm extends React.PureComponent {
|
|||||||
onClick={this.onSubmit}
|
onClick={this.onSubmit}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{providers && providers.length > 0 && (
|
||||||
|
<Box>
|
||||||
|
<ButtonsWrapper>{this.providerButtons()}</ButtonsWrapper>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* <Row className='confirm-row'>
|
{/* <Row className='confirm-row'>
|
||||||
|
|
||||||
@ -381,7 +527,15 @@ const CreateUserForm = (props) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
export default inject(({ auth }) => {
|
export default inject(({ auth }) => {
|
||||||
const { login, logout, isAuthenticated, settingsStore } = auth;
|
const {
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
isAuthenticated,
|
||||||
|
settingsStore,
|
||||||
|
setProviders,
|
||||||
|
providers,
|
||||||
|
thirdPartyLogin,
|
||||||
|
} = auth;
|
||||||
const {
|
const {
|
||||||
passwordSettings,
|
passwordSettings,
|
||||||
greetingSettings,
|
greetingSettings,
|
||||||
@ -389,6 +543,8 @@ export default inject(({ auth }) => {
|
|||||||
defaultPage,
|
defaultPage,
|
||||||
getSettings,
|
getSettings,
|
||||||
getPortalPasswordSettings,
|
getPortalPasswordSettings,
|
||||||
|
getOAuthToken,
|
||||||
|
getLoginLink,
|
||||||
} = settingsStore;
|
} = settingsStore;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -401,5 +557,10 @@ export default inject(({ auth }) => {
|
|||||||
logout,
|
logout,
|
||||||
getSettings,
|
getSettings,
|
||||||
getPortalPasswordSettings,
|
getPortalPasswordSettings,
|
||||||
|
thirdPartyLogin,
|
||||||
|
getOAuthToken,
|
||||||
|
getLoginLink,
|
||||||
|
setProviders,
|
||||||
|
providers,
|
||||||
};
|
};
|
||||||
})(withRouter(withTranslation("Confirm")(observer(CreateUserForm))));
|
})(withRouter(withTranslation("Confirm")(observer(CreateUserForm))));
|
||||||
|
@ -26,5 +26,12 @@
|
|||||||
"CookieSettingsTitle": "Session Lifetime",
|
"CookieSettingsTitle": "Session Lifetime",
|
||||||
"Authorization": "Authorization",
|
"Authorization": "Authorization",
|
||||||
"Or": "OR",
|
"Or": "OR",
|
||||||
"Register": "Register"
|
"Register": "Register",
|
||||||
|
|
||||||
|
"SignInWithGoogle": "Sign in with Google",
|
||||||
|
"SignInWithFacebook": "Sign in with Facebook",
|
||||||
|
"SignInWithTwitter": "Sign in with Twitter",
|
||||||
|
"SignInWithLinkedIn": "Sign in with LinkedIn",
|
||||||
|
"ProviderLoginError": "Authorization error",
|
||||||
|
"ProviderNotConnected": "Provider is not connected to your account"
|
||||||
}
|
}
|
||||||
|
@ -26,5 +26,12 @@
|
|||||||
"CookieSettingsTitle": "Время жизни сессии",
|
"CookieSettingsTitle": "Время жизни сессии",
|
||||||
"Authorization": "Авторизация",
|
"Authorization": "Авторизация",
|
||||||
"Or": "ИЛИ",
|
"Or": "ИЛИ",
|
||||||
"Register": "Регистрация"
|
"Register": "Регистрация",
|
||||||
|
|
||||||
|
"SignInWithGoogle": "Вход через Google",
|
||||||
|
"SignInWithFacebook": "Вход через Facebook",
|
||||||
|
"SignInWithTwitter": "Вход через Twitter",
|
||||||
|
"SignInWithLinkedIn": "Вход через LinkedIn",
|
||||||
|
"ProviderLoginError": "Ошибка авторизации",
|
||||||
|
"ProviderNotConnected": "Провайдер не подключен к вашему аккаунту"
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { withRouter } from "react-router";
|
import { withRouter } from "react-router";
|
||||||
@ -12,14 +12,24 @@ import Toast from "@appserver/components/toast";
|
|||||||
import HelpButton from "@appserver/components/help-button";
|
import HelpButton from "@appserver/components/help-button";
|
||||||
import PasswordInput from "@appserver/components/password-input";
|
import PasswordInput from "@appserver/components/password-input";
|
||||||
import FieldContainer from "@appserver/components/field-container";
|
import FieldContainer from "@appserver/components/field-container";
|
||||||
|
import SocialButton from "@appserver/components/social-button";
|
||||||
|
import FacebookButton from "@appserver/components/facebook-button";
|
||||||
import PageLayout from "@appserver/common/components/PageLayout";
|
import PageLayout from "@appserver/common/components/PageLayout";
|
||||||
import ForgotPasswordModalDialog from "./sub-components/forgot-password-modal-dialog";
|
import ForgotPasswordModalDialog from "./sub-components/forgot-password-modal-dialog";
|
||||||
import Register from "./sub-components/register-container";
|
import Register from "./sub-components/register-container";
|
||||||
|
import { getAuthProviders } from "@appserver/common/api/settings";
|
||||||
import { checkPwd } from "@appserver/common/desktop";
|
import { checkPwd } from "@appserver/common/desktop";
|
||||||
import { createPasswordHash, tryRedirectTo } from "@appserver/common/utils";
|
import { createPasswordHash } from "@appserver/common/utils";
|
||||||
|
import { providersData } from "@appserver/common/constants";
|
||||||
import { inject, observer } from "mobx-react";
|
import { inject, observer } from "mobx-react";
|
||||||
import i18n from "./i18n";
|
import i18n from "./i18n";
|
||||||
import { I18nextProvider, useTranslation } from "react-i18next";
|
import { I18nextProvider, useTranslation } from "react-i18next";
|
||||||
|
import toastr from "@appserver/components/toast/toastr";
|
||||||
|
|
||||||
|
const ButtonsWrapper = styled.div`
|
||||||
|
display: table;
|
||||||
|
margin: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
const LoginContainer = styled.div`
|
const LoginContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -33,6 +43,18 @@ const LoginContainer = styled.div`
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.buttonWrapper {
|
||||||
|
margin: 6px;
|
||||||
|
min-width: 225px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line {
|
||||||
|
height: 1px;
|
||||||
|
background-color: #eceef1;
|
||||||
|
flex-basis: 100%;
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
max-width: 475px;
|
max-width: 475px;
|
||||||
@ -140,7 +162,6 @@ const Form = (props) => {
|
|||||||
const [isDialogVisible, setIsDialogVisible] = useState(false);
|
const [isDialogVisible, setIsDialogVisible] = useState(false);
|
||||||
|
|
||||||
const [errorText, setErrorText] = useState("");
|
const [errorText, setErrorText] = useState("");
|
||||||
const [socialButtons, setSocialButtons] = useState([]);
|
|
||||||
|
|
||||||
const { t } = useTranslation("Login");
|
const { t } = useTranslation("Login");
|
||||||
|
|
||||||
@ -153,6 +174,8 @@ const Form = (props) => {
|
|||||||
organizationName,
|
organizationName,
|
||||||
greetingTitle,
|
greetingTitle,
|
||||||
history,
|
history,
|
||||||
|
thirdPartyLogin,
|
||||||
|
providers,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const { error, confirmedEmail } = match.params;
|
const { error, confirmedEmail } = match.params;
|
||||||
@ -175,7 +198,30 @@ const Form = (props) => {
|
|||||||
|
|
||||||
//const throttledKeyPress = throttle(onKeyPress, 500);
|
//const throttledKeyPress = throttle(onKeyPress, 500);
|
||||||
|
|
||||||
useEffect(() => {
|
const authCallback = (profile) => {
|
||||||
|
thirdPartyLogin(profile.Serialized)
|
||||||
|
.then(() => {
|
||||||
|
setIsLoading(true);
|
||||||
|
history.push(defaultPage);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toastr.error(t("ProviderNotConnected"), t("ProviderLoginError"));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const setProviders = async () => {
|
||||||
|
const { setProviders } = props;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await getAuthProviders().then((providers) => {
|
||||||
|
setProviders(providers);
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(async () => {
|
||||||
document.title = `${t("Authorization")} – ${organizationName}`; //TODO: implement the setDocumentTitle() utility in ASC.Web.Common
|
document.title = `${t("Authorization")} – ${organizationName}`; //TODO: implement the setDocumentTitle() utility in ASC.Web.Common
|
||||||
|
|
||||||
error && setErrorText(error);
|
error && setErrorText(error);
|
||||||
@ -183,6 +229,9 @@ const Form = (props) => {
|
|||||||
|
|
||||||
focusInput();
|
focusInput();
|
||||||
|
|
||||||
|
window.authCallback = authCallback;
|
||||||
|
|
||||||
|
await setProviders();
|
||||||
//window.addEventListener("keyup", throttledKeyPress, false);
|
//window.addEventListener("keyup", throttledKeyPress, false);
|
||||||
|
|
||||||
/*return () => {
|
/*return () => {
|
||||||
@ -245,9 +294,10 @@ const Form = (props) => {
|
|||||||
const hash = createPasswordHash(pass, hashSettings);
|
const hash = createPasswordHash(pass, hashSettings);
|
||||||
|
|
||||||
isDesktop && checkPwd();
|
isDesktop && checkPwd();
|
||||||
|
|
||||||
login(userName, hash)
|
login(userName, hash)
|
||||||
.then(() => history.push(defaultPage))
|
.then(() => {
|
||||||
|
history.push(defaultPage);
|
||||||
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setErrorText(error);
|
setErrorText(error);
|
||||||
setIdentifierValid(!error);
|
setIdentifierValid(!error);
|
||||||
@ -257,6 +307,89 @@ const Form = (props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSocialButtonClick = useCallback((e) => {
|
||||||
|
const providerName = e.target.dataset.providername;
|
||||||
|
const url = e.target.dataset.url;
|
||||||
|
|
||||||
|
const { getOAuthToken, getLoginLink } = props;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tokenGetterWin = window.open(
|
||||||
|
url,
|
||||||
|
"login",
|
||||||
|
"width=800,height=500,status=no,toolbar=no,menubar=no,resizable=yes,scrollbars=no"
|
||||||
|
);
|
||||||
|
|
||||||
|
getOAuthToken(tokenGetterWin).then((code) => {
|
||||||
|
const token = window.btoa(
|
||||||
|
JSON.stringify({
|
||||||
|
auth: providerName,
|
||||||
|
mode: "popup",
|
||||||
|
callback: "authCallback",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
tokenGetterWin.location.href = getLoginLink(token, code);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const addFacebookToStart = (facebookIndex, providerButtons) => {
|
||||||
|
const faceBookData = providers[facebookIndex];
|
||||||
|
const { icon, label, iconOptions } = providersData[faceBookData.provider];
|
||||||
|
providerButtons.unshift(
|
||||||
|
<div
|
||||||
|
className="buttonWrapper"
|
||||||
|
key={`${faceBookData.provider}ProviderItem`}
|
||||||
|
>
|
||||||
|
<FacebookButton
|
||||||
|
iconName={icon}
|
||||||
|
label={t(label)}
|
||||||
|
className="socialButton"
|
||||||
|
$iconOptions={iconOptions}
|
||||||
|
data-url={faceBookData.url}
|
||||||
|
data-providername={faceBookData.provider}
|
||||||
|
onClick={onSocialButtonClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const providerButtons = () => {
|
||||||
|
let facebookIndex = null;
|
||||||
|
const providerButtons =
|
||||||
|
providers &&
|
||||||
|
providers.map((item, index) => {
|
||||||
|
const { icon, label, iconOptions, className } = providersData[
|
||||||
|
item.provider
|
||||||
|
];
|
||||||
|
if (!icon) return;
|
||||||
|
if (item.provider === "Facebook") {
|
||||||
|
facebookIndex = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="buttonWrapper" key={`${item.provider}ProviderItem`}>
|
||||||
|
<SocialButton
|
||||||
|
iconName={icon}
|
||||||
|
label={t(label)}
|
||||||
|
className={`socialButton ${className ? className : ""}`}
|
||||||
|
$iconOptions={iconOptions}
|
||||||
|
data-url={item.url}
|
||||||
|
data-providername={item.provider}
|
||||||
|
onClick={onSocialButtonClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (facebookIndex) addFacebookToStart(facebookIndex, providerButtons);
|
||||||
|
|
||||||
|
return providerButtons;
|
||||||
|
};
|
||||||
|
|
||||||
//console.log("Login render");
|
//console.log("Login render");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -374,15 +507,19 @@ const Form = (props) => {
|
|||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{socialButtons.length ? (
|
{providers && providers.length > 0 && (
|
||||||
<Box displayProp="flex" alignItems="center">
|
<>
|
||||||
|
<Box displayProp="flex" alignItems="center" marginProp="0 0 16px 0">
|
||||||
<div className="login-bottom-border"></div>
|
<div className="login-bottom-border"></div>
|
||||||
<Text className="login-bottom-text" color="#A3A9AE">
|
<Text className="login-bottom-text" color="#A3A9AE">
|
||||||
{t("Or")}
|
{t("Or")}
|
||||||
</Text>
|
</Text>
|
||||||
<div className="login-bottom-border"></div>
|
<div className="login-bottom-border"></div>
|
||||||
</Box>
|
</Box>
|
||||||
) : null}
|
|
||||||
|
<ButtonsWrapper>{providerButtons()}</ButtonsWrapper>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
<Toast />
|
<Toast />
|
||||||
</LoginContainer>
|
</LoginContainer>
|
||||||
@ -394,7 +531,6 @@ Form.propTypes = {
|
|||||||
match: PropTypes.object.isRequired,
|
match: PropTypes.object.isRequired,
|
||||||
hashSettings: PropTypes.object,
|
hashSettings: PropTypes.object,
|
||||||
greetingTitle: PropTypes.string.isRequired,
|
greetingTitle: PropTypes.string.isRequired,
|
||||||
socialButtons: PropTypes.array,
|
|
||||||
organizationName: PropTypes.string,
|
organizationName: PropTypes.string,
|
||||||
homepage: PropTypes.string,
|
homepage: PropTypes.string,
|
||||||
defaultPage: PropTypes.string,
|
defaultPage: PropTypes.string,
|
||||||
@ -429,7 +565,15 @@ LoginForm.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Login = inject(({ auth }) => {
|
const Login = inject(({ auth }) => {
|
||||||
const { settingsStore, isAuthenticated, isLoaded, login } = auth;
|
const {
|
||||||
|
settingsStore,
|
||||||
|
isAuthenticated,
|
||||||
|
isLoaded,
|
||||||
|
login,
|
||||||
|
thirdPartyLogin,
|
||||||
|
setProviders,
|
||||||
|
providers,
|
||||||
|
} = auth;
|
||||||
const {
|
const {
|
||||||
greetingSettings: greetingTitle,
|
greetingSettings: greetingTitle,
|
||||||
organizationName,
|
organizationName,
|
||||||
@ -437,6 +581,8 @@ const Login = inject(({ auth }) => {
|
|||||||
enabledJoin,
|
enabledJoin,
|
||||||
defaultPage,
|
defaultPage,
|
||||||
isDesktopClient: isDesktop,
|
isDesktopClient: isDesktop,
|
||||||
|
getOAuthToken,
|
||||||
|
getLoginLink,
|
||||||
} = settingsStore;
|
} = settingsStore;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -449,6 +595,11 @@ const Login = inject(({ auth }) => {
|
|||||||
defaultPage,
|
defaultPage,
|
||||||
isDesktop,
|
isDesktop,
|
||||||
login,
|
login,
|
||||||
|
thirdPartyLogin,
|
||||||
|
getOAuthToken,
|
||||||
|
getLoginLink,
|
||||||
|
setProviders,
|
||||||
|
providers,
|
||||||
};
|
};
|
||||||
})(withRouter(observer(LoginForm)));
|
})(withRouter(observer(LoginForm)));
|
||||||
|
|
||||||
|