Skip to content

Commit 3f1c83e

Browse files
authored
Add delete whatsapp template (#72)
* Added new delete template method * Updated whatsapp tests
1 parent baefad2 commit 3f1c83e

File tree

10 files changed

+264
-3
lines changed

10 files changed

+264
-3
lines changed

infobip_channels/core/channel.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
from infobip_channels.core.http_client import _HttpClient
88
from infobip_channels.core.models import (
99
Authentication,
10+
DeleteHeaders,
1011
GetHeaders,
1112
MessageBodyBase,
1213
PathParameter,
1314
PostHeaders,
15+
PutHeaders,
1416
QueryParameter,
1517
ResponseBase,
1618
)
@@ -105,6 +107,16 @@ def build_post_request_headers(api_key: str) -> Dict:
105107
"""
106108
return PostHeaders(authorization=api_key).dict(by_alias=True)
107109

110+
@staticmethod
111+
def build_put_request_headers(api_key: str) -> Dict:
112+
"""Build the request headers dictionary which has to be used for each of the
113+
put requests.
114+
115+
:param api_key: Key used for populating Authorization header
116+
:return: Dictionary of headers to be used for post requests
117+
"""
118+
return PutHeaders(authorization=api_key).dict(by_alias=True)
119+
108120
@staticmethod
109121
def build_get_request_headers(api_key: str) -> Dict:
110122
"""Build the request headers dictionary which has to be used for each of the
@@ -115,6 +127,16 @@ def build_get_request_headers(api_key: str) -> Dict:
115127
"""
116128
return GetHeaders(authorization=api_key).dict(by_alias=True)
117129

130+
@staticmethod
131+
def build_delete_request_headers(api_key: str) -> Dict:
132+
"""Build the request headers dictionary which has to be used for each of the
133+
delete requests.
134+
135+
:param api_key: Key used for populating Authorization header
136+
:return: Dictionary of headers to be used for get requests
137+
"""
138+
return DeleteHeaders(authorization=api_key).dict(by_alias=True)
139+
118140
@staticmethod
119141
def convert_model_to_dict(
120142
model: BaseModel, by_alias: bool = True, exclude_unset: bool = True, **kwargs

infobip_channels/whatsapp/channel.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
from infobip_channels.whatsapp.models.body.template_message import TemplateMessageBody
2222
from infobip_channels.whatsapp.models.body.text_message import TextMessageBody
2323
from infobip_channels.whatsapp.models.body.video_message import VideoMessageBody
24+
from infobip_channels.whatsapp.models.path_parameters.delete_template import (
25+
DeleteTemplatePathParameters,
26+
)
2427
from infobip_channels.whatsapp.models.path_parameters.manage_templates import (
2528
ManageTemplatesPathParameters,
2629
)
@@ -44,6 +47,7 @@ class WhatsAppChannel(Channel):
4447

4548
SEND_MESSAGE_URL_TEMPLATE = "/whatsapp/1/message/"
4649
MANAGE_URL_TEMPLATE = "/whatsapp/1/senders/"
50+
DELETE_URL_TEMPLATE = "/whatsapp/2/senders/"
4751

4852
def _get_custom_response_class(
4953
self,
@@ -337,3 +341,29 @@ def create_template(
337341
message.dict(by_alias=True),
338342
)
339343
return self._construct_response(response, CreateTemplateResponseOK)
344+
345+
def delete_template(
346+
self, parameter: Union[DeleteTemplatePathParameters, Dict]
347+
) -> Union[ResponseBase, Any]:
348+
"""Delete a WhatsApp template. If registered in multiple languages, deleting
349+
the message template will also delete all its languages. The template will be
350+
deleted for all senders registered under the same WhatsApp Business Account (
351+
WABA). The system will attempt to deliver sent messages for 30 days,
352+
regardless of the template deletion. Once deleted, the name of the approved
353+
template cannot be reused for 30 days.
354+
355+
:param parameter: Registered WhatsApp sender number, must be in international
356+
format. Template name of WhatsApp template.
357+
:return: Received response
358+
"""
359+
path_parameter = self.validate_path_parameter(
360+
parameter, DeleteTemplatePathParameters
361+
)
362+
363+
response = self._client.delete(
364+
self.DELETE_URL_TEMPLATE
365+
+ "".join(
366+
[path_parameter.sender, "/templates/", path_parameter.template_name]
367+
)
368+
)
369+
return response
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from infobip_channels.core.models import PathParameter
2+
3+
4+
class WhatsAppPathParameters(PathParameter):
5+
sender: str
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from infobip_channels.whatsapp.models.path_parameters.core import WhatsAppPathParameters
2+
3+
4+
class DeleteTemplatePathParameters(WhatsAppPathParameters):
5+
template_name: str
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from infobip_channels.core.models import PathParameter
1+
from infobip_channels.whatsapp.models.path_parameters.core import WhatsAppPathParameters
22

33

4-
class ManageTemplatesPathParameters(PathParameter):
5-
sender: str
4+
class ManageTemplatesPathParameters(WhatsAppPathParameters):
5+
pass

tests/conftest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ def get(self, endpoint, headers=None):
3333
headers = headers or self.headers
3434
return requests.get(url=f"{self.url}" + endpoint, headers=headers)
3535

36+
def delete(self, endpoint, headers=None):
37+
headers = headers or self.headers
38+
return requests.delete(url=f"{self.url}" + endpoint, headers=headers)
39+
3640

3741
class Address(CamelCaseModel):
3842
street: str

tests/whatsapp/conftest.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
from infobip_channels.whatsapp.models.body.template_message import TemplateMessageBody
2323
from infobip_channels.whatsapp.models.body.text_message import TextMessageBody
2424
from infobip_channels.whatsapp.models.body.video_message import VideoMessageBody
25+
from infobip_channels.whatsapp.models.path_parameters.delete_template import (
26+
DeleteTemplatePathParameters,
27+
)
2528
from infobip_channels.whatsapp.models.path_parameters.manage_templates import (
2629
ManageTemplatesPathParameters,
2730
)
@@ -187,6 +190,10 @@ class CreateTemplatesPathParametersFactory(ModelFactory):
187190
__model__ = ManageTemplatesPathParameters
188191

189192

193+
class DeleteTemplatePathParametersFactory(ModelFactory):
194+
__model__ = DeleteTemplatePathParameters
195+
196+
190197
@pytest.fixture
191198
def authentication():
192199
return AuthenticationFactory.build()
@@ -211,6 +218,11 @@ def get(self, endpoint):
211218
"GET", url=f"{self.url}" + endpoint, headers=self.headers
212219
)
213220

221+
def delete(self, endpoint):
222+
return self.pool.request(
223+
"DELETE", url=f"{self.url}" + endpoint, headers=self.headers
224+
)
225+
214226

215227
@pytest.fixture
216228
def http_test_client_unofficial():
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
from pytest_cases import parametrize_with_cases
2+
3+
from infobip_channels.core.models import ResponseBase
4+
from infobip_channels.whatsapp.channel import WhatsAppChannel
5+
from infobip_channels.whatsapp.models.path_parameters.delete_template import (
6+
DeleteTemplatePathParameters,
7+
)
8+
from tests.conftest import get_expected_delete_headers, get_response_object
9+
from tests.whatsapp.conftest import (
10+
get_response_object_unofficial,
11+
get_whatsapp_channel_instance,
12+
)
13+
14+
15+
def delete_template_request(
16+
http_server,
17+
response,
18+
instantiation_type,
19+
path_parameters_type,
20+
**kwargs,
21+
):
22+
path_parameter_instance = path_parameter = DeleteTemplatePathParameters(
23+
sender="38598765321", template_name="test"
24+
)
25+
http_server.expect_request(
26+
"/whatsapp/2/senders/38598765321/templates/test",
27+
method="DELETE",
28+
headers=get_expected_delete_headers(),
29+
).respond_with_response(response)
30+
31+
whatsapp_channel = get_whatsapp_channel_instance(instantiation_type, **kwargs)
32+
33+
if path_parameters_type == "dict":
34+
path_parameter = path_parameter_instance.dict()
35+
36+
return whatsapp_channel.delete_template(path_parameter)
37+
38+
39+
@parametrize_with_cases(
40+
"status_code, response_content, path_parameters_type, "
41+
"whatsapp_channel_instantiation_type",
42+
prefix="from_all_instantiation_types_case__valid_content",
43+
)
44+
def test_delete_template_from_all_instantiation_types_case__valid_content(
45+
httpserver,
46+
http_test_client,
47+
status_code,
48+
response_content,
49+
path_parameters_type,
50+
whatsapp_channel_instantiation_type,
51+
):
52+
response = delete_template_request(
53+
http_server=httpserver,
54+
response=get_response_object(status_code, response_content),
55+
instantiation_type=whatsapp_channel_instantiation_type,
56+
path_parameters_type=path_parameters_type,
57+
server_url=httpserver.url_for("/"),
58+
client=http_test_client(
59+
url=httpserver.url_for("/"),
60+
headers=WhatsAppChannel.build_delete_request_headers("secret"),
61+
),
62+
)
63+
64+
assert response is not None
65+
assert response.status_code == status_code
66+
67+
68+
@parametrize_with_cases(
69+
"status_code, response_content, path_parameters_type, "
70+
"whatsapp_channel_instantiation_type",
71+
prefix="from_all_instantiation_types_case__invalid_content",
72+
)
73+
def test_create_template_from_all_instantiation_types_case__invalid_content(
74+
httpserver,
75+
http_test_client,
76+
http_test_client_unofficial,
77+
status_code,
78+
response_content,
79+
path_parameters_type,
80+
whatsapp_channel_instantiation_type,
81+
):
82+
if whatsapp_channel_instantiation_type == "client_unofficial":
83+
client = http_test_client_unofficial
84+
response_object = get_response_object_unofficial
85+
else:
86+
client = http_test_client
87+
response_object = get_response_object
88+
89+
response = delete_template_request(
90+
http_server=httpserver,
91+
response=response_object(status_code, response_content),
92+
instantiation_type=whatsapp_channel_instantiation_type,
93+
path_parameters_type=path_parameters_type,
94+
server_url=httpserver.url_for("/"),
95+
client=client(
96+
url=httpserver.url_for("/"),
97+
headers=WhatsAppChannel.build_delete_request_headers("secret"),
98+
),
99+
)
100+
101+
assert isinstance(response, ResponseBase) is False
102+
assert response is not None
103+
104+
if whatsapp_channel_instantiation_type != "client_unofficial":
105+
assert response.status_code == status_code
106+
assert response.json() == response_content
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from pytest_cases import parametrize
2+
3+
from tests.whatsapp.conftest import get_response_error_content
4+
5+
6+
def get_delete_template_ok_content():
7+
return {}
8+
9+
10+
@parametrize(
11+
path_parameters_type=("path_parameter_instance", "dict"),
12+
whatsapp_channel_instantiation_type=("auth_params", "auth_instance", "client"),
13+
responses=(
14+
[200, get_delete_template_ok_content()],
15+
[202, get_delete_template_ok_content()],
16+
[400, get_response_error_content()],
17+
[401, get_response_error_content()],
18+
[403, get_response_error_content()],
19+
[429, get_response_error_content()],
20+
),
21+
)
22+
def from_all_instantiation_types_case__valid_content(
23+
responses,
24+
path_parameters_type,
25+
whatsapp_channel_instantiation_type,
26+
):
27+
return (
28+
responses[0],
29+
responses[1],
30+
path_parameters_type,
31+
whatsapp_channel_instantiation_type,
32+
)
33+
34+
35+
@parametrize(
36+
path_parameters_type=("path_parameter_instance", "dict"),
37+
whatsapp_channel_instantiation_type=(
38+
"auth_params",
39+
"auth_instance",
40+
"client",
41+
"client_unofficial",
42+
),
43+
responses=(
44+
[201, get_delete_template_ok_content()],
45+
[202, get_delete_template_ok_content()],
46+
[403, get_response_error_content()],
47+
[405, get_response_error_content()],
48+
[500, get_response_error_content()],
49+
),
50+
)
51+
def from_all_instantiation_types_case__invalid_content(
52+
responses,
53+
path_parameters_type,
54+
whatsapp_channel_instantiation_type,
55+
):
56+
return (
57+
responses[0],
58+
responses[1],
59+
path_parameters_type,
60+
whatsapp_channel_instantiation_type,
61+
)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
from pydantic.error_wrappers import ValidationError
3+
4+
from tests.whatsapp.conftest import DeleteTemplatePathParametersFactory
5+
6+
7+
@pytest.mark.parametrize("sender", [None, {}])
8+
def test_when_sender_is_invalid__validation_error_is_raised(sender):
9+
with pytest.raises(ValidationError):
10+
DeleteTemplatePathParametersFactory.build(**{"sender": sender})
11+
12+
13+
@pytest.mark.parametrize("template_name", [None, {}])
14+
def test_when_template_name_is_invalid__validation_error_is_raised(template_name):
15+
with pytest.raises(ValidationError):
16+
DeleteTemplatePathParametersFactory.build(**{"templateName": template_name})

0 commit comments

Comments
 (0)