diff --git a/frontend/src/pages/data-grid/app-main.js b/frontend/src/pages/data-grid/app-main.js index 18c02a54e4..aa2aedd31e 100644 --- a/frontend/src/pages/data-grid/app-main.js +++ b/frontend/src/pages/data-grid/app-main.js @@ -9,7 +9,7 @@ import GridHeaderContextMenu from './grid-header-contextmenu'; import GridContentContextMenu from './grid-content-contextmenu'; import DTableStore from './store/dtable-store'; -const { repoID, filePath } = window.app.pageOptions; +const { workspaceID, fileName } = window.app.pageOptions; const DEFAULT_DATA = { columns: [ @@ -38,7 +38,7 @@ class AppMain extends React.Component { componentDidMount() { - seafileAPI.getFileDownloadLink(repoID, filePath).then(res => { + seafileAPI.getTableDownloadLink(workspaceID, fileName).then(res => { let url = res.data; seafileAPI.getFileContent(url).then(res => { let data = res.data ? res.data : JSON.stringify(DEFAULT_DATA); diff --git a/frontend/src/pages/dtable/dtable.js b/frontend/src/pages/dtable/dtable.js index 0241fe4969..10335d07af 100644 --- a/frontend/src/pages/dtable/dtable.js +++ b/frontend/src/pages/dtable/dtable.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import { Button, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'; import moment from 'moment'; import { seafileAPI } from '../../utils/seafile-api'; -import { Utils } from '../../utils/utils'; import { gettext, siteRoot } from '../../utils/constants'; import Loading from '../../components/loading'; import CreateWorkspaceDialog from '../../components/dialog/create-workspace-dialog'; @@ -17,7 +16,7 @@ moment.locale(window.app.config.lang); const tablePropTypes = { table: PropTypes.object.isRequired, - repoID: PropTypes.string.isRequired, + workspaceID: PropTypes.string.isRequired, renameTable: PropTypes.func.isRequired, deleteTable: PropTypes.func.isRequired, }; @@ -74,7 +73,7 @@ class Table extends Component { render() { let table = this.props.table; - let tableHref = siteRoot + 'lib/' + this.props.repoID + '/file' + Utils.encodePath(Utils.joinPath('/', table.name)); + let tableHref = siteRoot + 'workspace/' + this.props.workspaceID + '/dtable/' + table.name + '/'; return ( @@ -269,7 +268,7 @@ class Workspace extends Component { diff --git a/frontend/src/utils/constants.js b/frontend/src/utils/constants.js index f47dc922a8..709db1e78c 100644 --- a/frontend/src/utils/constants.js +++ b/frontend/src/utils/constants.js @@ -54,6 +54,9 @@ export const canLockUnlockFile = window.app.pageOptions.canLockUnlockFile; export const curNoteMsg = window.app.pageOptions.curNoteMsg; export const curNoteID = window.app.pageOptions.curNoteID; +// ctable +export const workspaceID = window.app.pageOptions.workspaceID; + // wiki export const slug = window.wiki ? window.wiki.config.slug : ''; export const repoID = window.wiki ? window.wiki.config.repoId : ''; diff --git a/seahub/api2/endpoints/dtable.py b/seahub/api2/endpoints/dtable.py index 909c0c66b3..5eeb2607f0 100644 --- a/seahub/api2/endpoints/dtable.py +++ b/seahub/api2/endpoints/dtable.py @@ -7,17 +7,26 @@ from rest_framework.authentication import SessionAuthentication from rest_framework.permissions import IsAuthenticated from rest_framework import status from rest_framework.response import Response +from django.http import HttpResponse, Http404 +from django.shortcuts import render +from django.utils.translation import ugettext as _ from pysearpc import SearpcError -from seaserv import seafile_api, edit_repo +from seaserv import seafile_api, edit_repo, is_repo_owner + from seahub.api2.authentication import TokenAuthentication from seahub.api2.throttling import UserRateThrottle from seahub.api2.utils import api_error +from seahub.api2.views import get_repo_file from seahub.dtable.models import WorkSpaces from seahub.base.templatetags.seahub_tags import email2nickname from seahub.utils.timeutils import timestamp_to_isoformat_timestr -from seahub.utils import is_valid_dirent_name, is_org_context, normalize_file_path, check_filename_with_rename -from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN +from seahub.utils import is_valid_dirent_name, is_org_context, normalize_file_path, \ + check_filename_with_rename, render_error, render_permission_error, CTABLE +from seahub.views.file import send_file_access_msg +from seahub.auth.decorators import login_required +from seahub.settings import MAX_UPLOAD_FILE_NAME_LEN, SHARE_LINK_EXPIRE_DAYS_MIN, \ + SHARE_LINK_EXPIRE_DAYS_MAX, SHARE_LINK_EXPIRE_DAYS_DEFAULT logger = logging.getLogger(__name__) @@ -233,6 +242,52 @@ class DTableView(APIView): permission_classes = (IsAuthenticated, ) throttle_classes = (UserRateThrottle, ) + def get(self, request, workspace_id): + """view table file, get table download link + """ + # argument check + table_name = request.GET.get('name', None) + if not table_name: + error_msg = 'name invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + reuse = request.GET.get('reuse', '0') + if reuse not in ('1', '0'): + error_msg = 'reuse invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + # resource check + workspace = WorkSpaces.objects.get_workspace_by_id(workspace_id) + if not workspace: + error_msg = 'WorkSpace %s not found.' % workspace_id + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + repo_id = workspace.repo_id + repo = seafile_api.get_repo(repo_id) + if not repo: + error_msg = 'Library %s not found.' % repo_id + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + table_path = normalize_file_path(table_name) + table_file_id = seafile_api.get_file_id_by_path(repo_id, table_path) + if not table_file_id: + error_msg = 'Library %s not found.' % repo_id + return api_error(status.HTTP_404_NOT_FOUND, error_msg) + + # permission check + username = request.user.username + owner = workspace.owner + if username != owner: + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + # send stats message + send_file_access_msg(request, repo, table_path, 'api') + + op = request.GET.get('op', 'download') + use_onetime = False if reuse == '1' else True + return get_repo_file(request, repo_id, table_file_id, table_name, op, use_onetime) + def post(self, request, workspace_id): """create a table file """ @@ -409,3 +464,41 @@ class DTableView(APIView): return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response({'success': True}, status=status.HTTP_200_OK) + + +@login_required +def dtable_file_view(request, workspace_id, name): + + # resource check + workspace = WorkSpaces.objects.get_workspace_by_id(workspace_id) + if not workspace: + raise Http404 + + repo_id = workspace.repo_id + repo = seafile_api.get_repo(repo_id) + if not repo: + raise Http404 + + table_path = normalize_file_path(name) + table_file_id = seafile_api.get_file_id_by_path(repo_id, table_path) + if not table_file_id: + return render_error(request, _(u'Table does not exist')) + + # permission check + username = request.user.username + owner = workspace.owner + if username != owner: + return render_permission_error(request, _(u'Unable to view file')) + + return_dict = { + 'repo': repo, + 'workspace_id': workspace_id, + 'path': table_path, + 'filename': name, + 'filetype': CTABLE, + 'share_link_expire_days_default': SHARE_LINK_EXPIRE_DAYS_DEFAULT, + 'share_link_expire_days_min': SHARE_LINK_EXPIRE_DAYS_MIN, + 'share_link_expire_days_max': SHARE_LINK_EXPIRE_DAYS_MAX, + } + + return render(request, 'ctable_file_view_react.html', return_dict) diff --git a/seahub/templates/file_view_react.html b/seahub/templates/file_view_react.html index 2a44ec8281..219129a200 100644 --- a/seahub/templates/file_view_react.html +++ b/seahub/templates/file_view_react.html @@ -41,6 +41,10 @@ window.app.pageOptions = { enableWatermark: {% if enable_watermark %}true{% else %}false{% endif %}, // for {{filetype}} file + {% if filetype == 'ctable' %} + workspaceID: '{{ workspace_id }}', + {% endif %} + {% block extra_data %} {% endblock %} }; diff --git a/seahub/urls.py b/seahub/urls.py index 018cec930a..62a44fa6d4 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -84,7 +84,7 @@ from seahub.api2.endpoints.related_files import RelatedFilesView, RelatedFileVie from seahub.api2.endpoints.webdav_secret import WebdavSecretView from seahub.api2.endpoints.starred_items import StarredItems from seahub.api2.endpoints.markdown_lint import MarkdownLintView -from seahub.api2.endpoints.dtable import WorkSpacesView, WorkSpaceView, DTableView +from seahub.api2.endpoints.dtable import WorkSpacesView, WorkSpaceView, DTableView, dtable_file_view # Admin from seahub.api2.endpoints.admin.revision_tag import AdminTaggedItemsView @@ -348,6 +348,7 @@ urlpatterns = [ url(r'^api/v2.1/workspaces/$', WorkSpacesView.as_view(), name='api-v2.1-workspaces'), url(r'^api/v2.1/workspace/(?P\d+)/$', WorkSpaceView.as_view(), name='api-v2.1-workspace'), url(r'^api/v2.1/workspace/(?P\d+)/dtable/$', DTableView.as_view(), name='api-v2.1-workspace-table'), + url(r'^workspace/(?P\d+)/dtable/(?P.*)/$', dtable_file_view, name='dtable-file-view'), # Deprecated url(r'^api/v2.1/repos/(?P[-0-9a-f]{36})/tags/$', FileTagsView.as_view(), name="api-v2.1-filetags-view"), diff --git a/seahub/views/file.py b/seahub/views/file.py index 2bbfb4ffac..3328da3590 100644 --- a/seahub/views/file.py +++ b/seahub/views/file.py @@ -734,8 +734,6 @@ def view_lib_file(request, repo_id, path): return render(request, template, return_dict) - elif filetype == CTABLE: - return render(request, template, return_dict) elif filetype == CDOC: return render(request, template, return_dict) elif filetype == IMAGE: