Skip to content

Commit ebf6822

Browse files
renzonrenzon
authored andcommitted
Added fixed length to user id, it has 10 digits from now on
Fix #1796
1 parent 307cfec commit ebf6822

File tree

2 files changed

+95
-18
lines changed

2 files changed

+95
-18
lines changed

pythonpro/email_marketing/facade.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,20 @@ def create_or_update_member(name: str, email: str, *tags, id='0'):
2929
return _create_or_update(name, email, _MEMBER, *tags, id=id)
3030

3131

32+
def _normalise_id(id):
33+
"""
34+
Need to normalize id because active campaing search for custom fields like a "startswith" metheod. Check:
35+
https://community.activecampaign.com/t/contact-api-v3-search-by-query-params-fields/5658/8?u=python
36+
37+
So we have to add 0 to avoid a not exact match
38+
"""
39+
id = int(id)
40+
return f'{id:010d}'
41+
42+
3243
def _create_or_update(name: str, email: str, role: str, *tags, id='0'):
3344
prospect_list_id = _get_lists()['Prospects']
34-
id = str(id)
45+
id = _normalise_id(id)
3546
tags = list(tags)
3647

3748
data = {
@@ -42,25 +53,26 @@ def _create_or_update(name: str, email: str, role: str, *tags, id='0'):
4253
f'p[{prospect_list_id}]': prospect_list_id,
4354
'status': '1',
4455
}
45-
if id == '0':
56+
if id == _normalise_id('0'):
4657
contact = _client.contacts.create_contact(data)
4758
else:
4859
try:
49-
contacts = _client.contacts.list({'filters[fields][%PYTHONPRO_ID%]': id})
60+
contact_id = _find_active_campaign_contact_id(id)
5061
except ActiveCampaignError:
5162
contact = _client.contacts.create_contact(data)
5263
else:
53-
data['id'] = contacts['0']['id']
64+
data['id'] = contact_id
5465
contact = _client.contacts.edit_contact(data)
5566
if role:
5667
grant_role(email, id, role)
5768
return contact
5869

5970

6071
def _find_active_campaign_contact_id(id):
61-
raise ActiveCampaignError()
62-
id = str(id)
63-
contacts_list = _client.contacts.list({'filters[fields][%PYTHONPRO_ID%]': id})
72+
id = _normalise_id(id)
73+
contacts_list = _client.contacts.list({'filters[fields][%PYTHONPRO_ID%]': id, 'full': 0})
74+
if '1' in contacts_list:
75+
raise ActiveCampaignError('Should return only one field')
6476
return contacts_list['0']['id']
6577

6678

pythonpro/email_marketing/tests/test_user_creation.py

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
from random import randint
2+
13
import pytest
24
import responses
35
from activecampaign.client import Client
46

57
from pythonpro.email_marketing import facade
8+
from pythonpro.email_marketing.facade import _normalise_id
69

710
API_URL = 'https://foo.pythonhosted.com'
811

@@ -54,14 +57,15 @@ def resps_user_not_found(setup_active_settings):
5457
r.GET,
5558
(
5659
'https://foo.pythonhosted.com/admin/api.php?api_action=contact_list&api_key=some+key&api_output='
57-
'json&filters%5Bfields%5D%5B%25PYTHONPRO_ID%25%5D=1'
60+
'json&filters%5Bfields%5D%5B%25PYTHONPRO_ID%25%5D=0000000001&full=0'
5861
),
5962
json=_user_not_found, status=200
6063
)
6164
r.add(
6265
r.POST,
6366
(
64-
'https://foo.pythonhosted.com/admin/api.php?api_action=contact_sync&api_key=some+key&api_output=json'
67+
'https://foo.pythonhosted.com/admin/api.php?api_action=contact_sync&'
68+
'api_key=some+key&api_output=json'
6569
),
6670
json=_user_editon_ok, status=200
6771
)
@@ -72,19 +76,20 @@ def resps_user_not_found(setup_active_settings):
7276
def test_client_creation_user_not_found(resps_user_not_found, grant_role_mock):
7377
facade.create_or_update_client('Renzo Nuccitelli', 'renzo@python.pro.br', 'turma', id=1)
7478
body_payload = (
75-
'email=renzo%40python.pro.br&first_name=Renzo&tags=turma&field%5B%25PYTHONPRO_ID%25%5D=1&p%5B4%5D=4&status=1'
79+
'email=renzo%40python.pro.br&first_name=Renzo&tags=turma&field%5B%25'
80+
'PYTHONPRO_ID%25%5D=0000000001&p%5B4%5D=4&status=1'
7681
)
7782
assert resps_user_not_found.calls[2].request.body == body_payload
7883

7984

8085
def test_lead_creation_user_not_found(resps_user_not_found, grant_role_mock):
8186
facade.create_or_update_lead('Renzo Nuccitelli', 'renzo@python.pro.br', 'turma', id=1)
82-
grant_role_mock.assert_called_once_with('renzo@python.pro.br', '1', 'lead')
87+
grant_role_mock.assert_called_once_with('renzo@python.pro.br', '0000000001', 'lead')
8388

8489

8590
def test_member_creation_user_not_found(resps_user_not_found, grant_role_mock):
8691
facade.create_or_update_member('Renzo Nuccitelli', 'renzo@python.pro.br', 'turma', id=1)
87-
grant_role_mock.assert_called_once_with('renzo@python.pro.br', '1', 'member')
92+
grant_role_mock.assert_called_once_with('renzo@python.pro.br', '0000000001', 'member')
8893

8994

9095
def test_prospect_creation_user_not_found(resps_user_not_found, grant_role_mock):
@@ -104,7 +109,7 @@ def resps_user_found(setup_active_settings):
104109
r.GET,
105110
(
106111
'https://foo.pythonhosted.com/admin/api.php?api_action=contact_list&api_key=some+key&api_output='
107-
'json&filters%5Bfields%5D%5B%25PYTHONPRO_ID%25%5D=1'
112+
'json&filters%5Bfields%5D%5B%25PYTHONPRO_ID%25%5D=0000000001&full=0'
108113
),
109114
json=_user_found_by_id, status=200
110115
)
@@ -122,15 +127,60 @@ def resps_user_found(setup_active_settings):
122127
def test_client_creation_user_found(resps_user_found, grant_role_mock):
123128
facade.create_or_update_client('Renzo Nuccitelli', 'renzo@python.pro.br', 'turma', id=1)
124129
body_payload = (
125-
'email=renzo%40python.pro.br&first_name=Renzo&tags=turma&field%5B%25PYTHONPRO_ID%25%5D=1&p%5B4%5D=4&status=1&'
126-
'id=1'
130+
'email=renzo%40python.pro.br&first_name=Renzo&tags=turma&field%5B%25'
131+
'PYTHONPRO_ID%25%5D=0000000001&p%5B4%5D=4&status=1&id=1'
127132
)
128133
assert resps_user_found.calls[2].request.body == body_payload
129134

130135

136+
@pytest.fixture
137+
def resps_two_users_found(setup_active_settings):
138+
with responses.RequestsMock() as r:
139+
r.add(
140+
r.GET,
141+
'https://foo.pythonhosted.com/admin/api.php?api_action=list_list&api_key=some+key&api_output=json&ids=all',
142+
json=_lists, status=200
143+
)
144+
r.add(
145+
r.GET,
146+
(
147+
'https://foo.pythonhosted.com/admin/api.php?api_action=contact_list&api_key=some+key&api_output='
148+
'json&filters%5Bfields%5D%5B%25PYTHONPRO_ID%25%5D=0000000001&full=0'
149+
),
150+
json=_two_users_found_by_id, status=200
151+
)
152+
r.add(
153+
r.POST,
154+
(
155+
'https://foo.pythonhosted.com/admin/api.php?api_action=contact_sync&'
156+
'api_key=some+key&api_output=json'
157+
),
158+
json=_user_editon_ok, status=200
159+
)
160+
161+
yield r
162+
163+
164+
def test_client_creation_two_users_found(resps_two_users_found, grant_role_mock):
165+
facade.create_or_update_client('Renzo Nuccitelli', 'renzo@python.pro.br', 'turma', id=1)
166+
body_payload = (
167+
'email=renzo%40python.pro.br&first_name=Renzo&tags=turma&field%5B%25'
168+
'PYTHONPRO_ID%25%5D=0000000001&p%5B4%5D=4&status=1'
169+
)
170+
assert resps_two_users_found.calls[2].request.body == body_payload
171+
172+
173+
@pytest.mark.parametrize('transform', [int, str])
174+
def test_normalise_id(transform):
175+
id = randint(1, 1000000000)
176+
normalized_id = _normalise_id(transform(id))
177+
assert len(normalized_id) == 10
178+
assert int(normalized_id) == id
179+
180+
131181
def test_granted_client_role(resps_user_found, grant_role_mock):
132182
facade.create_or_update_client('Renzo Nuccitelli', 'renzo@python.pro.br', 'turma', id=1)
133-
grant_role_mock.assert_called_once_with('renzo@python.pro.br', '1', 'client')
183+
grant_role_mock.assert_called_once_with('renzo@python.pro.br', '0000000001', 'client')
134184

135185

136186
_user_editon_ok = {
@@ -149,11 +199,26 @@ def test_granted_client_role(resps_user_found, grant_role_mock):
149199

150200
_user_found_by_id = {
151201
'0': {
152-
'id': '1', 'subscriberid': '1', 'listid': '4', 'formid': '0', 'seriesid': '0', 'sdate': '2019-12-11 14:54:15',
153-
'udate': '2019-12-11 13:02:10', 'status': '2', 'responder': '1', 'sync': '0',
202+
'id': '1', 'subscriberid': '1', 'cdate': '2019-11-28 10:06:18', 'sdate': '2019-12-11 15:09:13',
203+
'first_name': 'renzo', 'last_name': 'Nuccitelli', 'email': 'renzo@python.pro.br', 'last_list': 'Prospects',
204+
'avatar_url': 'foo'
154205
}, 'result_code': 1, 'result_message': 'Sucesso:algo retornou', 'result_output': 'json'
155206
}
156207

208+
_two_users_found_by_id = {
209+
'0': {
210+
'id': '1', 'subscriberid': '1', 'cdate': '2019-11-28 10:06:18', 'sdate': '2019-12-11 15:09:13',
211+
'first_name': 'renzo', 'last_name': 'Nuccitelli', 'email': 'renzo@python.pro.br', 'last_list': 'Prospects',
212+
'avatar_url': 'foo'
213+
},
214+
'1': {
215+
'id': '2', 'subscriberid': '2', 'cdate': '2019-11-28 10:06:18', 'sdate': '2019-12-11 15:09:13',
216+
'first_name': 'Foo', 'last_name': 'Bar', 'email': 'bar@python.pro.br', 'last_list': 'Prospects',
217+
'avatar_url': 'foo'
218+
},
219+
'result_code': 1, 'result_message': 'Sucesso:algo retornou', 'result_output': 'json'
220+
}
221+
157222
_user_not_found = {
158223
'result_code': 0, 'result_message': 'Falhou: não se obteu qualquer resultado', 'result_output': 'json'
159224
}

0 commit comments

Comments
 (0)