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
|
// nothing todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onItemCopy = () => {
|
||||||
|
const { historyVersion } = this.props;
|
||||||
|
this.props.onCopy(historyVersion);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { currentVersion, historyVersion } = this.props;
|
const { currentVersion, historyVersion } = this.props;
|
||||||
if (!currentVersion || !historyVersion) return null;
|
if (!currentVersion || !historyVersion) return null;
|
||||||
@@ -80,6 +85,7 @@ class HistoryVersion extends React.Component {
|
|||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
{(this.props.index !== 0) && <DropdownItem onClick={this.onItemRestore}>{gettext('Restore')}</DropdownItem>}
|
{(this.props.index !== 0) && <DropdownItem onClick={this.onItemRestore}>{gettext('Restore')}</DropdownItem>}
|
||||||
<DropdownItem tag='a' href={url} onClick={this.onItemDownLoad}>{gettext('Download')}</DropdownItem>
|
<DropdownItem tag='a' href={url} onClick={this.onItemDownLoad}>{gettext('Download')}</DropdownItem>
|
||||||
|
{(this.props.index !== 0) && <DropdownItem onClick={this.onItemCopy}>{gettext('Copy')}</DropdownItem>}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,6 +100,7 @@ HistoryVersion.propTypes = {
|
|||||||
historyVersion: PropTypes.object,
|
historyVersion: PropTypes.object,
|
||||||
onSelectHistoryVersion: PropTypes.func.isRequired,
|
onSelectHistoryVersion: PropTypes.func.isRequired,
|
||||||
onRestore: PropTypes.func.isRequired,
|
onRestore: PropTypes.func.isRequired,
|
||||||
|
onCopy: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default HistoryVersion;
|
export default HistoryVersion;
|
||||||
|
@@ -115,6 +115,19 @@ class SidePanel extends Component {
|
|||||||
this.props.onSelectHistoryVersion(historyVersion, historyVersions[historyVersionIndex + 1]);
|
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 = () => {
|
renderHistoryVersions = () => {
|
||||||
const { isLoading, historyVersions, errorMessage } = this.state;
|
const { isLoading, historyVersions, errorMessage } = this.state;
|
||||||
if (historyVersions.length === 0) {
|
if (historyVersions.length === 0) {
|
||||||
@@ -150,6 +163,7 @@ class SidePanel extends Component {
|
|||||||
historyVersion={historyVersion}
|
historyVersion={historyVersion}
|
||||||
onSelectHistoryVersion={this.onSelectHistoryVersion}
|
onSelectHistoryVersion={this.onSelectHistoryVersion}
|
||||||
onRestore={this.restoreVersion}
|
onRestore={this.restoreVersion}
|
||||||
|
onCopy={this.copyHistoryFile}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import requests
|
import requests
|
||||||
import posixpath
|
import posixpath
|
||||||
@@ -10,6 +11,7 @@ from rest_framework.authentication import SessionAuthentication
|
|||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.http import HttpResponseRedirect, HttpResponse
|
from django.http import HttpResponseRedirect, HttpResponse
|
||||||
|
from django.core.files.base import ContentFile
|
||||||
|
|
||||||
from seaserv import seafile_api, check_quota
|
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, \
|
gen_seadoc_image_parent_path, get_seadoc_asset_upload_link, get_seadoc_asset_download_link, \
|
||||||
can_access_seadoc_asset
|
can_access_seadoc_asset
|
||||||
from seahub.utils.file_types import SEADOC, IMAGE
|
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.tags.models import FileUUIDMap
|
||||||
from seahub.utils.error_msg import file_type_error_msg
|
from seahub.utils.error_msg import file_type_error_msg
|
||||||
|
from seahub.utils.repo import parse_repo_perm
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -286,3 +290,66 @@ class SeadocDownloadImage(APIView):
|
|||||||
filetype, fileext = get_file_type_and_ext(filename)
|
filetype, fileext = get_file_type_and_ext(filename)
|
||||||
return HttpResponse(
|
return HttpResponse(
|
||||||
content=resp.content, content_type='image/' + fileext)
|
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 django.urls import re_path
|
||||||
from .apis import SeadocAccessToken, SeadocUploadLink, SeadocDownloadLink, SeadocUploadFile, \
|
from .apis import SeadocAccessToken, SeadocUploadLink, SeadocDownloadLink, SeadocUploadFile, \
|
||||||
SeadocUploadImage, SeadocDownloadImage
|
SeadocUploadImage, SeadocDownloadImage, SeadocCopyHistoryFile
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
re_path(r'^access-token/(?P<repo_id>[-0-9a-f]{36})/$', SeadocAccessToken.as_view(), name='seadoc_access_token'),
|
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'^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'^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'^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