Skip to content

Commit b005c16

Browse files
authored
[TOOLSLIBS-442 | TOOLSLIBS-443] Email & SMS Update (#176)
* adds reg payload prop test * adds registration payload prop, update method * docstring * fixes bug where opted_in param was not passed * adds opted_in as property * changes out False for None * refactors register, adds registration_payload property * adds properties for email update and reg * adds email tests * uses proper stringtype for py2 * unicode when * fixes email reg payload and test
1 parent 0bb7e16 commit b005c16

File tree

4 files changed

+287
-36
lines changed

4 files changed

+287
-36
lines changed

tests/devices/test_email.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,64 @@ def setUp(self):
1818
self.timezone = "America/Los_Angeles"
1919
self.channel_id = str(uuid.uuid4())
2020
self.opt_in_mode = "double"
21+
self.email = ua.Email(
22+
airship=self.airship,
23+
address="[email protected]",
24+
commercial_opted_in="2021-01-01T12:00:00",
25+
locale_country="us",
26+
locale_language="en",
27+
timezone="America/Los_Angeles",
28+
transactional_opted_in="2021-02-21T13:00:00",
29+
opt_in_mode="double",
30+
)
31+
32+
def test_email_full_payload_property(self):
33+
self.assertEqual(
34+
self.email._full_payload,
35+
{
36+
"type": "email",
37+
"address": "[email protected]",
38+
"commercial_opted_in": "2021-01-01T12:00:00",
39+
"locale_country": "us",
40+
"locale_language": "en",
41+
"timezone": "America/Los_Angeles",
42+
"transactional_opted_in": "2021-02-21T13:00:00",
43+
"opt_in_mode": "double",
44+
},
45+
)
46+
47+
def test_email_reg_payload_property(self):
48+
self.assertEqual(
49+
self.email._registration_payload,
50+
{
51+
"opt_in_mode": "double",
52+
"channel": {
53+
"type": "email",
54+
"address": "[email protected]",
55+
"commercial_opted_in": "2021-01-01T12:00:00",
56+
"locale_country": "us",
57+
"locale_language": "en",
58+
"timezone": "America/Los_Angeles",
59+
"transactional_opted_in": "2021-02-21T13:00:00",
60+
},
61+
},
62+
)
63+
64+
def test_email_update_payload(self):
65+
self.assertEqual(
66+
self.email._update_payload,
67+
{
68+
"channel": {
69+
"type": "email",
70+
"address": "[email protected]",
71+
"commercial_opted_in": "2021-01-01T12:00:00",
72+
"locale_country": "us",
73+
"locale_language": "en",
74+
"timezone": "America/Los_Angeles",
75+
"transactional_opted_in": "2021-02-21T13:00:00",
76+
}
77+
},
78+
)
2179

2280
def test_email_reg(self):
2381
with mock.patch.object(ua.Airship, "_request") as mock_request:

tests/devices/test_sms.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,29 @@ def test_sms_uninstall(self):
8585

8686
self.assertTrue(r.ok)
8787

88+
def test_sms_registration_payload_property(self):
89+
sms = ua.Sms(
90+
airship=ua.Airship(TEST_KEY, TEST_SECRET),
91+
sender="12345",
92+
msisdn="15035556789",
93+
opted_in="2018-02-13T11:58:59",
94+
locale_country="us",
95+
locale_language="en",
96+
timezone="America/Los_Angeles",
97+
)
98+
99+
self.assertEqual(
100+
sms._registration_payload,
101+
{
102+
"sender": "12345",
103+
"msisdn": "15035556789",
104+
"locale_language": "en",
105+
"locale_country": "us",
106+
"timezone": "America/Los_Angeles",
107+
"opted_in": "2018-02-13T11:58:59",
108+
},
109+
)
110+
88111
def test_sms_lookup(self):
89112
sender = "12345"
90113
msisdn = "15035556789"

urbanairship/devices/email.py

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,57 @@ def transactional_opted_out(self, value):
149149
raise ValueError("Must use ISO 8601 timestamp format")
150150
self._transactional_opted_out = value
151151

152+
@property
153+
def _full_payload(self):
154+
if self.address == None:
155+
raise ValueError(
156+
"address must be set to register or update an email channel"
157+
)
158+
159+
payload = {"type": self._email_type}
160+
161+
reg_payload_keys = [
162+
"address",
163+
"commercial_opted_in",
164+
"commercial_opted_out",
165+
"locale_country",
166+
"locale_language",
167+
"opt_in_mode",
168+
"properties",
169+
"timezone",
170+
"transactional_opted_in",
171+
"transactional_opted_out",
172+
]
173+
174+
for key in reg_payload_keys:
175+
if getattr(self, key) is not None:
176+
payload[key] = getattr(self, key)
177+
178+
return payload
179+
180+
@property
181+
def _registration_payload(self):
182+
full_payload = self._full_payload
183+
opt_in_mode = full_payload.pop("opt_in_mode", None)
184+
properties = full_payload.pop("properties", None)
185+
186+
payload = {"channel": full_payload}
187+
if opt_in_mode:
188+
payload["opt_in_mode"] = opt_in_mode
189+
if properties:
190+
payload["properties"] = properties
191+
192+
return payload
193+
194+
@property
195+
def _update_payload(self):
196+
payload = self._full_payload
197+
198+
payload.pop("opt_in_mode", None)
199+
payload.pop("properties", None)
200+
201+
return {"channel": payload}
202+
152203
@property
153204
def create_and_send_audience(self):
154205
audience = {"ua_address": self.address}
@@ -170,35 +221,13 @@ def register(self):
170221
:return: The response object from the API.
171222
"""
172223
url = self.airship.urls.get("email_url")
173-
reg_payload = {"channel": {"type": self._email_type, "address": self.address}}
174-
175-
if self.commercial_opted_in:
176-
reg_payload["channel"]["commercial_opted_in"] = self.commercial_opted_in
177-
if self.commercial_opted_out:
178-
reg_payload["channel"]["commercial_opted_out"] = self.commercial_opted_out
179-
if self.transactional_opted_in:
180-
reg_payload["channel"][
181-
"transactional_opted_in"
182-
] = self.transactional_opted_in
183-
if self.transactional_opted_out:
184-
reg_payload["channel"][
185-
"transactional_opted_out"
186-
] = self.transactional_opted_out
187-
188-
if self.locale_language is not None:
189-
reg_payload["channel"]["locale_language"] = self.locale_language
190-
if self.locale_country is not None:
191-
reg_payload["channel"]["locale_country"] = self.locale_country
192-
if self.timezone is not None:
193-
reg_payload["channel"]["timezone"] = self.timezone
194-
if self.opt_in_mode is not None:
195-
reg_payload["channel"]["opt_in_mode"] = self.opt_in_mode
196-
if self.properties is not None:
197-
reg_payload["channel"]["properties"] = self.properties
198-
199-
body = json.dumps(reg_payload).encode("utf-8")
200224

201-
response = self.airship.request(method="POST", body=body, url=url, version=3)
225+
response = self.airship.request(
226+
method="POST",
227+
body=json.dumps(self._registration_payload).encode("utf-8"),
228+
url=url,
229+
version=3,
230+
)
202231

203232
if response.status_code == 201:
204233
self.channel_id = response.json().get("channel_id")
@@ -213,6 +242,31 @@ def register(self):
213242

214243
return response
215244

245+
def update(self, channel_id=None):
246+
"""
247+
Updates an existing email channel.
248+
249+
:param channel_id Optional: An existing airship-provided channel_id UUID for an
250+
email channel.
251+
If this object was created with this class, the channel_id value
252+
should be assigned. Otherwise, pass it here. Other values are set as
253+
properties on an instance of this class before the update call.
254+
"""
255+
if channel_id:
256+
self.channel_id = channel_id
257+
258+
if self.channel_id is None:
259+
raise ValueError("Email channel must have a channel_id to update.")
260+
261+
response = self.airship.request(
262+
method="PUT",
263+
body=json.dumps(self._update_payload),
264+
url=self.airship.urls.get("email_url") + self.channel_id,
265+
version=3,
266+
)
267+
268+
return response
269+
216270
def uninstall(self):
217271
"""Removes an email address from Urban Airship. Use with caution.
218272
If the uninstalled email address opts-in again, it will generate

0 commit comments

Comments
 (0)