mirror of
https://github.com/haiwen/seahub.git
synced 2025-04-28 03:10:45 +00:00
add-download-url (#6771)
* add-download-url * update unitest * update * update * update * update * Update test_view_lib_file.py * code-optimize * Update shared-dir-view.js * code-optimize
This commit is contained in:
parent
a5d8ef3fe2
commit
86770c47f9
@ -17,7 +17,7 @@ const propTypes = {
|
||||
class ImageDialog extends React.Component {
|
||||
|
||||
downloadImage = (imageSrc) => {
|
||||
let downloadUrl = imageSrc.indexOf('?dl=1') > -1 ? imageSrc : imageSrc + '?dl=1';
|
||||
let downloadUrl = imageSrc;
|
||||
|
||||
if (document.getElementById('downloadFrame')) {
|
||||
document.body.removeChild(document.getElementById('downloadFrame'));
|
||||
@ -72,7 +72,7 @@ class ImageDialog extends React.Component {
|
||||
zoomInLabel={gettext('Zoom in')}
|
||||
zoomOutLabel={gettext('Zoom out')}
|
||||
enableRotate={true}
|
||||
onClickDownload={() => this.downloadImage(imageItems[imageIndex].url)}
|
||||
onClickDownload={() => this.downloadImage(imageItems[imageIndex].downloadURL)}
|
||||
onClickDelete={this.props.onDeleteImage ? () => this.props.onDeleteImage(imageItems[imageIndex].name) : null}
|
||||
onViewOriginal={this.onViewOriginal}
|
||||
viewOriginalImageLabel={gettext('View original image')}
|
||||
|
@ -9,7 +9,7 @@ import Move from '../../components/dialog/move-dirent-dialog';
|
||||
import CreateFolder from '../../components/dialog/create-folder-dialog';
|
||||
import CreateFile from '../../components/dialog/create-file-dialog';
|
||||
import ImageDialog from '../../components/dialog/image-dialog';
|
||||
import { gettext, siteRoot, thumbnailSizeForOriginal } from '../../utils/constants';
|
||||
import { fileServerRoot, gettext, siteRoot, thumbnailSizeForOriginal } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import TextTranslation from '../../utils/text-translation';
|
||||
import TreeSection from '../../components/tree-section';
|
||||
@ -269,6 +269,7 @@ class DirColumnNav extends React.Component {
|
||||
'src': src,
|
||||
'thumbnail': `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${path}`,
|
||||
'node': items.find(item => item.path.split('/').pop() === name),
|
||||
'downloadURL': `${fileServerRoot}repos/${repoID}/files/?op=download&p=${path}`,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { siteRoot, username, enableSeadoc, thumbnailDefaultSize, thumbnailSizeForOriginal, gettext } from '../../utils/constants';
|
||||
import { siteRoot, username, enableSeadoc, thumbnailDefaultSize, thumbnailSizeForOriginal, gettext, fileServerRoot } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import URLDecorator from '../../utils/url-decorator';
|
||||
@ -591,6 +591,7 @@ class DirentGridView extends React.Component {
|
||||
'url': `${siteRoot}lib/${repoID}/file${path}`,
|
||||
'thumbnail': `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${path}`,
|
||||
'src': `${siteRoot}repo/${repoID}/raw${path}?t=${cacheBuster}`,
|
||||
'downloadURL': `${fileServerRoot}repos/${repoID}/files/?op=download&p=${path}`,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { siteRoot, gettext, username, enableSeadoc, thumbnailSizeForOriginal } from '../../utils/constants';
|
||||
import { siteRoot, gettext, username, enableSeadoc, thumbnailSizeForOriginal, fileServerRoot } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import TextTranslation from '../../utils/text-translation';
|
||||
import URLDecorator from '../../utils/url-decorator';
|
||||
@ -189,6 +189,7 @@ class DirentListView extends React.Component {
|
||||
'url': `${siteRoot}lib/${repoID}/file${path}`,
|
||||
'thumbnail': `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${path}`,
|
||||
'src': `${siteRoot}repo/${repoID}/raw${path}`,
|
||||
'downloadURL': `${fileServerRoot}repos/${repoID}/files/?op=download&p=${path}`,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import VideoPlayer from '../video-player';
|
||||
|
||||
import { MimetypesKind } from '../../utils/constants';
|
||||
import '../../css/video-file-view.css';
|
||||
|
||||
const {
|
||||
rawPath
|
||||
rawPath, fileExt
|
||||
} = window.app.pageOptions;
|
||||
|
||||
class FileContent extends React.Component {
|
||||
@ -15,7 +15,8 @@ class FileContent extends React.Component {
|
||||
preload: 'auto',
|
||||
playbackRates: [0.5, 1, 1.5, 2],
|
||||
sources: [{
|
||||
src: rawPath
|
||||
src: rawPath,
|
||||
type: MimetypesKind[fileExt] || 'video/mp4'
|
||||
}]
|
||||
};
|
||||
return (
|
||||
|
@ -28,6 +28,7 @@ const {
|
||||
canEditFile, err,
|
||||
// fileEnc, // for 'edit', not undefined only for some kinds of files (e.g. text file)
|
||||
canDownloadFile,
|
||||
fileDownloadURL,
|
||||
} = window.app.pageOptions;
|
||||
|
||||
class FileToolbar extends React.Component {
|
||||
@ -162,7 +163,7 @@ class FileToolbar extends React.Component {
|
||||
id="download-file"
|
||||
icon="download"
|
||||
text={gettext('Download')}
|
||||
href="?dl=1"
|
||||
href={fileDownloadURL}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
|
@ -19,7 +19,7 @@ const propTypes = {
|
||||
let loginUser = window.app.pageOptions.name;
|
||||
let contactEmail = window.app.pageOptions.contactEmail;
|
||||
const { sharedToken, trafficOverLimit, fileName, fileSize, sharedBy, siteName, enableWatermark, canDownload,
|
||||
zipped, filePath, enableShareLinkReportAbuse } = window.shared.pageOptions;
|
||||
zipped, filePath, enableShareLinkReportAbuse, sharedFileDownloadURL } = window.shared.pageOptions;
|
||||
|
||||
class SharedFileView extends React.Component {
|
||||
|
||||
@ -129,7 +129,8 @@ class SharedFileView extends React.Component {
|
||||
</Button>
|
||||
}{' '}
|
||||
{(canDownload && !trafficOverLimit) &&
|
||||
<a href={`?${zipped ? 'p=' + encodeURIComponent(filePath) + '&' : ''}dl=1`} className="btn btn-success">{gettext('Download')} ({Utils.bytesToSize(fileSize)})</a>
|
||||
|
||||
<a href={`${zipped ? '?p=' + encodeURIComponent(filePath) + '&dl=1' : sharedFileDownloadURL}`} className="btn btn-success">{gettext('Download')} ({Utils.bytesToSize(fileSize)})</a>
|
||||
}{' '}
|
||||
{(enableShareLinkReportAbuse && (loginUser !== sharedBy)) &&
|
||||
<Button
|
||||
|
@ -4,9 +4,10 @@ import { ModalPortal } from '@seafile/sf-metadata-ui-component';
|
||||
import { Utils } from '../../../utils/utils';
|
||||
import ImageDialog from '../../../components/dialog/image-dialog';
|
||||
import { EVENT_BUS_TYPE } from '../../../components/common/event-bus-type';
|
||||
import { siteRoot, thumbnailSizeForOriginal } from '../../../utils/constants';
|
||||
import { siteRoot, thumbnailSizeForOriginal, fileServerRoot } from '../../../utils/constants';
|
||||
import { PRIVATE_COLUMN_KEY } from '../../constants';
|
||||
|
||||
|
||||
const FileNameEditor = ({ column, record, table, onCommitCancel }) => {
|
||||
const [imageIndex, setImageIndex] = useState(0);
|
||||
|
||||
@ -30,6 +31,7 @@ const FileNameEditor = ({ column, record, table, onCommitCancel }) => {
|
||||
url: `${siteRoot}lib/${repoID}/file${path}`,
|
||||
thumbnail: `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${path}`,
|
||||
src: src,
|
||||
downloadURL: `${fileServerRoot}repos/${repoID}/files/?op=download&p=${path}`,
|
||||
};
|
||||
});
|
||||
}, [table]);
|
||||
|
@ -326,7 +326,8 @@ class SharedDirView extends React.Component {
|
||||
'name': name,
|
||||
'url': fileURL,
|
||||
'thumbnail': `${siteRoot}thumbnail/${repoID}/${thumbnailSizeForOriginal}${item.file_path}`,
|
||||
'src': src
|
||||
'src': src,
|
||||
'downloadURL': fileURL + '&dl=1',
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -3,10 +3,11 @@ import ReactDom from 'react-dom';
|
||||
import SharedFileView from './components/shared-file-view/shared-file-view';
|
||||
import SharedFileViewTip from './components/shared-file-view/shared-file-view-tip';
|
||||
import VideoPlayer from './components/video-player';
|
||||
import { MimetypesKind } from './utils/constants';
|
||||
|
||||
import './css/video-file-view.css';
|
||||
|
||||
const { rawPath, err } = window.shared.pageOptions;
|
||||
const { rawPath, err, fileExt } = window.shared.pageOptions;
|
||||
|
||||
class SharedFileViewImage extends React.Component {
|
||||
render() {
|
||||
@ -19,14 +20,14 @@ class FileContent extends React.Component {
|
||||
if (err) {
|
||||
return <SharedFileViewTip />;
|
||||
}
|
||||
|
||||
const videoJsOptions = {
|
||||
autoplay: false,
|
||||
controls: true,
|
||||
preload: 'auto',
|
||||
playbackRates: [0.5, 1, 1.5, 2],
|
||||
sources: [{
|
||||
src: rawPath
|
||||
src: rawPath,
|
||||
type: MimetypesKind[fileExt] || 'video/mp4'
|
||||
}]
|
||||
};
|
||||
return (
|
||||
|
@ -174,3 +174,27 @@ export const enableShareLinkReportAbuse = window.sysadmin ? window.sysadmin.page
|
||||
|
||||
// institution admin
|
||||
export const institutionName = window.app ? window.app.pageOptions.institutionName : '';
|
||||
|
||||
export const MimetypesKind = {
|
||||
opus: 'video/ogg',
|
||||
ogv: 'video/ogg',
|
||||
mp4: 'video/mp4',
|
||||
mov: 'video/mp4',
|
||||
m4v: 'video/mp4',
|
||||
mkv: 'video/x-matroska',
|
||||
m4a: 'audio/mp4',
|
||||
mp3: 'audio/mpeg',
|
||||
aac: 'audio/aac',
|
||||
caf: 'audio/x-caf',
|
||||
flac: 'audio/flac',
|
||||
oga: 'audio/ogg',
|
||||
wav: 'audio/wav',
|
||||
m3u8: 'application/x-mpegURL',
|
||||
mpd: 'application/dash+xml',
|
||||
jpg: 'image/jpeg',
|
||||
jpeg: 'image/jpeg',
|
||||
gif: 'image/gif',
|
||||
png: 'image/png',
|
||||
svg: 'image/svg+xml',
|
||||
webp: 'image/webp'
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { siteRoot, historyRepoID } from './constants';
|
||||
import { siteRoot, historyRepoID, fileServerRoot } from './constants';
|
||||
import { Utils } from './utils';
|
||||
class URLDecorator {
|
||||
|
||||
@ -11,7 +11,7 @@ class URLDecorator {
|
||||
url = siteRoot + 'repo/' + historyRepoID + '/' + options.objID + '/download?' + params;
|
||||
break;
|
||||
case 'download_file_url':
|
||||
url = siteRoot + 'lib/' + options.repoID + '/file' + Utils.encodePath(options.filePath) + '?dl=1';
|
||||
url = fileServerRoot + 'repos/' + options.repoID + '/files/?p=' + options.filePath + '&op=download';
|
||||
break;
|
||||
case 'file_revisions':
|
||||
params = 'p=' + Utils.encodePath(options.filePath);
|
||||
|
@ -33,7 +33,9 @@ enablePDFThumbnail: {% if enable_pdf_thumbnail %} true {% else %} false {% endif
|
||||
{% if filetype == 'XMind' %}
|
||||
xmindImageSrc: '{{ xmind_image_src|escapejs }}',
|
||||
{% endif %}
|
||||
rawPath: '{{ raw_path|escapejs }}'
|
||||
rawPath: '{{ raw_path|escapejs }}',
|
||||
fileDownloadURL: {% if file_download_url %}'{{ file_download_url|escapejs }}'{% else %}''{% endif %},
|
||||
fileExt: {% if fileext %}'{{fileext|escapejs }}'{% else %}''{% endif %},
|
||||
{% endblock %}
|
||||
|
||||
{% block render_bundle %}
|
||||
|
@ -43,7 +43,6 @@ window.app.pageOptions = {
|
||||
canDownloadFile: {% if can_download_file %}true{% else %}false{% endif %},
|
||||
enableWatermark: {% if enable_watermark %}true{% else %}false{% endif %},
|
||||
enableMetadataManagement: {% if enable_metadata_management %} true {% else %} false {% endif %},
|
||||
|
||||
// for {{filetype}} file
|
||||
{% block extra_data %}
|
||||
{% endblock %}
|
||||
|
@ -61,6 +61,7 @@
|
||||
lockedByMe: {% if locked_by_me %}true{% else %}false{% endif %},
|
||||
canLockUnlockFile: {% if can_lock_unlock_file %}true{% else %}false{% endif %},
|
||||
canDownloadFile: {% if can_download_file %}true{% else %}false{% endif %},
|
||||
fileDownloadURL: {% if file_download_url %}'{{ file_download_url|escapejs }}'{% else %}''{% endif %},
|
||||
},
|
||||
userInfo: {
|
||||
username: '{{ user.username }}',
|
||||
|
@ -96,6 +96,7 @@ body {
|
||||
prevImgPath: {% if img_prev %}'{{ img_prev|escapejs }}'{% else %}''{% endif %},
|
||||
nextImgPath: {% if img_next %}'{{ img_next|escapejs }}'{% else %}''{% endif %},
|
||||
assetsUrl: '{{ assets_url }}',
|
||||
sharedFileDownloadURL: {% if shared_file_download_url %}'{{ shared_file_download_url }}'{% else %}''{% endif %},
|
||||
|
||||
{% if filetype == 'SDoc' %}
|
||||
docPath: '{{ path|escapejs }}',
|
||||
|
@ -9,7 +9,8 @@
|
||||
{% block extra_data %}
|
||||
fileExt: '{{ fileext|escapejs }}',
|
||||
fileEnc: '{{ file_enc|escapejs }}',
|
||||
fileContent: '{{ file_content|escapejs }}'
|
||||
fileContent: '{{ file_content|escapejs }}',
|
||||
fileDownloadURL: {% if file_download_url %}'{{ file_download_url|escapejs }}'{% else %}''{% endif %},
|
||||
{% endblock %}
|
||||
|
||||
{% block render_bundle %}
|
||||
|
@ -546,10 +546,10 @@ def gen_file_get_url_by_sharelink(token):
|
||||
def gen_file_get_url_new(repo_id, filepath, op='download'):
|
||||
"""
|
||||
Generate fileserver file url.
|
||||
Format: http://<domain:port>/repos/<repo_id>files/<filepath>/?op=download
|
||||
Format: http://<domain:port>/repos/<repo_id>files/?p=<filepath>&op=download
|
||||
"""
|
||||
|
||||
return '%s/repos/%s/files/%s/?op=%s' % (
|
||||
return '%s/repos/%s/files/?p=%s&op=%s' % (
|
||||
get_fileserver_root(),
|
||||
repo_id,
|
||||
quote(filepath.strip('/')),
|
||||
|
@ -56,7 +56,7 @@ from seahub.utils import render_error, is_org_context, \
|
||||
generate_file_audit_event_type, FILE_AUDIT_ENABLED, \
|
||||
get_conf_text_ext, HAS_OFFICE_CONVERTER, PREVIEW_FILEEXT, \
|
||||
normalize_file_path, get_service_url, OFFICE_PREVIEW_MAX_SIZE, \
|
||||
normalize_cache_key, gen_file_get_url_by_sharelink
|
||||
normalize_cache_key, gen_file_get_url_by_sharelink, gen_file_get_url_new
|
||||
from seahub.utils.ip import get_remote_ip
|
||||
from seahub.utils.timeutils import utc_to_local
|
||||
from seahub.utils.file_types import (IMAGE, PDF, SVG,
|
||||
@ -511,14 +511,17 @@ def view_lib_file(request, repo_id, path):
|
||||
return HttpResponseRedirect(file_url)
|
||||
|
||||
operation = 'download' if dl else 'view'
|
||||
token = seafile_api.get_fileserver_access_token(
|
||||
repo_id, file_id, operation, username,
|
||||
use_onetime=settings.FILESERVER_TOKEN_ONCE_ONLY)
|
||||
if dl:
|
||||
dl_or_raw_url = gen_file_get_url_new(repo_id, path)
|
||||
else:
|
||||
token = seafile_api.get_fileserver_access_token(
|
||||
repo_id, file_id, operation, username,
|
||||
use_onetime=settings.FILESERVER_TOKEN_ONCE_ONLY)
|
||||
|
||||
if not token:
|
||||
return render_permission_error(request, _('Unable to view file'))
|
||||
|
||||
if not token:
|
||||
return render_permission_error(request, _('Unable to view file'))
|
||||
|
||||
dl_or_raw_url = gen_file_get_url(token, filename)
|
||||
dl_or_raw_url = gen_file_get_url(token, filename)
|
||||
|
||||
# send stats message
|
||||
send_file_access_msg(request, repo, path, 'web')
|
||||
@ -579,6 +582,7 @@ def view_lib_file(request, repo_id, path):
|
||||
'can_download_file': parse_repo_perm(permission).can_download,
|
||||
'seafile_collab_server': SEAFILE_COLLAB_SERVER,
|
||||
'enable_metadata_management': settings.ENABLE_METADATA_MANAGEMENT,
|
||||
'file_download_url': gen_file_get_url_new(repo_id, path)
|
||||
}
|
||||
|
||||
# check whether file is starred
|
||||
@ -641,6 +645,8 @@ def view_lib_file(request, repo_id, path):
|
||||
template = '%s_file_view_react.html' % filetype.lower()
|
||||
|
||||
if filetype in (IMAGE, VIDEO, AUDIO, PDF, SVG, XMIND, 'Unknown'):
|
||||
if filetype == VIDEO:
|
||||
raw_path = gen_file_get_url_new(repo_id, path)
|
||||
template = 'common_file_view_react.html'
|
||||
|
||||
if filetype == SEADOC:
|
||||
@ -1255,6 +1261,9 @@ def view_shared_file(request, fileshare):
|
||||
filetype, fileext = get_file_type_and_ext(filename)
|
||||
ret_dict = {'err': '', 'file_content': '', 'encoding': '', 'file_enc': '',
|
||||
'file_encoding_list': [], 'filetype': filetype}
|
||||
|
||||
if filetype == VIDEO:
|
||||
raw_path = gen_file_get_url_new(repo_id, path)
|
||||
|
||||
if filetype == SEADOC:
|
||||
file_uuid = get_seadoc_file_uuid(repo, path)
|
||||
@ -1384,6 +1393,7 @@ def view_shared_file(request, fileshare):
|
||||
'desc_for_ogp': desc_for_ogp,
|
||||
'icon_path_for_ogp': icon_path_for_ogp,
|
||||
'enable_share_link_report_abuse': ENABLE_SHARE_LINK_REPORT_ABUSE,
|
||||
'shared_file_download_url': gen_file_get_url_by_sharelink(fileshare.token)
|
||||
}
|
||||
if filetype == SEADOC:
|
||||
data['file_uuid'] = ret_dict['file_uuid']
|
||||
|
@ -56,12 +56,7 @@ class FileTest(BaseTestCase):
|
||||
dl_url = reverse('view_lib_file', args=[self.repo.id, self.file]) + '?dl=1'
|
||||
resp = self.client.get(dl_url)
|
||||
self.assertEqual(302, resp.status_code)
|
||||
assert '8082/files/' in resp.get('location')
|
||||
|
||||
resp = requests.request('GET', resp.get('location'))
|
||||
cont_disp = resp.headers['content-disposition']
|
||||
assert 'inline' not in cont_disp
|
||||
assert 'attachment' in cont_disp
|
||||
assert '8082/repos/' in resp.get('location')
|
||||
|
||||
def test_can_render_video(self):
|
||||
resp = self.client.get(reverse('view_lib_file', args=[
|
||||
|
@ -176,10 +176,6 @@ class ViewLibFileTest(BaseTestCase):
|
||||
self.assertTemplateUsed(resp, 'common_file_view_react.html')
|
||||
assert resp.context['filetype'].lower() == 'video'
|
||||
|
||||
raw_path = resp.context['raw_path']
|
||||
for _ in range(3): # token for video is not one time only
|
||||
r = requests.get(raw_path)
|
||||
self.assertEqual(200, r.status_code)
|
||||
|
||||
def test_can_download(self):
|
||||
self.login_as(self.user)
|
||||
@ -187,12 +183,7 @@ class ViewLibFileTest(BaseTestCase):
|
||||
url = reverse('view_lib_file', args=[self.repo.id, self.file]) + '?dl=1'
|
||||
resp = self.client.get(url)
|
||||
self.assertEqual(302, resp.status_code)
|
||||
assert '8082/files/' in resp.get('location')
|
||||
|
||||
resp = requests.request('GET', resp.get('location'))
|
||||
cont_disp = resp.headers['content-disposition']
|
||||
assert 'inline' not in cont_disp
|
||||
assert 'attachment' in cont_disp
|
||||
assert '8082/repos/' in resp.get('location')
|
||||
|
||||
def test_can_view_raw(self):
|
||||
self.login_as(self.user)
|
||||
|
@ -49,4 +49,4 @@ class ViewLibFileViaSmartLinkTest(BaseTestCase):
|
||||
assert 'dl=1' in resp.get('location')
|
||||
|
||||
resp = self.client.get(resp.get('location'))
|
||||
assert '8082/files/' in resp.get('location')
|
||||
assert '8082/repos/' in resp.get('location')
|
||||
|
Loading…
Reference in New Issue
Block a user