Skip to content

Commit 620d4ff

Browse files
committed
feat: add document replacement functionality with file upload
1 parent 76ba9d0 commit 620d4ff

File tree

8 files changed

+100
-0
lines changed

8 files changed

+100
-0
lines changed

apps/knowledge/serializers/document.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from common.event import ListenerManagement
2929
from common.event.common import work_thread_pool
3030
from common.exception.app_exception import AppApiException
31+
from common.field.common import UploadedFileField
3132
from common.handle.impl.qa.csv_parse_qa_handle import CsvParseQAHandle
3233
from common.handle.impl.qa.xls_parse_qa_handle import XlsParseQAHandle
3334
from common.handle.impl.qa.xlsx_parse_qa_handle import XlsxParseQAHandle
@@ -1503,6 +1504,38 @@ def delete_tags(self):
15031504
tag_id__in=tag_ids
15041505
).delete()
15051506

1507+
class ReplaceSourceFile(serializers.Serializer):
1508+
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
1509+
knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id'))
1510+
document_id = serializers.UUIDField(required=True, label=_('document id'))
1511+
file = UploadedFileField(required=True, label=_("file"))
1512+
1513+
def is_valid(self, *, raise_exception=False):
1514+
super().is_valid(raise_exception=True)
1515+
workspace_id = self.data.get('workspace_id')
1516+
query_set = QuerySet(Knowledge).filter(id=self.data.get('knowledge_id'))
1517+
if workspace_id and workspace_id != 'None':
1518+
query_set = query_set.filter(workspace_id=workspace_id)
1519+
if not query_set.exists():
1520+
raise AppApiException(500, _('Knowledge id does not exist'))
1521+
if not QuerySet(Document).filter(
1522+
id=self.data.get('document_id'),
1523+
knowledge_id=self.data.get('knowledge_id')
1524+
).exists():
1525+
raise AppApiException(500, _('Document id does not exist'))
1526+
1527+
def replace(self):
1528+
self.is_valid(raise_exception=True)
1529+
file = self.data.get('file')
1530+
source_file = QuerySet(File).filter(source_id=self.data.get('document_id')).first()
1531+
1532+
if not source_file:
1533+
raise AppApiException(500, _('Source file not found'))
1534+
1535+
source_file.save(file.read())
1536+
1537+
return True
1538+
15061539

15071540
class FileBufferHandle:
15081541
buffer = None

apps/knowledge/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/export', views.DocumentView.Export.as_view()),
4747
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/export_zip', views.DocumentView.ExportZip.as_view()),
4848
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/download_source_file', views.DocumentView.DownloadSourceFile.as_view()),
49+
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/replace_source_file', views.DocumentView.ReplaceSourceFile.as_view()),
4950
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/tags', views.DocumentView.Tags.as_view()),
5051
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/tags/batch_delete', views.DocumentView.Tags.BatchDelete.as_view()),
5152
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/document/<str:document_id>/paragraph', views.ParagraphView.as_view()),

apps/knowledge/views/document.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,31 @@ def get(self, request: Request, workspace_id: str, knowledge_id: str, document_i
686686
'workspace_id': workspace_id, 'document_id': document_id, 'knowledge_id': knowledge_id
687687
}).download_source_file()
688688

689+
class ReplaceSourceFile(APIView):
690+
authentication_classes = [TokenAuth]
691+
692+
@extend_schema(
693+
summary=_('Replace source file'),
694+
operation_id=_('Replace source file'), # type: ignore
695+
parameters=DocumentDownloadSourceAPI.get_parameters(),
696+
responses=DocumentDownloadSourceAPI.get_response(),
697+
tags=[_('Knowledge Base/Documentation')] # type: ignore
698+
)
699+
@has_permissions(
700+
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_knowledge_permission(),
701+
PermissionConstants.KNOWLEDGE_DOCUMENT_EDIT.get_workspace_permission_workspace_manage_role(),
702+
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
703+
ViewPermission([RoleConstants.USER.get_workspace_role()],
704+
[PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()], CompareConstants.AND),
705+
)
706+
def post(self, request: Request, workspace_id: str, knowledge_id: str, document_id: str):
707+
return result.success(DocumentSerializers.ReplaceSourceFile(data={
708+
'workspace_id': workspace_id,
709+
'document_id': document_id,
710+
'knowledge_id': knowledge_id,
711+
'file': request.FILES.get('file')
712+
}).replace())
713+
689714
class Tags(APIView):
690715
authentication_classes = [TokenAuth]
691716

ui/src/api/knowledge/document.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,14 @@ const getDownloadSourceFile: (knowledge_id: string, document_id: string, documen
144144
return exportFile(document_name, `${prefix.value}/${knowledge_id}/document/${document_id}/download_source_file`, {}, undefined)
145145
}
146146

147+
const postReplaceSourceFile: (knowledge_id: string, document_id: string, data: any) => Promise<Result<any>> = (
148+
knowledge_id,
149+
document_id,
150+
data,
151+
) => {
152+
return post(`${prefix.value}/${knowledge_id}/document/${document_id}/replace_source_file`, data, {}, undefined)
153+
}
154+
147155
/**
148156
* 导出文档
149157
* @param document_name 文档名称
@@ -608,6 +616,7 @@ export default {
608616
putBatchCancelTask,
609617
putCancelTask,
610618
getDownloadSourceFile,
619+
postReplaceSourceFile,
611620
exportDocument,
612621
exportDocumentZip,
613622
putDocumentRefresh,

ui/src/locales/lang/en-US/views/document.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default {
1414
cancelGenerate: 'Cancel Generation',
1515
export: 'Export to',
1616
download: 'Download',
17+
replace: 'Replace',
1718
},
1819

1920
tip: {

ui/src/locales/lang/zh-CN/views/document.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default {
1414
cancelGenerate: '取消生成',
1515
export: '导出',
1616
download: '下载原文档',
17+
replace: '替换原文档',
1718
},
1819
tip: {
1920
saveMessage: '当前的更改尚未保存,确认退出吗?',

ui/src/locales/lang/zh-Hant/views/document.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default {
1414
cancelGenerate: '取消生成',
1515
export: '匯出',
1616
download: '下載原文件',
17+
replace: '替換原文件',
1718
},
1819
tip: {
1920
saveMessage: '當前的更改尚未保存,確認退出嗎?',

ui/src/views/document/index.vue

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,21 @@
494494
</el-icon>
495495
{{ $t('views.document.setting.download') }}
496496
</el-dropdown-item>
497+
<el-upload
498+
ref="elUploadRef"
499+
:file-list="[]"
500+
action="#"
501+
:auto-upload="false"
502+
:show-file-list="false"
503+
:on-change="(file: any, fileList: any) => replaceDocument(file, row)"
504+
>
505+
<el-dropdown-item v-if="permissionPrecise.doc_edit(id)">
506+
<el-icon class="color-secondary">
507+
<Upload />
508+
</el-icon>
509+
{{ $t('views.document.setting.replace') }}
510+
</el-dropdown-item>
511+
</el-upload>
497512
<el-dropdown-item
498513
@click.stop="deleteDocument(row)"
499514
v-if="permissionPrecise.doc_delete(id)"
@@ -1079,6 +1094,20 @@ function downloadDocument(row: any) {
10791094
})
10801095
}
10811096
1097+
const elUploadRef = ref()
1098+
1099+
function replaceDocument(file: any, row: any) {
1100+
const formData = new FormData()
1101+
formData.append('file', file.raw, file.name)
1102+
elUploadRef.value.clearFiles()
1103+
loadSharedApi({ type: 'document', systemType: apiType.value })
1104+
.postReplaceSourceFile(id, row.id, formData, loading)
1105+
.then(() => {
1106+
getList()
1107+
})
1108+
.catch((e: any) => {})
1109+
}
1110+
10821111
function deleteDocument(row: any) {
10831112
MsgConfirm(
10841113
`${t('views.document.delete.confirmTitle3')} ${row.name} ?`,

0 commit comments

Comments
 (0)