1
0
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:
Ranjiwei 2024-09-19 11:12:10 +08:00 committed by GitHub
parent a5d8ef3fe2
commit 86770c47f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 82 additions and 48 deletions

View File

@ -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')}

View File

@ -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}`,
};
};

View File

@ -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}`,
};
};

View File

@ -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}`,
};
};

View File

@ -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 (

View File

@ -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

View File

@ -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

View File

@ -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]);

View File

@ -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',
};
};

View File

@ -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 (

View File

@ -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'
};

View File

@ -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);

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 }}',

View File

@ -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 }}',

View File

@ -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 %}

View File

@ -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('/')),

View File

@ -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']

View File

@ -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=[

View File

@ -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)

View File

@ -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')