Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/background processing #853

Merged
merged 9 commits into from
Jul 24, 2023
2 changes: 1 addition & 1 deletion parsons/action_builder/action_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def add_section_field_values_to_record(
{
"action_builder:name": tag,
"action_builder:field": field,
"action_builder:section": section
"action_builder:section": section,
}
for field, tag in field_values.items()
]
Expand Down
32 changes: 25 additions & 7 deletions parsons/action_network/action_network.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import json
from parsons import Table
import logging
import re

from parsons import Table
from parsons.utilities import check_env
from parsons.utilities.api_connector import APIConnector
import logging

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -98,6 +99,7 @@ def upsert_person(
postal_addresses=None,
mobile_number=None,
mobile_status="subscribed",
background_processing=False,
**kwargs,
):
"""
Expand Down Expand Up @@ -146,6 +148,11 @@ def upsert_person(
- "unsubscribed"
mobile_status:
'subscribed' or 'unsubscribed'
background_request: bool
If set `true`, utilize ActionNetwork's "background processing". This will return
an immediate success, with an empty JSON body, and send your request to the
background queue for eventual processing.
https://actionnetwork.org/docs/v2/#background-processing
**kwargs:
Any additional fields to store about the person. Action Network allows
any custom field.
Expand Down Expand Up @@ -210,10 +217,13 @@ def upsert_person(
data["person"]["postal_addresses"] = postal_addresses
if tags is not None:
data["add_tags"] = tags

data["person"]["custom_fields"] = {**kwargs}
response = self.api.post_request(
url=f"{self.api_url}/people", data=json.dumps(data)
)
url = f"{self.api_url}/people"
if background_processing:
url = f"{url}?background_processing=true"
response = self.api.post_request(url, data=json.dumps(data))

identifiers = response["identifiers"]
person_id = [
entry_id.split(":")[1]
Expand Down Expand Up @@ -257,14 +267,19 @@ def add_person(
**kwargs,
)

def update_person(self, entry_id, **kwargs):
def update_person(self, entry_id, background_processing=False, **kwargs):
"""
Updates a person's data in Action Network, given their Action Network ID. Note that you
can't alter a person's tags with this method. Instead, use upsert_person.

`Args:`
entry_id:
The person's Action Network id
background_processing: bool
If set `true`, utilize ActionNetwork's "background processing". This will return
an immediate success, with an empty JSON body, and send your request to the
background queue for eventual processing.
https://actionnetwork.org/docs/v2/#background-processing
**kwargs:
Fields to be updated. The possible fields are
email_address:
Expand Down Expand Up @@ -295,8 +310,11 @@ def update_person(self, entry_id, **kwargs):
A dictionary of any other fields to store about the person.
"""
data = {**kwargs}
url = f"{self.api_url}/people/{entry_id}"
if background_processing:
url = f"{url}?background_processing=true"
response = self.api.put_request(
url=f"{self.api_url}/people/{entry_id}",
url=url,
data=json.dumps(data),
success_codes=[204, 201, 200],
)
Expand Down
38 changes: 20 additions & 18 deletions test/test_action_builder/test_action_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def setUp(self, m):

self.fake_field_values = {
"Fake Field 2": "Fake Tag 5",
self.fake_field_1: self.fake_tag_4
self.fake_field_1: self.fake_tag_4,
}

self.fake_tagging = [
Expand All @@ -140,7 +140,7 @@ def setUp(self, m):
"action_builder:name": "Fake Tag 5",
"action_builder:field": "Fake Field 2",
"action_builder:section": self.fake_section,
}
},
]

self.fake_entity_id = "fake-entity-id-1"
Expand All @@ -162,7 +162,7 @@ def setUp(self, m):
"status": "unsubscribed",
"source": "api",
}
]
],
}

self.fake_upsert_person = {
Expand All @@ -179,9 +179,9 @@ def setUp(self, m):
"action_builder:identifier": "action_builder:fake-email-id-1",
"address": "fakey@mcfakerson.com",
"address_type": "Work",
"status": "unsubscribed"
"status": "unsubscribed",
}
]
],
}
}

Expand All @@ -197,7 +197,7 @@ def setUp(self, m):
"created_date": self.fake_datetime,
"modified_date": self.fake_datetime,
}
}
},
}

self.fake_update_person = {
Expand Down Expand Up @@ -234,7 +234,8 @@ def test_get_all_records(self, m):
text=json.dumps({"_embedded": {"osdi:tags": []}}),
)
assert_matching_tables(
self.bldr._get_all_records(self.campaign, "tags"), Table(self.fake_tags_list)
self.bldr._get_all_records(self.campaign, "tags"),
Table(self.fake_tags_list),
)

@requests_mock.Mocker()
Expand Down Expand Up @@ -274,14 +275,15 @@ def prepare_dict_key_intersection(self, dict1, dict2):
# Internal method to compare a reference dict to a new incoming one, keeping only common
# keys whose values are not lists (i.e. nested).

common_keys = {key for key, value in dict1.items() if key in dict2
and not isinstance(value, list)}
common_keys = {
key
for key, value in dict1.items()
if key in dict2 and not isinstance(value, list)
}

dict1_comp = {key: value for key, value in dict1.items()
if key in common_keys}
dict1_comp = {key: value for key, value in dict1.items() if key in common_keys}

dict2_comp = {key: value for key, value in dict2.items()
if key in common_keys}
dict2_comp = {key: value for key, value in dict2.items() if key in common_keys}

return dict1_comp, dict2_comp

Expand All @@ -291,7 +293,9 @@ def test_upsert_entity(self, m):

# Flatten and remove items added for spreadable arguments
upsert_person = self.fake_upsert_person["person"]
upsert_response = self.bldr._upsert_entity(self.fake_upsert_person, self.campaign)
upsert_response = self.bldr._upsert_entity(
self.fake_upsert_person, self.campaign
)

person_comp, upsert_response_comp = self.prepare_dict_key_intersection(
upsert_person, upsert_response
Expand Down Expand Up @@ -348,15 +352,13 @@ def tagging_callback(self, request, context):
tagging_data = post_data["add_tags"]

# Force the sort to allow for predictable comparison
return sorted(tagging_data, key=lambda k: k['action_builder:name'])
return sorted(tagging_data, key=lambda k: k["action_builder:name"])

@requests_mock.Mocker()
def test_add_section_field_values_to_record(self, m):
m.post(f"{self.api_url}/people", json=self.tagging_callback)
add_tags_response = self.bldr.add_section_field_values_to_record(
self.fake_entity_id,
self.fake_section,
self.fake_field_values
self.fake_entity_id, self.fake_section, self.fake_field_values
)
self.assertEqual(add_tags_response, self.fake_tagging)

Expand Down