1
0
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:
王健辉
2019-09-20 14:20:28 +08:00
committed by Daniel Pan
parent 39e720d375
commit e37f75d5e0
9 changed files with 319 additions and 44 deletions

View File

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

View File

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

View 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')
);

View File

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

View File

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

View File

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

View File

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

View File

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

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