mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-26 07:22:34 +00:00
improve dtable
This commit is contained in:
@@ -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,
|
||||
};
|
||||
|
@@ -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)
|
||||
|
@@ -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)),
|
||||
|
@@ -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)
|
||||
|
@@ -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 %}
|
||||
|
||||
|
@@ -136,7 +136,6 @@ PREVIEW_FILEEXT = {
|
||||
AUDIO: ('mp3', 'oga', 'ogg'),
|
||||
#'3D': ('stl', 'obj'),
|
||||
XMIND: ('xmind',),
|
||||
CTABLE: ('ctable',),
|
||||
CDOC: ('cdoc',),
|
||||
}
|
||||
|
||||
|
@@ -10,5 +10,4 @@ AUDIO = 'Audio'
|
||||
SPREADSHEET = 'SpreadSheet'
|
||||
DRAW = 'Draw'
|
||||
XMIND = 'XMind'
|
||||
CTABLE = 'ctable'
|
||||
CDOC = 'cdoc'
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user