mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-21 11:27:18 +00:00
copy_file_from_history (#5486)
* copy_file_from_history * fix SeadocCopyHistoryFile
This commit is contained in:
@@ -48,6 +48,11 @@ class HistoryVersion extends React.Component {
|
||||
// nothing todo
|
||||
}
|
||||
|
||||
onItemCopy = () => {
|
||||
const { historyVersion } = this.props;
|
||||
this.props.onCopy(historyVersion);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { currentVersion, historyVersion } = this.props;
|
||||
if (!currentVersion || !historyVersion) return null;
|
||||
@@ -80,6 +85,7 @@ class HistoryVersion extends React.Component {
|
||||
<DropdownMenu>
|
||||
{(this.props.index !== 0) && <DropdownItem onClick={this.onItemRestore}>{gettext('Restore')}</DropdownItem>}
|
||||
<DropdownItem tag='a' href={url} onClick={this.onItemDownLoad}>{gettext('Download')}</DropdownItem>
|
||||
{(this.props.index !== 0) && <DropdownItem onClick={this.onItemCopy}>{gettext('Copy')}</DropdownItem>}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</div>
|
||||
@@ -94,6 +100,7 @@ HistoryVersion.propTypes = {
|
||||
historyVersion: PropTypes.object,
|
||||
onSelectHistoryVersion: PropTypes.func.isRequired,
|
||||
onRestore: PropTypes.func.isRequired,
|
||||
onCopy: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default HistoryVersion;
|
||||
|
@@ -115,6 +115,19 @@ class SidePanel extends Component {
|
||||
this.props.onSelectHistoryVersion(historyVersion, historyVersions[historyVersionIndex + 1]);
|
||||
}
|
||||
|
||||
copyHistoryFile = (historyVersion) => {
|
||||
const { path, revFileId, ctime } = historyVersion;
|
||||
seafileAPI.sdocCopyHistoryFile(historyRepoID, path, revFileId, ctime).then(res => {
|
||||
let message = gettext('Successfully copied %(name)s.');
|
||||
let filename = res.data.file_name;
|
||||
message = message.replace('%(name)s', filename);
|
||||
toaster.success(message);
|
||||
}).catch(error => {
|
||||
const errorMessage = Utils.getErrorMsg(error, true);
|
||||
toaster.danger(gettext(errorMessage));
|
||||
});
|
||||
}
|
||||
|
||||
renderHistoryVersions = () => {
|
||||
const { isLoading, historyVersions, errorMessage } = this.state;
|
||||
if (historyVersions.length === 0) {
|
||||
@@ -150,6 +163,7 @@ class SidePanel extends Component {
|
||||
historyVersion={historyVersion}
|
||||
onSelectHistoryVersion={this.onSelectHistoryVersion}
|
||||
onRestore={this.restoreVersion}
|
||||
onCopy={this.copyHistoryFile}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
import requests
|
||||
import posixpath
|
||||
@@ -10,6 +11,7 @@ from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from django.utils.translation import gettext as _
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.core.files.base import ContentFile
|
||||
|
||||
from seaserv import seafile_api, check_quota
|
||||
|
||||
@@ -22,9 +24,11 @@ from seahub.seadoc.utils import is_valid_seadoc_access_token, get_seadoc_upload_
|
||||
gen_seadoc_image_parent_path, get_seadoc_asset_upload_link, get_seadoc_asset_download_link, \
|
||||
can_access_seadoc_asset
|
||||
from seahub.utils.file_types import SEADOC, IMAGE
|
||||
from seahub.utils import get_file_type_and_ext, normalize_file_path, PREVIEW_FILEEXT
|
||||
from seahub.utils import get_file_type_and_ext, normalize_file_path, PREVIEW_FILEEXT, \
|
||||
gen_inner_file_get_url, gen_inner_file_upload_url
|
||||
from seahub.tags.models import FileUUIDMap
|
||||
from seahub.utils.error_msg import file_type_error_msg
|
||||
from seahub.utils.repo import parse_repo_perm
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -286,3 +290,66 @@ class SeadocDownloadImage(APIView):
|
||||
filetype, fileext = get_file_type_and_ext(filename)
|
||||
return HttpResponse(
|
||||
content=resp.content, content_type='image/' + fileext)
|
||||
|
||||
|
||||
class SeadocCopyHistoryFile(APIView):
|
||||
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated,)
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
def post(self, request, repo_id):
|
||||
username = request.user.username
|
||||
obj_id = request.data.get('obj_id', '')
|
||||
path = request.data.get('p', '')
|
||||
ctime = request.data.get('ctime', '')
|
||||
|
||||
# only check the permissions at the repo level
|
||||
# to prevent file can not be copied on the history page
|
||||
if not parse_repo_perm(check_folder_permission(request, repo_id, '/')).can_copy:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
# new file name
|
||||
file_name = os.path.basename(path.rstrip('/'))
|
||||
parent_dir = os.path.dirname(path)
|
||||
new_file_name = '.'.join(file_name.split('.')[0:-1]) + \
|
||||
'(' + str(ctime) + ').' + file_name.split('.')[-1]
|
||||
new_file_path = posixpath.join(parent_dir, new_file_name)
|
||||
|
||||
# download
|
||||
token = seafile_api.get_fileserver_access_token(repo_id,
|
||||
obj_id, 'download', username)
|
||||
if not token:
|
||||
error_msg = 'file %s not found.' % obj_id
|
||||
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||
download_url = gen_inner_file_get_url(token, file_name)
|
||||
resp = requests.get(download_url)
|
||||
content = resp.content
|
||||
file = ContentFile(content)
|
||||
file.name = new_file_name
|
||||
|
||||
# upload
|
||||
obj_id = json.dumps({'parent_dir': parent_dir})
|
||||
token = seafile_api.get_fileserver_access_token(
|
||||
repo_id, obj_id, 'upload-link', username, use_onetime=True)
|
||||
if not token:
|
||||
error_msg = 'Internal Server Error'
|
||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||
upload_link = gen_inner_file_upload_url('upload-api', token)
|
||||
files = {
|
||||
'file': file,
|
||||
'file_name': new_file_name,
|
||||
'target_file': new_file_path,
|
||||
}
|
||||
data = {'parent_dir': parent_dir}
|
||||
resp = requests.post(upload_link, files=files, data=data)
|
||||
if not resp.ok:
|
||||
logger.error(resp.text)
|
||||
error_msg = 'Internal Server Error'
|
||||
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||
|
||||
return Response({
|
||||
'file_name': new_file_name,
|
||||
'file_path': new_file_path,
|
||||
})
|
||||
|
@@ -1,6 +1,6 @@
|
||||
from django.urls import re_path
|
||||
from .apis import SeadocAccessToken, SeadocUploadLink, SeadocDownloadLink, SeadocUploadFile, \
|
||||
SeadocUploadImage, SeadocDownloadImage
|
||||
SeadocUploadImage, SeadocDownloadImage, SeadocCopyHistoryFile
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^access-token/(?P<repo_id>[-0-9a-f]{36})/$', SeadocAccessToken.as_view(), name='seadoc_access_token'),
|
||||
@@ -9,4 +9,5 @@ urlpatterns = [
|
||||
re_path(r'^download-link/(?P<file_uuid>[-0-9a-f]{36})/$', SeadocDownloadLink.as_view(), name='seadoc_download_link'),
|
||||
re_path(r'^upload-image/(?P<file_uuid>[-0-9a-f]{36})/$', SeadocUploadImage.as_view(), name='seadoc_upload_image'),
|
||||
re_path(r'^download-image/(?P<file_uuid>[-0-9a-f]{36})/(?P<filename>.*)$', SeadocDownloadImage.as_view(), name='seadoc_download_image'),
|
||||
re_path(r'^copy-history-file/(?P<repo_id>[-0-9a-f]{36})/$', SeadocCopyHistoryFile.as_view(), name='seadoc_copy_history_file'),
|
||||
]
|
||||
|
Reference in New Issue
Block a user