1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-05 08:53:14 +00:00

Md copy view (#6598)

* duplicate md view

* optimize code

* optimize code

* Update metadata_manage.py

* Update metadata_manage.py

---------

Co-authored-by: 孙永强 <11704063+s-yongqiang@user.noreply.gitee.com>
Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
This commit is contained in:
awu0403
2024-08-28 16:06:47 +08:00
committed by GitHub
parent 055a6c7814
commit 99c58486f7
7 changed files with 97 additions and 4 deletions

View File

@@ -118,6 +118,12 @@ class MetadataManagerAPI {
return this._sendPostRequest(url, params, { headers: { 'Content-type': 'application/json' } }); return this._sendPostRequest(url, params, { headers: { 'Content-type': 'application/json' } });
}; };
duplicateView = (repoID, viewId) => {
const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/duplicate-view/';
const params = { view_id: viewId };
return this._sendPostRequest(url, params, { headers: { 'Content-type': 'application/json' } });
};
modifyView = (repoID, viewId, viewData) => { modifyView = (repoID, viewId, viewData) => {
const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/views/'; const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/views/';
const params = { const params = {

View File

@@ -120,6 +120,20 @@ export const MetadataProvider = ({ repoID, hideMetadataView, selectMetadataView,
}); });
}, [navigation, repoID, viewsMap, selectView]); }, [navigation, repoID, viewsMap, selectView]);
const duplicateView = useCallback((viewId) => {
metadataAPI.duplicateView(repoID, viewId).then(res => {
const view = res.data.view;
let newNavigation = navigation.slice(0);
newNavigation.push({ _id: view._id, type: 'view' });
viewsMap.current[view._id] = view;
setNavigation(newNavigation);
selectView(view);
}).catch(error => {
const errorMsg = Utils.getErrorMsg(error);
toaster.danger(errorMsg);
});
}, [navigation, repoID, viewsMap, selectView]);
const deleteView = useCallback((viewId, isSelected) => { const deleteView = useCallback((viewId, isSelected) => {
metadataAPI.deleteView(repoID, viewId).then(res => { metadataAPI.deleteView(repoID, viewId).then(res => {
const newNavigation = navigation.filter(item => item._id !== viewId); const newNavigation = navigation.filter(item => item._id !== viewId);
@@ -170,6 +184,7 @@ export const MetadataProvider = ({ repoID, hideMetadataView, selectMetadataView,
viewsMap: viewsMap.current, viewsMap: viewsMap.current,
selectView, selectView,
addView, addView,
duplicateView,
deleteView, deleteView,
updateView, updateView,
moveView, moveView,

View File

@@ -23,6 +23,7 @@ const MetadataTreeView = ({ userPerm, currentPath }) => {
viewsMap, viewsMap,
selectView, selectView,
addView, addView,
duplicateView,
deleteView, deleteView,
updateView, updateView,
moveView moveView
@@ -122,6 +123,7 @@ const MetadataTreeView = ({ userPerm, currentPath }) => {
view={view} view={view}
onClick={(view) => selectView(view, isSelected)} onClick={(view) => selectView(view, isSelected)}
onDelete={() => deleteView(view._id, isSelected)} onDelete={() => deleteView(view._id, isSelected)}
onCopy={() => duplicateView(view._id)}
onUpdate={(update, successCallback, failCallback) => onUpdateView(view._id, update, successCallback, failCallback)} onUpdate={(update, successCallback, failCallback) => onUpdateView(view._id, update, successCallback, failCallback)}
onMove={moveView} onMove={moveView}
/>); />);

View File

@@ -16,6 +16,7 @@ const ViewItem = ({
view, view,
onClick, onClick,
onDelete, onDelete,
onCopy,
onUpdate, onUpdate,
onMove, onMove,
}) => { }) => {
@@ -38,6 +39,7 @@ const ViewItem = ({
if (!canUpdate) return []; if (!canUpdate) return [];
let value = [ let value = [
{ key: 'rename', value: gettext('Rename') }, { key: 'rename', value: gettext('Rename') },
{ key: 'duplicate', value: gettext('Duplicate') }
]; ];
if (canDelete) { if (canDelete) {
value.push({ key: 'delete', value: gettext('Delete') }); value.push({ key: 'delete', value: gettext('Delete') });
@@ -75,11 +77,16 @@ const ViewItem = ({
return; return;
} }
if (operationKey === 'duplicate') {
onCopy();
return;
}
if (operationKey === 'delete') { if (operationKey === 'delete') {
onDelete(); onDelete();
return; return;
} }
}, [onDelete]); }, [onDelete, onCopy]);
const closeRenamePopover = useCallback((event) => { const closeRenamePopover = useCallback((event) => {
event.stopPropagation(); event.stopPropagation();

View File

@@ -697,6 +697,52 @@ class MetadataViews(APIView):
return Response({'success': True}) return Response({'success': True})
class MetadataViewsDuplicateView(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,)
throttle_classes = (UserRateThrottle,)
def post(self, request, repo_id):
view_id = request.data.get('view_id')
if not view_id:
error_msg = 'view_id invalid'
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
record = RepoMetadata.objects.filter(repo_id=repo_id).first()
if not record or not record.enabled:
error_msg = f'The metadata module is disabled for repo {repo_id}.'
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
views = RepoMetadataViews.objects.filter(
repo_id=repo_id
).first()
if not views:
error_msg = 'The metadata views does not exists.'
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
if view_id not in views.view_ids:
error_msg = 'view_id %s does not exists.' % view_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
repo = seafile_api.get_repo(repo_id)
if not repo:
error_msg = 'Library %s not found.' % repo_id
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
permission = check_folder_permission(request, repo_id, '/')
if permission != 'rw':
error_msg = 'Permission denied.'
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
try:
result = RepoMetadataViews.objects.duplicate_view(repo_id, view_id)
except Exception as e:
logger.exception(e)
error_msg = 'Internal Server Error'
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
return Response({'view': result})
class MetadataViewsDetailView(APIView): class MetadataViewsDetailView(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication) authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)

View File

@@ -2,6 +2,7 @@ import logging
import json import json
import random import random
import string import string
import copy
from django.db import models from django.db import models
from seahub.utils import get_no_duplicate_obj_name from seahub.utils import get_no_duplicate_obj_name
@@ -140,7 +141,23 @@ class RepoMetadataViewsManager(models.Manager):
metadata_views.details = json.dumps(view_details) metadata_views.details = json.dumps(view_details)
metadata_views.save() metadata_views.save()
return json.loads(metadata_views.details) return json.loads(metadata_views.details)
def duplicate_view(self, repo_id, view_id):
metadata_views = self.filter(repo_id=repo_id).first()
view_details = json.loads(metadata_views.details)
exist_view_ids = metadata_views.view_ids
new_view_id = generate_view_id(4, exist_view_ids)
duplicate_view = next((copy.deepcopy(view) for view in view_details['views'] if view.get('_id') == view_id), None)
duplicate_view['_id'] = new_view_id
view_name = get_no_duplicate_obj_name(duplicate_view['name'], metadata_views.view_names)
duplicate_view['name'] = view_name
view_details['views'].append(duplicate_view)
view_details['navigation'].append({'_id': new_view_id, 'type': 'view'})
metadata_views.details = json.dumps(view_details)
metadata_views.save()
return duplicate_view
def delete_view(self, repo_id, view_id): def delete_view(self, repo_id, view_id):
metadata_views = self.filter(repo_id=repo_id).first() metadata_views = self.filter(repo_id=repo_id).first()
view_details = json.loads(metadata_views.details) view_details = json.loads(metadata_views.details)

View File

@@ -208,7 +208,7 @@ from seahub.api2.endpoints.wiki2 import Wikis2View, Wiki2View, Wiki2ConfigView,
Wiki2DuplicatePageView, WikiPageTrashView Wiki2DuplicatePageView, WikiPageTrashView
from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView from seahub.api2.endpoints.subscription import SubscriptionView, SubscriptionPlansView, SubscriptionLogsView
from seahub.api2.endpoints.metadata_manage import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \ from seahub.api2.endpoints.metadata_manage import MetadataRecords, MetadataManage, MetadataColumns, MetadataRecordInfo, \
MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataSummarizeDocs MetadataViews, MetadataViewsMoveView, MetadataViewsDetailView, MetadataSummarizeDocs, MetadataViewsDuplicateView
from seahub.api2.endpoints.user_list import UserListView from seahub.api2.endpoints.user_list import UserListView
@@ -1038,5 +1038,5 @@ if settings.ENABLE_METADATA_MANAGEMENT:
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/views/(?P<view_id>[-0-9a-zA-Z]{4})/$', MetadataViewsDetailView.as_view(), name='api-v2.1-metadata-views-detail'), re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/views/(?P<view_id>[-0-9a-zA-Z]{4})/$', MetadataViewsDetailView.as_view(), name='api-v2.1-metadata-views-detail'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/move-views/$', MetadataViewsMoveView.as_view(), name='api-v2.1-metadata-views-move'), re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/move-views/$', MetadataViewsMoveView.as_view(), name='api-v2.1-metadata-views-move'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/ai/summarize-documents/$', MetadataSummarizeDocs.as_view(), name='api-v2.1-metadata-summarize-documents'), re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/ai/summarize-documents/$', MetadataSummarizeDocs.as_view(), name='api-v2.1-metadata-summarize-documents'),
re_path(r'^api/v2.1/repos/(?P<repo_id>[-0-9a-f]{36})/metadata/duplicate-view/$', MetadataViewsDuplicateView.as_view(), name='api-v2.1-metadata-view-duplicate'),
] ]