diff --git a/apps/knowledge/serializers/document.py b/apps/knowledge/serializers/document.py index ee532a16e..6cacf727e 100644 --- a/apps/knowledge/serializers/document.py +++ b/apps/knowledge/serializers/document.py @@ -28,6 +28,7 @@ from common.db.search import native_search, get_dynamics_model, native_page_sear from common.event import ListenerManagement from common.event.common import work_thread_pool from common.exception.app_exception import AppApiException +from common.field.common import UploadedFileField from common.handle.impl.qa.csv_parse_qa_handle import CsvParseQAHandle from common.handle.impl.qa.xls_parse_qa_handle import XlsParseQAHandle from common.handle.impl.qa.xlsx_parse_qa_handle import XlsxParseQAHandle @@ -1503,6 +1504,38 @@ class DocumentSerializers(serializers.Serializer): tag_id__in=tag_ids ).delete() + class ReplaceSourceFile(serializers.Serializer): + workspace_id = serializers.CharField(required=True, label=_('workspace id')) + knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id')) + document_id = serializers.UUIDField(required=True, label=_('document id')) + file = UploadedFileField(required=True, label=_("file")) + + def is_valid(self, *, raise_exception=False): + super().is_valid(raise_exception=True) + workspace_id = self.data.get('workspace_id') + query_set = QuerySet(Knowledge).filter(id=self.data.get('knowledge_id')) + if workspace_id and workspace_id != 'None': + query_set = query_set.filter(workspace_id=workspace_id) + if not query_set.exists(): + raise AppApiException(500, _('Knowledge id does not exist')) + if not QuerySet(Document).filter( + id=self.data.get('document_id'), + knowledge_id=self.data.get('knowledge_id') + ).exists(): + raise AppApiException(500, _('Document id does not exist')) + + def replace(self): + self.is_valid(raise_exception=True) + file = self.data.get('file') + source_file = QuerySet(File).filter(source_id=self.data.get('document_id')).first() + + if not source_file: + raise AppApiException(500, _('Source file not found')) + + source_file.save(file.read()) + + return True + class FileBufferHandle: buffer = None diff --git a/apps/knowledge/urls.py b/apps/knowledge/urls.py index e5776da30..3b41be1e9 100644 --- a/apps/knowledge/urls.py +++ b/apps/knowledge/urls.py @@ -46,6 +46,7 @@ urlpatterns = [ path('workspace//knowledge//document//export', views.DocumentView.Export.as_view()), path('workspace//knowledge//document//export_zip', views.DocumentView.ExportZip.as_view()), path('workspace//knowledge//document//download_source_file', views.DocumentView.DownloadSourceFile.as_view()), + path('workspace//knowledge//document//replace_source_file', views.DocumentView.ReplaceSourceFile.as_view()), path('workspace//knowledge//document//tags', views.DocumentView.Tags.as_view()), path('workspace//knowledge//document//tags/batch_delete', views.DocumentView.Tags.BatchDelete.as_view()), path('workspace//knowledge//document//paragraph', views.ParagraphView.as_view()), diff --git a/apps/knowledge/views/document.py b/apps/knowledge/views/document.py index 558d2ccb1..a63883856 100644 --- a/apps/knowledge/views/document.py +++ b/apps/knowledge/views/document.py @@ -686,6 +686,31 @@ class DocumentView(APIView): 'workspace_id': workspace_id, 'document_id': document_id, 'knowledge_id': knowledge_id }).download_source_file() + class ReplaceSourceFile(APIView): + authentication_classes = [TokenAuth] + + @extend_schema( + summary=_('Replace source file'), + operation_id=_('Replace source file'), # type: ignore + parameters=DocumentDownloadSourceAPI.get_parameters(), + responses=DocumentDownloadSourceAPI.get_response(), + tags=[_('Knowledge Base/Documentation')] # type: ignore + ) + @has_permissions( + PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_knowledge_permission(), + PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_permission_workspace_manage_role(), + RoleConstants.WORKSPACE_MANAGE.get_workspace_role(), + ViewPermission([RoleConstants.USER.get_workspace_role()], + [PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()], CompareConstants.AND), + ) + def post(self, request: Request, workspace_id: str, knowledge_id: str, document_id: str): + return result.success(DocumentSerializers.ReplaceSourceFile(data={ + 'workspace_id': workspace_id, + 'document_id': document_id, + 'knowledge_id': knowledge_id, + 'file': request.FILES.get('file') + }).replace()) + class Tags(APIView): authentication_classes = [TokenAuth] diff --git a/ui/src/api/knowledge/document.ts b/ui/src/api/knowledge/document.ts index a4dad8944..86587b8b1 100644 --- a/ui/src/api/knowledge/document.ts +++ b/ui/src/api/knowledge/document.ts @@ -144,6 +144,14 @@ const getDownloadSourceFile: (knowledge_id: string, document_id: string, documen return exportFile(document_name, `${prefix.value}/${knowledge_id}/document/${document_id}/download_source_file`, {}, undefined) } +const postReplaceSourceFile: (knowledge_id: string, document_id: string, data: any) => Promise> = ( + knowledge_id, + document_id, + data, +) => { + return post(`${prefix.value}/${knowledge_id}/document/${document_id}/replace_source_file`, data, {}, undefined) +} + /** * 导出文档 * @param document_name 文档名称 @@ -608,6 +616,7 @@ export default { putBatchCancelTask, putCancelTask, getDownloadSourceFile, + postReplaceSourceFile, exportDocument, exportDocumentZip, putDocumentRefresh, diff --git a/ui/src/locales/lang/en-US/views/document.ts b/ui/src/locales/lang/en-US/views/document.ts index a13e4159b..ed01e8da6 100644 --- a/ui/src/locales/lang/en-US/views/document.ts +++ b/ui/src/locales/lang/en-US/views/document.ts @@ -14,6 +14,7 @@ export default { cancelGenerate: 'Cancel Generation', export: 'Export to', download: 'Download', + replace: 'Replace', }, tip: { diff --git a/ui/src/locales/lang/zh-CN/views/document.ts b/ui/src/locales/lang/zh-CN/views/document.ts index 7b129ad99..76b74dad6 100644 --- a/ui/src/locales/lang/zh-CN/views/document.ts +++ b/ui/src/locales/lang/zh-CN/views/document.ts @@ -14,6 +14,7 @@ export default { cancelGenerate: '取消生成', export: '导出', download: '下载原文档', + replace: '替换原文档', }, tip: { saveMessage: '当前的更改尚未保存,确认退出吗?', diff --git a/ui/src/locales/lang/zh-Hant/views/document.ts b/ui/src/locales/lang/zh-Hant/views/document.ts index 0295ad160..9e0a768ed 100644 --- a/ui/src/locales/lang/zh-Hant/views/document.ts +++ b/ui/src/locales/lang/zh-Hant/views/document.ts @@ -14,6 +14,7 @@ export default { cancelGenerate: '取消生成', export: '匯出', download: '下載原文件', + replace: '替換原文件', }, tip: { saveMessage: '當前的更改尚未保存,確認退出嗎?', diff --git a/ui/src/views/document/index.vue b/ui/src/views/document/index.vue index 9d1e9e830..16f0393eb 100644 --- a/ui/src/views/document/index.vue +++ b/ui/src/views/document/index.vue @@ -494,6 +494,21 @@ {{ $t('views.document.setting.download') }} + + + + + + {{ $t('views.document.setting.replace') }} + + { + getList() + }) + .catch((e: any) => {}) +} + function deleteDocument(row: any) { MsgConfirm( `${t('views.document.delete.confirmTitle3')} ${row.name} ?`,