mirror of https://gitee.com/answerdev/answer.git
feat: add oauth plugin
This commit is contained in:
parent
a88b476803
commit
479892b156
|
@ -747,6 +747,13 @@ ui:
|
|||
lang:
|
||||
label: Interface Language
|
||||
text: User interface language. It will change when you refresh the page.
|
||||
my_logins:
|
||||
title: My Logins
|
||||
lable: Log in or sign up on this site using these accounts.
|
||||
modal_title: Remove Login
|
||||
modal_content: Are you sure you want to remove this login from your account?
|
||||
modal_confirm_btn: Remove
|
||||
remove_success: Removed successfully
|
||||
toast:
|
||||
update: update success
|
||||
update_password: Password changed successfully.
|
||||
|
@ -1362,7 +1369,7 @@ ui:
|
|||
btn_submit: Save
|
||||
not_found_props: "Required property {{ key }} not found."
|
||||
select: Select
|
||||
|
||||
|
||||
page_review:
|
||||
review: Review
|
||||
proposed: proposed
|
||||
|
|
|
@ -521,3 +521,14 @@ export interface OauthBindEmailReq {
|
|||
email: string;
|
||||
must: boolean;
|
||||
}
|
||||
|
||||
export interface OauthConnectorItem {
|
||||
icon: string;
|
||||
name: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export interface UserOauthConnectorItem extends OauthConnectorItem {
|
||||
binding: boolean;
|
||||
external_id: string;
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
import { memo, FC } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Icon } from '@/components';
|
||||
|
||||
interface Props {
|
||||
// data: any[]; // should use oauth plugin schemes
|
||||
className?: string;
|
||||
}
|
||||
const Index: FC<Props> = ({ className }) => {
|
||||
return (
|
||||
<div className={classnames('d-grid gap-2', className)}>
|
||||
<Button
|
||||
variant="outline-secondary"
|
||||
href="https://github.com/login/oauth/authorize?client_id=8cb9d4760cfd71c24de9&edirect_uri=http://10.0.20.88:8080/answer/api/v1/connector/redirect/github">
|
||||
<Icon name="github" className="me-2" />
|
||||
<span>Connect with Github</span>
|
||||
</Button>
|
||||
|
||||
<Button variant="outline-secondary">
|
||||
<Icon name="twitter" className="me-2" />
|
||||
<span>Connect with Google</span>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Index);
|
|
@ -32,7 +32,6 @@ import CustomizeTheme from './CustomizeTheme';
|
|||
import PageTags from './PageTags';
|
||||
import QuestionListLoader from './QuestionListLoader';
|
||||
import TagsLoader from './TagsLoader';
|
||||
import OauthButtons from './OauthButtons';
|
||||
|
||||
export {
|
||||
Avatar,
|
||||
|
@ -71,6 +70,5 @@ export {
|
|||
PageTags,
|
||||
QuestionListLoader,
|
||||
TagsLoader,
|
||||
OauthButtons,
|
||||
};
|
||||
export type { EditorRef, JSONSchema, UISchema };
|
||||
|
|
|
@ -302,3 +302,9 @@ a {
|
|||
.bg-fade-out {
|
||||
animation: 2s ease 1s bg-fade-out;
|
||||
}
|
||||
|
||||
|
||||
.btnSvg, .btnSvg:hover {
|
||||
fill: currentColor;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ import type {
|
|||
ImgCodeRes,
|
||||
FormDataType,
|
||||
} from '@/common/interface';
|
||||
import { Unactivate, OauthButtons } from '@/components';
|
||||
import { Unactivate } from '@/components';
|
||||
import { PluginOauth } from '@/plugins';
|
||||
import { loggedUserInfoStore, loginSettingStore } from '@/stores';
|
||||
import { guard, floppyNavigation, handleFormError } from '@/utils';
|
||||
import { login, checkImgCode } from '@/services';
|
||||
|
@ -173,7 +174,7 @@ const Index: React.FC = () => {
|
|||
<h3 className="text-center mb-5">{t('page_title')}</h3>
|
||||
{step === 1 && (
|
||||
<Col className="mx-auto" md={3}>
|
||||
<OauthButtons className="mb-5" />
|
||||
<PluginOauth className="mb-5" />
|
||||
<Form noValidate onSubmit={handleSubmit}>
|
||||
<Form.Group controlId="email" className="mb-3">
|
||||
<Form.Label>{t('email.label')}</Form.Label>
|
||||
|
|
|
@ -1,40 +1,65 @@
|
|||
import { memo } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Icon, Modal } from '@/components';
|
||||
import { Modal } from '@/components';
|
||||
import { useOauthConnectorInfoByUser, userOauthUnbind } from '@/services';
|
||||
import { useToast } from '@/hooks';
|
||||
|
||||
const Index = () => {
|
||||
const deleteLogins = (type) => {
|
||||
const { data, mutate } = useOauthConnectorInfoByUser();
|
||||
const toast = useToast();
|
||||
|
||||
const { t } = useTranslation('translation', {
|
||||
keyPrefix: 'settings.my_logins',
|
||||
});
|
||||
|
||||
const deleteLogins = (e, item) => {
|
||||
if (!item.binding) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
Modal.confirm({
|
||||
title: 'Remove Login',
|
||||
content: 'Are you sure you want to delete this logins?',
|
||||
title: t('modal_title'),
|
||||
content: t('modal_content'),
|
||||
confirmBtnVariant: 'danger',
|
||||
confirmText: 'Remove',
|
||||
confirmText: t('modal_confirm_btn'),
|
||||
onConfirm: () => {
|
||||
console.log('delete login by: ', type);
|
||||
userOauthUnbind({ external_id: item.external_id }).then(() => {
|
||||
mutate();
|
||||
toast.onShow({
|
||||
msg: t('remove_success'),
|
||||
variant: 'success',
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="mt-5">
|
||||
<div className="form-label">My Logins</div>
|
||||
<small className="form-text mt-0">
|
||||
Log in or sign up on this site using these accounts.
|
||||
</small>
|
||||
<div className="form-label">{t('title')}</div>
|
||||
<small className="form-text mt-0">{t('lable')}</small>
|
||||
|
||||
<div className="mt-3">
|
||||
<Button variant="outline-secondary" className="d-block mb-2">
|
||||
<Icon name="google" className="me-2" />
|
||||
<span>Connect with Google</span>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="outline-danger"
|
||||
className="mb-2"
|
||||
onClick={() => deleteLogins('github')}>
|
||||
<Icon name="github" className="me-2" />
|
||||
<span>Remove GitHub</span>
|
||||
</Button>
|
||||
{data?.map((item) => {
|
||||
return (
|
||||
<Button
|
||||
variant={item.binding ? 'outline-danger' : 'outline-secondary'}
|
||||
href={item.link}
|
||||
onClick={(e) => deleteLogins(e, item)}
|
||||
key={item.name}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
className="btnSvg"
|
||||
viewBox="0 0 24 24">
|
||||
<path d={item.icon} />
|
||||
</svg>
|
||||
<span> {item.name}</span>
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import { memo, FC } from 'react';
|
||||
import { Button } from 'react-bootstrap';
|
||||
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { useGetStartUseOauthConnector } from '@/services';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
}
|
||||
const Index: FC<Props> = ({ className }) => {
|
||||
const { data } = useGetStartUseOauthConnector();
|
||||
|
||||
if (!data?.length) return null;
|
||||
return (
|
||||
<div className={classnames('d-grid gap-2', className)}>
|
||||
{data?.map((item) => {
|
||||
return (
|
||||
<Button variant="outline-secondary" href={item.link} key={item.name}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
className="btnSvg"
|
||||
viewBox="0 0 24 24">
|
||||
<path d={item.icon} />
|
||||
</svg>
|
||||
<span> {item.name}</span>
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Index);
|
|
@ -0,0 +1,3 @@
|
|||
import PluginOauth from './PluginOauth';
|
||||
|
||||
export { PluginOauth };
|
|
@ -1,6 +1,36 @@
|
|||
import useSWR from 'swr';
|
||||
|
||||
import request from '@/utils/request';
|
||||
import type * as Type from '@/common/interface';
|
||||
|
||||
export const oAuthBindEmail = (data: Type.OauthBindEmailReq) => {
|
||||
return request.post('/answer/api/v1/connector/binding/email', data);
|
||||
};
|
||||
|
||||
export const useOauthConnectorInfoByUser = () => {
|
||||
const { data, error, mutate } = useSWR<Type.UserOauthConnectorItem[]>(
|
||||
'/answer/api/v1/connector/user/info',
|
||||
request.instance.get,
|
||||
);
|
||||
return {
|
||||
data,
|
||||
mutate,
|
||||
isLoading: !data && !error,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
export const userOauthUnbind = (data: { external_id: string }) => {
|
||||
return request.delete('/answer/api/v1/connector/user/unbinding', data);
|
||||
};
|
||||
|
||||
export const useGetStartUseOauthConnector = () => {
|
||||
const { data, error } = useSWR<Type.OauthConnectorItem[]>(
|
||||
'/answer/api/v1/connector/info',
|
||||
request.instance.get,
|
||||
);
|
||||
return {
|
||||
data,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue