mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-12 04:10:47 +00:00
dtable-asset-file-view (#4094)
* dtable-asset-file-view * repair code * modify code * modify workspace/dtable permission check
This commit is contained in:
@@ -218,7 +218,12 @@ module.exports = {
|
||||
require.resolve('./polyfills'),
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/app-dtable",
|
||||
]
|
||||
],
|
||||
dtableAssetFileView: [
|
||||
require.resolve('./polyfills'),
|
||||
require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
paths.appSrc + "/dtable-asset-file-view.js",
|
||||
],
|
||||
},
|
||||
|
||||
output: {
|
||||
|
@@ -92,6 +92,7 @@ module.exports = {
|
||||
viewCdoc: [require.resolve('./polyfills'), paths.appSrc + "/view-file-cdoc.js"],
|
||||
search: [require.resolve('./polyfills'), paths.appSrc + "/pages/search"],
|
||||
appDTable: [require.resolve('./polyfills'), paths.appSrc + "/app-dtable"],
|
||||
dtableAssetFileView: [require.resolve('./polyfills'), paths.appSrc + "/dtable-asset-file-view.js"],
|
||||
},
|
||||
|
||||
output: {
|
||||
|
169
frontend/src/dtable-asset-file-view.js
Normal file
169
frontend/src/dtable-asset-file-view.js
Normal file
@@ -0,0 +1,169 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { seafileAPI } from './utils/seafile-api';
|
||||
import { gettext, siteRoot, mediaUrl, logoPath, logoWidth, logoHeight, siteTitle } from './utils/constants';
|
||||
import Loading from './components/loading';
|
||||
import Account from './components/common/account';
|
||||
import FileViewTip from './components/file-view/file-view-tip';
|
||||
import PDFViewer from './components/pdf-viewer';
|
||||
import Audio from './components/file-content-view/audio';
|
||||
import Image from './components/file-content-view/image';
|
||||
import Markdown from './components/file-content-view/markdown';
|
||||
import PDF from './components/file-content-view/pdf';
|
||||
import SVG from './components/file-content-view/svg';
|
||||
import Text from './components/file-content-view/text';
|
||||
import Video from './components/file-content-view/video';
|
||||
|
||||
import './css/shared-file-view.css';
|
||||
|
||||
let loginUser = window.app.pageOptions.name;
|
||||
const {
|
||||
fileType, err, fileName, filePath, repoID, commitID
|
||||
} = window.app.pageOptions;
|
||||
|
||||
class FileContent extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
errorMsg: '',
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let queryStatus = () => {
|
||||
seafileAPI.queryOfficeFileConvertStatus(repoID, commitID, filePath, fileType.toLowerCase()).then((res) => {
|
||||
const convertStatus = res.data['status'];
|
||||
switch (convertStatus) {
|
||||
case 'QUEUED':
|
||||
case 'PROCESSING':
|
||||
this.setState({
|
||||
isLoading: true
|
||||
});
|
||||
setTimeout(queryStatus, 2000);
|
||||
break;
|
||||
case 'ERROR':
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
errorMsg: gettext('Document convertion failed.')
|
||||
});
|
||||
break;
|
||||
case 'DONE':
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
errorMsg: ''
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
if (error.response) {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
errorMsg: gettext('Document convertion failed.')
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
errorMsg: gettext('Please check the network.')
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
queryStatus();
|
||||
}
|
||||
|
||||
setIframeHeight = (e) => {
|
||||
const iframe = e.currentTarget;
|
||||
iframe.height = iframe.contentDocument.body.scrollHeight;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isLoading, errorMsg } = this.state;
|
||||
if (isLoading) {
|
||||
return <Loading />;
|
||||
}
|
||||
if (errorMsg) {
|
||||
return <FileViewTip errorMsg={errorMsg} />;
|
||||
}
|
||||
return (
|
||||
<Fragment>
|
||||
{
|
||||
fileType === 'Document' ?
|
||||
<div className="shared-file-view-body pdf-file-view">
|
||||
<PDFViewer />
|
||||
</div> :
|
||||
<div className="shared-file-view-body spreadsheet-file-view">
|
||||
<iframe id="spreadsheet-container" title={fileName} src={`${siteRoot}office-convert/static/${repoID}/${commitID}${encodeURIComponent(filePath)}/index.html`} onLoad={this.setIframeHeight}></iframe>
|
||||
</div>
|
||||
}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DTableAssetFileView extends React.Component {
|
||||
|
||||
render() {
|
||||
let renderItem;
|
||||
|
||||
if (err) {
|
||||
renderItem = <FileViewTip />;
|
||||
} else {
|
||||
switch (fileType) {
|
||||
case 'Audio':
|
||||
renderItem = <Audio />;
|
||||
break;
|
||||
case 'Document':
|
||||
case 'SpreadSheet':
|
||||
renderItem = <FileContent />;
|
||||
break;
|
||||
case 'Image':
|
||||
renderItem = <Image />;
|
||||
break;
|
||||
case 'Markdown':
|
||||
renderItem = <Markdown />;
|
||||
break;
|
||||
case 'PDF':
|
||||
renderItem = <PDF />;
|
||||
break;
|
||||
case 'SVG':
|
||||
renderItem = <SVG />;
|
||||
break;
|
||||
case 'Text':
|
||||
renderItem = <Text />;
|
||||
break;
|
||||
case 'Video':
|
||||
renderItem = <Video />;
|
||||
break;
|
||||
default:
|
||||
renderItem = (
|
||||
<FileViewTip />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="shared-file-view-md">
|
||||
<div className="shared-file-view-md-header d-flex">
|
||||
<a href={siteRoot}>
|
||||
<img src={mediaUrl + logoPath} height={logoHeight} width={logoWidth} title={siteTitle} alt="logo" />
|
||||
</a>
|
||||
{ loginUser && <Account /> }
|
||||
</div>
|
||||
<div className="shared-file-view-md-main">
|
||||
<div className="shared-file-view-head">
|
||||
<div className="float-left">
|
||||
<h2 className="ellipsis" title={fileName}>{fileName}</h2>
|
||||
</div>
|
||||
</div>
|
||||
{renderItem}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render (
|
||||
<DTableAssetFileView />,
|
||||
document.getElementById('wrapper')
|
||||
);
|
@@ -24,7 +24,7 @@ from seahub.group.utils import group_id_to_name
|
||||
from seahub.utils import is_valid_dirent_name, is_org_context, normalize_file_path, \
|
||||
check_filename_with_rename, gen_file_upload_url
|
||||
from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN, DTABLE_PRIVATE_KEY
|
||||
from seahub.dtable.utils import check_dtable_share_permission, check_dtable_permission
|
||||
from seahub.dtable.utils import check_dtable_permission
|
||||
from seahub.constants import PERMISSION_ADMIN, PERMISSION_READ_WRITE
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ class DTablesView(APIView):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
if not check_dtable_permission(username, table_owner):
|
||||
if not check_dtable_permission(username, workspace):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
@@ -288,8 +288,7 @@ class DTableView(APIView):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
owner = workspace.owner
|
||||
if not check_dtable_permission(username, owner):
|
||||
if not check_dtable_permission(username, workspace):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
@@ -358,8 +357,7 @@ class DTableView(APIView):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
owner = workspace.owner
|
||||
if not check_dtable_permission(username, owner):
|
||||
if not check_dtable_permission(username, workspace):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
@@ -439,9 +437,7 @@ class DTableAssetUploadLinkView(APIView):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
owner = workspace.owner
|
||||
if not check_dtable_permission(username, owner) and \
|
||||
check_dtable_share_permission(dtable, username) not in WRITE_PERMISSION_TUPLE:
|
||||
if check_dtable_permission(username, workspace, dtable) not in WRITE_PERMISSION_TUPLE:
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
@@ -508,9 +504,7 @@ class DTableAccessTokenView(APIView):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
owner = workspace.owner
|
||||
if not check_dtable_permission(username, owner) and \
|
||||
not check_dtable_share_permission(dtable, username):
|
||||
if not check_dtable_permission(username, workspace, dtable):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
|
@@ -14,8 +14,7 @@ from seahub.api2.authentication import TokenAuthentication
|
||||
from seahub.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.utils import api_error, get_user_common_info
|
||||
from seahub.dtable.models import Workspaces, DTables
|
||||
from seahub.dtable.utils import check_dtable_permission, check_dtable_share_permission, \
|
||||
list_dtable_related_users
|
||||
from seahub.dtable.utils import check_dtable_permission, list_dtable_related_users
|
||||
from seahub.utils import normalize_file_path
|
||||
from seahub.api2.endpoints.dtable import FILE_TYPE
|
||||
|
||||
@@ -65,9 +64,7 @@ class DTableRelatedUsersView(APIView):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
owner = workspace.owner
|
||||
if not check_dtable_permission(username, owner) and \
|
||||
not check_dtable_share_permission(dtable, username):
|
||||
if not check_dtable_permission(username, workspace, dtable):
|
||||
error_msg = 'Permission denied.'
|
||||
return api_error(status.HTTP_403_FORBIDDEN, error_msg)
|
||||
|
||||
|
@@ -1,10 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import dtable_file_view, dtable_asset_access
|
||||
from .views import dtable_file_view, dtable_asset_access, dtable_asset_file_view
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^(?P<workspace_id>\d+)/dtable/(?P<name>.*)/$', dtable_file_view, name='dtable_file_view'),
|
||||
url(r'^(?P<workspace_id>\d+)/asset/(?P<dtable_id>[-0-9a-f]{36})/(?P<path>.*)$', dtable_asset_access, name='dtable_asset_access'),
|
||||
url(r'^(?P<workspace_id>\d+)/asset-file/(?P<dtable_id>[-0-9a-f]{36})/(?P<path>.*)$', dtable_asset_file_view, name='dtable_asset_file_view'),
|
||||
]
|
||||
|
@@ -5,29 +5,27 @@ from seahub.constants import PERMISSION_READ_WRITE
|
||||
from seaserv import ccnet_api
|
||||
|
||||
|
||||
def check_dtable_share_permission(dtable, to_user):
|
||||
share_dtable_obj = DTableShare.objects.get_by_dtable_and_to_user(dtable, to_user)
|
||||
if share_dtable_obj:
|
||||
return share_dtable_obj.permission
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def check_dtable_permission(username, owner):
|
||||
def check_dtable_permission(username, workspace, dtable=None):
|
||||
"""Check workspace/dtable access permission of a user.
|
||||
"""
|
||||
owner = workspace.owner
|
||||
|
||||
if dtable:
|
||||
dtable_share = DTableShare.objects.get_by_dtable_and_to_user(dtable, username)
|
||||
if dtable_share:
|
||||
return dtable_share.permission
|
||||
|
||||
if '@seafile_group' in owner:
|
||||
group_id = int(owner.split('@')[0])
|
||||
if not is_group_member(group_id, username):
|
||||
return None
|
||||
else:
|
||||
if is_group_member(group_id, username):
|
||||
return PERMISSION_READ_WRITE
|
||||
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if username != owner:
|
||||
return None
|
||||
else:
|
||||
if username == owner:
|
||||
return PERMISSION_READ_WRITE
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def list_dtable_related_users(workspace, dtable):
|
||||
|
@@ -8,12 +8,14 @@ from seaserv import seafile_api
|
||||
|
||||
from seahub.dtable.models import Workspaces, DTables
|
||||
from seahub.utils import normalize_file_path, render_error, render_permission_error, \
|
||||
gen_file_get_url
|
||||
gen_file_get_url, get_file_type_and_ext, gen_inner_file_get_url
|
||||
from seahub.auth.decorators import login_required
|
||||
from seahub.settings import SHARE_LINK_EXPIRE_DAYS_MIN, SHARE_LINK_EXPIRE_DAYS_MAX, \
|
||||
SHARE_LINK_EXPIRE_DAYS_DEFAULT, DTABLE_SERVER_URL, SEAFILE_COLLAB_SERVER, MEDIA_URL
|
||||
from seahub.dtable.utils import check_dtable_share_permission, check_dtable_permission
|
||||
SHARE_LINK_EXPIRE_DAYS_DEFAULT, DTABLE_SERVER_URL, SEAFILE_COLLAB_SERVER, MEDIA_URL, \
|
||||
FILE_ENCODING_LIST
|
||||
from seahub.dtable.utils import check_dtable_permission
|
||||
from seahub.constants import PERMISSION_ADMIN, PERMISSION_READ_WRITE
|
||||
from seahub.views.file import get_file_content
|
||||
|
||||
|
||||
FILE_TYPE = '.dtable'
|
||||
@@ -51,9 +53,7 @@ def dtable_file_view(request, workspace_id, name):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
owner = workspace.owner
|
||||
if not check_dtable_permission(username, owner) and \
|
||||
not check_dtable_share_permission(dtable, username):
|
||||
if not check_dtable_permission(username, workspace, dtable):
|
||||
return render_permission_error(request, _('Permission denied.'))
|
||||
|
||||
return_dict = {
|
||||
@@ -106,9 +106,7 @@ def dtable_asset_access(request, workspace_id, dtable_id, path):
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
owner = workspace.owner
|
||||
if not check_dtable_permission(username, owner) and \
|
||||
check_dtable_share_permission(dtable, username) not in WRITE_PERMISSION_TUPLE:
|
||||
if check_dtable_permission(username, workspace, dtable) not in WRITE_PERMISSION_TUPLE:
|
||||
return render_permission_error(request, _('Permission denied.'))
|
||||
|
||||
dl = request.GET.get('dl', '0') == '1'
|
||||
@@ -121,3 +119,60 @@ def dtable_asset_access(request, workspace_id, dtable_id, path):
|
||||
url = gen_file_get_url(token, asset_name)
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@login_required
|
||||
def dtable_asset_file_view(request, workspace_id, dtable_id, path):
|
||||
|
||||
# resource check
|
||||
workspace = Workspaces.objects.get_workspace_by_id(workspace_id)
|
||||
if not workspace:
|
||||
return render_error(request, 'Workspace does not exist.')
|
||||
|
||||
repo_id = workspace.repo_id
|
||||
repo = seafile_api.get_repo(repo_id)
|
||||
if not repo:
|
||||
return render_error(request, 'Library does not exist.')
|
||||
|
||||
dtable = DTables.objects.get_dtable_by_uuid(dtable_id)
|
||||
if not dtable:
|
||||
return render_error(request, 'DTable does not exist.')
|
||||
|
||||
asset_path = normalize_file_path(os.path.join('/asset', dtable_id, path))
|
||||
asset_id = seafile_api.get_file_id_by_path(repo_id, asset_path)
|
||||
if not asset_id:
|
||||
return render_error(request, 'Asset file does not exist.')
|
||||
|
||||
# permission check
|
||||
username = request.user.username
|
||||
if not check_dtable_permission(username, workspace, dtable):
|
||||
return render_permission_error(request, _('Permission denied.'))
|
||||
|
||||
file_enc = request.GET.get('file_enc', 'auto')
|
||||
if file_enc not in FILE_ENCODING_LIST:
|
||||
file_enc = 'auto'
|
||||
|
||||
token = seafile_api.get_fileserver_access_token(
|
||||
repo_id, asset_id, 'view', '', use_onetime=False
|
||||
)
|
||||
|
||||
file_name = os.path.basename(normalize_file_path(path))
|
||||
file_type, file_ext = get_file_type_and_ext(file_name)
|
||||
|
||||
inner_path = gen_inner_file_get_url(token, file_name)
|
||||
error_msg, file_content, encoding = get_file_content(file_type, inner_path, file_enc)
|
||||
|
||||
raw_path = gen_file_get_url(token, file_name)
|
||||
|
||||
return_dict = {
|
||||
'repo': repo,
|
||||
'filename': file_name,
|
||||
'file_path': asset_path,
|
||||
'file_type': file_type,
|
||||
'file_ext': file_ext,
|
||||
'raw_path': raw_path,
|
||||
'file_content': file_content,
|
||||
'err': 'File preview unsupported' if file_type == 'Unknown' else error_msg,
|
||||
}
|
||||
|
||||
return render(request, 'dtable_asset_file_view_react.html', return_dict)
|
||||
|
55
seahub/templates/dtable_asset_file_view_react.html
Normal file
55
seahub/templates/dtable_asset_file_view_react.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{% extends "file_view_react.html" %}
|
||||
{% load seahub_tags i18n %}
|
||||
{% load render_bundle from webpack_loader %}
|
||||
|
||||
{% block extra_ogp_tags %}
|
||||
<meta property="og:type" content="object" />
|
||||
<meta property="og:site_name" content="{{ site_name }}">
|
||||
<meta property="og:url" content="{{ service_url }}{{ file_share_link }}" />
|
||||
<meta property="og:title" content="{{ file_name }}" />
|
||||
<meta property="og:image" content="{{ service_url }}{{ MEDIA_URL }}img/file/{{ icon_path_for_ogp }}" />
|
||||
<meta property="og:description" content="{{ desc_for_ogp }}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_style %}
|
||||
{% if file_type == 'PDF' or file_type == 'Document' %}
|
||||
<link rel="resource" type="application/l10n" href="{{ MEDIA_URL }}js/pdf/locale/locale.properties" />
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_script %}
|
||||
<script type="text/javascript">
|
||||
window.app.pageOptions = {
|
||||
repoID: '{{ repo.id }}',
|
||||
commitID: '{{ repo.head_cmmt_id }}',
|
||||
fileName: '{{ filename|escapejs }}',
|
||||
filePath: '{{ file_path|escapejs }}',
|
||||
fileType: '{{ file_type }}',
|
||||
fileExt: '{{ file_ext }}',
|
||||
rawPath: '{{ raw_path|escapejs }}',
|
||||
fileContent: '{{ file_content|escapejs }}',
|
||||
err: {% if err %}'{{ err }}'{% else %}''{% endif %},
|
||||
name: '{{request.user.username|email2nickname|escapejs}}',
|
||||
};
|
||||
</script>
|
||||
{% render_bundle 'dtableAssetFileView' 'js' %}
|
||||
|
||||
{% if file_type == 'PDF' %}
|
||||
<script type="text/javascript">
|
||||
let sf_file_url = '{{ raw_path|escapejs }}';
|
||||
let sf_pdfworkerjs_url = '{{MEDIA_URL}}js/pdf/pdf.worker.min.js';
|
||||
let sf_pdf_images_path = '{{MEDIA_URL}}js/pdf/images/';
|
||||
</script>
|
||||
<script type="text/javascript" src="{{MEDIA_URL}}js/pdf/pdf.min.js"></script>
|
||||
<script type="text/javascript" src="{{MEDIA_URL}}js/pdf/viewer.js"></script>
|
||||
{% elif file_type == 'Document' %}
|
||||
<script type="text/javascript">
|
||||
let commit_id = '{{ repo.head_cmmt_id }}';
|
||||
let sf_file_url = '{{ SITE_ROOT }}office-convert/static/{{ repo.id }}/' + commit_id + '{{ file_path|urlencode }}/fake.pdf';
|
||||
let sf_pdfworkerjs_url = '{{MEDIA_URL}}js/pdf/pdf.worker.min.js';
|
||||
let sf_pdf_images_path = '{{MEDIA_URL}}js/pdf/images/';
|
||||
</script>
|
||||
<script type="text/javascript" src="{{MEDIA_URL}}js/pdf/pdf.min.js"></script>
|
||||
<script type="text/javascript" src="{{MEDIA_URL}}js/pdf/viewer.js"></script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
Reference in New Issue
Block a user