Commit 9fb5d058 by gggaaallleee Committed by GitHub

add audit (#4923)

* add audit

* update audit

* update audit
parent b9745741
## Premise ## Premise
Since FastGPT is managed in the same way as monorepo, it is recommended to install ‘make’ first during development. Since FastGPT is managed in the same way as monorepo, it is recommended to install ‘make’ first during development.
monorepo Project Name: monorepo Project Name:
- app: main project - app: main project
-...... -......
## Dev ## Dev
```sh ```sh
# Give automatic script code execution permission (on non-Linux systems, you can manually execute the postinstall.sh file content) # Give automatic script code execution permission (on non-Linux systems, you can manually execute the postinstall.sh file content)
chmod -R +x ./scripts/ chmod -R +x ./scripts/
# Executing under the code root directory installs all dependencies within the root package, projects, and packages # Executing under the code root directory installs all dependencies within the root package, projects, and packages
pnpm i pnpm i
# Not make cmd # Not make cmd
cd projects/app cd projects/app
pnpm dev pnpm dev
# Make cmd # Make cmd
make dev name=app make dev name=app
``` ```
Note: If the Node version is >= 20, you need to pass the `--no-node-snapshot` parameter to Node when running `pnpm i` Note: If the Node version is >= 20, you need to pass the `--no-node-snapshot` parameter to Node when running `pnpm i`
```sh ```sh
NODE_OPTIONS=--no-node-snapshot pnpm i NODE_OPTIONS=--no-node-snapshot pnpm i
``` ```
### Jest ### Jest
https://fael3z0zfze.feishu.cn/docx/ZOI1dABpxoGhS7xzhkXcKPxZnDL https://fael3z0zfze.feishu.cn/docx/ZOI1dABpxoGhS7xzhkXcKPxZnDL
## I18N ## I18N
### Install i18n-ally Plugin ### Install i18n-ally Plugin
1. Open the Extensions Marketplace in VSCode, search for and install the `i18n Ally` plugin. 1. Open the Extensions Marketplace in VSCode, search for and install the `i18n Ally` plugin.
### Code Optimization Examples ### Code Optimization Examples
#### Fetch Specific Namespace Translations in `getServerSideProps` #### Fetch Specific Namespace Translations in `getServerSideProps`
```typescript ```typescript
// pages/yourPage.tsx // pages/yourPage.tsx
export async function getServerSideProps(context: any) { export async function getServerSideProps(context: any) {
return { return {
props: { props: {
currentTab: context?.query?.currentTab || TabEnum.info, currentTab: context?.query?.currentTab || TabEnum.info,
...(await serverSideTranslations(context.locale, ['publish', 'user'])) ...(await serverSideTranslations(context.locale, ['publish', 'user']))
} }
}; };
} }
``` ```
#### Use useTranslation Hook in Page #### Use useTranslation Hook in Page
```typescript ```typescript
// pages/yourPage.tsx // pages/yourPage.tsx
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
const YourComponent = () => { const YourComponent = () => {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
mr={2} mr={2}
onClick={() => setShowSelected(false)} onClick={() => setShowSelected(false)}
> >
{t('common:close')} {t('common:close')}
</Button> </Button>
); );
}; };
export default YourComponent; export default YourComponent;
``` ```
#### Handle Static File Translations #### Handle Static File Translations
```typescript ```typescript
// utils/i18n.ts // utils/i18n.ts
import { i18nT } from '@fastgpt/web/i18n/utils'; import { i18nT } from '@fastgpt/web/i18n/utils';
const staticContent = { const staticContent = {
id: 'simpleChat', id: 'simpleChat',
avatar: 'core/workflow/template/aiChat', avatar: 'core/workflow/template/aiChat',
name: i18nT('app:template.simple_robot'), name: i18nT('app:template.simple_robot'),
}; };
export default staticContent; export default staticContent;
``` ```
### Standardize Translation Format ### Standardize Translation Format
- Use the t(namespace:key) format to ensure consistent naming. - Use the t(namespace:key) format to ensure consistent naming.
- Translation keys should use lowercase letters and underscores, e.g., common.close. - Translation keys should use lowercase letters and underscores, e.g., common.close.
## Build ## audit
```sh Please fill the OperationLogEventEnum and operationLog/audit function is added to the ts, and on the corresponding position to fill i18n, at the same time to add the location of the log using addOpearationLog function add function
# Docker cmd: Build image, not proxy
docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app ## Build
# Make cmd: Build image, not proxy
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 ```sh
# Docker cmd: Build image, not proxy
# Docker cmd: Build image with proxy docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app
docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app --build-arg proxy=taobao # Make cmd: Build image, not proxy
# Make cmd: Build image with proxy make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 proxy=taobao
``` # Docker cmd: Build image with proxy
docker build -f ./projects/app/Dockerfile -t registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 . --build-arg name=app --build-arg proxy=taobao
# Make cmd: Build image with proxy
make build name=app image=registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.1 proxy=taobao
```
export enum OperationLogEventEnum { export enum OperationLogEventEnum {
//Team
LOGIN = 'LOGIN', LOGIN = 'LOGIN',
CREATE_INVITATION_LINK = 'CREATE_INVITATION_LINK', CREATE_INVITATION_LINK = 'CREATE_INVITATION_LINK',
JOIN_TEAM = 'JOIN_TEAM', JOIN_TEAM = 'JOIN_TEAM',
...@@ -11,5 +12,52 @@ export enum OperationLogEventEnum { ...@@ -11,5 +12,52 @@ export enum OperationLogEventEnum {
RELOCATE_DEPARTMENT = 'RELOCATE_DEPARTMENT', RELOCATE_DEPARTMENT = 'RELOCATE_DEPARTMENT',
CREATE_GROUP = 'CREATE_GROUP', CREATE_GROUP = 'CREATE_GROUP',
DELETE_GROUP = 'DELETE_GROUP', DELETE_GROUP = 'DELETE_GROUP',
ASSIGN_PERMISSION = 'ASSIGN_PERMISSION' ASSIGN_PERMISSION = 'ASSIGN_PERMISSION',
//APP
CREATE_APP = 'CREATE_APP',
UPDATE_APP_INFO = 'UPDATE_APP_INFO',
MOVE_APP = 'MOVE_APP',
DELETE_APP = 'DELETE_APP',
UPDATE_APP_COLLABORATOR = 'UPDATE_APP_COLLABORATOR',
DELETE_APP_COLLABORATOR = 'DELETE_APP_COLLABORATOR',
TRANSFER_APP_OWNERSHIP = 'TRANSFER_APP_OWNERSHIP',
CREATE_APP_COPY = 'CREATE_APP_COPY',
CREATE_APP_FOLDER = 'CREATE_APP_FOLDER',
UPDATE_PUBLISH_APP = 'UPDATE_PUBLISH_APP',
CREATE_APP_PUBLISH_CHANNEL = 'CREATE_APP_PUBLISH_CHANNEL',
UPDATE_APP_PUBLISH_CHANNEL = 'UPDATE_APP_PUBLISH_CHANNEL',
DELETE_APP_PUBLISH_CHANNEL = 'DELETE_APP_PUBLISH_CHANNEL',
EXPORT_APP_CHAT_LOG = 'EXPORT_APP_CHAT_LOG',
//Dataset
CREATE_DATASET = 'CREATE_DATASET',
UPDATE_DATASET = 'UPDATE_DATASET',
DELETE_DATASET = 'DELETE_DATASET',
MOVE_DATASET = 'MOVE_DATASET',
UPDATE_DATASET_COLLABORATOR = 'UPDATE_DATASET_COLLABORATOR',
DELETE_DATASET_COLLABORATOR = 'DELETE_DATASET_COLLABORATOR',
TRANSFER_DATASET_OWNERSHIP = 'TRANSFER_DATASET_OWNERSHIP',
EXPORT_DATASET = 'EXPORT_DATASET',
CREATE_DATASET_FOLDER = 'CREATE_DATASET_FOLDER',
//Collection
CREATE_COLLECTION = 'CREATE_COLLECTION',
UPDATE_COLLECTION = 'UPDATE_COLLECTION',
DELETE_COLLECTION = 'DELETE_COLLECTION',
RETRAIN_COLLECTION = 'RETRAIN_COLLECTION',
//Data
CREATE_DATA = 'CREATE_DATA',
UPDATE_DATA = 'UPDATE_DATA',
DELETE_DATA = 'DELETE_DATA',
//SearchTest
SEARCH_TEST = 'SEARCH_TEST',
//Account
CHANGE_PASSWORD = 'CHANGE_PASSWORD',
CHANGE_NOTIFICATION_SETTINGS = 'CHANGE_NOTIFICATION_SETTINGS',
CHANGE_MEMBER_NAME_ACCOUNT = 'CHANGE_MEMBER_NAME_ACCOUNT',
PURCHASE_PLAN = 'PURCHASE_PLAN',
EXPORT_BILL_RECORDS = 'EXPORT_BILL_RECORDS',
CREATE_INVOICE = 'CREATE_INVOICE',
SET_INVOICE_HEADER = 'SET_INVOICE_HEADER',
CREATE_API_KEY = 'CREATE_API_KEY',
UPDATE_API_KEY = 'UPDATE_API_KEY',
DELETE_API_KEY = 'DELETE_API_KEY'
} }
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { i18nT } from '../../../web/i18n/utils';
export function getI18nAppType(type: AppTypeEnum): string {
if (type === AppTypeEnum.folder) return i18nT('account_team:type.Folder');
if (type === AppTypeEnum.simple) return i18nT('account_team:type.Simple bot');
if (type === AppTypeEnum.workflow) return i18nT('account_team:type.Workflow bot');
if (type === AppTypeEnum.plugin) return i18nT('account_team:type.Plugin');
if (type === AppTypeEnum.httpPlugin) return i18nT('account_team:type.Http plugin');
if (type === AppTypeEnum.toolSet) return i18nT('account_team:type.Tool set');
if (type === AppTypeEnum.tool) return i18nT('account_team:type.Tool');
return i18nT('common:UnKnow');
}
export function getI18nCollaboratorItemType(
tmbId: string | undefined,
groupId: string | undefined,
orgId: string | undefined
): string {
if (tmbId) return i18nT('account_team:member');
if (groupId) return i18nT('account_team:group');
if (orgId) return i18nT('account_team:department');
return i18nT('common:UnKnow');
}
export function getI18nDatasetType(type: DatasetTypeEnum | string): string {
if (type === DatasetTypeEnum.folder) return i18nT('account_team:dataset.folder_dataset');
if (type === DatasetTypeEnum.dataset) return i18nT('account_team:dataset.common_dataset');
if (type === DatasetTypeEnum.websiteDataset) return i18nT('account_team:dataset.website_dataset');
if (type === DatasetTypeEnum.externalFile) return i18nT('account_team:dataset.external_file');
if (type === DatasetTypeEnum.apiDataset) return i18nT('account_team:dataset.api_file');
if (type === DatasetTypeEnum.feishu) return i18nT('account_team:dataset.feishu_dataset');
if (type === DatasetTypeEnum.yuque) return i18nT('account_team:dataset.yuque_dataset');
return i18nT('common:UnKnow');
}
...@@ -197,6 +197,9 @@ ...@@ -197,6 +197,9 @@
"type.MCP tools": "MCP Toolset", "type.MCP tools": "MCP Toolset",
"type.MCP_tools_url": "MCP Address", "type.MCP_tools_url": "MCP Address",
"type.Plugin": "Plugin", "type.Plugin": "Plugin",
"type.Folder": "Folder",
"type.Tool set": "Toolset",
"type.Tool": "Tool",
"type.Simple bot": "Simple App", "type.Simple bot": "Simple App",
"type.Workflow bot": "Workflow", "type.Workflow bot": "Workflow",
"type.error.Workflow data is empty": "No workflow data was obtained", "type.error.Workflow data is empty": "No workflow data was obtained",
...@@ -238,4 +241,4 @@ ...@@ -238,4 +241,4 @@
"workflow.user_file_input_desc": "Links to documents and images uploaded by users.", "workflow.user_file_input_desc": "Links to documents and images uploaded by users.",
"workflow.user_select": "User Select", "workflow.user_select": "User Select",
"workflow.user_select_tip": "This module can configure multiple options for selection during the dialogue. Different options can lead to different workflow branches." "workflow.user_select_tip": "This module can configure multiple options for selection during the dialogue. Different options can lead to different workflow branches."
} }
\ No newline at end of file
...@@ -215,6 +215,7 @@ ...@@ -215,6 +215,7 @@
"core.app.Interval timer run": "Scheduled Execution", "core.app.Interval timer run": "Scheduled Execution",
"core.app.Interval timer tip": "Can Execute App on Schedule", "core.app.Interval timer tip": "Can Execute App on Schedule",
"core.app.Make a brief introduction of your app": "Give Your AI App an Introduction", "core.app.Make a brief introduction of your app": "Give Your AI App an Introduction",
"core.app.name": "name",
"core.app.Name and avatar": "Avatar & Name", "core.app.Name and avatar": "Avatar & Name",
"core.app.Publish": "Publish", "core.app.Publish": "Publish",
"core.app.Publish Confirm": "Confirm to Publish App? This Will Immediately Update the App Status on All Publishing Channels.", "core.app.Publish Confirm": "Confirm to Publish App? This Will Immediately Update the App Status on All Publishing Channels.",
...@@ -1305,4 +1306,4 @@ ...@@ -1305,4 +1306,4 @@
"zoomin_tip_mac": "Zoom Out ⌘ -", "zoomin_tip_mac": "Zoom Out ⌘ -",
"zoomout_tip": "Zoom In ctrl +", "zoomout_tip": "Zoom In ctrl +",
"zoomout_tip_mac": "Zoom In ⌘ +" "zoomout_tip_mac": "Zoom In ⌘ +"
} }
\ No newline at end of file
{ {
"account_team.delete_dataset": "删除知识库",
"active_model": "可用模型", "active_model": "可用模型",
"add_default_model": "添加预设模型", "add_default_model": "添加预设模型",
"api_key": "API 密钥", "api_key": "API 密钥",
......
...@@ -189,6 +189,7 @@ ...@@ -189,6 +189,7 @@
"type.Create simple bot tip": "通过填表单形式,创建简单的 AI 应用,适合新手", "type.Create simple bot tip": "通过填表单形式,创建简单的 AI 应用,适合新手",
"type.Create workflow bot": "创建工作流", "type.Create workflow bot": "创建工作流",
"type.Create workflow tip": "通过低代码的方式,构建逻辑复杂的多轮对话 AI 应用,推荐高级玩家使用", "type.Create workflow tip": "通过低代码的方式,构建逻辑复杂的多轮对话 AI 应用,推荐高级玩家使用",
"type.Folder": "文件夹",
"type.Http plugin": "HTTP 插件", "type.Http plugin": "HTTP 插件",
"type.Import from json": "导入 JSON 配置", "type.Import from json": "导入 JSON 配置",
"type.Import from json tip": "通过 JSON 配置文件,直接创建应用", "type.Import from json tip": "通过 JSON 配置文件,直接创建应用",
...@@ -198,6 +199,8 @@ ...@@ -198,6 +199,8 @@
"type.MCP_tools_url": "MCP 地址", "type.MCP_tools_url": "MCP 地址",
"type.Plugin": "插件", "type.Plugin": "插件",
"type.Simple bot": "简易应用", "type.Simple bot": "简易应用",
"type.Tool": "工具",
"type.Tool set": "工具集",
"type.Workflow bot": "工作流", "type.Workflow bot": "工作流",
"type.error.Workflow data is empty": "没有获取到工作流数据", "type.error.Workflow data is empty": "没有获取到工作流数据",
"type.error.workflowresponseempty": "响应内容为空", "type.error.workflowresponseempty": "响应内容为空",
...@@ -238,4 +241,4 @@ ...@@ -238,4 +241,4 @@
"workflow.user_file_input_desc": "用户上传的文档和图片链接", "workflow.user_file_input_desc": "用户上传的文档和图片链接",
"workflow.user_select": "用户选择", "workflow.user_select": "用户选择",
"workflow.user_select_tip": "该模块可配置多个选项,以供对话时选择。不同选项可导向不同工作流支线" "workflow.user_select_tip": "该模块可配置多个选项,以供对话时选择。不同选项可导向不同工作流支线"
} }
\ No newline at end of file
...@@ -215,6 +215,7 @@ ...@@ -215,6 +215,7 @@
"core.app.Interval timer run": "定时执行", "core.app.Interval timer run": "定时执行",
"core.app.Interval timer tip": "可定时执行应用", "core.app.Interval timer tip": "可定时执行应用",
"core.app.Make a brief introduction of your app": "给你的 AI 应用一个介绍", "core.app.Make a brief introduction of your app": "给你的 AI 应用一个介绍",
"core.app.name": "名称",
"core.app.Name and avatar": "头像 & 名称", "core.app.Name and avatar": "头像 & 名称",
"core.app.Publish": "发布", "core.app.Publish": "发布",
"core.app.Publish Confirm": "确认发布应用?会立即更新所有发布渠道的应用状态。", "core.app.Publish Confirm": "确认发布应用?会立即更新所有发布渠道的应用状态。",
...@@ -1305,4 +1306,4 @@ ...@@ -1305,4 +1306,4 @@
"zoomin_tip_mac": "缩小 ⌘ -", "zoomin_tip_mac": "缩小 ⌘ -",
"zoomout_tip": "放大 ctrl +", "zoomout_tip": "放大 ctrl +",
"zoomout_tip_mac": "放大 ⌘ +" "zoomout_tip_mac": "放大 ⌘ +"
} }
\ No newline at end of file
...@@ -198,6 +198,9 @@ ...@@ -198,6 +198,9 @@
"type.MCP_tools_url": "MCP 地址", "type.MCP_tools_url": "MCP 地址",
"type.Plugin": "外掛", "type.Plugin": "外掛",
"type.Simple bot": "簡易應用程式", "type.Simple bot": "簡易應用程式",
"type.Folder": "資料夾",
"type.Tool set": "工具集",
"type.Tool": "工具",
"type.Workflow bot": "工作流程", "type.Workflow bot": "工作流程",
"type.error.Workflow data is empty": "沒有獲取到工作流數據", "type.error.Workflow data is empty": "沒有獲取到工作流數據",
"type.error.workflowresponseempty": "響應內容為空", "type.error.workflowresponseempty": "響應內容為空",
...@@ -238,4 +241,4 @@ ...@@ -238,4 +241,4 @@
"workflow.user_file_input_desc": "使用者上傳的檔案和圖片連結", "workflow.user_file_input_desc": "使用者上傳的檔案和圖片連結",
"workflow.user_select": "使用者選擇", "workflow.user_select": "使用者選擇",
"workflow.user_select_tip": "這個模組可以設定多個選項,供對話時選擇。不同選項可以導向不同的工作流程支線" "workflow.user_select_tip": "這個模組可以設定多個選項,供對話時選擇。不同選項可以導向不同的工作流程支線"
} }
\ No newline at end of file
...@@ -215,6 +215,7 @@ ...@@ -215,6 +215,7 @@
"core.app.Interval timer run": "排程執行", "core.app.Interval timer run": "排程執行",
"core.app.Interval timer tip": "可排程執行應用程式", "core.app.Interval timer tip": "可排程執行應用程式",
"core.app.Make a brief introduction of your app": "為您的 AI 應用程式寫一段介紹", "core.app.Make a brief introduction of your app": "為您的 AI 應用程式寫一段介紹",
"core.app.name": "名稱",
"core.app.Name and avatar": "頭像與名稱", "core.app.Name and avatar": "頭像與名稱",
"core.app.Publish": "發布", "core.app.Publish": "發布",
"core.app.Publish Confirm": "確認發布應用程式?這將立即更新所有發布管道的應用程式狀態。", "core.app.Publish Confirm": "確認發布應用程式?這將立即更新所有發布管道的應用程式狀態。",
...@@ -1305,4 +1306,4 @@ ...@@ -1305,4 +1306,4 @@
"zoomin_tip_mac": "縮小 ⌘ -", "zoomin_tip_mac": "縮小 ⌘ -",
"zoomout_tip": "放大 ctrl +", "zoomout_tip": "放大 ctrl +",
"zoomout_tip_mac": "放大 ⌘ +" "zoomout_tip_mac": "放大 ⌘ +"
} }
\ No newline at end of file
...@@ -26,6 +26,7 @@ import MultipleSelect, { ...@@ -26,6 +26,7 @@ import MultipleSelect, {
} from '@fastgpt/web/components/common/MySelect/MultipleSelect'; } from '@fastgpt/web/components/common/MySelect/MultipleSelect';
import Avatar from '@fastgpt/web/components/common/Avatar'; import Avatar from '@fastgpt/web/components/common/Avatar';
import { getTeamMembers } from '@/web/support/user/team/api'; import { getTeamMembers } from '@/web/support/user/team/api';
import { createMetadataProcessorMap, type MetadataProcessor } from './processors';
function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) { function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
const { t } = useTranslation(); const { t } = useTranslation();
...@@ -58,6 +59,14 @@ function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) { ...@@ -58,6 +59,14 @@ function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
[t] [t]
); );
const processMetadataByEvent = useMemo(() => {
const metadataProcessorMap = createMetadataProcessorMap();
return (event: string, metadata: any) => {
const processor = metadataProcessorMap[event as OperationLogEventEnum];
return processor ? processor(metadata, t) : metadata;
};
}, [t]);
const { const {
data: operationLogs = [], data: operationLogs = [],
isLoading: loadingLogs, isLoading: loadingLogs,
...@@ -159,17 +168,7 @@ function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) { ...@@ -159,17 +168,7 @@ function OperationLogTable({ Tabs }: { Tabs: React.ReactNode }) {
<Tbody> <Tbody>
{operationLogs?.map((log) => { {operationLogs?.map((log) => {
const i18nData = operationLogMap[log.event]; const i18nData = operationLogMap[log.event];
const metadata = { ...log.metadata }; const metadata = processMetadataByEvent(log.event, { ...log.metadata });
if (log.event === OperationLogEventEnum.ASSIGN_PERMISSION) {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new TeamPermission({ per: permissionValue });
metadata.appCreate = permission.hasAppCreatePer ? '✔' : '✘';
metadata.datasetCreate = permission.hasDatasetCreatePer ? '✔' : '✘';
metadata.apiKeyCreate = permission.hasApikeyCreatePer ? '✔' : '✘';
metadata.manage = permission.hasManagePer ? '✔' : '✘';
}
return i18nData ? ( return i18nData ? (
<Tr key={log._id} overflow={'unset'}> <Tr key={log._id} overflow={'unset'}>
......
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';
import { createSpecialProcessor } from './commonProcessor';
export const processUpdateAppCollaboratorSpecific = (metadata: any) => {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new AppPermission({ per: permissionValue });
return {
...metadata,
readPermission: permission.hasReadPer ? '✔' : '✘',
writePermission: permission.hasWritePer ? '✔' : '✘',
managePermission: permission.hasManagePer ? '✔' : '✘'
};
};
export const createAppProcessors = () => ({
UPDATE_APP_COLLABORATOR: createSpecialProcessor(processUpdateAppCollaboratorSpecific)
});
export interface CommonMetadataFields {
appType?: string;
datasetType?: string;
operationName?: string;
itemName?: string;
newItemNames?: string[] | string;
[key: string]: any;
}
export const defaultMetadataProcessor = (metadata: CommonMetadataFields, t: any): any => {
const result = { ...metadata };
const translatableFields = ['appType', 'datasetType', 'operationName', 'itemName'];
Object.entries(metadata)
.filter(([key, value]) => translatableFields.includes(key) && value)
.forEach(([key, value]) => {
result[key] = t(value as any);
});
if (metadata.newItemNames) {
if (Array.isArray(metadata.newItemNames)) {
result.newItemNames = metadata.newItemNames
.map((itemName: string) => t(itemName as any))
.join(',');
} else if (typeof metadata.newItemNames === 'string') {
result.newItemNames = metadata.newItemNames
.split(',')
.map((itemName: string) => t(itemName as any))
.join(',');
}
}
return result;
};
export const createSpecialProcessor = (specificProcessor: (metadata: any) => any) => {
return (metadata: any, t: any) => {
let processedMetadata = defaultMetadataProcessor(metadata, t);
processedMetadata = specificProcessor(processedMetadata);
return processedMetadata;
};
};
import { DatasetPermission } from '@fastgpt/global/support/permission/dataset/controller';
import { createSpecialProcessor } from './commonProcessor';
export const processUpdateDatasetCollaboratorSpecific = (metadata: any) => {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new DatasetPermission({ per: permissionValue });
return {
...metadata,
readPermission: permission.hasReadPer ? '✔' : '✘',
writePermission: permission.hasWritePer ? '✔' : '✘',
managePermission: permission.hasManagePer ? '✔' : '✘'
};
};
export const createDatasetProcessors = () => ({
UPDATE_DATASET_COLLABORATOR: createSpecialProcessor(processUpdateDatasetCollaboratorSpecific)
});
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { defaultMetadataProcessor } from './commonProcessor';
import { createTeamProcessors } from './teamProcessors';
import { createAppProcessors } from './appProcessors';
import { createDatasetProcessors } from './datasetProcessors';
export type MetadataProcessor = (metadata: any, t: any) => any;
export const createMetadataProcessorMap = (): Record<OperationLogEventEnum, MetadataProcessor> => {
const specialProcessors: Partial<Record<OperationLogEventEnum, MetadataProcessor>> = {
...createTeamProcessors(),
...createAppProcessors(),
...createDatasetProcessors()
};
const processorMap = {} as Record<OperationLogEventEnum, MetadataProcessor>;
Object.values(OperationLogEventEnum).forEach((event) => {
processorMap[event] =
specialProcessors[event] ||
((metadata: any, t: any) => defaultMetadataProcessor(metadata, t));
});
return processorMap;
};
export * from './commonProcessor';
export * from './teamProcessors';
export * from './appProcessors';
export * from './datasetProcessors';
import { TeamPermission } from '@fastgpt/global/support/permission/user/controller';
import { createSpecialProcessor } from './commonProcessor';
export const processAssignPermissionSpecific = (metadata: any) => {
const permissionValue = parseInt(metadata.permission, 10);
const permission = new TeamPermission({ per: permissionValue });
return {
...metadata,
appCreate: permission.hasAppCreatePer ? '✔' : '✘',
datasetCreate: permission.hasDatasetCreatePer ? '✔' : '✘',
apiKeyCreate: permission.hasApikeyCreatePer ? '✔' : '✘',
manage: permission.hasManagePer ? '✔' : '✘'
};
};
export const createTeamProcessors = () => ({
ASSIGN_PERMISSION: createSpecialProcessor(processAssignPermissionSpecific)
});
...@@ -5,7 +5,10 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth'; ...@@ -5,7 +5,10 @@ import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth'; import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next'; import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { onCreateApp } from './create'; import { onCreateApp } from './create';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type copyAppQuery = {}; export type copyAppQuery = {};
export type copyAppBody = { appId: string }; export type copyAppBody = { appId: string };
...@@ -18,7 +21,7 @@ async function handler( ...@@ -18,7 +21,7 @@ async function handler(
req: ApiRequestProps<copyAppBody, copyAppQuery>, req: ApiRequestProps<copyAppBody, copyAppQuery>,
res: ApiResponseType<any> res: ApiResponseType<any>
): Promise<copyAppResponse> { ): Promise<copyAppResponse> {
const { app } = await authApp({ const { app, teamId } = await authApp({
req, req,
authToken: true, authToken: true,
per: WritePermissionVal, per: WritePermissionVal,
...@@ -42,6 +45,17 @@ async function handler( ...@@ -42,6 +45,17 @@ async function handler(
tmbId, tmbId,
pluginData: app.pluginData pluginData: app.pluginData
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP_COPY,
params: {
appName: app.name,
appType: getI18nAppType(app.type)
}
});
})();
return { appId }; return { appId };
} }
......
...@@ -19,6 +19,9 @@ import { checkTeamAppLimit } from '@fastgpt/service/support/permission/teamLimit ...@@ -19,6 +19,9 @@ import { checkTeamAppLimit } from '@fastgpt/service/support/permission/teamLimit
import { authUserPer } from '@fastgpt/service/support/permission/user/auth'; import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema'; import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { type ApiRequestProps } from '@fastgpt/service/type/next'; import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type CreateAppBody = { export type CreateAppBody = {
parentId?: ParentIdType; parentId?: ParentIdType;
...@@ -148,6 +151,17 @@ export const onCreateApp = async ({ ...@@ -148,6 +151,17 @@ export const onCreateApp = async ({
{ session, ordered: true } { session, ordered: true }
); );
} }
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP,
params: {
appName: name!,
appType: getI18nAppType(type!)
}
});
})();
await refreshSourceAvatar(avatar, undefined, session); await refreshSourceAvatar(avatar, undefined, session);
......
...@@ -19,7 +19,10 @@ import { deleteChatFiles } from '@fastgpt/service/core/chat/controller'; ...@@ -19,7 +19,10 @@ import { deleteChatFiles } from '@fastgpt/service/core/chat/controller';
import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils'; import { pushTrack } from '@fastgpt/service/common/middle/tracks/utils';
import { MongoOpenApi } from '@fastgpt/service/support/openapi/schema'; import { MongoOpenApi } from '@fastgpt/service/support/openapi/schema';
import { removeImageByPath } from '@fastgpt/service/common/file/image/controller'; import { removeImageByPath } from '@fastgpt/service/common/file/image/controller';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) { async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string }; const { appId } = req.query as { appId: string };
...@@ -39,6 +42,17 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) { ...@@ -39,6 +42,17 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
teamId, teamId,
appId appId
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_APP,
params: {
appName: app.name,
appType: getI18nAppType(app.type)
}
});
})();
// Tracks // Tracks
pushTrack.countAppNodes({ teamId, tmbId, uid: userId, appId }); pushTrack.countAppNodes({ teamId, tmbId, uid: userId, appId });
......
...@@ -18,7 +18,8 @@ import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPe ...@@ -18,7 +18,8 @@ import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPe
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema'; import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth'; import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import { type ApiRequestProps } from '@fastgpt/service/type/next'; import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
export type CreateAppFolderBody = { export type CreateAppFolderBody = {
parentId?: ParentIdType; parentId?: ParentIdType;
name: string; name: string;
...@@ -83,6 +84,16 @@ async function handler(req: ApiRequestProps<CreateAppFolderBody>) { ...@@ -83,6 +84,16 @@ async function handler(req: ApiRequestProps<CreateAppFolderBody>) {
); );
} }
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP_FOLDER,
params: {
folderName: name
}
});
})();
} }
export default NextAPI(handler); export default NextAPI(handler);
...@@ -13,6 +13,9 @@ import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination'; ...@@ -13,6 +13,9 @@ import { parsePaginationRequest } from '@fastgpt/service/common/api/pagination';
import { type PaginationResponse } from '@fastgpt/web/common/fetch/type'; import { type PaginationResponse } from '@fastgpt/web/common/fetch/type';
import { addSourceMember } from '@fastgpt/service/support/user/utils'; import { addSourceMember } from '@fastgpt/service/support/user/utils';
import { replaceRegChars } from '@fastgpt/global/common/string/tools'; import { replaceRegChars } from '@fastgpt/global/common/string/tools';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
async function handler( async function handler(
req: NextApiRequest, req: NextApiRequest,
...@@ -33,7 +36,12 @@ async function handler( ...@@ -33,7 +36,12 @@ async function handler(
} }
// 凭证校验 // 凭证校验
const { teamId } = await authApp({ req, authToken: true, appId, per: WritePermissionVal }); const { teamId, tmbId, app } = await authApp({
req,
authToken: true,
appId,
per: WritePermissionVal
});
const where = { const where = {
teamId: new Types.ObjectId(teamId), teamId: new Types.ObjectId(teamId),
...@@ -139,6 +147,18 @@ async function handler( ...@@ -139,6 +147,18 @@ async function handler(
const listWithoutTmbId = list.filter((item) => !item.tmbId); const listWithoutTmbId = list.filter((item) => !item.tmbId);
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.EXPORT_APP_CHAT_LOG,
params: {
appName: app.name,
appType: getI18nAppType(app.type)
}
});
})();
return { return {
list: listWithSourceMember.concat(listWithoutTmbId), list: listWithSourceMember.concat(listWithoutTmbId),
total total
......
...@@ -24,6 +24,10 @@ import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/u ...@@ -24,6 +24,10 @@ import { TeamAppCreatePermissionVal } from '@fastgpt/global/support/permission/u
import { AppErrEnum } from '@fastgpt/global/common/error/code/app'; import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller'; import { refreshSourceAvatar } from '@fastgpt/service/common/file/image/controller';
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema'; import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
import { i18nT } from '@fastgpt/web/i18n/utils';
export type AppUpdateQuery = { export type AppUpdateQuery = {
appId: string; appId: string;
...@@ -54,7 +58,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) { ...@@ -54,7 +58,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
// this step is to get the app and its permission, and we will check the permission manually for // this step is to get the app and its permission, and we will check the permission manually for
// different cases // different cases
const { app, permission } = await authApp({ const { app, permission, teamId, tmbId } = await authApp({
req, req,
authToken: true, authToken: true,
appId, appId,
...@@ -65,11 +69,23 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) { ...@@ -65,11 +69,23 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
Promise.reject(AppErrEnum.unExist); Promise.reject(AppErrEnum.unExist);
} }
let targetName = '';
if (isMove) { if (isMove) {
if (parentId) { if (parentId) {
// move to a folder, check the target folder's permission // move to a folder, check the target folder's permission
await authApp({ req, authToken: true, appId: parentId, per: ManagePermissionVal }); const { app: targetApp } = await authApp({
req,
authToken: true,
appId: parentId,
per: ManagePermissionVal
});
targetName = targetApp.name;
} else {
targetName = 'root';
} }
if (app.parentId) { if (app.parentId) {
// move from a folder, check the (old) folder's permission // move from a folder, check the (old) folder's permission
await authApp({ req, authToken: true, appId: app.parentId, per: ManagePermissionVal }); await authApp({ req, authToken: true, appId: app.parentId, per: ManagePermissionVal });
...@@ -160,6 +176,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) { ...@@ -160,6 +176,7 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
session session
}); });
} else { } else {
logAppMove({ tmbId, teamId, app, targetName });
// Not folder, delete all clb // Not folder, delete all clb
await MongoResourcePermission.deleteMany( await MongoResourcePermission.deleteMany(
{ resourceType: PerResourceTypeEnum.app, teamId: app.teamId, resourceId: app._id }, { resourceType: PerResourceTypeEnum.app, teamId: app.teamId, resourceId: app._id },
...@@ -169,8 +186,85 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) { ...@@ -169,8 +186,85 @@ async function handler(req: ApiRequestProps<AppUpdateBody, AppUpdateQuery>) {
return onUpdate(session); return onUpdate(session);
}); });
} else { } else {
logAppUpdate({ tmbId, teamId, app, name, intro });
return onUpdate(); return onUpdate();
} }
} }
export default NextAPI(handler); export default NextAPI(handler);
const logAppMove = ({
tmbId,
teamId,
app,
targetName
}: {
tmbId: string;
teamId: string;
app: any;
targetName: string;
}) => {
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.MOVE_APP,
params: {
appName: app.name,
targetFolderName: targetName,
appType: getI18nAppType(app.type)
}
});
})();
};
const logAppUpdate = ({
tmbId,
teamId,
app,
name,
intro
}: {
tmbId: string;
teamId: string;
app: any;
name?: string;
intro?: string;
}) => {
(async () => {
const getUpdateItems = () => {
const names: string[] = [];
const values: string[] = [];
if (name !== undefined) {
names.push(i18nT('common:core.app.name'));
values.push(name);
}
if (intro !== undefined) {
names.push(i18nT('common:Intro'));
values.push(intro);
}
return {
names,
values
};
};
const { names: newItemNames, values: newItemValues } = getUpdateItems();
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_APP_INFO,
params: {
appName: app.name,
newItemNames: newItemNames,
newItemValues: newItemValues,
appType: getI18nAppType(app.type)
}
});
})();
};
...@@ -11,12 +11,20 @@ import { WritePermissionVal } from '@fastgpt/global/support/permission/constant' ...@@ -11,12 +11,20 @@ import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'
import { type ApiRequestProps } from '@fastgpt/service/type/next'; import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { rewriteAppWorkflowToSimple } from '@fastgpt/service/core/app/utils'; import { rewriteAppWorkflowToSimple } from '@fastgpt/service/core/app/utils';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
import { i18nT } from '@fastgpt/web/i18n/utils';
async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiResponse<any>) { async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiResponse<any>) {
const { appId } = req.query as { appId: string }; const { appId } = req.query as { appId: string };
const { nodes = [], edges = [], chatConfig, isPublish, versionName, autoSave } = req.body; const { nodes = [], edges = [], chatConfig, isPublish, versionName, autoSave } = req.body;
const { app, tmbId } = await authApp({ appId, req, per: WritePermissionVal, authToken: true }); const { app, tmbId, teamId } = await authApp({
appId,
req,
per: WritePermissionVal,
authToken: true
});
const { nodes: formatNodes } = beforeUpdateAppFormat({ const { nodes: formatNodes } = beforeUpdateAppFormat({
nodes, nodes,
...@@ -26,12 +34,26 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe ...@@ -26,12 +34,26 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe
await rewriteAppWorkflowToSimple(formatNodes); await rewriteAppWorkflowToSimple(formatNodes);
if (autoSave) { if (autoSave) {
return MongoApp.findByIdAndUpdate(appId, { await MongoApp.findByIdAndUpdate(appId, {
modules: formatNodes, modules: formatNodes,
edges, edges,
chatConfig, chatConfig,
updateTime: new Date() updateTime: new Date()
}); });
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_PUBLISH_APP,
params: {
appName: app.name,
operationName: i18nT('account_team:update'),
appId,
appType: getI18nAppType(app.type)
}
});
return;
} }
await mongoSessionRun(async (session) => { await mongoSessionRun(async (session) => {
...@@ -79,6 +101,22 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe ...@@ -79,6 +101,22 @@ async function handler(req: ApiRequestProps<PostPublishAppProps>, res: NextApiRe
} }
); );
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_PUBLISH_APP,
params: {
appName: app.name,
operationName: isPublish
? i18nT('account_team:save_and_publish')
: i18nT('account_team:update'),
appId,
appType: getI18nAppType(app.type)
}
});
})();
} }
export default NextAPI(handler); export default NextAPI(handler);
...@@ -4,11 +4,14 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth'; ...@@ -4,11 +4,14 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller'; import { createOneCollection } from '@fastgpt/service/core/dataset/collection/controller';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) { async function handler(req: NextApiRequest) {
const body = req.body as CreateDatasetCollectionParams; const body = req.body as CreateDatasetCollectionParams;
const { teamId, tmbId } = await authDataset({ const { teamId, tmbId, dataset } = await authDataset({
req, req,
authToken: true, authToken: true,
authApiKey: true, authApiKey: true,
...@@ -21,6 +24,20 @@ async function handler(req: NextApiRequest) { ...@@ -21,6 +24,20 @@ async function handler(req: NextApiRequest) {
teamId, teamId,
tmbId tmbId
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_COLLECTION,
params: {
collectionName: body.name,
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
return _id; return _id;
} }
......
...@@ -14,6 +14,9 @@ import { authDatasetCollection } from '@fastgpt/service/support/permission/datas ...@@ -14,6 +14,9 @@ import { authDatasetCollection } from '@fastgpt/service/support/permission/datas
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { i18nT } from '@fastgpt/web/i18n/utils'; import { i18nT } from '@fastgpt/web/i18n/utils';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
type RetrainingCollectionResponse = { type RetrainingCollectionResponse = {
collectionId: string; collectionId: string;
...@@ -124,6 +127,19 @@ async function handler( ...@@ -124,6 +127,19 @@ async function handler(
} }
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.RETRAIN_COLLECTION,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
return { collectionId }; return { collectionId };
}); });
} }
......
...@@ -6,7 +6,9 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; ...@@ -6,7 +6,9 @@ import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) { async function handler(req: NextApiRequest) {
const { id: collectionId } = req.query as { id: string }; const { id: collectionId } = req.query as { id: string };
...@@ -14,7 +16,7 @@ async function handler(req: NextApiRequest) { ...@@ -14,7 +16,7 @@ async function handler(req: NextApiRequest) {
return Promise.reject(CommonErrEnum.missingParams); return Promise.reject(CommonErrEnum.missingParams);
} }
const { teamId, collection } = await authDatasetCollection({ const { teamId, collection, tmbId } = await authDatasetCollection({
req, req,
authToken: true, authToken: true,
authApiKey: true, authApiKey: true,
...@@ -39,6 +41,19 @@ async function handler(req: NextApiRequest) { ...@@ -39,6 +41,19 @@ async function handler(req: NextApiRequest) {
session session
}) })
); );
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_COLLECTION,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
} }
export default NextAPI(handler); export default NextAPI(handler);
...@@ -12,7 +12,9 @@ import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant ...@@ -12,7 +12,9 @@ import { DatasetCollectionTypeEnum } from '@fastgpt/global/core/dataset/constant
import { type ClientSession } from '@fastgpt/service/common/mongo'; import { type ClientSession } from '@fastgpt/service/common/mongo';
import { type CollectionWithDatasetType } from '@fastgpt/global/core/dataset/type'; import { type CollectionWithDatasetType } from '@fastgpt/global/core/dataset/type';
import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
export type UpdateDatasetCollectionParams = { export type UpdateDatasetCollectionParams = {
id?: string; id?: string;
parentId?: string; parentId?: string;
...@@ -88,7 +90,7 @@ async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) { ...@@ -88,7 +90,7 @@ async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) {
} }
// 凭证校验 // 凭证校验
const { collection, teamId } = await authDatasetCollection({ const { collection, teamId, tmbId } = await authDatasetCollection({
req, req,
authToken: true, authToken: true,
authApiKey: true, authApiKey: true,
...@@ -131,6 +133,19 @@ async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) { ...@@ -131,6 +133,19 @@ async function handler(req: ApiRequestProps<UpdateDatasetCollectionParams>) {
}); });
} }
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_COLLECTION,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
} }
export default NextAPI(handler); export default NextAPI(handler);
...@@ -18,6 +18,9 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth'; ...@@ -18,6 +18,9 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { checkTeamDatasetLimit } from '@fastgpt/service/support/permission/teamLimit'; import { checkTeamDatasetLimit } from '@fastgpt/service/support/permission/teamLimit';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth'; import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import type { ApiRequestProps } from '@fastgpt/service/type/next'; import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
export type DatasetCreateQuery = {}; export type DatasetCreateQuery = {};
export type DatasetCreateBody = CreateDatasetParams; export type DatasetCreateBody = CreateDatasetParams;
...@@ -102,6 +105,18 @@ async function handler( ...@@ -102,6 +105,18 @@ async function handler(
uid: userId uid: userId
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_DATASET,
params: {
datasetName: name,
datasetType: getI18nDatasetType(type)
}
});
})();
return datasetId; return datasetId;
} }
export default NextAPI(handler); export default NextAPI(handler);
...@@ -4,7 +4,9 @@ import { deleteDatasetData } from '@/service/core/dataset/data/controller'; ...@@ -4,7 +4,9 @@ import { deleteDatasetData } from '@/service/core/dataset/data/controller';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) { async function handler(req: NextApiRequest) {
const { id: dataId } = req.query as { const { id: dataId } = req.query as {
id: string; id: string;
...@@ -15,7 +17,7 @@ async function handler(req: NextApiRequest) { ...@@ -15,7 +17,7 @@ async function handler(req: NextApiRequest) {
} }
// 凭证校验 // 凭证校验
const { datasetData } = await authDatasetData({ const { datasetData, tmbId, teamId, collection } = await authDatasetData({
req, req,
authToken: true, authToken: true,
authApiKey: true, authApiKey: true,
...@@ -24,7 +26,18 @@ async function handler(req: NextApiRequest) { ...@@ -24,7 +26,18 @@ async function handler(req: NextApiRequest) {
}); });
await deleteDatasetData(datasetData); await deleteDatasetData(datasetData);
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_DATA,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
return 'success'; return 'success';
} }
......
...@@ -17,6 +17,9 @@ import { NextAPI } from '@/service/middleware/entry'; ...@@ -17,6 +17,9 @@ import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { getLLMMaxChunkSize } from '@fastgpt/global/core/dataset/training/utils'; import { getLLMMaxChunkSize } from '@fastgpt/global/core/dataset/training/utils';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) { async function handler(req: NextApiRequest) {
const { collectionId, q, a, indexes } = req.body as InsertOneDatasetDataProps; const { collectionId, q, a, indexes } = req.body as InsertOneDatasetDataProps;
...@@ -30,7 +33,7 @@ async function handler(req: NextApiRequest) { ...@@ -30,7 +33,7 @@ async function handler(req: NextApiRequest) {
} }
// 凭证校验 // 凭证校验
const { teamId, tmbId } = await authDatasetCollection({ const { teamId, tmbId, collection } = await authDatasetCollection({
req, req,
authToken: true, authToken: true,
authApiKey: true, authApiKey: true,
...@@ -96,6 +99,18 @@ async function handler(req: NextApiRequest) { ...@@ -96,6 +99,18 @@ async function handler(req: NextApiRequest) {
model: vectorModelData.model model: vectorModelData.model
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_DATA,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
return insertId; return insertId;
} }
......
...@@ -5,7 +5,9 @@ import { NextAPI } from '@/service/middleware/entry'; ...@@ -5,7 +5,9 @@ import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { authDatasetData } from '@fastgpt/service/support/permission/dataset/auth'; import { authDatasetData } from '@fastgpt/service/support/permission/dataset/auth';
import { type ApiRequestProps } from '@fastgpt/service/type/next'; import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) { async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
const { dataId, q, a, indexes = [] } = req.body; const { dataId, q, a, indexes = [] } = req.body;
...@@ -15,7 +17,8 @@ async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) { ...@@ -15,7 +17,8 @@ async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
dataset: { vectorModel } dataset: { vectorModel }
}, },
teamId, teamId,
tmbId tmbId,
collection
} = await authDatasetData({ } = await authDatasetData({
req, req,
authToken: true, authToken: true,
...@@ -39,6 +42,19 @@ async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) { ...@@ -39,6 +42,19 @@ async function handler(req: ApiRequestProps<UpdateDatasetDataProps>) {
inputTokens: tokens, inputTokens: tokens,
model: vectorModel model: vectorModel
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_DATA,
params: {
collectionName: collection.name,
datasetName: collection.dataset?.name || '',
datasetType: getI18nDatasetType(collection.dataset?.type || '')
}
});
})();
} else { } else {
// await MongoDatasetData.findByIdAndUpdate(dataId, { // await MongoDatasetData.findByIdAndUpdate(dataId, {
// ...(forbid !== undefined && { forbid }) // ...(forbid !== undefined && { forbid })
......
...@@ -11,6 +11,9 @@ import { MongoDatasetCollectionTags } from '@fastgpt/service/core/dataset/tag/sc ...@@ -11,6 +11,9 @@ import { MongoDatasetCollectionTags } from '@fastgpt/service/core/dataset/tag/sc
import { removeImageByPath } from '@fastgpt/service/common/file/image/controller'; import { removeImageByPath } from '@fastgpt/service/common/file/image/controller';
import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants'; import { DatasetTypeEnum } from '@fastgpt/global/core/dataset/constants';
import { removeWebsiteSyncJobScheduler } from '@fastgpt/service/core/dataset/websiteSync'; import { removeWebsiteSyncJobScheduler } from '@fastgpt/service/core/dataset/websiteSync';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) { async function handler(req: NextApiRequest) {
const { id: datasetId } = req.query as { const { id: datasetId } = req.query as {
...@@ -22,7 +25,7 @@ async function handler(req: NextApiRequest) { ...@@ -22,7 +25,7 @@ async function handler(req: NextApiRequest) {
} }
// auth owner // auth owner
const { teamId } = await authDataset({ const { teamId, tmbId, dataset } = await authDataset({
req, req,
authToken: true, authToken: true,
authApiKey: true, authApiKey: true,
...@@ -66,6 +69,18 @@ async function handler(req: NextApiRequest) { ...@@ -66,6 +69,18 @@ async function handler(req: NextApiRequest) {
await removeImageByPath(dataset.avatar, session); await removeImageByPath(dataset.avatar, session);
} }
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_DATASET,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
} }
export default NextAPI(handler); export default NextAPI(handler);
...@@ -17,6 +17,8 @@ import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPe ...@@ -17,6 +17,8 @@ import { syncCollaborators } from '@fastgpt/service/support/permission/inheritPe
import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema'; import { MongoResourcePermission } from '@fastgpt/service/support/permission/schema';
import { authUserPer } from '@fastgpt/service/support/permission/user/auth'; import { authUserPer } from '@fastgpt/service/support/permission/user/auth';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next'; import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
export type DatasetFolderCreateQuery = {}; export type DatasetFolderCreateQuery = {};
export type DatasetFolderCreateBody = { export type DatasetFolderCreateBody = {
parentId?: string; parentId?: string;
...@@ -92,6 +94,16 @@ async function handler( ...@@ -92,6 +94,16 @@ async function handler(
); );
} }
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_DATASET_FOLDER,
params: {
folderName: name
}
});
})();
return {}; return {};
} }
......
...@@ -14,7 +14,9 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; ...@@ -14,7 +14,9 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { useIPFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit'; import { useIPFrequencyLimit } from '@fastgpt/service/common/middle/reqFrequencyLimit';
import { type ApiRequestProps } from '@fastgpt/service/type/next'; import { type ApiRequestProps } from '@fastgpt/service/type/next';
import { getRerankModel } from '@fastgpt/service/core/ai/model'; import { getRerankModel } from '@fastgpt/service/core/ai/model';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTestResponse> { async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTestResponse> {
const { const {
datasetId, datasetId,
...@@ -130,6 +132,17 @@ async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTes ...@@ -130,6 +132,17 @@ async function handler(req: ApiRequestProps<SearchTestProps>): Promise<SearchTes
totalPoints: embeddingTotalPoints + reRankTotalPoints totalPoints: embeddingTotalPoints + reRankTotalPoints
}); });
} }
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.SEARCH_TEST,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
return { return {
list: searchRes, list: searchRes,
......
...@@ -37,6 +37,9 @@ import { ...@@ -37,6 +37,9 @@ import {
} from '@fastgpt/service/core/dataset/websiteSync'; } from '@fastgpt/service/core/dataset/websiteSync';
import { delDatasetRelevantData } from '@fastgpt/service/core/dataset/controller'; import { delDatasetRelevantData } from '@fastgpt/service/core/dataset/controller';
import { isEqual } from 'lodash'; import { isEqual } from 'lodash';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
export type DatasetUpdateQuery = {}; export type DatasetUpdateQuery = {};
export type DatasetUpdateResponse = any; export type DatasetUpdateResponse = any;
...@@ -79,16 +82,27 @@ async function handler( ...@@ -79,16 +82,27 @@ async function handler(
const isMove = parentId !== undefined; const isMove = parentId !== undefined;
const { dataset, permission } = await authDataset({ const { dataset, permission, tmbId, teamId } = await authDataset({
req, req,
authToken: true, authToken: true,
datasetId: id, datasetId: id,
per: ReadPermissionVal per: ReadPermissionVal
}); });
let targetName = '';
if (isMove) { if (isMove) {
if (parentId) { if (parentId) {
// move to a folder, check the target folder's permission // move to a folder, check the target folder's permission
await authDataset({ req, authToken: true, datasetId: parentId, per: ManagePermissionVal }); const { dataset: targetDataset } = await authDataset({
req,
authToken: true,
datasetId: parentId,
per: ManagePermissionVal
});
targetName = targetDataset.name;
} else {
targetName = 'root';
} }
if (dataset.parentId) { if (dataset.parentId) {
// move from a folder, check the (old) folder's permission // move from a folder, check the (old) folder's permission
...@@ -221,7 +235,9 @@ async function handler( ...@@ -221,7 +235,9 @@ async function handler(
collaborators: parentClbsAndGroups, collaborators: parentClbsAndGroups,
session session
}); });
logDatasetMove({ tmbId, teamId, dataset, targetName });
} else { } else {
logDatasetMove({ tmbId, teamId, dataset, targetName });
// Not folder, delete all clb // Not folder, delete all clb
await MongoResourcePermission.deleteMany( await MongoResourcePermission.deleteMany(
{ resourceId: id, teamId: dataset.teamId, resourceType: PerResourceTypeEnum.dataset }, { resourceId: id, teamId: dataset.teamId, resourceType: PerResourceTypeEnum.dataset },
...@@ -230,6 +246,7 @@ async function handler( ...@@ -230,6 +246,7 @@ async function handler(
} }
return onUpdate(session); return onUpdate(session);
} else { } else {
logDatasetUpdate({ tmbId, teamId, dataset });
return onUpdate(session); return onUpdate(session);
} }
}); });
...@@ -315,3 +332,50 @@ const updateSyncSchedule = async ({ ...@@ -315,3 +332,50 @@ const updateSyncSchedule = async ({
} }
} }
}; };
const logDatasetMove = ({
tmbId,
teamId,
dataset,
targetName
}: {
tmbId: string;
teamId: string;
dataset: any;
targetName: string;
}) => {
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.MOVE_DATASET,
params: {
datasetName: dataset.name,
targetFolderName: targetName,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
};
const logDatasetUpdate = ({
tmbId,
teamId,
dataset
}: {
tmbId: string;
teamId: string;
dataset: any;
}) => {
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_DATASET,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
};
...@@ -8,7 +8,8 @@ import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant ...@@ -8,7 +8,8 @@ import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant
import { authApp } from '@fastgpt/service/support/permission/app/auth'; import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { OpenApiErrEnum } from '@fastgpt/global/common/error/code/openapi'; import { OpenApiErrEnum } from '@fastgpt/global/common/error/code/openapi';
import { TeamApikeyCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant'; import { TeamApikeyCreatePermissionVal } from '@fastgpt/global/support/permission/user/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> { async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
const { appId, name, limit } = req.body; const { appId, name, limit } = req.body;
const { tmbId, teamId } = await (async () => { const { tmbId, teamId } = await (async () => {
...@@ -48,6 +49,18 @@ async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> { ...@@ -48,6 +49,18 @@ async function handler(req: ApiRequestProps<EditApiKeyProps>): Promise<string> {
name, name,
limit limit
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_API_KEY,
params: {
keyName: name
}
});
})();
return apiKey; return apiKey;
} }
......
...@@ -4,7 +4,8 @@ import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant' ...@@ -4,7 +4,8 @@ import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant'
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next'; import type { ApiRequestProps, ApiResponseType } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
export type OpenAPIDeleteQuery = { id: string }; export type OpenAPIDeleteQuery = { id: string };
export type OpenAPIDeleteBody = {}; export type OpenAPIDeleteBody = {};
export type OpenAPIDeleteResponse = {}; export type OpenAPIDeleteResponse = {};
...@@ -19,9 +20,26 @@ async function handler( ...@@ -19,9 +20,26 @@ async function handler(
return Promise.reject(CommonErrEnum.missingParams); return Promise.reject(CommonErrEnum.missingParams);
} }
await authOpenApiKeyCrud({ req, authToken: true, id, per: OwnerPermissionVal }); const { tmbId, teamId, openapi } = await authOpenApiKeyCrud({
req,
authToken: true,
id,
per: OwnerPermissionVal
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_API_KEY,
params: {
keyName: openapi.name
}
});
})();
await MongoOpenApi.deleteOne({ _id: id }); await MongoOpenApi.deleteOne({ _id: id });
return {}; return {};
} }
......
...@@ -4,11 +4,28 @@ import { authOpenApiKeyCrud } from '@fastgpt/service/support/permission/auth/ope ...@@ -4,11 +4,28 @@ import { authOpenApiKeyCrud } from '@fastgpt/service/support/permission/auth/ope
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant'; import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps } from '@fastgpt/service/type/next'; import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
async function handler(req: ApiRequestProps<EditApiKeyProps & { _id: string }>): Promise<void> { async function handler(req: ApiRequestProps<EditApiKeyProps & { _id: string }>): Promise<void> {
const { _id, name, limit } = req.body; const { _id, name, limit } = req.body;
await authOpenApiKeyCrud({ req, authToken: true, id: _id, per: OwnerPermissionVal }); const { tmbId, teamId } = await authOpenApiKeyCrud({
req,
authToken: true,
id: _id,
per: OwnerPermissionVal
});
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_API_KEY,
params: {
keyName: name
}
});
})();
await MongoOpenApi.findByIdAndUpdate(_id, { await MongoOpenApi.findByIdAndUpdate(_id, {
...(name && { name }), ...(name && { name }),
......
...@@ -6,7 +6,9 @@ import type { PublishChannelEnum } from '@fastgpt/global/support/outLink/constan ...@@ -6,7 +6,9 @@ import type { PublishChannelEnum } from '@fastgpt/global/support/outLink/constan
import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant'; import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps } from '@fastgpt/service/type/next'; import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
/* create a shareChat */ /* create a shareChat */
const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24); const nanoid = customAlphabet('abcdefghijklmnopqrstuvwxyz1234567890', 24);
...@@ -23,7 +25,7 @@ async function handler( ...@@ -23,7 +25,7 @@ async function handler(
): Promise<OutLinkCreateResponse> { ): Promise<OutLinkCreateResponse> {
const { appId, ...props } = req.body; const { appId, ...props } = req.body;
const { teamId, tmbId } = await authApp({ const { teamId, tmbId, app } = await authApp({
req, req,
authToken: true, authToken: true,
appId, appId,
...@@ -39,6 +41,19 @@ async function handler( ...@@ -39,6 +41,19 @@ async function handler(
...props ...props
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CREATE_APP_PUBLISH_CHANNEL,
params: {
appName: app.name,
channelName: props.name,
appType: getI18nAppType(app.type)
}
});
})();
return shareId; return shareId;
} }
......
...@@ -3,6 +3,9 @@ import { authOutLinkCrud } from '@fastgpt/service/support/permission/publish/aut ...@@ -3,6 +3,9 @@ import { authOutLinkCrud } from '@fastgpt/service/support/permission/publish/aut
import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant'; import { OwnerPermissionVal } from '@fastgpt/global/support/permission/constant';
import type { ApiRequestProps } from '@fastgpt/service/type/next'; import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type OutLinkDeleteQuery = { export type OutLinkDeleteQuery = {
id: string; id: string;
...@@ -15,8 +18,28 @@ async function handler( ...@@ -15,8 +18,28 @@ async function handler(
req: ApiRequestProps<OutLinkDeleteBody, OutLinkDeleteQuery> req: ApiRequestProps<OutLinkDeleteBody, OutLinkDeleteQuery>
): Promise<OutLinkDeleteResponse> { ): Promise<OutLinkDeleteResponse> {
const { id } = req.query; const { id } = req.query;
await authOutLinkCrud({ req, outLinkId: id, authToken: true, per: OwnerPermissionVal }); const { tmbId, teamId, outLink, app } = await authOutLinkCrud({
req,
outLinkId: id,
authToken: true,
per: OwnerPermissionVal
});
await MongoOutLink.findByIdAndDelete(id); await MongoOutLink.findByIdAndDelete(id);
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.DELETE_APP_PUBLISH_CHANNEL,
params: {
appName: app.name,
channelName: outLink.name,
appType: getI18nAppType(app.type)
}
});
})();
return {}; return {};
} }
......
...@@ -5,7 +5,9 @@ import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant ...@@ -5,7 +5,9 @@ import { ManagePermissionVal } from '@fastgpt/global/support/permission/constant
import type { ApiRequestProps } from '@fastgpt/service/type/next'; import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common'; import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nAppType } from '@fastgpt/service/support/operationLog/util';
export type OutLinkUpdateQuery = {}; export type OutLinkUpdateQuery = {};
// { // {
...@@ -30,7 +32,17 @@ async function handler( ...@@ -30,7 +32,17 @@ async function handler(
return Promise.reject(CommonErrEnum.missingParams); return Promise.reject(CommonErrEnum.missingParams);
} }
await authOutLinkCrud({ req, outLinkId: _id, authToken: true, per: ManagePermissionVal }); const {
tmbId,
teamId,
outLink,
app: logApp
} = await authOutLinkCrud({
req,
outLinkId: _id,
authToken: true,
per: ManagePermissionVal
});
await MongoOutLink.findByIdAndUpdate(_id, { await MongoOutLink.findByIdAndUpdate(_id, {
name, name,
...@@ -41,6 +53,19 @@ async function handler( ...@@ -41,6 +53,19 @@ async function handler(
limit, limit,
app app
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.UPDATE_APP_PUBLISH_CHANNEL,
params: {
appName: logApp.name,
channelName: outLink.name,
appType: getI18nAppType(logApp.type)
}
});
})();
return {}; return {};
} }
export default NextAPI(handler); export default NextAPI(handler);
...@@ -5,7 +5,8 @@ import { MongoUser } from '@fastgpt/service/support/user/schema'; ...@@ -5,7 +5,8 @@ import { MongoUser } from '@fastgpt/service/support/user/schema';
import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema'; import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema';
import { i18nT } from '@fastgpt/web/i18n/utils'; import { i18nT } from '@fastgpt/web/i18n/utils';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
async function handler(req: NextApiRequest, res: NextApiResponse<any>) { async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const { oldPsw, newPsw } = req.body as { oldPsw: string; newPsw: string }; const { oldPsw, newPsw } = req.body as { oldPsw: string; newPsw: string };
...@@ -13,7 +14,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) { ...@@ -13,7 +14,7 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
return Promise.reject('Params is missing'); return Promise.reject('Params is missing');
} }
const { tmbId } = await authCert({ req, authToken: true }); const { tmbId, teamId } = await authCert({ req, authToken: true });
const tmb = await MongoTeamMember.findById(tmbId); const tmb = await MongoTeamMember.findById(tmbId);
if (!tmb) { if (!tmb) {
return Promise.reject('can not find it'); return Promise.reject('can not find it');
...@@ -39,6 +40,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) { ...@@ -39,6 +40,14 @@ async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
passwordUpdateTime: new Date() passwordUpdateTime: new Date()
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.CHANGE_PASSWORD,
params: {}
});
})();
return user; return user;
} }
......
...@@ -3,6 +3,9 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth'; ...@@ -3,6 +3,9 @@ import { authDataset } from '@fastgpt/service/support/permission/dataset/auth';
import { checkExportDatasetLimit } from '@fastgpt/service/support/user/utils'; import { checkExportDatasetLimit } from '@fastgpt/service/support/user/utils';
import { NextAPI } from '@/service/middleware/entry'; import { NextAPI } from '@/service/middleware/entry';
import { WritePermissionVal } from '@fastgpt/global/support/permission/constant'; import { WritePermissionVal } from '@fastgpt/global/support/permission/constant';
import { addOperationLog } from '@fastgpt/service/support/operationLog/addOperationLog';
import { OperationLogEventEnum } from '@fastgpt/global/support/operationLog/constants';
import { getI18nDatasetType } from '@fastgpt/service/support/operationLog/util';
async function handler(req: NextApiRequest) { async function handler(req: NextApiRequest) {
const { datasetId } = req.query as { const { datasetId } = req.query as {
...@@ -14,7 +17,7 @@ async function handler(req: NextApiRequest) { ...@@ -14,7 +17,7 @@ async function handler(req: NextApiRequest) {
} }
// 凭证校验 // 凭证校验
const { teamId } = await authDataset({ const { teamId, tmbId, dataset } = await authDataset({
req, req,
authToken: true, authToken: true,
datasetId, datasetId,
...@@ -25,6 +28,18 @@ async function handler(req: NextApiRequest) { ...@@ -25,6 +28,18 @@ async function handler(req: NextApiRequest) {
teamId, teamId,
limitMinutes: global.feConfigs?.limit?.exportDatasetLimitMinutes limitMinutes: global.feConfigs?.limit?.exportDatasetLimitMinutes
}); });
(async () => {
addOperationLog({
tmbId,
teamId,
event: OperationLogEventEnum.EXPORT_DATASET,
params: {
datasetName: dataset.name,
datasetType: getI18nDatasetType(dataset.type)
}
});
})();
} }
export default NextAPI(handler); export default NextAPI(handler);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment