Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions packages/global/common/system/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export type ExternalProviderWorkflowVarType = {
url?: string;
};

export type FastGPTRegisterMethodType = 'email' | 'phone';
export type FastGPTRegisterMethodCompatType = FastGPTRegisterMethodType | 'sync';
export type FastGPTTeamModeType = 'multi' | 'single' | 'sync';

/* fastgpt main */
export type FastGPTConfigFileType = {
feConfigs: FastGPTFeConfigsType;
Expand All @@ -42,10 +46,14 @@ export type FastGPTFeConfigsType = {
show_emptyChat?: boolean;
isPlus?: boolean;
hideChatCopyrightSetting?: boolean;
register_method?: ['email' | 'phone' | 'sync'];
login_method?: ['email' | 'phone']; // Attention: login method is different with oauth
find_password_method?: ['email' | 'phone'];
bind_notification_method?: ['email' | 'phone'];
/**
* 用户自助注册方式。兼容期允许读取旧配置中的 sync,但新配置不再写入 sync。
*/
register_method?: FastGPTRegisterMethodCompatType[];
teamMode?: FastGPTTeamModeType;
login_method?: FastGPTRegisterMethodType[]; // Attention: login method is different with oauth
find_password_method?: FastGPTRegisterMethodType[];
bind_notification_method?: FastGPTRegisterMethodType[];
googleClientVerKey?: string;
/**
* @deprecated MCP SSE 代理地址已迁移到环境变量 SSE_MCP_SERVER_PROXY_ENDPOINT。
Expand Down
2 changes: 1 addition & 1 deletion pro
Submodule pro updated from 2b3e11 to 5d37df
4 changes: 2 additions & 2 deletions projects/app/src/pageComponents/account/team/MemberTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { format } from 'date-fns/format';
import OrgTags from '@/components/support/user/team/OrgTags';
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
import { useCallback, useState, useMemo } from 'react';
import { downloadFetch } from '@/web/common/system/utils';
import { downloadFetch, getIsMemberSyncMode } from '@/web/common/system/utils';
import { type TeamMemberItemType } from '@fastgpt/global/support/user/team/type';
import { useToast } from '@fastgpt/web/hooks/useToast';
import MyBox from '@fastgpt/web/components/common/MyBox';
Expand All @@ -59,7 +59,7 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) {
const { toast } = useToast();
const { userInfo, initUserInfo } = useUserStore();
const { feConfigs } = useSystemStore();
const isSyncMode = feConfigs?.register_method?.includes('sync');
const isSyncMode = getIsMemberSyncMode(feConfigs);

const { myTeams, onSwitchTeam } = useContextSelector(TeamContext, (v) => v);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
import { delRemoveMember } from '@/web/support/user/team/api';
import SearchInput from '@fastgpt/web/components/common/Input/SearchInput';
import useOrg from '@/web/support/user/team/org/hooks/useOrg';
import { getIsMemberSyncMode } from '@/web/common/system/utils';

const OrgInfoModal = dynamic(() => import('./OrgInfoModal'));
const OrgMemberManageModal = dynamic(() => import('./OrgMemberManageModal'));
Expand Down Expand Up @@ -74,7 +75,7 @@ function OrgTable({ Tabs }: { Tabs: React.ReactNode }) {
const { t } = useTranslation();
const { userInfo, isTeamAdmin } = useUserStore();
const { feConfigs } = useSystemStore();
const isSyncMember = feConfigs.register_method?.includes('sync');
const isSyncMember = getIsMemberSyncMode(feConfigs);
const [editOrg, setEditOrg] = useState<OrgFormType>();
const [manageMemberOrg, setManageMemberOrg] = useState<OrgListItemType>();
const [movingOrg, setMovingOrg] = useState<OrgListItemType>();
Expand Down
58 changes: 32 additions & 26 deletions projects/app/src/pageComponents/login/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useMount } from 'ahooks';
import type { LangEnum } from '@fastgpt/global/common/i18n/type';
import type { LoginSuccessResponseType } from '@fastgpt/global/openapi/support/user/account/login/api';
import PolicyTip from './PolicyTip';
import { getRegisterMethods } from '@/web/common/system/utils';

type LoginSuccessHandler = (res: LoginSuccessResponseType) => void | Promise<void>;

Expand All @@ -32,6 +33,9 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
const { feConfigs } = useSystemStore();
const query = useSearchParams();
const router = useRouter();
const registerMethods = getRegisterMethods(feConfigs);
const hasRegisterMethod = registerMethods.length > 0;
const hasFindPasswordMethod = !!feConfigs?.find_password_method?.length;

const {
register,
Expand Down Expand Up @@ -74,7 +78,7 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
}
);

const isCommunityVersion = !!(feConfigs?.register_method && !feConfigs?.isPlus);
const isCommunityVersion = hasRegisterMethod && !feConfigs?.isPlus;

const placeholder = (() => {
if (isCommunityVersion) {
Expand Down Expand Up @@ -158,29 +162,31 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
{t('login:Login')}
</Button>

<Flex
mt={6}
align={'center'}
justifyContent={'center'}
gap={0}
color={'primary.700'}
fontWeight={'medium'}
h={'16px'}
lineHeight={'16px'}
>
{feConfigs?.find_password_method && feConfigs.find_password_method.length > 0 && (
<Box
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
onClick={() => setPageType('forgetPassword')}
fontSize="mini"
>
{t('login:forget_password')}
</Box>
)}
{feConfigs?.register_method && feConfigs.register_method.length > 0 && (
<>
{(hasFindPasswordMethod || hasRegisterMethod) && (
<Flex
mt={6}
align={'center'}
justifyContent={'center'}
gap={0}
color={'primary.700'}
fontWeight={'medium'}
h={'16px'}
lineHeight={'16px'}
>
{hasFindPasswordMethod && (
<Box
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
onClick={() => setPageType('forgetPassword')}
fontSize="mini"
>
{t('login:forget_password')}
</Box>
)}
{hasFindPasswordMethod && hasRegisterMethod && (
<Box display={['block', 'block']} mx={3} h={'12px'} w={'1px'} bg={'myGray.250'}></Box>
)}
{hasRegisterMethod && (
<Box
cursor={'pointer'}
_hover={{ textDecoration: 'underline' }}
Expand All @@ -190,9 +196,9 @@ const LoginForm = ({ setPageType, loginSuccess }: Props) => {
>
{t('login:register')}
</Box>
</>
)}
</Flex>
)}
</Flex>
)}
</Box>
</FormLayout>
);
Expand Down
5 changes: 3 additions & 2 deletions projects/app/src/pageComponents/login/RegisterForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { checkPasswordRule } from '@fastgpt/global/common/string/password';
import type { LoginSuccessResponseType } from '@fastgpt/global/openapi/support/user/account/login/api';
import type { LangEnum } from '@fastgpt/global/common/i18n/type';
import { getRegisterMethods } from '@/web/common/system/utils';

type LoginSuccessHandler = (res: LoginSuccessResponseType) => void | Promise<void>;

Expand Down Expand Up @@ -88,8 +89,8 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
}
};

const placeholder = feConfigs?.register_method
?.map((item) => {
const placeholder = getRegisterMethods(feConfigs)
.map((item) => {
switch (item) {
case 'email':
return t('common:support.user.login.Email');
Expand Down
3 changes: 2 additions & 1 deletion projects/app/src/pages/account/info/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { useUploadAvatar } from '@fastgpt/web/common/file/hooks/useUploadAvatar'
import { getUploadAvatarPresignedUrl } from '@/web/common/file/api';
import { TeamErrEnum } from '@fastgpt/global/common/error/code/team';
import { i18nT } from '@fastgpt/global/common/i18n/utils';
import { getIsMemberSyncMode } from '@/web/common/system/utils';

const RedeemCouponModal = dynamic(() => import('@/pageComponents/account/info/RedeemCouponModal'), {
ssr: false
Expand Down Expand Up @@ -196,7 +197,7 @@ const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => {
letterSpacing: '0.15px'
};

const isSyncMember = feConfigs.register_method?.includes('sync');
const isSyncMember = getIsMemberSyncMode(feConfigs);
return (
<Box>
{/* user info */}
Expand Down
24 changes: 24 additions & 0 deletions projects/app/src/web/common/system/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,33 @@ import {
type EmbeddingModelItemType,
type LLMModelItemType
} from '@fastgpt/global/core/ai/model.schema';
import type {
FastGPTFeConfigsType,
FastGPTRegisterMethodType
} from '@fastgpt/global/common/system/types';
import { useSystemStore } from './useSystemStore';
import { getWebReqUrl } from '@fastgpt/web/common/system/utils';

/**
* 获取真实支持的自助注册方式,兼容过滤旧配置中被混入的 sync 团队模式。
*/
export const getRegisterMethods = (feConfigs?: FastGPTFeConfigsType): FastGPTRegisterMethodType[] =>
feConfigs?.register_method?.filter(
(method): method is FastGPTRegisterMethodType => method === 'email' || method === 'phone'
) ?? [];

/**
* 判断是否为成员同步模式。teamMode 是当前权威字段;旧 register_method: ['sync']
* 仅用于兼容缺少 teamMode 的历史配置,避免新旧字段冲突时前后端模式不一致。
*/
export const getIsMemberSyncMode = (feConfigs?: FastGPTFeConfigsType) => {
if (feConfigs?.teamMode) {
return feConfigs.teamMode === 'sync';
}

return !!feConfigs?.register_method?.includes('sync');
};

export const downloadFetch = async ({
url,
filename,
Expand Down
38 changes: 38 additions & 0 deletions projects/app/test/web/common/system/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, expect, it } from 'vitest';

import type { FastGPTFeConfigsType } from '@fastgpt/global/common/system/types';
import { getIsMemberSyncMode, getRegisterMethods } from '@/web/common/system/utils';

const createFeConfigs = (overrides: Partial<FastGPTFeConfigsType>): FastGPTFeConfigsType => ({
uploadFileMaxAmount: 10,
uploadFileMaxSize: 100,
...overrides
});

describe('system fe config utils', () => {
it('filters legacy sync from register methods', () => {
expect(getRegisterMethods(createFeConfigs({ register_method: ['sync'] }))).toEqual([]);
expect(
getRegisterMethods(createFeConfigs({ register_method: ['email', 'sync', 'phone'] }))
).toEqual(['email', 'phone']);
});

it('detects member sync mode from new teamMode and legacy register_method', () => {
expect(getIsMemberSyncMode(createFeConfigs({ teamMode: 'sync', register_method: [] }))).toBe(
true
);
expect(getIsMemberSyncMode(createFeConfigs({ register_method: ['sync'] }))).toBe(true);
expect(
getIsMemberSyncMode(createFeConfigs({ teamMode: 'single', register_method: ['sync'] }))
).toBe(false);
expect(
getIsMemberSyncMode(createFeConfigs({ teamMode: 'multi', register_method: ['sync'] }))
).toBe(false);
expect(
getIsMemberSyncMode(createFeConfigs({ teamMode: 'multi', register_method: ['phone'] }))
).toBe(false);
expect(getIsMemberSyncMode(createFeConfigs({ teamMode: 'single', register_method: [] }))).toBe(
false
);
});
});
Loading