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:
@@ -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 = {
|
||||||
|
@@ -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,
|
||||||
|
@@ -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}
|
||||||
/>);
|
/>);
|
||||||
|
@@ -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();
|
||||||
|
@@ -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,)
|
||||||
|
@@ -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)
|
||||||
|
@@ -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'),
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user