diff --git a/api/controllers/console/auth/data_source_oauth.py b/api/controllers/console/auth/data_source_oauth.py index 77e46815e7d95e..f42b82ab351e33 100644 --- a/api/controllers/console/auth/data_source_oauth.py +++ b/api/controllers/console/auth/data_source_oauth.py @@ -45,7 +45,7 @@ def get(self, provider: str): if current_app.config.get('NOTION_INTEGRATION_TYPE') == 'internal': internal_secret = current_app.config.get('NOTION_INTERNAL_SECRET') oauth_provider.save_internal_access_token(internal_secret) - return { 'data': f'{current_app.config.get("CONSOLE_WEB_URL")}?oauth_data_source=success' } + return { 'data': '' } else: auth_url = oauth_provider.get_authorization_url() return { 'data': auth_url }, 200 @@ -54,6 +54,25 @@ def get(self, provider: str): class OAuthDataSourceCallback(Resource): + def get(self, provider: str): + OAUTH_DATASOURCE_PROVIDERS = get_oauth_providers() + with current_app.app_context(): + oauth_provider = OAUTH_DATASOURCE_PROVIDERS.get(provider) + if not oauth_provider: + return {'error': 'Invalid provider'}, 400 + if 'code' in request.args: + code = request.args.get('code') + + return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?type=notion&code={code}') + elif 'error' in request.args: + error = request.args.get('error') + + return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?type=notion&error={error}') + else: + return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?type=notion&error=Access denied') + + +class OAuthDataSourceBinding(Resource): def get(self, provider: str): OAUTH_DATASOURCE_PROVIDERS = get_oauth_providers() with current_app.app_context(): @@ -69,12 +88,7 @@ def get(self, provider: str): f"An error occurred during the OAuthCallback process with {provider}: {e.response.text}") return {'error': 'OAuth data source process failed'}, 400 - return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?oauth_data_source=success') - elif 'error' in request.args: - error = request.args.get('error') - return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?oauth_data_source={error}') - else: - return redirect(f'{current_app.config.get("CONSOLE_WEB_URL")}?oauth_data_source=access_denied') + return {'result': 'success'}, 200 class OAuthDataSourceSync(Resource): @@ -101,4 +115,5 @@ def get(self, provider, binding_id): api.add_resource(OAuthDataSource, '/oauth/data-source/') api.add_resource(OAuthDataSourceCallback, '/oauth/data-source/callback/') +api.add_resource(OAuthDataSourceBinding, '/oauth/data-source/binding/') api.add_resource(OAuthDataSourceSync, '/oauth/data-source///sync') diff --git a/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx b/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx index f71fe93024dc7f..c2ca64ec4c3d2f 100644 --- a/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx +++ b/web/app/components/header/account-setting/data-source-page/data-source-notion/index.tsx @@ -20,7 +20,7 @@ const DataSourceNotion = ({ const { t } = useTranslation() const { isCurrentWorkspaceManager } = useAppContext() const [canConnectNotion, setCanConnectNotion] = useState(false) - const { data } = useSWR(canConnectNotion ? '/oauth/data-source/notion' : null, fetchNotionConnection) + const { data, mutate } = useSWR(canConnectNotion ? '/oauth/data-source/notion' : null, fetchNotionConnection) const connected = !!workspaces.length @@ -115,7 +115,7 @@ const DataSourceNotion = ({ }
- + mutate()} />
)) } diff --git a/web/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx b/web/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx index ea8d121b498fe0..e115034ff733aa 100644 --- a/web/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx +++ b/web/app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx @@ -1,11 +1,9 @@ 'use client' import { useTranslation } from 'react-i18next' import { Fragment } from 'react' -import Link from 'next/link' import { useSWRConfig } from 'swr' import { EllipsisHorizontalIcon } from '@heroicons/react/24/solid' import { Menu, Transition } from '@headlessui/react' -import { apiPrefix } from '@/config' import { syncDataSourceNotion, updateDataSourceNotionAction } from '@/service/common' import Toast from '@/app/components/base/toast' import type { DataSourceNotion } from '@/models/common' @@ -15,9 +13,11 @@ import { Trash03 } from '@/app/components/base/icons/src/vender/line/general' type OperateProps = { workspace: DataSourceNotion + onAuthAgain: () => void } export default function Operate({ workspace, + onAuthAgain, }: OperateProps) { const itemClassName = ` flex px-3 py-2 hover:bg-gray-50 text-sm text-gray-700 @@ -71,9 +71,10 @@ export default function Operate({ >
- + onClick={onAuthAgain} + >
{t('common.dataSource.notion.changeAuthorizedPages')}
@@ -81,7 +82,7 @@ export default function Operate({ {workspace.source_info.total} {t('common.dataSource.notion.pagesAuthorized')}
- +
diff --git a/web/hooks/use-pay.tsx b/web/hooks/use-pay.tsx index c11a1a4b37b608..fee4b8fa14950f 100644 --- a/web/hooks/use-pay.tsx +++ b/web/hooks/use-pay.tsx @@ -7,7 +7,10 @@ import useSWR from 'swr' import { useContext } from 'use-context-selector' import I18n from '@/context/i18n' import { ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations' -import { fetchFreeQuotaVerify } from '@/service/common' +import { + fetchDataSourceNotionBinding, + fetchFreeQuotaVerify, +} from '@/service/common' import type { ConfirmCommonProps } from '@/app/components/base/confirm/common' import Confirm from '@/app/components/base/confirm/common' @@ -92,6 +95,42 @@ export const useCheckFreeQuota = () => { : null } +export const useCheckNotion = () => { + const router = useRouter() + const [confirm, setConfirm] = useState(null) + const [canBinding, setCanBinding] = useState(false) + const searchParams = useSearchParams() + const type = searchParams.get('type') + const notionCode = searchParams.get('code') + const notionError = searchParams.get('error') + const { data } = useSWR( + canBinding + ? `/oauth/data-source/binding/notion?code=${notionCode}` + : null, + fetchDataSourceNotionBinding, + ) + + useEffect(() => { + if (data) + router.replace('/', { forceOptimisticNavigation: false }) + }, [data, router]) + useEffect(() => { + if (type === 'notion') { + if (notionError) { + setConfirm({ + type: 'danger', + title: notionError, + }) + } + else if (notionCode) { + setCanBinding(true) + } + } + }, [type, notionCode, notionError]) + + return confirm +} + export const CheckModal = () => { const router = useRouter() const { t } = useTranslation() diff --git a/web/service/common.ts b/web/service/common.ts index 5f36d6729f8913..f7b8d038de2ef6 100644 --- a/web/service/common.ts +++ b/web/service/common.ts @@ -192,3 +192,7 @@ export const fetchFreeQuotaVerify: Fetcher<{ result: string; flag: boolean; reas export const fetchNotionConnection: Fetcher<{ data: string }, string> = (url) => { return get(url) as Promise<{ data: string }> } + +export const fetchDataSourceNotionBinding: Fetcher<{ result: string }, string> = (url) => { + return get(url) as Promise<{ result: string }> +}