8000 [Subscriptions] Add new fields and ability to update (#794) · TableauJoe/server-client-python@88a0188 · GitHub
[go: up one dir, main page]

Skip to content

Commit 88a0188

Browse files
author
Chris Shin
authored
[Subscriptions] Add new fields and ability to update (tableau#794)
* Add fields and parsing logic * Update subscription create request * Adds update request to subscriptions * Changes subscription change request creation to use tsrequest annotation * Update tests for parsing new fields * Fixes codestyle issues * Removes user and schedule name * Fixes test failure
1 parent 026bca8 commit 88a0188

File tree

5 files changed

+172
-19
lines changed

5 files changed

+172
-19
lines changed
Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import xml.etree.ElementTree as ET
22
from .target import Target
3+
from .property_decorators import property_is_boolean
34

45

56
class SubscriptionItem(object):
67

78
def __init__(self, subject, schedule_id, user_id, target):
8-
self.id = None
9-
self.subject = subject
9+
self._id = None
10+
self.attach_image = True
11+
self.attach_pdf = False
12+
self.message = None
13+
self.page_orientation = None
14+
self.page_size_option = None
1015
self.schedule_id = schedule_id
11-
self.user_id = user_id
16+
self.send_if_view_empty = True
17+
self.subject = subject
18+
self.suspended = False
1219
self.target = target
20+
self.user_id = user_id
1321

1422
def __repr__(self):
1523
if self.id is not None:
@@ -19,8 +27,45 @@ def __repr__(self):
1927
return "<Subscription subject({subject}) schedule_id({schedule_id}) user_id({user_id}) \
2028
target({target})".format(**self.__dict__)
2129

22-
def _set_id(self, id_):
23-
self.id = id_
30+
@property
31+
def id(self):
32+
return self._id
33+
34+
@property
35+
def attach_image(self):
36+
return self._attach_image
37+
38+
@attach_image.setter
39+
@property_is_boolean
40+
def attach_image(self, value):
41+
self._attach_image = value
42+
43+
@property
44+
def attach_pdf(self):
45+
return self._attach_pdf
46+
47+
@attach_pdf.setter
48+
@property_is_boolean
49+
def attach_pdf(self, value):
50+
self._attach_pdf = value
51+
52+
@property
53+
def send_if_view_empty(self):
54+
return self._send_if_view_empty
55+
56+
@send_if_view_empty.setter
57+
@property_is_boolean
58+ def send_if_view_empty(self, value):
59+
self._send_if_view_empty = value
60+
61+
@property
62+
def suspended(self):
63+
return self._suspended
64+
65+
@suspended.setter
66+
@property_is_boolean
67+
def suspended(self, value):
68+
self._suspended = value
2469

2570
@classmethod
2671
def from_response(cls, xml, ns):
@@ -33,24 +78,51 @@ def from_response(cls, xml, ns):
3378

3479
@classmethod
3580
def _parse_element(cls, element, ns):
36-
schedule_id = None
37-
target = None
38-
3981
schedule_element = element.find('.//t:schedule', namespaces=ns)
4082
content_element = element.find('.//t:content', namespaces=ns)
4183
user_element = element.find('.//t:user', namespaces=ns)
4284

85+
# Schedule element
86+
schedule_id = None
4387
if schedule_element is not None:
4488
schedule_id = schedule_element.get('id', None)
4589

90+
# Content element
91+
target = None
92+
send_if_view_empty = None
4693
if content_element is not None:
4794
target = Target(content_element.get('id', None), content_element.get('type'))
95+
send_if_view_empty = string_to_bool(content_element.get('sendIfViewEmpty', ''))
4896

97+
# User element
98+
user_id = None
4999
if user_element is not None:
50-
user_id = user_element.get('id')
100+
user_id = user_element.get('id', None)
51101

102+
# Main attributes
52103
id_ = element.get('id', None)
53104
subject = element.get('subject', None)
105+
attach_image = string_to_bool(element.get('attachImage', ''))
106+
attach_pdf = string_to_bool(element.get('attachPdf', ''))
107+
message = element.get('message', None)
108+
page_orientation = element.get('pageOrientation', None)
109+
page_size_option = element.get('pageSizeOption', None)
110+
suspended = string_to_bool(element.get('suspended', ''))
111+
112+
# Create SubscriptionItem and set fields
54113
sub = cls(subject, schedule_id, user_id, target)
55-
sub._set_id(id_)
114+
sub._id = id_
115+
sub.attach_image = attach_image
116+
sub.attach_pdf = attach_pdf
117+
sub.message = message
118+
sub.page_orientation = page_orientation
119+
sub.page_size_option = page_size_option
120+
sub.send_if_view_empty = send_if_view_empty
121+
sub.suspended = suspended
122+
56123
return sub
124+
125+
126+
# Used to convert string represented boolean to a boolean type
127+
def string_to_bool(s):
128+
return s.lower() == 'true'

tableauserverclient/server/endpoint/subscriptions_endpoint.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .endpoint import Endpoint, api
2+
from .exceptions import MissingRequiredFieldError
23
from .. import RequestFactory, SubscriptionItem, PaginationItem
34

45
import logging
@@ -51,3 +52,14 @@ def delete(self, subscription_id):
5152
url = "{0}/{1}".format(self.baseurl, subscription_id)
5253
self.delete_request(url)
5354
logger.info('Deleted subscription (ID: {0})'.format(subscription_id))
55+
56+
@api(version='2.3')
57+
def update(self, subscription_item):
58+
if not subscription_item.id:
59+
error = "Subscription item missing ID. Subscription must be retrieved from server first."
60+
raise MissingRequiredFieldError(error)
61+
url = "{0}/{1}".format(self.baseurl, subscription_item.id)
62+
update_req = RequestFactory.Subscription.update_req(subscription_item)
63+
server_response = self.put_request(url, update_req)
64+
logger.info('Updated subscription item (ID: {0})'.format(subscription_item.id))
65+
return SubscriptionItem.from_response(server_response.content, self.parent_srv.namespace)[0]

tableauserverclient/server/request_factory.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -827,22 +827,68 @@ def run_req(self, xml_request, task_item):
827827

828828

829829
class SubscriptionRequest(object):
830-
def create_req(self, subscription_item):
831-
xml_request = ET.Element('tsRequest')
830+
@_tsrequest_wrapped
831+
def create_req(self, xml_request, subscription_item):
832832
subscription_element = ET.SubElement(xml_request, 'subscription')
833-
subscription_element.attrib['subject'] = subscription_item.subject
834833

834+
# Main attributes
835+
subscription_element.attrib['subject'] = subscription_item.subject
836+
if subscription_item.attach_image is not None:
837+
subscription_element.attrib['attachImage'] = str(subscription_item.attach_image).lower()
838+
if subscription_item.attach_pdf is not None:
839+
subscription_element.attrib['attachPdf'] = str(subscription_item.attach_pdf).lower()
840+
if subscription_item.message is not None:
841+
subscription_element.attrib['message'] = subscription_item.message
842+
if subscription_item.page_orientation is not None:
843+
subscription_element.attrib['pageOrientation'] = subscription_item.page_orientation
844+
if subscription_item.page_size_option is not None:
845+
subscription_element.attrib['pageSizeOption'] = subscription_item.page_size_option
846+
847+
# Content element
835848
content_element = ET.SubElement(subscription_element, 'content')
836849
content_element.attrib['id'] = subscription_item.target.id
837850
content_element.attrib['type'] = subscription_item.target.type
851+
if subscription_item.send_if_view_empty is not None:
852+
content_element.attrib['sendIfViewEmpty'] = str(subscription_item.send_if_view_empty).lower()
838853

854+
# Schedule element
839855
schedule_element = ET.SubElement(subscription_element, 'schedule')
840856
schedule_element.attrib['id'] = subscription_item.schedule_id
841857

858+
# User element
842859
user_element = ET.SubElement(subscription_element, 'user')
843860
user_element.attrib['id'] = subscription_item.user_id
844861
return ET.tostring(xml_request)
845862

863+
@_tsrequest_wrapped
864+
def update_req(self, xml_request, subscription_item):
865+
subscription = ET.SubElement(xml_request, 'subscription')
866+
867+
# Main attributes
868+
if subscription_item.subject is not None:
869+
subscription.attrib['subject'] = subscription_item.subject
870+
if subscription_item.attach_image is not None:
871+
subscription.attrib['attachImage'] = str(subscription_item.attach_image).lower()
872+
if subscription_item.attach_pdf is not None:
873+
subscription.attrib['attachPdf'] = str(subscription_item.attach_pdf).lower()
874+
if subscription_item.page_orientation is not None:
875+
subscription.attrib['pageOrientation'] = subscription_item.page_orientation
876+
if subscription_item.page_size_option is not None:
877+
subscription.attrib['pageSizeOption'] = subscription_item.page_size_option
878+
if subscription_item.suspended is not None:
879+
subscription.attrib['suspended'] = str(subscription_item.suspended).lower()
880+
881+
# Schedule element
882+
schedule = ET.SubElement(subscription, 'schedule')
883+
if subscription_item.schedule_id is not None:
884+
schedule.attrib['id'] = subscription_item.schedule_id
885+
886+
# Content element
887+
content = ET.SubElement(subscription, 'content')
888+
if subscription_item.send_if_view_empty is not None:
889+
content.attrib['sendIfViewEmpty'] = str(subscription_item.send_if_view_empty).lower()
890+
return ET.tostring(xml_request)
891+
846892

847893
class EmptyRequest(object):
848894
@_tsrequest_wrapped

test/assets/subscription_get.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tableau.com/api http://tableau.com/api/ts-api-2.6.xsd">
55
<pagination pageNumber="1" pageSize="100" totalAvailable="2" />
66
<subscriptions>
7-
<subscription id="382e9a6e-0c08-4a95-b6c1-c14df7bac3e4" subject="Not Found Alert">
8-
<content id="cdd716ca-5818-470e-8bec-086885dbadee" type="View" />
7+
<subscription id="382e9a6e-0c08-4a95-b6c1-c14df7bac3e4" subject="Not Found Alert" message="NOT FOUND!" attachImage="true" attachPdf="false" suspended="false">
8+
<content id="cdd716ca-5818-470e-8bec-086885dbadee" type="View" sendIfViewEmpty="false" />
99
<schedule id="7617c389-cdca-4940-a66e-69956fcebf3e" name="Subscribe daily [00:00 - 04:00, Pacific US] [migrated at 1490824351877]" />
1010
<user id="c0d5fc44-ad8c-4957-bec0-b70ed0f8df1e" name="jonsnow@winterfell.com" />
1111
</subscription>
12-
<subscription id="23cb7630-afc8-4c8e-b6cd-83ae0322ec66" subject="Last 7 Days">
13-
<content id="2e6b4e8f-22dd-4061-8f75-bf33703da7e5" type="View" />
12+
<subscription id="23cb7630-afc8-4c8e-b6cd-83ae0322ec66" subject="Last 7 Days" message="overview" attachImage="false" attachPdf="true" suspended="true" pageOrientation="PORTRAIT" pageSizeOption="A5">
13+
<content id="2e6b4e8f-22dd-4061-8f75-bf33703da7e5" type="Workbook" sendIfViewEmpty="true"/>
1414
<schedule id="3407cd38-7b39-4983-86a6-67a1506a5e3f" name="SSS_27212a85-6b28-41f6-8c69-29b02043d7a5" />
1515
<user id="c0d5fc44-ad8c-4957-bec0-b70ed0f8df1e" name="jonsnow@winterfell.com" />
1616
</subscription>

test/test_subscription.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,37 @@ def test_get_subscriptions(self):
2828
m.get(self.baseurl, text=response_xml)
2929
all_subscriptions, pagination_item = self.server.subscriptions.get()
3030

31+
self.assertEqual(2, pagination_item.total_available)
3132
subscription = all_subscriptions[0]
3233
self.assertEqual('382e9a6e-0c08-4a95-b6c1-c14df7bac3e4', subscription.id)
33-
self.assertEqual('View', subscription.target.type)
34+
self.assertEqual('NOT FOUND!', subscription.message)
35+
self.assertTrue(subscription.attach_image)
36+
self.assertFalse(subscription.attach_pdf)
37+
self.assertFalse(subscription.suspended)
38+
self.assertFalse(subscription.send_if_view_empty)
39+
self.assertIsNone(subscription.page_orientation)
40+
self.assertIsNone(subscription.page_size_option)
41+
self.assertEqual('Not Found Alert', subscription.subject)
3442
self.assertEqual('cdd716ca-5818-470e-8bec-086885dbadee', subscription.target.id)
43+
self.assertEqual('View', subscription.target.type)
3544
self.assertEqual('c0d5fc44-ad8c-4957-bec0-b70ed0f8df1e', subscription.user_id)
36-
self.assertEqual('Not Found Alert', subscription.subject)
3745
self.assertEqual('7617c389-cdca-4940-a66e-69956fcebf3e', subscription.schedule_id)
3846

47+
subscription = all_subscriptions[1]
48+
self.assertEqual('23cb7630-afc8-4c8e-b6cd-83ae0322ec66', subscription.id)
49+
self.assertEqual('overview', subscription.message)
50+
self.assertFalse(subscription.attach_image)
51+
self.assertTrue(subscription.attach_pdf)
52+
self.assertTrue(subscription.suspended)
53+
self.assertTrue(subscription.send_if_view_empty)
54+
self.assertEqual('PORTRAIT', subscription.page_orientation)
55+
self.assertEqual('A5', subscription.page_size_option)
56+
self.assertEqual('Last 7 Days', subscription.subject)
57+
self.assertEqual('2e6b4e8f-22dd-4061-8f75-bf33703da7e5', subscription.target.id)
58+
self.assertEqual('Workbook', subscription.target.type)
59+
self.assertEqual('c0d5fc44-ad8c-4957-bec0-b70ed0f8df1e', subscription.user_id)
60+
self.assertEqual('3407cd38-7b39-4983-86a6-67a1506a5e3f', subscription.schedule_id)
61+
3962
def test_get_subscription_by_id(self):
4063
with open(GET_XML_BY_ID, "rb") as f:
4164
response_xml = f.read().decode("utf-8")

0 commit comments

Comments
 (0)
0