From a43ebeed87db27b79963d7beb4f7f965d959c925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=81=A5=E8=BE=89?= Date: Wed, 5 Jun 2019 15:26:25 +0800 Subject: [PATCH] improve dtable --- frontend/src/pages/dtable/dtable.js | 2 +- seahub/api2/endpoints/dtable.py | 65 ++++++++-------- seahub/dtable/migrations/0001_initial.py | 7 +- seahub/dtable/models.py | 4 +- ...react.html => dtable_file_view_react.html} | 0 seahub/templates/file_view_react.html | 2 +- seahub/utils/__init__.py | 1 - seahub/utils/file_types.py | 1 - tests/api/endpoints/test_dtable.py | 74 +++++++++++-------- 9 files changed, 81 insertions(+), 75 deletions(-) rename seahub/templates/{ctable_file_view_react.html => dtable_file_view_react.html} (100%) diff --git a/frontend/src/pages/dtable/dtable.js b/frontend/src/pages/dtable/dtable.js index 345f622288..123fdc2ab6 100644 --- a/frontend/src/pages/dtable/dtable.js +++ b/frontend/src/pages/dtable/dtable.js @@ -16,7 +16,7 @@ moment.locale(window.app.config.lang); const tablePropTypes = { table: PropTypes.object.isRequired, - workspaceID: PropTypes.string.isRequired, + workspaceID: PropTypes.number.isRequired, renameTable: PropTypes.func.isRequired, deleteTable: PropTypes.func.isRequired, }; diff --git a/seahub/api2/endpoints/dtable.py b/seahub/api2/endpoints/dtable.py index 23f94b63e5..62162782ae 100644 --- a/seahub/api2/endpoints/dtable.py +++ b/seahub/api2/endpoints/dtable.py @@ -22,8 +22,7 @@ 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, render_error, render_permission_error, gen_file_upload_url, \ - get_file_type_and_ext, CTABLE + check_filename_with_rename, render_error, render_permission_error, gen_file_upload_url 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, \ @@ -62,7 +61,7 @@ class WorkspacesView(APIView): table_list = list() for table_obj in table_objs: table = dict() - table["name"] = table_obj.obj_name + table["name"] = table_obj.obj_name[:-7] table["mtime"] = timestamp_to_isoformat_timestr(table_obj.mtime) table["modifier"] = email2nickname(table_obj.modifier) if table_obj.modifier else email2nickname(owner) table_list.append(table) @@ -184,7 +183,7 @@ class WorkspaceView(APIView): table_list = list() for table_obj in table_objs: table = dict() - table["name"] = table_obj.obj_name + table["name"] = table_obj.obj_name[:-7] table["mtime"] = timestamp_to_isoformat_timestr(table_obj.mtime) table["modifier"] = email2nickname(table_obj.modifier) if table_obj.modifier else email2nickname(owner) table_list.append(table) @@ -273,7 +272,8 @@ class DTableView(APIView): 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_name = table_name + '.dtable' + table_path = normalize_file_path(table_file_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 @@ -291,7 +291,7 @@ class DTableView(APIView): 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) + return get_repo_file(request, repo_id, table_file_id, table_file_name, op, use_onetime) def post(self, request, workspace_id): """create a table file @@ -302,7 +302,8 @@ class DTableView(APIView): error_msg = 'name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - if not is_valid_dirent_name(table_name): + table_file_name = table_name + '.dtable' + if not is_valid_dirent_name(table_file_name): error_msg = 'name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) @@ -332,19 +333,19 @@ class DTableView(APIView): return api_error(status.HTTP_403_FORBIDDEN, error_msg) # create new empty table - table_name = check_filename_with_rename(repo_id, '/', table_name) + table_file_name = check_filename_with_rename(repo_id, '/', table_file_name) try: - seafile_api.post_empty_file(repo_id, '/', table_name, owner) + seafile_api.post_empty_file(repo_id, '/', table_file_name, owner) except SearpcError, e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - table_path = normalize_file_path(table_name) + table_path = normalize_file_path(table_file_name) table_obj = seafile_api.get_dirent_by_path(repo_id, table_path) table = dict() - table["name"] = table_obj.obj_name + table["name"] = table_obj.obj_name[:-7] table["mtime"] = timestamp_to_isoformat_timestr(table_obj.mtime) table["modifier"] = email2nickname(table_obj.modifier) if table_obj.modifier else email2nickname(owner) @@ -364,11 +365,12 @@ class DTableView(APIView): error_msg = 'new_name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - if not is_valid_dirent_name(new_table_name): + new_table_file_name = new_table_name + '.dtable' + if not is_valid_dirent_name(new_table_file_name): error_msg = 'new_name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - if len(new_table_name) > MAX_UPLOAD_FILE_NAME_LEN: + if len(new_table_file_name) > MAX_UPLOAD_FILE_NAME_LEN: error_msg = 'new_name is too long.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) @@ -384,7 +386,8 @@ class DTableView(APIView): error_msg = 'Library %s not found.' % repo_id return api_error(status.HTTP_404_NOT_FOUND, error_msg) - old_table_path = normalize_file_path(old_table_name) + old_table_file_name = old_table_name + '.dtable' + old_table_path = normalize_file_path(old_table_file_name) table_file_id = seafile_api.get_file_id_by_path(repo_id, old_table_path) if not table_file_id: error_msg = 'table %s not found.' % old_table_name @@ -404,18 +407,18 @@ class DTableView(APIView): return api_error(status.HTTP_403_FORBIDDEN, error_msg) # rename table - new_table_name = check_filename_with_rename(repo_id, '/', new_table_name) + new_table_file_name = check_filename_with_rename(repo_id, '/', new_table_file_name) try: - seafile_api.rename_file(repo_id, '/', old_table_name, new_table_name, owner) + seafile_api.rename_file(repo_id, '/', old_table_file_name, new_table_file_name, owner) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - new_table_path = normalize_file_path(new_table_name) + new_table_path = normalize_file_path(new_table_file_name) table_obj = seafile_api.get_dirent_by_path(repo_id, new_table_path) table = dict() - table["name"] = table_obj.obj_name + table["name"] = table_obj.obj_name[:-7] table["mtime"] = timestamp_to_isoformat_timestr(table_obj.mtime) table["modifier"] = email2nickname(table_obj.modifier) if table_obj.modifier else email2nickname(owner) @@ -429,6 +432,7 @@ class DTableView(APIView): if not table_name: error_msg = 'name invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + table_file_name = table_name + '.dtable' # resource check workspace = Workspaces.objects.get_workspace_by_id(workspace_id) @@ -442,7 +446,7 @@ class DTableView(APIView): 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_path = normalize_file_path(table_file_name) table_file_id = seafile_api.get_file_id_by_path(repo_id, table_path) if not table_file_id: return Response({'success': True}, status=status.HTTP_200_OK) @@ -462,7 +466,7 @@ class DTableView(APIView): # delete table try: - seafile_api.del_file(repo_id, '/', table_name, owner) + seafile_api.del_file(repo_id, '/', table_file_name, owner) except SearpcError as e: logger.error(e) error_msg = 'Internal Server Error' @@ -527,7 +531,8 @@ def dtable_file_view(request, workspace_id, name): if not repo: raise Http404 - table_path = normalize_file_path(name) + table_file_name = name + '.dtable' + table_path = normalize_file_path(table_file_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')) @@ -538,21 +543,15 @@ def dtable_file_view(request, workspace_id, name): if username != owner: return render_permission_error(request, _(u'Unable to view file')) - filetype, fileext = get_file_type_and_ext(name) - return_dict = { '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, + 'repo': repo, + 'filename': name, + 'path': table_path, + 'filetype': 'dtable', + 'workspace_id': workspace_id, } - if filetype == CTABLE: - return_dict['repo'] = repo - return_dict['workspace_id'] = workspace_id - return_dict['path'] = table_path - return_dict['filename'] = name - return_dict['filetype'] = filetype - return render(request, 'ctable_file_view_react.html', return_dict) - else: - return_dict['err'] = "File preview unsupported" - return render(request, 'unknown_file_view_react.html', return_dict) + return render(request, 'dtable_file_view_react.html', return_dict) diff --git a/seahub/dtable/migrations/0001_initial.py b/seahub/dtable/migrations/0001_initial.py index 2a5124b48e..298275d53e 100644 --- a/seahub/dtable/migrations/0001_initial.py +++ b/seahub/dtable/migrations/0001_initial.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.15 on 2019-05-24 03:56 +# Generated by Django 1.11.15 on 2019-06-05 05:21 from __future__ import unicode_literals from django.db import migrations, models -import seahub.base.fields class Migration(migrations.Migration): @@ -15,10 +14,10 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='WorkSpaces', + name='Workspaces', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', seahub.base.fields.LowerCaseCharField(max_length=255)), + ('name', models.CharField(max_length=255)), ('owner', models.CharField(max_length=255)), ('repo_id', models.CharField(db_index=True, max_length=36)), ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)), diff --git a/seahub/dtable/models.py b/seahub/dtable/models.py index 5809e1e3b3..70499359e8 100644 --- a/seahub/dtable/models.py +++ b/seahub/dtable/models.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models + from seaserv import seafile_api -from seahub.base.fields import LowerCaseCharField from seahub.utils.timeutils import timestamp_to_isoformat_timestr, datetime_to_isoformat_timestr @@ -40,7 +40,7 @@ class WorkspacesManager(models.Manager): class Workspaces(models.Model): - name = LowerCaseCharField(max_length=255) + name = models.CharField(max_length=255) owner = models.CharField(max_length=255) repo_id = models.CharField(max_length=36, db_index=True) created_at = models.DateTimeField(auto_now_add=True, db_index=True) diff --git a/seahub/templates/ctable_file_view_react.html b/seahub/templates/dtable_file_view_react.html similarity index 100% rename from seahub/templates/ctable_file_view_react.html rename to seahub/templates/dtable_file_view_react.html diff --git a/seahub/templates/file_view_react.html b/seahub/templates/file_view_react.html index 219129a200..8ae6216b47 100644 --- a/seahub/templates/file_view_react.html +++ b/seahub/templates/file_view_react.html @@ -41,7 +41,7 @@ window.app.pageOptions = { enableWatermark: {% if enable_watermark %}true{% else %}false{% endif %}, // for {{filetype}} file - {% if filetype == 'ctable' %} + {% if filetype == 'dtable' %} workspaceID: '{{ workspace_id }}', {% endif %} diff --git a/seahub/utils/__init__.py b/seahub/utils/__init__.py index 435e758cf0..67f55e0923 100644 --- a/seahub/utils/__init__.py +++ b/seahub/utils/__init__.py @@ -136,7 +136,6 @@ PREVIEW_FILEEXT = { AUDIO: ('mp3', 'oga', 'ogg'), #'3D': ('stl', 'obj'), XMIND: ('xmind',), - CTABLE: ('ctable',), CDOC: ('cdoc',), } diff --git a/seahub/utils/file_types.py b/seahub/utils/file_types.py index 5078f99682..b46e2deca4 100644 --- a/seahub/utils/file_types.py +++ b/seahub/utils/file_types.py @@ -10,5 +10,4 @@ AUDIO = 'Audio' SPREADSHEET = 'SpreadSheet' DRAW = 'Draw' XMIND = 'XMind' -CTABLE = 'ctable' CDOC = 'cdoc' diff --git a/tests/api/endpoints/test_dtable.py b/tests/api/endpoints/test_dtable.py index e71800a40f..fd20180a72 100644 --- a/tests/api/endpoints/test_dtable.py +++ b/tests/api/endpoints/test_dtable.py @@ -12,7 +12,11 @@ from seahub.test_utils import BaseTestCase class WorkspacesViewTest(BaseTestCase): def setUp(self): - workspace = Workspaces.objects.create_workspace("name1", self.user.username, self.repo.id) + self.workspace = Workspaces.objects.create_workspace( + "workspace1", + self.user.username, + self.repo.id + ) self.url = reverse('api-v2.1-workspaces') self.login_as(self.user) @@ -28,7 +32,7 @@ class WorkspacesViewTest(BaseTestCase): def test_list_with_invalid_repo(self): assert len(Workspaces.objects.all()) == 1 - url = reverse('api2-repo', args=[self.repo.id]) + url = reverse('api2-repo', args=[self.workspace.repo_id]) resp = self.client.delete(url, {}, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) @@ -37,39 +41,44 @@ class WorkspacesViewTest(BaseTestCase): json_resp = json.loads(resp.content) assert json_resp["workspace_list"] == [] + assert len(Workspaces.objects.all()) == 1 def test_can_create(self): assert len(Workspaces.objects.all()) == 1 - resp = self.client.post(self.url, {'name': 'name2'}) + resp = self.client.post(self.url, {'name': 'workspace2'}) self.assertEqual(201, resp.status_code) assert len(Workspaces.objects.all()) == 2 json_resp = json.loads(resp.content) - assert json_resp["workspace"]["name"] == 'name2' + assert json_resp["workspace"]["name"] == 'workspace2' class WorkspaceViewTest(BaseTestCase): def setUp(self): - self.workspace = Workspaces.objects.create_workspace("name1", self.user.username, self.repo.id) + self.workspace = Workspaces.objects.create_workspace( + "workspace3", + self.user.username, + self.repo.id + ) self.url = reverse('api-v2.1-workspace', args=[self.workspace.id]) self.login_as(self.user) def test_can_rename(self): - data = 'name=%s' % 'name2' + data = 'name=%s' % 'workspace4' resp = self.client.put(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["workspace"]["name"] == 'name2' + assert json_resp["workspace"]["name"] == 'workspace4' def test_rename_with_invalid_permission(self): self.logout() self.login_as(self.admin) - data = 'name=%s' % 'name2' + data = 'name=%s' % 'workspace5' resp = self.client.put(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(403, resp.status_code) @@ -78,14 +87,14 @@ class WorkspaceViewTest(BaseTestCase): resp = self.client.delete(url, {}, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) - data = 'name=%s' % 'name2' + data = 'name=%s' % 'workspace6' resp = self.client.put(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(404, resp.status_code) def test_can_delete(self): assert len(Workspaces.objects.all()) == 1 - resp = self.client.delete(self.url, {'name': 'name1'}) + resp = self.client.delete(self.url, {'name': 'workspace3'}) self.assertEqual(200, resp.status_code) assert len(Workspaces.objects.all()) == 0 @@ -94,14 +103,18 @@ class WorkspaceViewTest(BaseTestCase): self.logout() self.login_as(self.admin) - resp = self.client.delete(self.url, {'name': 'name1'}) + resp = self.client.delete(self.url, {'name': 'workspace3'}) self.assertEqual(403, resp.status_code) class DTableTest(BaseTestCase): def setUp(self): - self.workspace = Workspaces.objects.create_workspace("workspace", self.user.username, self.repo.id) + self.workspace = Workspaces.objects.create_workspace( + "workspace", + self.user.username, + self.repo.id + ) self.url = reverse('api-v2.1-workspace-dtable', args=[self.workspace.id]) self.login_as(self.user) @@ -117,36 +130,33 @@ class DTableTest(BaseTestCase): resp = self.client.delete(url, {}, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) - resp = self.client.post(self.url, {'name': 'table1'}) + resp = self.client.post(self.url, {'name': 'table2'}) self.assertEqual(404, resp.status_code) def test_can_rename(self): - resp = self.client.post(self.url, {'name': 'table4'}) + resp = self.client.post(self.url, {'name': 'table3'}) self.assertEqual(201, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["table"]["name"] == 'table4' - - old_name = json_resp["table"]["name"] - new_name = 'table5' + assert json_resp["table"]["name"] == 'table3' resp = self.client.put( self.url, - 'old_name=table4&new_name=table5', + 'old_name=table3&new_name=table4', 'application/x-www-form-urlencoded' ) self.assertEqual(200, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["table"]["name"] == 'table5' + assert json_resp["table"]["name"] == 'table4' def test_rename_with_invalid_workspace(self): - resp = self.client.post(self.url, {'name': 'table6'}) + resp = self.client.post(self.url, {'name': 'table5'}) self.assertEqual(201, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["table"]["name"] == 'table6' + assert json_resp["table"]["name"] == 'table5' url = reverse('api-v2.1-workspace', args=[self.workspace.id]) resp = self.client.delete(url, {'name': 'workspace'}) @@ -155,46 +165,46 @@ class DTableTest(BaseTestCase): resp = self.client.put( self.url, - 'old_name=table6&new_name=table7', + 'old_name=table5&new_name=table6', 'application/x-www-form-urlencoded' ) self.assertEqual(404, resp.status_code) def test_can_delete(self): - resp = self.client.post(self.url, {'name': 'table1'}) + resp = self.client.post(self.url, {'name': 'table7'}) self.assertEqual(201, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["table"]["name"] == 'table1' + assert json_resp["table"]["name"] == 'table7' - data = 'name=%s' % 'table1' + data = 'name=%s' % 'table7' resp = self.client.delete(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(200, resp.status_code) def test_delete_with_invalid_permission(self): - resp = self.client.post(self.url, {'name': 'table2'}) + resp = self.client.post(self.url, {'name': 'table8'}) self.assertEqual(201, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["table"]["name"] == 'table2' + assert json_resp["table"]["name"] == 'table8' self.logout() self.login_as(self.admin) - data = 'name=%s' % 'table2' + data = 'name=%s' % 'table8' resp = self.client.delete(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(403, resp.status_code) def test_delete_with_repo_only_read(self): - resp = self.client.post(self.url, {'name': 'table3'}) + resp = self.client.post(self.url, {'name': 'table9'}) self.assertEqual(201, resp.status_code) json_resp = json.loads(resp.content) - assert json_resp["table"]["name"] == 'table3' + assert json_resp["table"]["name"] == 'table9' seafile_api.set_repo_status(self.workspace.repo_id, 1) - data = 'name=%s' % 'table3' + data = 'name=%s' % 'table9' resp = self.client.delete(self.url, data, 'application/x-www-form-urlencoded') self.assertEqual(403, resp.status_code)