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

Add ActionKit methods to add a phone number, create and update event fields, and search events in a campaign #1076

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions parsons/action_kit/action_kit.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,28 @@ def create_user(self, email, **kwargs):
**kwargs,
)

def add_phone(self, user_id, phone_type, phone):
"""
Add a phone number to a user.

`Args:`
user_id: string
The id of the user.
phone_type: string
The type of the phone (e.g., "Home").
phone: string
The phone number.
`Returns:`
Phone json object
"""
return self._base_post(
endpoint="phone",
exception_message="Could not create phone",
user=f"/rest/v1/user/{user_id}/",
phone_type=phone_type,
phone=phone,
)

def delete_actionfield(self, actionfield_id):
"""
Delete an actionfield.
Expand Down Expand Up @@ -232,6 +254,54 @@ def update_event(self, event_id, **kwargs):
resp = self.conn.patch(self._base_endpoint("event", event_id), data=json.dumps(kwargs))
logger.info(f"{resp.status_code}: {event_id}")

def create_event_field(self, event_id, name, value):
"""
Create an event field (custom field on an event). Note that if an event
field with this name already exists, this will add a second record.

`Args:`
event_id: int
The id for the event.
name: string
The name of the event field.
value: string
The value of the event field.
`Returns:`
Event field json object
"""
return self._base_post(
endpoint="eventfield",
exception_message="Could not create event field",
event=f"/rest/v1/event/{event_id}/",
name=name,
value=value,
)

def update_event_field(self, eventfield_id, name, value):
"""
Update an event field.

`Args:`
eventfield_id: int
The id of the event field to update.
name: string
The name of the event field.
value: string
The value of the event field.
`Returns:`
``None``
"""
resp = self.conn.patch(
self._base_endpoint("eventfield", eventfield_id),
data=json.dumps(
{
"name": name,
"value": value,
}
),
)
logger.info(f"{resp.status_code}: {eventfield_id}")

def get_blackholed_email(self, email):
"""
Get a blackholed email. A blackholed email is an email that has been prevented from
Expand Down Expand Up @@ -354,6 +424,73 @@ def create_campaign(self, name, **kwargs):
**kwargs,
)

def search_events_in_campaign(
self,
campaign_id,
limit=None,
order_by="id",
ascdesc="asc",
filters=None,
exclude=None,
**kwargs,
):
"""
Get events in a campaign, with optional search filters.

`Args:`
campaign_id: int
The id of the event campaign.
limit: int
The maximum number of objects to return.
order_by: string
Event attribute to order the results by. Defaults to id, which will normally
be equivalent to ordering by created_at. See `ActionKit's docs on ordering
<https://roboticdogs.actionkit.com/docs//manual/api/rest/overview.html#ordering>`_.
ascdesc: string
If "asc" (the default), returns events ordered by the attribute specified by
the order_by parameter. If "desc", returns events in reverse order.
filters: dictionary
A dictionary for filtering by the attributes of the event or related object.
Not all attributes are available for filtering, but an eventfield will work.
For additional info, visit `Django's docs on field lookups
<https://docs.djangoproject.com/en/3.1/topics/db/queries/#field-lookups>`_ and
`ActionKit's docs on the search API
<https://roboticdogs.actionkit.com/docs/manual/api/rest/examples/eventsearch.html>`_.

.. code-block:: python

{
"title": "Example Event Title",
"field__name": "example_event_field_name",
"field__value": "Example event field value",
}
exclude: dictionary
A dictionary for excluding by the attributes of the event or related object.
Uses the same format as the filters argument.
**kwargs:
A dictionary of other options for filtering. See `ActionKit's docs on the
search API
<https://roboticdogs.actionkit.com/docs/manual/api/rest/examples/eventsearch.html>`_.
`Returns:`
Parsons.Table
The list of events.
"""
if filters:
for field, value in filters.items():
kwargs[f"filter[{field}]"] = value
if exclude:
for field, value in exclude.items():
kwargs[f"exclude[{field}]"] = value
if ascdesc == "asc":
kwargs["order_by"] = order_by
else:
kwargs["order_by"] = f"-{order_by}"
return self.paginated_get(
f"campaign/{campaign_id}/event_search",
limit=limit,
**kwargs,
)

def get_event_create_page(self, event_create_page_id):
"""
Get a event create page.
Expand Down
86 changes: 86 additions & 0 deletions test/test_action_kit.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,26 @@ def test_create_user(self):
data=json.dumps({"email": "test"}),
)

def test_add_phone(self):
# Test add phone

# Mock resp and status code
resp_mock = mock.MagicMock()
type(resp_mock.post()).status_code = mock.PropertyMock(return_value=201)
self.actionkit.conn = resp_mock

self.actionkit.add_phone(user_id=123, phone_type="home", phone="+12025550101")
self.actionkit.conn.post.assert_called_with(
"https://domain.actionkit.com/rest/v1/phone/",
data=json.dumps(
{
"user": "/rest/v1/user/123/",
"phone_type": "home",
"phone": "+12025550101",
}
),
)

def test_update_user(self):
# Test update user

Expand Down Expand Up @@ -110,6 +130,39 @@ def test_update_event(self):
data=json.dumps({"is_approved": "test"}),
)

def test_create_event_field(self):
# Test create event field

# Mock resp and status code
resp_mock = mock.MagicMock()
type(resp_mock.post()).status_code = mock.PropertyMock(return_value=201)
self.actionkit.conn = resp_mock

self.actionkit.create_event_field(event_id=123, name="name", value="value")
self.actionkit.conn.post.assert_called_with(
"https://domain.actionkit.com/rest/v1/eventfield/",
data=json.dumps(
{
"event": "/rest/v1/event/123/",
"name": "name",
"value": "value",
}
),
)

def test_update_event_field(self):
# Test update event field

# Mock resp and status code
resp_mock = mock.MagicMock()
type(resp_mock.patch()).status_code = mock.PropertyMock(return_value=202)
self.actionkit.conn = resp_mock
self.actionkit.update_event_field(456, name="name", value="value")
self.actionkit.conn.patch.assert_called_with(
"https://domain.actionkit.com/rest/v1/eventfield/456/",
data=json.dumps({"name": "name", "value": "value"}),
)

def test_get_blackholed_email(self):
# Test get blackholed email
resp_mock = mock.MagicMock()
Expand Down Expand Up @@ -185,6 +238,39 @@ def test_create_campaign(self):
data=json.dumps({"name": "new_campaign", "field": "field"}),
)

def test_search_events_in_campaign(self):
# Test search events in campaign
resp_mock = mock.MagicMock()
type(resp_mock.get()).status_code = mock.PropertyMock(return_value=201)
type(resp_mock.get()).json = lambda x: {"meta": {"next": ""}, "objects": []}
self.actionkit.conn = resp_mock

self.actionkit.search_events_in_campaign(
123,
limit=100,
order_by="created_at",
ascdesc="desc",
filters={
"title": "Event Title",
"field__name": "event_field_name",
"field__value": "Event field value",
},
exclude={
"creator__email": "host@example.com",
},
)
self.actionkit.conn.get.assert_called_with(
"https://domain.actionkit.com/rest/v1/campaign/123/event_search/",
params={
"filter[title]": "Event Title",
"filter[field__name]": "event_field_name",
"filter[field__value]": "Event field value",
"exclude[creator__email]": "host@example.com",
"order_by": "-created_at",
"_limit": 100,
},
)

def test_get_event(self):
# Test get event
self.actionkit.get_event(1)
Expand Down
Loading