8000 create/delete encrypted extracts for ds and wb · zeninpalm/server-client-python@c395c18 · GitHub
[go: up one dir, main page]

Skip to content

Commit c395c18

Browse files
committed
create/delete encrypted extracts for ds and wb
1 parent 972f10a commit c395c18

File tree

8 files changed

+161
-11
lines changed

8 files changed

+161
-11
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 0.13 (19 Aug 2020)
2+
* Add support for basic Extract operations - Create, Delete, en/re/decrypt for site
3+
14
## 0.12.1 (22 July 2020)
25

36
* Fixed login.py sample to properly handle sitename (#652)

tableauserverclient/server/endpoint/datasources_endpoint.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ def refresh(self, datasource_item):
151151
server_response = self.post_request(url, empty_req)
152152
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
153153
return new_job
154+
155+
@api(version='3.5')
156+
def create_extract(self, datasource_item, encrypt=False):
157+
id_ = getattr(datasource_item, 'id', datasource_item)
158+
url = "{0}/{1}/createExtract?encrypt={2}".format(self.baseurl, id_, encrypt)
159+
empty_req = RequestFactory.Empty.empty_req()
160+
server_response = self.post_request(url, empty_req)
161+
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
162+
return new_job
163+
164+
@api(version='3.5')
165+
def delete_extract(self, datasource_item):
166+
id_ = getattr(datasource_item, 'id', datasource_item)
167+
url = "{0}/{1}/deleteExtract".format(self.baseurl, id_)
168+
empty_req = RequestFactory.Empty.empty_req()
169+
self.post_request(url, empty_req)
170+
154171

155172
# Publish datasource
156173
@api(version="2.0")
@@ -227,14 +244,6 @@ def populate_permissions(self, item):
227244

228245
@api(version='2.0')
229246
def update_permission(self, item, permission_item):
230-
import warnings
231-
warnings.warn('Server.datasources.update_permission is deprecated, '
232-
'please use Server.datasources.update_permissions instead.',
233-
DeprecationWarning)
234-
self._permissions.update(item, permission_item)
235-
236-
@api(version='2.0')
237-
def update_permissions(self, item, permission_item):
238247
self._permissions.update(item, permission_item)
239248

240249
@api(version='2.0')

tableauserverclient/server/endpoint/sites_endpoint.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,33 @@ def create(self, site_item):
103103
new_site = SiteItem.from_response(server_response.content, self.parent_srv.namespace)[0]
104104
logger.info('Created new site (ID: {0})'.format(new_site.id))
105105
return new_site
106+
107+
@api(version="3.5")
108+
def encrypt_extracts(self, site_id):
109+
if not site_id:
110+
error = "Site ID undefined."
111+
raise ValueError(error)
112+
url = "{0}/{1}/encrypt-extracts".format(self.baseurl, site_id)
113+
empty_req = RequestFactory.Empty.empty_req()
114+
self.post_request(url,empty_req)
115+
116+
117+
@api(version="3.5")
118+
def decrypt_extracts(self, site_id):
119+
if not site_id:
120+
error = "Site ID undefined."
121+
raise ValueError(error)
122+
url = "{0}/{1}/decrypt-extracts".format(self.baseurl, site_id)
123+
empty_req = RequestFactory.Empty.empty_req()
124+
self.post_request(url,empty_req)
125+
126+
127+
@api(version="3.5")
128+
def re_encrypt_extracts(self, site_id):
129+
if not site_id:
130+
error = "Site ID undefined."
131+
raise ValueError(error)
132+
url = "{0}/{1}/reencrypt-extracts".format(self.baseurl, site_id)
133+
134+
empty_req = RequestFactory.Empty.empty_req()
135+
self.post_request(url,empty_req)

tableauserverclient/server/endpoint/workbooks_endpoint.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,26 @@ def refresh(self, workbook_id):
6161
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
6262
return new_job
6363

64+
65+
@api(version='3.5')
66+
def create_extract(self, workbook_item, encrypt=False, includeAll=True, datasources=None):
67+
id_ = getattr(workbook_item, 'id', workbook_item)
< F438 /code>68+
url = "{0}/{1}/createExtract?encrypt={2}".format(self.baseurl, id_, encrypt)
69+
70+
datasource_req = RequestFactory.WorkbookR.embedded_extract_req(includeAll, datasources)
71+
72+
server_response = self.post_request(url, datasource_req)
73+
new_job = JobItem.from_response(server_response.content, self.parent_srv.namespace)[0]
74+
return new_job
75+
76+
@api(version='3.5')
77+
def delete_extract(self, workbook_item):
78+
id_ = getattr(workbook_item, 'id', workbook_item)
79+
url = "{0}/{1}/deleteExtract".format(self.baseurl, id_)
80+
empty_req = RequestFactory.Empty.empty_req()
81+
server_response = self.post_request(url, empty_req)
82+
83+
6484
# Delete 1 workbook by id
6585
@api(version="2.0")
6686
def delete(self, workbook_id):

tableauserverclient/server/request_factory.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,17 @@ def publish_req_chunked(
569569
return _add_multipart(parts)
570570

571571

572+
@_tsrequest_wrapped
573+
def embedded_extract_req(self, xml_request, include_all=True, datasources=None):
574+
list_element = ET.SubElement(xml_request, 'datasources')
575+
if include_all:
576+
list_element.attrib['includeAll']="true"
577+
else:
578+
for datasource_item in datasources:
579+
datasource_element = list_element.SubElement(xml_request, 'datasource')
580+
datasource_element.attrib['id'] = datasource_item.id
581+
582+
572583
class Connection(object):
573584
@_tsrequest_wrapped
574585
def update_req(self, xml_request, connection_item):
@@ -623,7 +634,7 @@ def create_req(self, xml_request, webhook_item):
623634
webhook.attrib['name'] = webhook_item.name
624635

625636
source = ET.SubElement(webhook, 'webhook-source')
626-
event = ET.SubElement(source, webhook_item._event)
637+
ET.SubElement(source, webhook_item._event)
627638

628639
destination = ET.SubElement(webhook, 'webhook-destination')
629640
post = ET.SubElement(destination, 'webhook-destination-http')

test/test_datasource.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,3 +381,30 @@ def test_synchronous_publish_timeout_error(self):
381381
self.assertRaisesRegex(InternalServerError, 'Please use asynchronous publishing to avoid timeouts.',
382382
self.server.datasources.publish, new_datasource,
383383
asset('SampleDS.tds'), publish_mode)
384+
385+
def test_delete_extracts(self):
386+
self.server.version = "3.10"
387+
self.baseurl = self.server.datasources.baseurl
388+
with requests_mock.mock() as m:
389+
m.post(self.baseurl + '/3cc6cd06-89ce-4fdc-b935-5294135d6d42/deleteExtract', status_code=200)
390+
self.server.datasources.delete_extract('3cc6cd06-89ce-4fdc-b935-5294135d6d42')
391+
392+
def test_create_extracts(self):
393+
self.server.version = "3.10"
394+
self.baseurl = self.server.datasources.baseurl
395+
396+
response_xml = read_xml_asset(PUBLISH_XML_ASYNC)
397+
with requests_mock.mock() as m:
398+
m.post(self.baseurl + '/3cc6cd06-89ce-4fdc-b935-5294135d6d42/createExtract', status_code=200, text=response_xml)
399+
self.server.datasources.create_extract('3cc6cd06-89ce-4fdc-b935-5294135d6d42')
400+
401+
def test_create_extracts_encrypted(self):
402+
self.server.version = "3.10"
403+
self.baseurl = self.server.datasources.baseurl
404+
405+
response_xml = read_xml_asset(PUBLISH_XML_ASYNC)
406+
with requests_mock.mock() as m:
407+
m.post(self.baseurl + '/3cc6cd06-89ce-4fdc-b935-5294135d6d42/createExtract', status_code=200, text=response_xml)
408+
self.s F987 erver.datasources.create_extract('3cc6cd06-89ce-4fdc-b935-5294135d6d42', True)
409+
410+

test/test_site.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
class SiteTests(unittest.TestCase):
1616
def setUp(self):
1717
self.server = TSC.Server('http://test')
18+
self.server.version = "3.10"
1819

1920
# Fake signin
2021
self.server._auth_token = 'j80k54ll2lfMZ0tv97mlPvvSCRyD0DOM'
@@ -140,3 +141,18 @@ def test_delete(self):
140141

141142
def test_delete_missing_id(self):
142143
self.assertRaises(ValueError, self.server.sites.delete, '')
144+
145+
def test_encrypt(self):
146+
with requests_mock.mock() as m:
147+
m.post(self.baseurl + '/0626857c-1def-4503-a7d8-7907c3ff9d9f/encrypt-extracts', status_code=200)
148+
self.server.sites.encrypt_extracts('0626857c-1def-4503-a7d8-7907c3ff9d9f')
149+
150+
def test_recrypt(self):
151+
with requests_mock.mock() as m:
152+
m.post(self.baseurl + '/0626857c-1def-4503-a7d8-7907c3ff9d9f/reencrypt-extracts', status_code=200)
153+
self.server.sites.re_encrypt_extracts('0626857c-1def-4503-a7d8-7907c3ff9d9f')
154+
155+
def test_decrypt(self):
156+
with requests_mock.mock() as m:
157+
m.post(self.baseurl + '/0626857c-1def-4503-a7d8-7907c3ff9d9f/decrypt-extracts', status_code=200)
158+
self.server.sites.decrypt_extracts('0626857c-1def-4503-a7d8-7907c3ff9d9f')

test/test_workbook.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,8 +470,11 @@ def test_publish_with_hidden_view(self):
470470
hidden_views=['GDP per capita'])
471471

472472
request_body = m._adapter.request_history[0]._request.body
473-
self.assertTrue(re.search(rb'<views><view.*?hidden=\"true\".*?\/><\/views>', request_body))
474-
self.assertTrue(re.search(rb'<views><view.*?name=\"GDP per capita\".*?\/><\/views>', request_body))
473+
# order of attributes in xml is unspecified
474+
self.assertTrue(
475+
(b'<views><view hidden="true" name="GDP per capita" /></views>' in request_body)
476+
or
477+
(b'<views><view name="GDP per capita" hidden="true" /></views>' in request_body))
475478

476479
def test_publish_async(self):
477480
self.server.version = '3.0'
@@ -566,3 +569,34 @@ def test_synchronous_publish_timeout_error(self):
566569

567570
self.assertRaisesRegex(InternalServerError, 'Please use asynchronous publishing to avoid timeouts',
568571
self.server.workbooks.publish, new_workbook, asset('SampleWB.twbx'), publish_mode)
572+
573+
def test_delete_extracts_all(self):
574+
self.server.version = "3.10"
575+
self.baseurl = self.server.workbooks.baseurl
576+
with requests_mock.mock() as m:
577+
m.post(self.baseurl + '/3cc6cd06-89ce-4fdc-b935-5294135d6d42/deleteExtract', status_code=200)
578+
self.server.workbooks.delete_extract('3cc6cd06-89ce-4fdc-b935-5294135d6d42')
579+
580+
def test_create_extracts_all(self):
581+
self.server.version = "3.10"
582+
self.baseurl = self.server.workbooks.baseurl
583+
584+
with open(PUBLISH_ASYNC_XML, 'rb') as f:
585+
response_xml = f.read().decode('utf-8')
586+
with requests_mock.mock() as m:
587+
m.post(self.baseurl + '/3cc6cd06-89ce-4fdc-b935-5294135d6d42/createExtract', status_code=200, text=response_xml)
588+
self.server.workbooks.create_extract('3cc6cd06-89ce-4fdc-b935-5294135d6d42')
589+
590+
591+
def test_create_extracts_one(self):
592+
self.server.version = "3.10"
593+
self.baseurl = self.server.workbooks.baseurl
594+
595+
datasource = TSC.DatasourceItem('test')
596+
datasource._id = '1f951daf-4061-451a-9df1-69a8062664f2'
597+
598+
with open(PUBLISH_ASYNC_XML, 'rb') as f:
599+
response_xml = f.read().decode('utf-8')
600+
with requests_mock.mock() as m:
601+
m.post(self.baseurl + '/3cc6cd06-89ce-4fdc-b935-5294135d6d42/createExtract', status_code=200, text=response_xml)
602+
self.server.workbooks.create_extract('3cc6cd06-89ce-4fdc-b935-5294135d6d42', False, datasource)

0 commit comments

Comments
 (0)
0