feat: gate permission
This commit is contained in:
parent
e74ab643fe
commit
81202c53a8
@ -1,9 +1,18 @@
|
||||
import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
|
||||
import { type PermissionListType } from '../type';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
export enum AppPermissionKeyEnum {}
|
||||
|
||||
export enum AppPermissionKeyEnum {
|
||||
log = 'log'
|
||||
log = 'log',
|
||||
quickGate = 'quickGate',
|
||||
featuredGate = 'featuredGate'
|
||||
}
|
||||
|
||||
export const AppLogPermission = 0b100000;
|
||||
export const GateQuickAppPermission = 0b001100;
|
||||
export const GateFeaturedAppPermission = 0b010100;
|
||||
|
||||
export const AppPermissionList: PermissionListType<AppPermissionKeyEnum> = {
|
||||
[PermissionKeyEnum.read]: {
|
||||
...PermissionList[PermissionKeyEnum.read],
|
||||
@ -15,14 +24,26 @@ export const AppPermissionList: PermissionListType<AppPermissionKeyEnum> = {
|
||||
},
|
||||
[PermissionKeyEnum.manage]: {
|
||||
...PermissionList[PermissionKeyEnum.manage],
|
||||
value: 0b1111,
|
||||
value: 0b111111,
|
||||
description: i18nT('app:permission.des.manage')
|
||||
},
|
||||
[AppPermissionKeyEnum.log]: {
|
||||
name: i18nT('app:permission.name.log'),
|
||||
value: 0b1000,
|
||||
value: AppLogPermission,
|
||||
checkBoxType: 'multiple',
|
||||
description: i18nT('app:permission.des.log')
|
||||
},
|
||||
[AppPermissionKeyEnum.quickGate]: {
|
||||
name: '门户快捷应用权限',
|
||||
description: '',
|
||||
value: GateQuickAppPermission,
|
||||
checkBoxType: 'multiple' // TODO: 加个隐藏选项
|
||||
},
|
||||
[AppPermissionKeyEnum.featuredGate]: {
|
||||
name: '门户推荐应用权限',
|
||||
description: '',
|
||||
value: GateFeaturedAppPermission,
|
||||
checkBoxType: 'multiple' // TODO: 加个隐藏选项
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,86 @@
|
||||
import { MongoTeamGate, gateCollectionName } from './schema';
|
||||
import { MongoTeamGate } from './schema';
|
||||
import { Types } from '../../../../common/mongo';
|
||||
import type { ClientSession } from '../../../../common/mongo';
|
||||
import { mongoSessionRun } from '../../../../common/mongo/sessionRun';
|
||||
import {
|
||||
GateFeaturedAppPermission,
|
||||
GateQuickAppPermission
|
||||
} from '@fastgpt/global/support/permission/app/constant';
|
||||
import { PerResourceTypeEnum } from '@fastgpt/global/support/permission/constant';
|
||||
import { DefaultGroupName } from '@fastgpt/global/support/user/team/group/constant';
|
||||
import { MongoMemberGroupModel } from '../../../permission/memberGroup/memberGroupSchema';
|
||||
import { MongoResourcePermission } from '../../../permission/schema';
|
||||
|
||||
export const addGatePermission = async ({
|
||||
teamId,
|
||||
appId,
|
||||
per,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
per: number;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
// 1. 先找全员组
|
||||
const teamGroup = await MongoMemberGroupModel.findOne({
|
||||
teamId,
|
||||
name: DefaultGroupName
|
||||
});
|
||||
if (!teamGroup) {
|
||||
return Promise.reject('找不到全员组');
|
||||
}
|
||||
|
||||
// 2. 加权限
|
||||
await MongoResourcePermission.updateOne(
|
||||
{
|
||||
teamId,
|
||||
groupId: teamGroup?._id,
|
||||
resourceType: PerResourceTypeEnum.app,
|
||||
resourceId: appId
|
||||
},
|
||||
{
|
||||
permission: per
|
||||
},
|
||||
{
|
||||
session,
|
||||
upsert: true
|
||||
}
|
||||
);
|
||||
};
|
||||
export const removeGatePermission = async ({
|
||||
teamId,
|
||||
appId,
|
||||
per,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
per: number;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
// 1. 先找全员组
|
||||
const teamGroup = await MongoMemberGroupModel.findOne({
|
||||
teamId,
|
||||
name: DefaultGroupName
|
||||
});
|
||||
if (!teamGroup) {
|
||||
return Promise.reject('找不到全员组');
|
||||
}
|
||||
|
||||
await MongoResourcePermission.deleteOne(
|
||||
{
|
||||
teamId,
|
||||
groupId: teamGroup?._id,
|
||||
resourceType: PerResourceTypeEnum.app,
|
||||
resourceId: appId,
|
||||
permission: per
|
||||
},
|
||||
{
|
||||
session
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建团队门户配置
|
||||
@ -133,8 +214,20 @@ export const addFeaturedApp = async ({ teamId, appId }: { teamId: string; appId:
|
||||
/**
|
||||
* 删除特色应用
|
||||
*/
|
||||
export const removeFeaturedApp = async ({ teamId, appId }: { teamId: string; appId: string }) => {
|
||||
await MongoTeamGate.updateOne({ teamId }, { $pull: { featuredApps: new Types.ObjectId(appId) } });
|
||||
export const removeFeaturedApp = async ({
|
||||
teamId,
|
||||
appId,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appId: string;
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $pull: { featuredApps: new Types.ObjectId(appId) } },
|
||||
{ session }
|
||||
);
|
||||
return MongoTeamGate.findOne({ teamId }).lean();
|
||||
};
|
||||
|
||||
@ -252,7 +345,34 @@ export const batchUpdateFeaturedApps = async (
|
||||
return true;
|
||||
}
|
||||
|
||||
await MongoTeamGate.bulkWrite(operations);
|
||||
const teamId = updates[0]?.teamId;
|
||||
|
||||
const gateConfig = await MongoTeamGate.findOne({ teamId });
|
||||
if (!gateConfig) return Promise.reject('无 gate 配置');
|
||||
|
||||
const updatedAppId = updates[0].featuredApps;
|
||||
const deleteAppId = gateConfig.featuredApps.filter((id) => !updatedAppId.includes(id));
|
||||
|
||||
await mongoSessionRun(async (session) => {
|
||||
await MongoTeamGate.bulkWrite(operations, { session });
|
||||
|
||||
for (const id of deleteAppId) {
|
||||
await removeGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateFeaturedAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
for (const id of updatedAppId) {
|
||||
await addGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateFeaturedAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -291,10 +411,12 @@ export const batchUpdateToolsOrder = async (
|
||||
*/
|
||||
export const batchDeleteFeaturedApps = async ({
|
||||
teamId,
|
||||
appIds
|
||||
appIds,
|
||||
session
|
||||
}: {
|
||||
teamId: string;
|
||||
appIds: string[];
|
||||
session?: ClientSession;
|
||||
}) => {
|
||||
if (!appIds || appIds.length === 0) {
|
||||
return false;
|
||||
@ -302,7 +424,10 @@ export const batchDeleteFeaturedApps = async ({
|
||||
|
||||
await MongoTeamGate.updateOne(
|
||||
{ teamId },
|
||||
{ $pull: { featuredApps: { $in: appIds.map((id) => new Types.ObjectId(id)) } } }
|
||||
{ $pull: { featuredApps: { $in: appIds.map((id) => new Types.ObjectId(id)) } } },
|
||||
{
|
||||
session
|
||||
}
|
||||
);
|
||||
return true;
|
||||
};
|
||||
@ -384,31 +509,39 @@ export const moveQuickAppToPosition = async ({
|
||||
/**
|
||||
* 批量更新快速应用
|
||||
*/
|
||||
export const batchUpdateQuickApps = async (
|
||||
updates: {
|
||||
teamId: string;
|
||||
quickApps: string[];
|
||||
}[]
|
||||
) => {
|
||||
const operations = updates.map((update) => {
|
||||
const { teamId, quickApps } = update;
|
||||
// 将字符串数组转换为 ObjectId 数组
|
||||
const objectIdArray = quickApps.map((id) => new Types.ObjectId(id));
|
||||
return {
|
||||
updateOne: {
|
||||
filter: { teamId },
|
||||
update: { $set: { quickApps: objectIdArray } },
|
||||
upsert: true
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
if (operations.length === 0) {
|
||||
return true;
|
||||
export const batchUpdateQuickApps = async (teamId: string, quickApps: string[]) => {
|
||||
const gateConfig = await MongoTeamGate.findOne({ teamId });
|
||||
if (!gateConfig) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await MongoTeamGate.bulkWrite(operations);
|
||||
return true;
|
||||
// 计算删除的appId
|
||||
const deleteAppIds = gateConfig.quickApps.filter((id) => !quickApps.includes(id.toString()));
|
||||
|
||||
return mongoSessionRun(async (session) => {
|
||||
// 1. 删除权限
|
||||
for (const id of deleteAppIds) {
|
||||
await removeGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateQuickAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
// 加权限
|
||||
for (const id of quickApps) {
|
||||
await addGatePermission({
|
||||
teamId,
|
||||
appId: id,
|
||||
per: GateQuickAppPermission,
|
||||
session
|
||||
});
|
||||
}
|
||||
|
||||
gateConfig.quickApps = quickApps;
|
||||
await gateConfig.save({ session });
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -62,11 +62,15 @@ const AccountContainer = ({
|
||||
label: t('account:usage_records'),
|
||||
value: TabEnum.usage
|
||||
},
|
||||
{
|
||||
icon: 'support/gate/gateLight',
|
||||
label: t('account:gateways'),
|
||||
value: TabEnum.gateway
|
||||
}
|
||||
...(userInfo?.team?.permission.hasManagePer
|
||||
? [
|
||||
{
|
||||
icon: 'support/gate/gateLight',
|
||||
label: t('account:gateways'),
|
||||
value: TabEnum.gateway
|
||||
}
|
||||
]
|
||||
: [])
|
||||
]
|
||||
: []),
|
||||
...(feConfigs?.show_pay && userInfo?.team?.permission.hasManagePer
|
||||
|
||||
@ -338,7 +338,8 @@ const AppTable = () => {
|
||||
);
|
||||
|
||||
const { openConfirm: openConfirmDel, ConfirmModal: DelConfirmModal } = useConfirm({
|
||||
type: 'delete'
|
||||
type: 'delete',
|
||||
title: '确认删除该应用?'
|
||||
});
|
||||
|
||||
const { runAsync: onDeleteApp } = useRequest2(delAppById, {
|
||||
@ -487,12 +488,11 @@ const AppTable = () => {
|
||||
flexDirection={{ base: 'column', md: 'row' }}
|
||||
alignItems={{ base: 'stretch', md: 'center' }}
|
||||
>
|
||||
<Flex flex={1} gap={4}>
|
||||
<Flex gap={4}>
|
||||
<SearchInput
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={t('app:search_app')}
|
||||
flex={1}
|
||||
/>
|
||||
<Box w="200px">
|
||||
<Menu closeOnSelect={false}>
|
||||
|
||||
@ -158,12 +158,7 @@ const CopyrightTable = ({
|
||||
{t('account_gate:gate_logo')}
|
||||
</Text>
|
||||
|
||||
<Flex
|
||||
gap={{ base: 4, md: 8 }}
|
||||
alignItems="center"
|
||||
justifyContent="flex-start"
|
||||
flexDirection={{ base: 'column', md: 'row' }}
|
||||
>
|
||||
<Flex gap={{ base: 4, md: 8 }} alignItems="center" justifyContent="flex-start">
|
||||
{/* 左侧 Banner 显示 - 带文字 */}
|
||||
<Flex direction="column" gap={2} alignItems="center">
|
||||
<Box
|
||||
@ -369,8 +364,8 @@ const CopyrightTable = ({
|
||||
<LogoFile
|
||||
onSelect={(e: File[]) =>
|
||||
onSelectLogoImage(e, {
|
||||
maxH: 300,
|
||||
maxW: 300,
|
||||
maxH: 3000,
|
||||
maxW: 3000,
|
||||
callback: (e: string) => {
|
||||
setValue('logo', e);
|
||||
handleGateLogoChange(e);
|
||||
@ -382,8 +377,8 @@ const CopyrightTable = ({
|
||||
<BannerFile
|
||||
onSelect={(e: File[]) =>
|
||||
onSelectBannerImage(e, {
|
||||
maxH: 300,
|
||||
maxW: 300,
|
||||
maxH: 3000,
|
||||
maxW: 3000,
|
||||
callback: (e: string) => {
|
||||
setValue('banner', e);
|
||||
handleGateBannerChange(e);
|
||||
|
||||
@ -35,9 +35,7 @@ const GatewayConfig = () => {
|
||||
//从 appForm 中获取 selectedTools的 id 组成 string 数组
|
||||
|
||||
//gateConfig?.tools 改成
|
||||
const [copyRightConfig, setCopyRightConfig] = useState<
|
||||
getGateConfigCopyRightResponse | undefined
|
||||
>(undefined);
|
||||
const [copyRightConfig, setCopyRightConfig] = useState<getGateConfigCopyRightResponse>();
|
||||
const [tab, setTab] = useState<TabType>('home');
|
||||
const [isLoadingApps, setIsLoadingApps] = useState(true);
|
||||
const [gateApps, setGateApps] = useState<AppListItemType[]>([]);
|
||||
@ -247,8 +245,6 @@ const GatewayConfig = () => {
|
||||
}, [
|
||||
gateConfig,
|
||||
copyRightConfig,
|
||||
isLoadingApps,
|
||||
gateApps,
|
||||
Tab,
|
||||
isAppTab,
|
||||
tab,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user