feat: add app log permission (#4932)
* feat: add app log permission * fix: org search bug
This commit is contained in:
parent
5a5367d30b
commit
d7b9f94270
@ -1,8 +1,10 @@
|
||||
import { NullPermission, PermissionKeyEnum, PermissionList } from '../constant';
|
||||
import { type PermissionListType } from '../type';
|
||||
import { i18nT } from '../../../../web/i18n/utils';
|
||||
export enum AppPermissionKeyEnum {}
|
||||
export const AppPermissionList: PermissionListType = {
|
||||
export enum AppPermissionKeyEnum {
|
||||
log = 'log'
|
||||
}
|
||||
export const AppPermissionList: PermissionListType<AppPermissionKeyEnum> = {
|
||||
[PermissionKeyEnum.read]: {
|
||||
...PermissionList[PermissionKeyEnum.read],
|
||||
description: i18nT('app:permission.des.read')
|
||||
@ -13,8 +15,16 @@ export const AppPermissionList: PermissionListType = {
|
||||
},
|
||||
[PermissionKeyEnum.manage]: {
|
||||
...PermissionList[PermissionKeyEnum.manage],
|
||||
value: 0b1111,
|
||||
description: i18nT('app:permission.des.manage')
|
||||
},
|
||||
[AppPermissionKeyEnum.log]: {
|
||||
name: i18nT('app:permission.name.log'),
|
||||
value: 0b1000,
|
||||
checkBoxType: 'multiple',
|
||||
description: i18nT('app:permission.des.log')
|
||||
}
|
||||
};
|
||||
|
||||
export const AppDefaultPermissionVal = NullPermission;
|
||||
export const AppLogPermissionVal = AppPermissionList[AppPermissionKeyEnum.log].value;
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { type PerConstructPros, Permission } from '../controller';
|
||||
import { AppDefaultPermissionVal } from './constant';
|
||||
import { AppDefaultPermissionVal, AppPermissionList } from './constant';
|
||||
|
||||
export class AppPermission extends Permission {
|
||||
hasLogPer: boolean = false;
|
||||
constructor(props?: PerConstructPros) {
|
||||
if (!props) {
|
||||
props = {
|
||||
@ -11,5 +12,11 @@ export class AppPermission extends Permission {
|
||||
props.per = AppDefaultPermissionVal;
|
||||
}
|
||||
super(props);
|
||||
this.setUpdatePermissionCallback(() => {
|
||||
this.hasReadPer = this.checkPer(AppPermissionList.read.value);
|
||||
this.hasWritePer = this.checkPer(AppPermissionList.write.value);
|
||||
this.hasManagePer = this.checkPer(AppPermissionList.manage.value);
|
||||
this.hasLogPer = this.checkPer(AppPermissionList.log.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,6 +123,8 @@
|
||||
"permission.des.manage": "Based on write permissions, you can configure publishing channels, view conversation logs, and assign permissions to the application.",
|
||||
"permission.des.read": "Use the app to have conversations",
|
||||
"permission.des.write": "Can view and edit apps",
|
||||
"permission.des.log": "Can view conversation logs",
|
||||
"permission.name.log": "View logs",
|
||||
"plugin.Instructions": "Instructions",
|
||||
"plugin_cost_by_token": "Charged based on token usage",
|
||||
"plugin_cost_per_times": "{{cost}} points/time",
|
||||
|
||||
@ -123,6 +123,8 @@
|
||||
"permission.des.manage": "写权限基础上,可配置发布渠道、查看对话日志、分配该应用权限",
|
||||
"permission.des.read": "可使用该应用进行对话",
|
||||
"permission.des.write": "可查看和编辑应用",
|
||||
"permission.des.log": "可查看对话日志",
|
||||
"permission.name.log": "查看日志",
|
||||
"plugin.Instructions": "使用说明",
|
||||
"plugin_cost_by_token": "依据 token 消耗计费",
|
||||
"plugin_cost_per_times": "{{cost}} 积分/次",
|
||||
|
||||
@ -123,6 +123,8 @@
|
||||
"permission.des.manage": "在寫入權限基礎上,可以設定發布通道、檢視對話紀錄、分配這個應用程式的權限",
|
||||
"permission.des.read": "可以使用這個應用程式進行對話",
|
||||
"permission.des.write": "可以檢視和編輯應用程式",
|
||||
"permission.des.log": "可查看對話日誌",
|
||||
"permission.name.log": "查看日誌",
|
||||
"plugin.Instructions": "使用說明",
|
||||
"plugin_cost_by_token": "根據 token 消耗計費",
|
||||
"plugin_cost_per_times": "{{cost}} 積分/次",
|
||||
|
||||
@ -46,16 +46,22 @@ function MemberModal({
|
||||
const collaboratorList = useContextSelector(CollaboratorContext, (v) => v.collaboratorList);
|
||||
const [filterClass, setFilterClass] = useState<'member' | 'org' | 'group'>();
|
||||
const {
|
||||
paths,
|
||||
paths: orgPaths,
|
||||
onClickOrg,
|
||||
members: orgMembers,
|
||||
MemberScrollData: OrgMemberScrollData,
|
||||
onPathClick,
|
||||
onPathClick: onOrgPathClick,
|
||||
orgs,
|
||||
searchKey,
|
||||
setSearchKey
|
||||
} = useOrg({ withPermission: false });
|
||||
|
||||
const onExpandOrg = (org: OrgListItemType) => {
|
||||
setFilterClass('org');
|
||||
setSearchKey('');
|
||||
onClickOrg(org);
|
||||
};
|
||||
|
||||
const {
|
||||
data: members,
|
||||
ScrollData: TeamMemberScrollData,
|
||||
@ -104,8 +110,8 @@ function MemberModal({
|
||||
permissionList?.read?.value
|
||||
);
|
||||
const perLabel = useMemo(() => {
|
||||
if (selectedPermission === undefined) return '';
|
||||
return getPerLabelList(selectedPermission!).join('、');
|
||||
if (selectedPermission === undefined) return [];
|
||||
return getPerLabelList(selectedPermission!);
|
||||
}, [getPerLabelList, selectedPermission]);
|
||||
|
||||
const onUpdateCollaborators = useContextSelector(
|
||||
@ -194,6 +200,7 @@ function MemberModal({
|
||||
placeholder={t('user:search_group_org_user')}
|
||||
bgColor="myGray.50"
|
||||
onChange={(e) => setSearchKey(e.target.value)}
|
||||
value={searchKey}
|
||||
/>
|
||||
|
||||
<Flex flexDirection="column" mt="3" overflow={'auto'} flex={'1 0 0'} h={0}>
|
||||
@ -238,21 +245,21 @@ function MemberModal({
|
||||
? t('user:team.org.org')
|
||||
: t('user:team.group.group')
|
||||
},
|
||||
...paths
|
||||
...orgPaths
|
||||
]}
|
||||
onClick={(parentId) => {
|
||||
if (parentId === '') {
|
||||
setFilterClass(undefined);
|
||||
onPathClick('');
|
||||
onOrgPathClick('');
|
||||
} else if (
|
||||
parentId === 'member' ||
|
||||
parentId === 'org' ||
|
||||
parentId === 'group'
|
||||
) {
|
||||
setFilterClass(parentId);
|
||||
onPathClick('');
|
||||
onOrgPathClick('');
|
||||
} else {
|
||||
onPathClick(parentId);
|
||||
onOrgPathClick(parentId);
|
||||
}
|
||||
}}
|
||||
rootName={t('common:Team')}
|
||||
@ -329,8 +336,8 @@ function MemberModal({
|
||||
bgColor: 'myGray.200'
|
||||
}}
|
||||
onClick={(e) => {
|
||||
onClickOrg(org);
|
||||
// setPath(getOrgChildrenPath(org));
|
||||
// onClickOrg(org);
|
||||
onExpandOrg(org);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
@ -438,7 +445,7 @@ function MemberModal({
|
||||
borderRadius={'md'}
|
||||
h={'32px'}
|
||||
>
|
||||
{t(perLabel as any)}
|
||||
{perLabel.map((item) => t(item as any)).join('、')}
|
||||
<ChevronDownIcon fontSize={'md'} />
|
||||
</Flex>
|
||||
}
|
||||
|
||||
@ -7,7 +7,8 @@ import {
|
||||
Radio,
|
||||
useOutsideClick,
|
||||
HStack,
|
||||
MenuButton
|
||||
MenuButton,
|
||||
Checkbox
|
||||
} from '@chakra-ui/react';
|
||||
import React, { useMemo, useRef, useState } from 'react';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@ -89,19 +90,21 @@ function PermissionSelect({
|
||||
|
||||
return permissionList['read'].value;
|
||||
}, [permissionList, value]);
|
||||
// const selectedMultipleValues = useMemo(() => {
|
||||
// const per = new Permission({ per: value });
|
||||
//
|
||||
// return permissionSelectList.multipleCheckBoxList
|
||||
// .filter((item) => {
|
||||
// return per.checkPer(item.value);
|
||||
// })
|
||||
// .map((item) => item.value);
|
||||
// }, [permissionSelectList.multipleCheckBoxList, value]);
|
||||
const selectedMultipleValues = useMemo(() => {
|
||||
const per = new Permission({ per: value });
|
||||
|
||||
const onSelectPer = (per: PermissionValueType) => {
|
||||
if (per === value) return;
|
||||
onChange(per);
|
||||
return permissionSelectList.multipleCheckBoxList
|
||||
.filter((item) => {
|
||||
return per.checkPer(item.value);
|
||||
})
|
||||
.map((item) => item.value);
|
||||
}, [permissionSelectList.multipleCheckBoxList, value]);
|
||||
|
||||
const onSelectPer = (perValue: PermissionValueType) => {
|
||||
if (perValue === value) return;
|
||||
const per = new Permission({ per: perValue });
|
||||
per.addPer(...selectedMultipleValues);
|
||||
onChange(per.value);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
@ -184,50 +187,61 @@ function PermissionSelect({
|
||||
);
|
||||
})}
|
||||
|
||||
{/* <MyDivider my={3} />
|
||||
<MyDivider my={2} />
|
||||
|
||||
{multipleValues.length > 0 && <Box m="4">其他权限(多选)</Box>} */}
|
||||
{/* {permissionSelectList.multipleCheckBoxList.length > 0 && (
|
||||
<Box m="4">其他权限(多选)</Box>
|
||||
)} */}
|
||||
|
||||
{/* The list of multiple select permissions */}
|
||||
{/* {list
|
||||
.filter((item) => item.type === 'multiple')
|
||||
.map((item) => {
|
||||
const change = () => {
|
||||
if (checkPermission(valueState, item.value)) {
|
||||
setValueState(new Permission(valueState).remove(item.value).value);
|
||||
} else {
|
||||
setValueState(new Permission(valueState).add(item.value).value);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Flex
|
||||
key={item.value}
|
||||
{...(checkPermission(valueState, item.value)
|
||||
? {
|
||||
color: 'primary.500',
|
||||
bg: 'myWhite.300'
|
||||
}
|
||||
: {})}
|
||||
whiteSpace="pre-wrap"
|
||||
flexDirection="row"
|
||||
justifyContent="start"
|
||||
p="2"
|
||||
_hover={{
|
||||
bg: 'myGray.50'
|
||||
}}
|
||||
>
|
||||
<Checkbox
|
||||
size="lg"
|
||||
isChecked={checkPermission(valueState, item.value)}
|
||||
onChange={change}
|
||||
/>
|
||||
<Flex px="4" flexDirection="column" onClick={change}>
|
||||
<Box fontWeight="500">{item.name}</Box>
|
||||
<Box fontWeight="400">{item.description}</Box>
|
||||
</Flex>
|
||||
{permissionSelectList.multipleCheckBoxList.map((item) => {
|
||||
const isChecked = selectedMultipleValues.includes(item.value);
|
||||
const isDisabled = new Permission({ per: selectedSingleValue }).checkPer(item.value);
|
||||
const change = () => {
|
||||
if (isDisabled) return;
|
||||
const per = new Permission({ per: value });
|
||||
if (isChecked) {
|
||||
per.removePer(item.value);
|
||||
} else {
|
||||
per.addPer(item.value);
|
||||
}
|
||||
onChange(per.value);
|
||||
};
|
||||
return (
|
||||
<Flex
|
||||
key={item.value}
|
||||
{...(isChecked
|
||||
? {
|
||||
color: 'primary.500',
|
||||
bg: 'myWhite.300'
|
||||
}
|
||||
: {})}
|
||||
whiteSpace="pre-wrap"
|
||||
flexDirection="row"
|
||||
justifyContent="start"
|
||||
p="2"
|
||||
_hover={{
|
||||
bg: 'myGray.50'
|
||||
}}
|
||||
{...(isDisabled
|
||||
? {
|
||||
cursor: 'not-allowed',
|
||||
opacity: 0.5
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
<Checkbox
|
||||
size="lg"
|
||||
isChecked={isChecked}
|
||||
onChange={change}
|
||||
isDisabled={isDisabled}
|
||||
/>
|
||||
<Flex px="4" flexDirection="column" onClick={change}>
|
||||
<Box fontWeight="500">{t(item.name as any)}</Box>
|
||||
<Box fontWeight="400">{t(item.description as any)}</Box>
|
||||
</Flex>
|
||||
);
|
||||
})}*/}
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
{onDelete && (
|
||||
<>
|
||||
<MyDivider my={2} h={'2px'} borderColor={'myGray.200'} />
|
||||
|
||||
@ -35,10 +35,10 @@ const RouteTab = () => {
|
||||
{
|
||||
label: t('app:publish_channel'),
|
||||
id: TabEnum.publish
|
||||
},
|
||||
{ label: t('app:chat_logs'), id: TabEnum.logs }
|
||||
}
|
||||
]
|
||||
: [])
|
||||
: []),
|
||||
...(appDetail.permission.hasLogPer ? [{ label: t('app:chat_logs'), id: TabEnum.logs }] : [])
|
||||
],
|
||||
[appDetail.permission.hasManagePer, appDetail.type]
|
||||
);
|
||||
|
||||
@ -18,6 +18,7 @@ import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSc
|
||||
import type { ChatSourceEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
|
||||
import { type AIChatItemValueItemType } from '@fastgpt/global/core/chat/type';
|
||||
import { AppLogPermissionVal } from '@fastgpt/global/support/permission/app/constant';
|
||||
|
||||
const formatJsonString = (data: any) => {
|
||||
return JSON.stringify(data).replace(/"/g, '""').replace(/\n/g, '\\n');
|
||||
@ -44,7 +45,7 @@ async function handler(req: ApiRequestProps<ExportChatLogsBody, {}>, res: NextAp
|
||||
throw new Error('缺少参数');
|
||||
}
|
||||
|
||||
const { teamId } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
|
||||
const { teamId } = await authApp({ req, authToken: true, appId, per: AppLogPermissionVal });
|
||||
|
||||
const teamMemberWithContact = await MongoTeamMember.aggregate([
|
||||
{ $match: { teamId: new Types.ObjectId(teamId) } },
|
||||
|
||||
@ -13,6 +13,7 @@ import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
|
||||
import { type PaginationResponse } from '@fastgpt/web/common/fetch/type';
|
||||
import { addSourceMember } from '@fastgpt/service/support/user/utils';
|
||||
import { replaceRegChars } from '@fastgpt/global/common/string/tools';
|
||||
import { AppLogPermissionVal } from '@fastgpt/global/support/permission/app/constant';
|
||||
|
||||
async function handler(
|
||||
req: NextApiRequest,
|
||||
@ -33,7 +34,7 @@ async function handler(
|
||||
}
|
||||
|
||||
// 凭证校验
|
||||
const { teamId } = await authApp({ req, authToken: true, appId, per: WritePermissionVal });
|
||||
const { teamId } = await authApp({ req, authToken: true, appId, per: AppLogPermissionVal });
|
||||
|
||||
const where = {
|
||||
teamId: new Types.ObjectId(teamId),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user