From b01ecdd0e37303593d0d49da6202d3a866ae6393 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Tue, 11 Oct 2022 13:44:48 -0400 Subject: [PATCH 01/35] Initializing Strive class with Shauna --- parsons/__init__.py | 1 + parsons/strive/__init__.py | 0 parsons/strive/strive.py | 47 ++++++++++++++++++++++++++++ test/test_strive/strive_test_data.py | 35 +++++++++++++++++++++ test/test_strive/test_strive.py | 24 ++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 parsons/strive/__init__.py create mode 100644 parsons/strive/strive.py create mode 100644 test/test_strive/strive_test_data.py create mode 100644 test/test_strive/test_strive.py diff --git a/parsons/__init__.py b/parsons/__init__.py index ce609595af..381f517702 100644 --- a/parsons/__init__.py +++ b/parsons/__init__.py @@ -76,6 +76,7 @@ ("parsons.sftp.sftp", "SFTP"), ("parsons.shopify.shopify", "Shopify"), ("parsons.sisense.sisense", "Sisense"), + ("parsons.strive.strive", "Strive"), ("parsons.targetsmart.targetsmart_api", "TargetSmartAPI"), ("parsons.targetsmart.targetsmart_automation", "TargetSmartAutomation"), ("parsons.turbovote.turbovote", "TurboVote"), diff --git a/parsons/strive/__init__.py b/parsons/strive/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py new file mode 100644 index 0000000000..7fcdd61195 --- /dev/null +++ b/parsons/strive/strive.py @@ -0,0 +1,47 @@ +import logging +import os +from parsons.utilities import check_env +from parsons.utilities.api_connector import APIConnector +from parsons import Table + +logger = logging.getLogger(__name__) + + +class Strive(object): + """ + Instantiate Strive class. + + `Args:` + """ + + def __init__(self, api_key=None): + self.api_key = check_env.check("STRIVE_KEY", api_key) + self.uri = "https://api.strivedigital.org" + self.headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {self.api_key}", + } + self.client = APIConnector(self.uri, headers=self.headers) + + def get_members(self, params: dict): + response = self.client.get_request(url="members", params=params) + return Table(response) + + +# Instrantiate Strive class +s = Strive() + +# Headers +data = {"limit": "5"} +# Testing get members +response = s.get_members(params=data) +# Convert data into Parsons Table + +print(response.num_rows) + +# Put results into Parsons table + +## To Do +# Create Other Get Methods +# Specifying other paramters instead of taking them as a dictionary +# Tackle POST methods \ No newline at end of file diff --git a/test/test_strive/strive_test_data.py b/test/test_strive/strive_test_data.py new file mode 100644 index 0000000000..a9404057f3 --- /dev/null +++ b/test/test_strive/strive_test_data.py @@ -0,0 +1,35 @@ +get_members_expected_output = { + "id": 252025504, + "campaign_id": 558, + "phone_number": "+16072629160", + "first_name": "Katie", + "last_name": "A Sprague", + "city": None, + "state": "NY", + "postal_code": "14521", + "email": "ksprague365@gmail.com", + "notes": None, + "additional_notes": None, + "opt_in": True, + "custom": {}, + "created_at": "2022-09-16T13:48:41.314+00:00", + "updated_at": "2022-10-08T17:00:48.395+00:00", + "groups": [ + {"id": 251726, "name": "wfp"}, + { + "id": 548978, + "name": "20220921 Election Defenders (Frontline opt-ins + actives)", + }, + { + "id": 548979, + "name": "20220921 Election Defenders (Frontline opt-ins and actives)", + }, + {"id": 555505, "name": "20220929 EOQ test final group"}, + {"id": 556849, "name": "20220930 EOQ 2 group"}, + {"id": 563286, "name": "20221006 Digital Defenders base audience"}, + {"id": 563287, "name": "20221006 Digital Defenders final audience"}, + {"id": 563344, "name": "20221007 NY full state"}, + {"id": 565163, "name": "20221008 One month out fundraiser - V1 (long)"}, + ], + "carrier": "Verizon", +} \ No newline at end of file diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py new file mode 100644 index 0000000000..2b11d46089 --- /dev/null +++ b/test/test_strive/test_strive.py @@ -0,0 +1,24 @@ +from parsons import Strive +import pytest +import unittest +import strive_test_data + + +class TestStrive(unittest.TestCase): + def setUp(self): + self.strive = Strive() + + def test_get_member(self): + # Headers + data = {"limit": "5"} + # Testing get members + response = self.strive.get_members(params=data) + # Convert data into Parsons Table + data = {"limit": "5"} + + assert self.strive.get_members(data).num_rows == 5 + assert ( + self.strive.get_members(data)[0] + == strive_test_data.get_members_expected_output + ) + From 4bde1b8e9eeb167ad074a5ab1fa061f9bcf2a7f3 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Wed, 25 Jan 2023 15:43:57 -0500 Subject: [PATCH 02/35] Cleaned up test for get member --- test/test_strive/test_strive.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index 2b11d46089..9ce75f1293 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -2,6 +2,7 @@ import pytest import unittest import strive_test_data +from parsons import Table class TestStrive(unittest.TestCase): @@ -13,12 +14,17 @@ def test_get_member(self): data = {"limit": "5"} # Testing get members response = self.strive.get_members(params=data) - # Convert data into Parsons Table - data = {"limit": "5"} - assert self.strive.get_members(data).num_rows == 5 - assert ( - self.strive.get_members(data)[0] - == strive_test_data.get_members_expected_output - ) + assert response.num_rows == 5 + + assert isinstance(response, Table) + + # TO DO + # Validate content of response + + + # assert ( + # self.strive.get_members(data)[0] + # == strive_test_data.get_members_expected_output + # ) From d6fcc3e11375482953b111a70c2ab82f5fbbc303 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Thu, 26 Jan 2023 11:05:45 -0500 Subject: [PATCH 03/35] adding broadcast message --- test/test_strive/test_strive.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index 9ce75f1293..b15cc27c3c 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -21,8 +21,20 @@ def test_get_member(self): # TO DO # Validate content of response + + def test_get_broadcasts(self): + # Headers + data = {"apple" : "yummy"} + + # Testing get broadcasts with bad params + import ipdb; ipdb.set_trace() - + response = self.strive.get_broadcasts(params=data) + + + + print("Done") + # assert ( # self.strive.get_members(data)[0] # == strive_test_data.get_members_expected_output From d6bd0e734bb404ef7c7ac4aed4452acfa339b562 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Sun, 16 Apr 2023 15:09:35 -0400 Subject: [PATCH 04/35] make /members method more robust --- parsons/strive/strive.py | 118 ++++++++++++++++++++++++++++---- test/test_strive/test_strive.py | 15 ++-- 2 files changed, 117 insertions(+), 16 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 7fcdd61195..c45aa845dc 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -23,23 +23,117 @@ def __init__(self, api_key=None): } self.client = APIConnector(self.uri, headers=self.headers) - def get_members(self, params: dict): - response = self.client.get_request(url="members", params=params) - return Table(response) + def get_members(self, **kwargs): + """ + The get_members method sends a GET request to the /members endpoint with specified parameters, and returns the response in a Table object. + + `Args:` + id: str + Filter to the ID of the member + campaign_id: str + Filter to members associated with a specific `campaign_id`. + phone_number: str + Filter to members associated with the specified phone number. + only sent on the specified date (ex. ``2019-01-01``). + first_name: str + Filter to the first name of the member. + last_name: str + Filter to the last name of the member. + city: str + Filter to the city of the member. + state: str + Filter to the state of the member. + postal_code: str + Filter to the postal code of the member. + email: str + Filter to the email address of the member. + notes: str + Filter to the content of notes associated with the member + additional_notes: str + Filter to the content of additional notes field associated with the member + opt_in: str + Filter on whether or not the member is subscribed to recieve further messages + custom: str + Filter on the custom fields associated with the member + created_at: str + Filter on the member was either first imported or opted-in to recieve messages + updated_at: str + Filter on when the member was last updated with a change + groups: str + Filter on the groups the member belongs to + carrier: str + Filter on the mobile carrier of the user + first_sub_id: str + Filter on the ID of the first subscription event retained for the member. + select: str + Select for specific columns to be returned + order: str + Order the results returned. + offset: str + Offset the results returned. + limit: str + Limit the results returned. + `Raises:` + ValueError: If an invalid parameter is passed or if a parameter's value does not match the expected data type. + `Returns:` + Parsons Table + See :ref:`parsons-table` for output options. + """ + + valid_params = { + "id": str, + "campaign_id": str, + "phone_number": str, + "first_name": str, + "last_name": str, + "city": str, + "state": str, + "postal_code":str, + "email":str, + "notes":str, + "additional_notes":str, + "opt_in":str, + "custom":str, + "created_at":str, + "updated_at":str, + "groups":str, + "carrier":str, + "first_sub_id":str, + "select": str, + "order":str, + "offset":str, + "limit":str + } -# Instrantiate Strive class -s = Strive() + # Check that params are in list of valid paramaters + invalid_params = [k for k in kwargs if k not in valid_params] + if invalid_params: + raise ValueError(f"Invalid parameter(s) passed: {', '.join(invalid_params)}") -# Headers -data = {"limit": "5"} -# Testing get members -response = s.get_members(params=data) -# Convert data into Parsons Table + # Check that params match the correct data type + for key, value in kwargs.items(): + if key in valid_params: + if not isinstance(value, valid_params[key]): + raise ValueError(f"Invalid data type for parameter '{key}': expected {valid_params[key]}, got {type(value)}") + if value is not None: + params[key] = value + + # Make the get request at the /members endpoint + response = self.client.get_request(url="members", params=params) + return Table(response) -print(response.num_rows) + def get_broadcasts(self, params: dict): + response = self.client.get_request(url="broadcasts", params=params) + return Table(response) -# Put results into Parsons table + def get_p2ps(self, params: list): + response = self.client.get_request(url="p2ps", params=params) + return Table(response) + + def get_custom_fields(self, params: dict): + response = self.client.get_request(url="custom_fields", params=params) + return Table(response) ## To Do # Create Other Get Methods diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index b15cc27c3c..8f1a55169b 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -27,11 +27,8 @@ def test_get_broadcasts(self): data = {"apple" : "yummy"} # Testing get broadcasts with bad params - import ipdb; ipdb.set_trace() - - response = self.strive.get_broadcasts(params=data) - + response = self.strive.get_broadcasts(params=data) print("Done") @@ -40,3 +37,13 @@ def test_get_broadcasts(self): # == strive_test_data.get_members_expected_output # ) + def test_get_p2ps(self): + params = { "message" : "Working" } + import ipdb; ipdb.set_trace() + response = self.strive.get_p2ps(params=params) + + + def test_get_custom_fields(self): + print("Testing method get_custom_fields...") + params = {"label" : "WFP Number"} + response = self.strive.get_custom_fields(params=params) \ No newline at end of file From 4c15a99196aeb004c05e745a4e8f240715811f5b Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Sun, 16 Apr 2023 16:22:11 -0400 Subject: [PATCH 05/35] cannot pass params to get_members endpoint --- parsons/strive/strive.py | 12 +++-- test/test_strive/strive_test_data.py | 36 +++++---------- test/test_strive/test_strive.py | 66 ++++++++++++---------------- 3 files changed, 47 insertions(+), 67 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index c45aa845dc..569159aa46 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -82,8 +82,8 @@ def get_members(self, **kwargs): """ valid_params = { - "id": str, - "campaign_id": str, + "id": int, + "campaign_id": int, "phone_number": str, "first_name": str, "last_name": str, @@ -93,7 +93,7 @@ def get_members(self, **kwargs): "email":str, "notes":str, "additional_notes":str, - "opt_in":str, + "opt_in":bool, "custom":str, "created_at":str, "updated_at":str, @@ -121,7 +121,11 @@ def get_members(self, **kwargs): # Make the get request at the /members endpoint response = self.client.get_request(url="members", params=params) - return Table(response) + if response.status_code == 200: + return Table(response) + else: + # Handle the error + print(f"Error {response.status_code}: {response.text}") def get_broadcasts(self, params: dict): response = self.client.get_request(url="broadcasts", params=params) diff --git a/test/test_strive/strive_test_data.py b/test/test_strive/strive_test_data.py index a9404057f3..8959d1b23a 100644 --- a/test/test_strive/strive_test_data.py +++ b/test/test_strive/strive_test_data.py @@ -1,13 +1,14 @@ -get_members_expected_output = { +from parsons import Table +get_members_expected_output = Table({ "id": 252025504, "campaign_id": 558, - "phone_number": "+16072629160", - "first_name": "Katie", - "last_name": "A Sprague", - "city": None, - "state": "NY", - "postal_code": "14521", - "email": "ksprague365@gmail.com", + "phone_number": "+1234567891", + "first_name": "brittany", + "last_name": "bennett", + "city": "Pittsburgh", + "state": "PA", + "postal_code": "15224", + "email": "johndoe@example.com", "notes": None, "additional_notes": None, "opt_in": True, @@ -15,21 +16,8 @@ "created_at": "2022-09-16T13:48:41.314+00:00", "updated_at": "2022-10-08T17:00:48.395+00:00", "groups": [ - {"id": 251726, "name": "wfp"}, - { - "id": 548978, - "name": "20220921 Election Defenders (Frontline opt-ins + actives)", - }, - { - "id": 548979, - "name": "20220921 Election Defenders (Frontline opt-ins and actives)", - }, - {"id": 555505, "name": "20220929 EOQ test final group"}, - {"id": 556849, "name": "20220930 EOQ 2 group"}, - {"id": 563286, "name": "20221006 Digital Defenders base audience"}, - {"id": 563287, "name": "20221006 Digital Defenders final audience"}, - {"id": 563344, "name": "20221007 NY full state"}, - {"id": 565163, "name": "20221008 One month out fundraiser - V1 (long)"}, + {"id": 251726, "name": "example_group"}, + {"id": 555505, "name": "Election 2022 Countdown"}, ], "carrier": "Verizon", -} \ No newline at end of file +}) \ No newline at end of file diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index 8f1a55169b..f70940e89c 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -3,47 +3,35 @@ import unittest import strive_test_data from parsons import Table - +from unittest.mock import patch class TestStrive(unittest.TestCase): + def setUp(self): self.strive = Strive() - - def test_get_member(self): - # Headers - data = {"limit": "5"} - # Testing get members - response = self.strive.get_members(params=data) - - assert response.num_rows == 5 - - assert isinstance(response, Table) - - # TO DO - # Validate content of response - - def test_get_broadcasts(self): - # Headers - data = {"apple" : "yummy"} - - # Testing get broadcasts with bad params + + def test_get_members_with_first_name(self): + mock_response = strive_test_data.get_members_expected_output + # Mock the GET request method to return the mock response + with patch.object(self.strive, "get_members", return_value=mock_response): + # Call the get_members method with the first_name parameter + result = self.strive.get_members(first_name="brittany") + # Verify that the result is a Table object + assert isinstance(result, Table) + # Verify that the result contains the expected data + expected_data = [{"id": 252025504, "first_name": "brittany", "last_name": "bennett", "phone_number": "+1234567891"}] + assert result.columns == ['id', 'first_name', 'last_name', 'phone_number'] + assert result.data == expected_data - response = self.strive.get_broadcasts(params=data) - - print("Done") - - # assert ( - # self.strive.get_members(data)[0] - # == strive_test_data.get_members_expected_output - # ) - - def test_get_p2ps(self): - params = { "message" : "Working" } - import ipdb; ipdb.set_trace() - response = self.strive.get_p2ps(params=params) - - - def test_get_custom_fields(self): - print("Testing method get_custom_fields...") - params = {"label" : "WFP Number"} - response = self.strive.get_custom_fields(params=params) \ No newline at end of file + def test_get_members_with_last_name(self): + mock_response = strive_test_data.get_members_expected_output + # Mock the GET request method to return the mock response + with patch.object(self.strive, "get_members", return_value=mock_response): + # Call the get_members method with the first_name parameter + result = self.strive.get_members(first_name="bennett") + # Verify that the result is a Table object + assert isinstance(result, Table) + # Verify that the result contains the expected data + expected_data = [{"id": 252025504, "first_name": "brittany", "last_name": "bennett", "phone_number": "+1234567891"}] + assert result.columns == ['id', 'first_name', 'last_name', 'phone_number'] + assert result.data == expected_data From 8c5b1c4ed1b577d2c746132f470a380f84b7db1f Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Thu, 20 Apr 2023 11:37:54 -0400 Subject: [PATCH 06/35] add init method --- parsons/strive/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/parsons/strive/__init__.py b/parsons/strive/__init__.py index e69de29bb2..f2fe037d80 100644 --- a/parsons/strive/__init__.py +++ b/parsons/strive/__init__.py @@ -0,0 +1,5 @@ +from parsons.strive.strive import Strive + +__all__ = [ + 'Strive' +] From 844ee51ee65fb5095a28f0274b2c5ca4e2027b1c Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Thu, 20 Apr 2023 12:41:24 -0400 Subject: [PATCH 07/35] get requests now accept params --- parsons/strive/strive.py | 302 ++++++++++++++++++++++++++------------- 1 file changed, 203 insertions(+), 99 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 569159aa46..cabcda3763 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -24,112 +24,216 @@ def __init__(self, api_key=None): self.client = APIConnector(self.uri, headers=self.headers) - def get_members(self, **kwargs): + def get_members(self, id=None, campaign_id=None, phone_number=None, sent_on=None, + first_name=None, last_name=None, city=None, state=None, postal_code=None, + email=None, notes=None, additional_notes=None, opt_in=None, custom=None, + created_at=None, updated_at=None, groups=None, carrier=None, first_sub_id=None, + select=None, order=None, offset=None, limit=None): """ - The get_members method sends a GET request to the /members endpoint with specified parameters, and returns the response in a Table object. - - `Args:` - id: str - Filter to the ID of the member - campaign_id: str - Filter to members associated with a specific `campaign_id`. - phone_number: str - Filter to members associated with the specified phone number. - only sent on the specified date (ex. ``2019-01-01``). - first_name: str - Filter to the first name of the member. - last_name: str - Filter to the last name of the member. - city: str - Filter to the city of the member. - state: str - Filter to the state of the member. - postal_code: str - Filter to the postal code of the member. - email: str - Filter to the email address of the member. - notes: str - Filter to the content of notes associated with the member - additional_notes: str - Filter to the content of additional notes field associated with the member - opt_in: str - Filter on whether or not the member is subscribed to recieve further messages - custom: str - Filter on the custom fields associated with the member - created_at: str - Filter on the member was either first imported or opted-in to recieve messages - updated_at: str - Filter on when the member was last updated with a change - groups: str - Filter on the groups the member belongs to - carrier: str - Filter on the mobile carrier of the user - first_sub_id: str - Filter on the ID of the first subscription event retained for the member. - select: str - Select for specific columns to be returned - order: str - Order the results returned. - offset: str - Offset the results returned. - limit: str - Limit the results returned. - `Raises:` - ValueError: If an invalid parameter is passed or if a parameter's value does not match the expected data type. - `Returns:` - Parsons Table - See :ref:`parsons-table` for output options. + Sends a GET request to the /members endpoint with specified parameters, + and returns the response in a Table object. """ - - valid_params = { - "id": int, - "campaign_id": int, - "phone_number": str, - "first_name": str, - "last_name": str, - "city": str, - "state": str, - "postal_code":str, - "email":str, - "notes":str, - "additional_notes":str, - "opt_in":bool, - "custom":str, - "created_at":str, - "updated_at":str, - "groups":str, - "carrier":str, - "first_sub_id":str, - "select": str, - "order":str, - "offset":str, - "limit":str + + params = {} + + # Build dictionary of params + if id: + params["id"] = id + if campaign_id: + params["campaign_id"] = campaign_id + if phone_number: + params["phone_number"] = phone_number + if sent_on: + params["sent_on"] = sent_on + if first_name: + params["first_name"] = first_name + if last_name: + params["last_name"] = last_name + if city: + params["city"] = city + if state: + params["state"] = state + if postal_code: + params["postal_code"] = postal_code + if email: + params["email"] = email + if notes: + params["notes"] = notes + if additional_notes: + params["additional_notes"] = additional_notes + if opt_in: + params["opt_in"] = opt_in + if custom: + params["custom"] = custom + if created_at: + params["created_at"] = created_at + if updated_at: + params["updated_at"] = updated_at + if groups: + params["groups"] = groups + if carrier: + params["carrier"] = carrier + if first_sub_id: + params["first_sub_id"] = first_sub_id + if select: + params["select"] = select + if order: + params["order"] = order + if offset: + params["offset"] = offset + if limit: + params["limit"] = limit + + + # Define valid filter parameters and their expected data types + filter_params = { + 'id': int, + 'campaign_id': int, + 'phone_number': str, + 'sent_on': str, + 'first_name': str, + 'last_name': str, + 'city': str, + 'state': str, + 'postal_code': str, + 'email': str, + 'notes': str, + 'additional_notes': str, + 'opt_in': str, + 'custom': str, + 'created_at': str, + 'updated_at': str, + 'groups': str, + 'carrier': str, + 'first_sub_id': str, + 'select': str, + 'order': str, + 'offset': str, + 'limit': str } - # Check that params are in list of valid paramaters - invalid_params = [k for k in kwargs if k not in valid_params] - if invalid_params: - raise ValueError(f"Invalid parameter(s) passed: {', '.join(invalid_params)}") - - # Check that params match the correct data type - for key, value in kwargs.items(): - if key in valid_params: - if not isinstance(value, valid_params[key]): - raise ValueError(f"Invalid data type for parameter '{key}': expected {valid_params[key]}, got {type(value)}") - if value is not None: - params[key] = value - - # Make the get request at the /members endpoint - response = self.client.get_request(url="members", params=params) + # Validate filter parameters + for param, value in params.items(): + print(param) + print(value) + if param in filter_params: + expected_type = filter_params[param] + if not isinstance(value, expected_type): + raise ValueError(f"Invalid data type for parameter {param}: expected {expected_type.__name__}") + + # Build the API request URL with filter parameters + params = {} + for param, value in params.items(): + if param in filter_params and value is not None: + params[param] = value + + # Build the query string for the URL + query_string = '&'.join([f'{key}={value}' for key, value in params.items()]) + + # Build the full URL with the query string + url = "members" + full_url = f'{url}?{query_string}' + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response if response.status_code == 200: - return Table(response) + # Convert the API response to a Parsons Table object + table = Table(response) + if select: + table = table.select(select) + if order: + table = table.order_by(order) + if offset: + table = table.offset(offset) + if limit: + table = table.limit(limit) + return table else: - # Handle the error - print(f"Error {response.status_code}: {response.text}") + logger.info(f'Error: {response.status_code}') + + def get_broadcasts(self, broadcast_id=None, group_id=None, updated_at=None, campaign_id=None, + select=None, order=None, offset=None, limit=None): + """ + Sends a GET request to the /members endpoint with specified parameters, + and returns the response in a Table object. + """ + + params = {} + + # Build dictionary of params + if broadcast_id: + params["broadcast_id"] = broadcast_id + if group_id: + params["group_id"] = group_id + if updated_at: + params["updated_at"] = updated_at + if campaign_id: + params["campaign_id"] = campaign_id + if select: + params["select"] = select + if order: + params["order"] = order + if offset: + params["offset"] = offset + if limit: + params["limit"] = limit + + + # Define valid filter parameters and their expected data types + filter_params = { + 'broadcast_id': int, + 'group_id': int, + 'updated_at': str, + 'campaign_id': str, + 'select': str, + 'order': str, + 'offset': str, + 'limit': str + } - def get_broadcasts(self, params: dict): - response = self.client.get_request(url="broadcasts", params=params) - return Table(response) + # Validate filter parameters + for param, value in params.items(): + print(param) + print(value) + if param in filter_params: + expected_type = filter_params[param] + if not isinstance(value, expected_type): + raise ValueError(f"Invalid data type for parameter {param}: expected {expected_type.__name__}") + + # Build the API request URL with filter parameters + params = {} + for param, value in params.items(): + if param in filter_params and value is not None: + params[param] = value + + # Build the query string for the URL + query_string = '&'.join([f'{key}={value}' for key, value in params.items()]) + + # Build the full URL with the query string + url = "broadcasts_groups" + full_url = f'{url}?{query_string}' + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + if response.status_code == 200: + table = Table(response) + # Convert the API response to a Parsons Table object + table = Table(response) + if select: + table = table.select(select) + if order: + table = table.order_by(order) + if offset: + table = table.offset(offset) + if limit: + table = table.limit(limit) + return table + else: + logger.info(f'Error: {response.status_code}') def get_p2ps(self, params: list): response = self.client.get_request(url="p2ps", params=params) From 207c862b3d082a121af969fae7313c696c033b37 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Thu, 20 Apr 2023 13:21:55 -0400 Subject: [PATCH 08/35] adding docstrings --- parsons/strive/strive.py | 557 ++++++++++++++++++++++++++++++++------- 1 file changed, 459 insertions(+), 98 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index cabcda3763..241f6752ce 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -10,8 +10,6 @@ class Strive(object): """ Instantiate Strive class. - - `Args:` """ def __init__(self, api_key=None): @@ -23,15 +21,263 @@ def __init__(self, api_key=None): } self.client = APIConnector(self.uri, headers=self.headers) + def validate_filter_params(params, filter_params): + """ + For a given set of params and set paramter types, validate that the + input params match the set parameter data types. + + Raises an error if an invalid data type has been passed as a parameter. + """ + # Validate filter parameters + for param, value in params.items(): + print(param) + print(value) + if param in filter_params: + expected_type = filter_params[param] + if not isinstance(value, expected_type): + raise ValueError( + f"Invalid data type for parameter {param}: expected {expected_type.__name__}" + ) + + def build_url(params, endpoint): + """ + Takes a set of parameters and an API endpoint and builds a URL using horizontal + filter rules. + """ + # Build the query string for the URL + query_string = "&".join([f"{key}={value}" for key, value in params.items()]) + + # Build the full URL with the query string + url = endpoint + full_url = f"{url}?{query_string}" + + return full_url + + def get_p2ps( + self, + id=None, + user_id=None, + campaign_id=None, + message=None, + attachment=None, + scheduled_at=None, + cancelled_at=None, + sent_at=None, + created_at=None, + updated_at=None, + select=None, + order=None, + offset=None, + limit=None, + ): + """ + Sends a GET request to the /p2ps endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: int + The ID of the P2P message. + user_id: int + The ID of the user who created the P2P message. + campaign_id: int + The ID of the campaign that the P2P message is associated with. + message: str + The text content of the P2P message. + attachment: str + A URL to an attachment that was sent with the P2P message. + scheduled_at: str + The date and time that the P2P message is scheduled to be sent. + cancelled_at: str + The date and time that the P2P message was cancelled, if applicable. + sent_at: str + The date and time that the P2P message was sent, if applicable. + created_at: str + The date and time that the P2P message was created. + updated_at: str + The date and time that the P2P message was last updated. + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /p2ps endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + + """ + + params = {} + + # Build dictionary of params + if id: + params["id"] = id + if user_id: + params["user_id"] = user_id + if campaign_id: + params["campaign_id"] = campaign_id + if message: + params["message"] = message + if attachment: + params["attachment"] = attachment + if scheduled_at: + params["scheduled_at"] = scheduled_at + if cancelled_at: + params["cancelled_at"] = cancelled_at + if sent_at: + params["sent_at"] = sent_at + if created_at: + params["created_at"] = created_at + if updated_at: + params["updated_at"] = updated_at + if select: + params["select"] = select + if order: + params["order"] = order + if offset: + params["offset"] = offset + if limit: + params["limit"] = limit + + # Define valid filter parameters and their expected data types + filter_params = { + "id": int, + "campaign_id": int, + "phone_number": str, + "sent_on": str, + "first_name": str, + "last_name": str, + "city": str, + "state": str, + "postal_code": str, + "email": str, + "notes": str, + "additional_notes": str, + "opt_in": str, + "custom": str, + "created_at": str, + "updated_at": str, + "groups": str, + "carrier": str, + "first_sub_id": str, + "select": str, + "order": str, + "offset": str, + "limit": str, + } + + # Validate filter params + validate_filter_params(params, filter_params) + + # Get full URL with filter params + full_url = build_url(params, "p2ps") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + if response.status_code == 200: + # Convert the API response to a Parsons Table object + table = Table(response) + if select: + table = table.select(select) + if order: + table = table.order_by(order) + if offset: + table = table.offset(offset) + if limit: + table = table.limit(limit) + return table + else: + logger.info(f"Error: {response.status_code}") - def get_members(self, id=None, campaign_id=None, phone_number=None, sent_on=None, - first_name=None, last_name=None, city=None, state=None, postal_code=None, - email=None, notes=None, additional_notes=None, opt_in=None, custom=None, - created_at=None, updated_at=None, groups=None, carrier=None, first_sub_id=None, - select=None, order=None, offset=None, limit=None): + def get_members( + self, + id=None, + campaign_id=None, + phone_number=None, + sent_on=None, + first_name=None, + last_name=None, + city=None, + state=None, + postal_code=None, + email=None, + notes=None, + additional_notes=None, + opt_in=None, + custom=None, + created_at=None, + updated_at=None, + groups=None, + carrier=None, + first_sub_id=None, + select=None, + order=None, + offset=None, + limit=None, + ): """ Sends a GET request to the /members endpoint with specified parameters, and returns the response in a Table object. + + `Args:` + id: int + The ID of the member + campaign_id: int + The campaign associated with the member + phone_number: str + The member's phone number + first_name: str + The member's first name + last_name: str + The member's last name + city: str + The City associated with the member + state: str + The State assoicated with the member + postal_code: str + The zip or postcal code assoicated with the member + email: str + The member's email address + notes: str + The content of notes associated with the member + additional_notes: str + The content of additional notes field associated with the member + opt_in: str + Whether or not the member is subscribed to recieve further messages + custom: str + The custom fields associated with the member + created_at: str + When the member was either first imported or opted-in to recieve messages + updated_at: str + When the member was last updated with a change + group: str + Groups this member belongs to (json) + carrier: str + The mobile carrier this member uses + first_sub_id: int + The ID of the first subscription event retained for the member + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /p2ps endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ params = {} @@ -84,55 +330,38 @@ def get_members(self, id=None, campaign_id=None, phone_number=None, sent_on=None if limit: params["limit"] = limit - # Define valid filter parameters and their expected data types filter_params = { - 'id': int, - 'campaign_id': int, - 'phone_number': str, - 'sent_on': str, - 'first_name': str, - 'last_name': str, - 'city': str, - 'state': str, - 'postal_code': str, - 'email': str, - 'notes': str, - 'additional_notes': str, - 'opt_in': str, - 'custom': str, - 'created_at': str, - 'updated_at': str, - 'groups': str, - 'carrier': str, - 'first_sub_id': str, - 'select': str, - 'order': str, - 'offset': str, - 'limit': str + "id": int, + "campaign_id": int, + "phone_number": str, + "sent_on": str, + "first_name": str, + "last_name": str, + "city": str, + "state": str, + "postal_code": str, + "email": str, + "notes": str, + "additional_notes": str, + "opt_in": str, + "custom": str, + "created_at": str, + "updated_at": str, + "groups": str, + "carrier": str, + "first_sub_id": str, + "select": str, + "order": str, + "offset": str, + "limit": str, } - # Validate filter parameters - for param, value in params.items(): - print(param) - print(value) - if param in filter_params: - expected_type = filter_params[param] - if not isinstance(value, expected_type): - raise ValueError(f"Invalid data type for parameter {param}: expected {expected_type.__name__}") - - # Build the API request URL with filter parameters - params = {} - for param, value in params.items(): - if param in filter_params and value is not None: - params[param] = value + # Validate filter params + validate_filter_params(params, filter_params) - # Build the query string for the URL - query_string = '&'.join([f'{key}={value}' for key, value in params.items()]) - - # Build the full URL with the query string - url = "members" - full_url = f'{url}?{query_string}' + # Get full URL with filter params + full_url = build_url(params, "p2ps") # Send the GET request response = self.client.get_request(url=full_url) @@ -151,15 +380,47 @@ def get_members(self, id=None, campaign_id=None, phone_number=None, sent_on=None table = table.limit(limit) return table else: - logger.info(f'Error: {response.status_code}') + logger.info(f"Error: {response.status_code}") - def get_broadcasts(self, broadcast_id=None, group_id=None, updated_at=None, campaign_id=None, - select=None, order=None, offset=None, limit=None): + def get_broadcasts_groups( + self, + broadcast_id=None, + group_id=None, + updated_at=None, + campaign_id=None, + select=None, + order=None, + offset=None, + limit=None, + ): """ - Sends a GET request to the /members endpoint with specified parameters, + Sends a GET request to the /broadcasts endpoint with specified parameters, and returns the response in a Table object. - """ + `Args:` + broadcast_id: int + The ID of the Broadcast + group_id: int + The ID of the group of members targeted by the broadcast + updated_at: str + string + campaign_id: int + The campaign that the broadcast belongs to + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts_groups endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ params = {} # Build dictionary of params @@ -180,47 +441,160 @@ def get_broadcasts(self, broadcast_id=None, group_id=None, updated_at=None, camp if limit: params["limit"] = limit - # Define valid filter parameters and their expected data types filter_params = { - 'broadcast_id': int, - 'group_id': int, - 'updated_at': str, - 'campaign_id': str, - 'select': str, - 'order': str, - 'offset': str, - 'limit': str + "broadcast_id": int, + "group_id": int, + "updated_at": str, + "campaign_id": str, + "select": str, + "order": str, + "offset": str, + "limit": str, } - # Validate filter parameters - for param, value in params.items(): - print(param) - print(value) - if param in filter_params: - expected_type = filter_params[param] - if not isinstance(value, expected_type): - raise ValueError(f"Invalid data type for parameter {param}: expected {expected_type.__name__}") - - # Build the API request URL with filter parameters + # Validate filter params + validate_filter_params(params, filter_params) + + # Get full URL with filter params + full_url = build_url(params, "broadcast_groups") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + if response.status_code == 200: + # Convert the API response to a Parsons Table object + table = Table(response) + if select: + table = table.select(select) + if order: + table = table.order_by(order) + if offset: + table = table.offset(offset) + if limit: + table = table.limit(limit) + return table + else: + logger.info(f"Error: {response.status_code}") + + def get_broadcasts(): + """ + Sends a GET request to the /broadcasts endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: int + The ID of the Broadcast + user_id: int + The Strive user who sent the broadcast + campaign_id: int + The campaign that the broadcast belongs to + flow_id: int + The flow that was broadcasted + name: str + The name of the Broadcast + message: str + The content of the first message sent in the broadcast + attachment: str + The attachment or MMS included in the broadcast + recipient_count: int + How many members were targeted for the broadcast + scheduled_at: str + When the broadcast is scheduled to send + cancelled_at: str + When the broadcast was cancelled + sent_at: str + When the broadcast began to deliver + created_at: str + When the broadcast was first created + updated_at: str + When the broadcast was last updated + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ params = {} - for param, value in params.items(): - if param in filter_params and value is not None: - params[param] = value - # Build the query string for the URL - query_string = '&'.join([f'{key}={value}' for key, value in params.items()]) + # Build dictionary of params + if id: + params["id"] = id + if user_id: + params["user_id"] = user_id + if campaign_id: + params["campaign_id"] = campaign_id + if flow_id: + params["flow_id"] = flow_id + if name: + params["name"] = name + if message: + params["message"] = message + if attachment: + params["attachment"] = attachment + if recipient_count: + params["recipient_count"] = recipient_count + if scheduled_at: + params["scheduled_at"] = scheduled_at + if cancelled_at: + params["cancelled_at"] = cancelled_at + if sent_at: + params["sent_at"] = sent_at + if created_at: + params["created_at"] = created_at + if updated_at: + params["updated_at"] = updated_at + if select: + params["select"] = select + if order: + params["order"] = order + if offset: + params["offset"] = offset + if limit: + params["limit"] = limit - # Build the full URL with the query string - url = "broadcasts_groups" - full_url = f'{url}?{query_string}' + # Define valid filter parameters and their expected data types + filter_params = { + "id": int, + "user_id": int, + "campaign_id": int, + "flow_id": int, + "name": str, + "message": str, + "attachment": str, + "recipient_count": int, + "scheduled_at": str, + "cancelled_at": str, + "sent_at": str, + "created_at": str, + "updated_at": str, + "select": str, + "order": str, + "offset": str, + "limit": str + } + + # Validate filter params + validate_filter_params(params, filter_params) + + # Get full URL with filter params + full_url = build_url(params, "broadcasts") # Send the GET request response = self.client.get_request(url=full_url) # Process the response if response.status_code == 200: - table = Table(response) # Convert the API response to a Parsons Table object table = Table(response) if select: @@ -233,17 +607,4 @@ def get_broadcasts(self, broadcast_id=None, group_id=None, updated_at=None, camp table = table.limit(limit) return table else: - logger.info(f'Error: {response.status_code}') - - def get_p2ps(self, params: list): - response = self.client.get_request(url="p2ps", params=params) - return Table(response) - - def get_custom_fields(self, params: dict): - response = self.client.get_request(url="custom_fields", params=params) - return Table(response) - -## To Do -# Create Other Get Methods -# Specifying other paramters instead of taking them as a dictionary -# Tackle POST methods \ No newline at end of file + logger.info(f"Error: {response.status_code}") \ No newline at end of file From 5458adff19b9e201a1916856375262aead89997a Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Thu, 20 Apr 2023 13:30:21 -0400 Subject: [PATCH 09/35] remove print statement --- parsons/strive/strive.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 241f6752ce..30e2e01055 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -30,8 +30,6 @@ def validate_filter_params(params, filter_params): """ # Validate filter parameters for param, value in params.items(): - print(param) - print(value) if param in filter_params: expected_type = filter_params[param] if not isinstance(value, expected_type): From 7892f83f477296253ef51e7709856dfc1a33ebed Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Thu, 20 Apr 2023 13:44:33 -0400 Subject: [PATCH 10/35] add self --- parsons/strive/strive.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 30e2e01055..2fe18d6394 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -21,7 +21,7 @@ def __init__(self, api_key=None): } self.client = APIConnector(self.uri, headers=self.headers) - def validate_filter_params(params, filter_params): + def validate_filter_params(self, params, filter_params): """ For a given set of params and set paramter types, validate that the input params match the set parameter data types. @@ -37,7 +37,7 @@ def validate_filter_params(params, filter_params): f"Invalid data type for parameter {param}: expected {expected_type.__name__}" ) - def build_url(params, endpoint): + def build_url(self, params, endpoint): """ Takes a set of parameters and an API endpoint and builds a URL using horizontal filter rules. @@ -170,7 +170,7 @@ def get_p2ps( } # Validate filter params - validate_filter_params(params, filter_params) + self.validate_filter_params(params, filter_params) # Get full URL with filter params full_url = build_url(params, "p2ps") @@ -356,7 +356,7 @@ def get_members( } # Validate filter params - validate_filter_params(params, filter_params) + self.validate_filter_params(params, filter_params) # Get full URL with filter params full_url = build_url(params, "p2ps") @@ -452,7 +452,7 @@ def get_broadcasts_groups( } # Validate filter params - validate_filter_params(params, filter_params) + self.validate_filter_params(params, filter_params) # Get full URL with filter params full_url = build_url(params, "broadcast_groups") @@ -583,7 +583,7 @@ def get_broadcasts(): } # Validate filter params - validate_filter_params(params, filter_params) + self.validate_filter_params(params, filter_params) # Get full URL with filter params full_url = build_url(params, "broadcasts") From 86b4f29b232a31a2121adee1ffdf23b2f7e0d9ed Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Thu, 20 Apr 2023 13:45:30 -0400 Subject: [PATCH 11/35] add more self --- parsons/strive/strive.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 2fe18d6394..0e399f83f7 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -173,7 +173,7 @@ def get_p2ps( self.validate_filter_params(params, filter_params) # Get full URL with filter params - full_url = build_url(params, "p2ps") + full_url = self.build_url(params, "p2ps") # Send the GET request response = self.client.get_request(url=full_url) @@ -359,7 +359,7 @@ def get_members( self.validate_filter_params(params, filter_params) # Get full URL with filter params - full_url = build_url(params, "p2ps") + full_url = self.build_url(params, "p2ps") # Send the GET request response = self.client.get_request(url=full_url) @@ -455,7 +455,7 @@ def get_broadcasts_groups( self.validate_filter_params(params, filter_params) # Get full URL with filter params - full_url = build_url(params, "broadcast_groups") + full_url = self.build_url(params, "broadcast_groups") # Send the GET request response = self.client.get_request(url=full_url) @@ -586,7 +586,7 @@ def get_broadcasts(): self.validate_filter_params(params, filter_params) # Get full URL with filter params - full_url = build_url(params, "broadcasts") + full_url = self.build_url(params, "broadcasts") # Send the GET request response = self.client.get_request(url=full_url) From f4101273f6055bd10a92e484efec24f836e7efc9 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Fri, 16 Jun 2023 10:03:02 -0400 Subject: [PATCH 12/35] working get methods with params --- parsons/strive/strive.py | 96 ++++++++++++---------------------------- 1 file changed, 28 insertions(+), 68 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 0e399f83f7..10ca8413f0 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -169,31 +169,19 @@ def get_p2ps( "limit": str, } - # Validate filter params + # Type check params self.validate_filter_params(params, filter_params) - # Get full URL with filter params + # Build URL full_url = self.build_url(params, "p2ps") # Send the GET request response = self.client.get_request(url=full_url) # Process the response - if response.status_code == 200: - # Convert the API response to a Parsons Table object - table = Table(response) - if select: - table = table.select(select) - if order: - table = table.order_by(order) - if offset: - table = table.offset(offset) - if limit: - table = table.limit(limit) - return table - else: - logger.info(f"Error: {response.status_code}") - + table = Table(response) + return table + def get_members( self, id=None, @@ -355,30 +343,19 @@ def get_members( "limit": str, } - # Validate filter params + # Type check params self.validate_filter_params(params, filter_params) - # Get full URL with filter params - full_url = self.build_url(params, "p2ps") + # Build URL + full_url = self.build_url(params, "members") # Send the GET request response = self.client.get_request(url=full_url) - # Process the response - if response.status_code == 200: - # Convert the API response to a Parsons Table object - table = Table(response) - if select: - table = table.select(select) - if order: - table = table.order_by(order) - if offset: - table = table.offset(offset) - if limit: - table = table.limit(limit) - return table - else: - logger.info(f"Error: {response.status_code}") + # Convert the API response to a Parsons Table object + table = Table(response) + return table + def get_broadcasts_groups( self, @@ -451,30 +428,18 @@ def get_broadcasts_groups( "limit": str, } - # Validate filter params + # Type check params self.validate_filter_params(params, filter_params) - # Get full URL with filter params + # Build URL full_url = self.build_url(params, "broadcast_groups") # Send the GET request response = self.client.get_request(url=full_url) - # Process the response - if response.status_code == 200: - # Convert the API response to a Parsons Table object - table = Table(response) - if select: - table = table.select(select) - if order: - table = table.order_by(order) - if offset: - table = table.offset(offset) - if limit: - table = table.limit(limit) - return table - else: - logger.info(f"Error: {response.status_code}") + # Convert the API response to a Parsons Table object + table = Table(response) + return table def get_broadcasts(): """ @@ -582,27 +547,22 @@ def get_broadcasts(): "limit": str } - # Validate filter params + # Type check params self.validate_filter_params(params, filter_params) - # Get full URL with filter params + # Build URL full_url = self.build_url(params, "broadcasts") # Send the GET request response = self.client.get_request(url=full_url) # Process the response - if response.status_code == 200: - # Convert the API response to a Parsons Table object - table = Table(response) - if select: - table = table.select(select) - if order: - table = table.order_by(order) - if offset: - table = table.offset(offset) - if limit: - table = table.limit(limit) - return table - else: - logger.info(f"Error: {response.status_code}") \ No newline at end of file + table = Table(response) + return table + +# Testing +# strive = Strive() +# strive.get_members(first_name = 'eq.brittany') + +#in the docs, youw ant to pass params like this, here is an example. +# then add link to their documentation \ No newline at end of file From 1e1695cf92cbd42c1c8368d48a739da4daeb52d1 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 13:21:45 -0400 Subject: [PATCH 13/35] remove type checking and substitue kwargs --- parsons/strive/strive.py | 432 +++++++++++---------------------------- 1 file changed, 123 insertions(+), 309 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 10ca8413f0..e89353e4b1 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -21,21 +21,6 @@ def __init__(self, api_key=None): } self.client = APIConnector(self.uri, headers=self.headers) - def validate_filter_params(self, params, filter_params): - """ - For a given set of params and set paramter types, validate that the - input params match the set parameter data types. - - Raises an error if an invalid data type has been passed as a parameter. - """ - # Validate filter parameters - for param, value in params.items(): - if param in filter_params: - expected_type = filter_params[param] - if not isinstance(value, expected_type): - raise ValueError( - f"Invalid data type for parameter {param}: expected {expected_type.__name__}" - ) def build_url(self, params, endpoint): """ @@ -51,27 +36,22 @@ def build_url(self, params, endpoint): return full_url - def get_p2ps( - self, - id=None, - user_id=None, - campaign_id=None, - message=None, - attachment=None, - scheduled_at=None, - cancelled_at=None, - sent_at=None, - created_at=None, - updated_at=None, - select=None, - order=None, - offset=None, - limit=None, - ): + def get_p2ps(self, **kwargs): """ Sends a GET request to the /p2ps endpoint with specified parameters, and returns the response in a Table object. + The Strive connector uses horizontal filtering. You can learn more about + horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows + + For example, if you want to filter on a specific `id`, you would pass `eq.12345` to the `id` param + where `12345` is the P2P id. + + If you want to search on a key word in a message, you would pass `like*hello*` to the `message` param + where `hello` is the keyword you want to search for in the message. The `*` is a wildcard operator + similar to `%` in SQL. + + `Args:` id: int The ID of the P2P message. @@ -107,73 +87,57 @@ def get_p2ps( `Raises:` ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "p2ps") + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + + def get_custom_fields(self, **kwargs): """ + Sends a GET request to the /custom_fields endpoint with specified parameters, + and returns the response in a Table object. - params = {} - - # Build dictionary of params - if id: - params["id"] = id - if user_id: - params["user_id"] = user_id - if campaign_id: - params["campaign_id"] = campaign_id - if message: - params["message"] = message - if attachment: - params["attachment"] = attachment - if scheduled_at: - params["scheduled_at"] = scheduled_at - if cancelled_at: - params["cancelled_at"] = cancelled_at - if sent_at: - params["sent_at"] = sent_at - if created_at: - params["created_at"] = created_at - if updated_at: - params["updated_at"] = updated_at - if select: - params["select"] = select - if order: - params["order"] = order - if offset: - params["offset"] = offset - if limit: - params["limit"] = limit - - # Define valid filter parameters and their expected data types - filter_params = { - "id": int, - "campaign_id": int, - "phone_number": str, - "sent_on": str, - "first_name": str, - "last_name": str, - "city": str, - "state": str, - "postal_code": str, - "email": str, - "notes": str, - "additional_notes": str, - "opt_in": str, - "custom": str, - "created_at": str, - "updated_at": str, - "groups": str, - "carrier": str, - "first_sub_id": str, - "select": str, - "order": str, - "offset": str, - "limit": str, - } + The Strive connector uses horizontal filtering. You can learn more about + horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows - # Type check params - self.validate_filter_params(params, filter_params) + For example, if you want to filter on a specific `campaign_id`, you would pass `eq.12345` to the `campaign_id` param + where `12345` is the campaign id. + `Args:` + campaign_id: int + The ID of the campaign that the P2P message is associated with. + field: str + The name of the field within the API + label: str + The name of the field within the product + type: str + The type of field the custom field is + updated_at: str + The date and time that the P2P message was last updated. + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /p2ps endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ # Build URL - full_url = self.build_url(params, "p2ps") + full_url = self.build_url(kwargs, "custom_fields") # Send the GET request response = self.client.get_request(url=full_url) @@ -181,33 +145,68 @@ def get_p2ps( # Process the response table = Table(response) return table - - def get_members( - self, - id=None, - campaign_id=None, - phone_number=None, - sent_on=None, - first_name=None, - last_name=None, - city=None, - state=None, - postal_code=None, - email=None, - notes=None, - additional_notes=None, - opt_in=None, - custom=None, - created_at=None, - updated_at=None, - groups=None, - carrier=None, - first_sub_id=None, - select=None, - order=None, - offset=None, - limit=None, - ): + + def get_outgoing_messages(self, **kwargs): + """ + Sends a GET request to the /outgoing_messages endpoint with specified parameters, + and returns the response in a Table object. + + The Strive connector uses horizontal filtering. You can learn more about + horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows + + For example, if you want to filter on a specific `campaign_id`, you would pass `eq.12345` to the `campaign_id` param + where `12345` is the campaign id. + + `Args:` + id: string + The ID of the outgoing message + campaign_id: string + The campaign associated with the outgoing message + member_id: string + The member targeted by the outgoing message + message: string + The contents of the outgoing message + broadcast_id: string + The parent broadcast that the outgoing message was part of + p2p_id: string + The ID of the inbox message the outgoing message was part of + flow_action_id: string + The flow action that happened in response to the outgoing message + status: string + That status of the outgoing message's delivery + error_code: string + The error code returned by carriers in repsonse to the outgoing message + sent_at: string + When the outgoing message was sent + queued_at: string + When the outgoing message was added to our aggregators queue + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /p2ps endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "custom_fields") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + + def get_members(self, **kwargs): """ Sends a GET request to the /members endpoint with specified parameters, and returns the response in a Table object. @@ -266,88 +265,8 @@ def get_members( """ - params = {} - - # Build dictionary of params - if id: - params["id"] = id - if campaign_id: - params["campaign_id"] = campaign_id - if phone_number: - params["phone_number"] = phone_number - if sent_on: - params["sent_on"] = sent_on - if first_name: - params["first_name"] = first_name - if last_name: - params["last_name"] = last_name - if city: - params["city"] = city - if state: - params["state"] = state - if postal_code: - params["postal_code"] = postal_code - if email: - params["email"] = email - if notes: - params["notes"] = notes - if additional_notes: - params["additional_notes"] = additional_notes - if opt_in: - params["opt_in"] = opt_in - if custom: - params["custom"] = custom - if created_at: - params["created_at"] = created_at - if updated_at: - params["updated_at"] = updated_at - if groups: - params["groups"] = groups - if carrier: - params["carrier"] = carrier - if first_sub_id: - params["first_sub_id"] = first_sub_id - if select: - params["select"] = select - if order: - params["order"] = order - if offset: - params["offset"] = offset - if limit: - params["limit"] = limit - - # Define valid filter parameters and their expected data types - filter_params = { - "id": int, - "campaign_id": int, - "phone_number": str, - "sent_on": str, - "first_name": str, - "last_name": str, - "city": str, - "state": str, - "postal_code": str, - "email": str, - "notes": str, - "additional_notes": str, - "opt_in": str, - "custom": str, - "created_at": str, - "updated_at": str, - "groups": str, - "carrier": str, - "first_sub_id": str, - "select": str, - "order": str, - "offset": str, - "limit": str, - } - - # Type check params - self.validate_filter_params(params, filter_params) - # Build URL - full_url = self.build_url(params, "members") + full_url = self.build_url(kwargs, "members") # Send the GET request response = self.client.get_request(url=full_url) @@ -357,17 +276,7 @@ def get_members( return table - def get_broadcasts_groups( - self, - broadcast_id=None, - group_id=None, - updated_at=None, - campaign_id=None, - select=None, - order=None, - offset=None, - limit=None, - ): + def get_broadcasts_groups(self, **kwargs): """ Sends a GET request to the /broadcasts endpoint with specified parameters, and returns the response in a Table object. @@ -396,43 +305,9 @@ def get_broadcasts_groups( `Raises:` ValueError: If any of the filter parameters have an invalid data type. """ - params = {} - - # Build dictionary of params - if broadcast_id: - params["broadcast_id"] = broadcast_id - if group_id: - params["group_id"] = group_id - if updated_at: - params["updated_at"] = updated_at - if campaign_id: - params["campaign_id"] = campaign_id - if select: - params["select"] = select - if order: - params["order"] = order - if offset: - params["offset"] = offset - if limit: - params["limit"] = limit - - # Define valid filter parameters and their expected data types - filter_params = { - "broadcast_id": int, - "group_id": int, - "updated_at": str, - "campaign_id": str, - "select": str, - "order": str, - "offset": str, - "limit": str, - } - - # Type check params - self.validate_filter_params(params, filter_params) # Build URL - full_url = self.build_url(params, "broadcast_groups") + full_url = self.build_url(kwargs, "broadcast_groups") # Send the GET request response = self.client.get_request(url=full_url) @@ -488,70 +363,9 @@ def get_broadcasts(): `Raises:` ValueError: If any of the filter parameters have an invalid data type. """ - params = {} - - # Build dictionary of params - if id: - params["id"] = id - if user_id: - params["user_id"] = user_id - if campaign_id: - params["campaign_id"] = campaign_id - if flow_id: - params["flow_id"] = flow_id - if name: - params["name"] = name - if message: - params["message"] = message - if attachment: - params["attachment"] = attachment - if recipient_count: - params["recipient_count"] = recipient_count - if scheduled_at: - params["scheduled_at"] = scheduled_at - if cancelled_at: - params["cancelled_at"] = cancelled_at - if sent_at: - params["sent_at"] = sent_at - if created_at: - params["created_at"] = created_at - if updated_at: - params["updated_at"] = updated_at - if select: - params["select"] = select - if order: - params["order"] = order - if offset: - params["offset"] = offset - if limit: - params["limit"] = limit - - # Define valid filter parameters and their expected data types - filter_params = { - "id": int, - "user_id": int, - "campaign_id": int, - "flow_id": int, - "name": str, - "message": str, - "attachment": str, - "recipient_count": int, - "scheduled_at": str, - "cancelled_at": str, - "sent_at": str, - "created_at": str, - "updated_at": str, - "select": str, - "order": str, - "offset": str, - "limit": str - } - - # Type check params - self.validate_filter_params(params, filter_params) # Build URL - full_url = self.build_url(params, "broadcasts") + full_url = self.build_url(kwargs, "broadcasts") # Send the GET request response = self.client.get_request(url=full_url) From 3a8b953c02f07d49f99205ee22e4a11b91633072 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 13:26:27 -0400 Subject: [PATCH 14/35] add subscription events endpoint --- parsons/strive/strive.py | 56 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index e89353e4b1..917f60670b 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -206,7 +206,61 @@ def get_outgoing_messages(self, **kwargs): table = Table(response) return table - def get_members(self, **kwargs): + def get_subscription_events(self, **kwargs): + """ + Sends a GET request to the /subscription_events endpoint with specified parameters, + and returns the response in a Table object. + + The Strive connector uses horizontal filtering. You can learn more about + horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows + + For example, if you want to filter on a specific `campaign_id`, you would pass `eq.12345` to the `campaign_id` param + where `12345` is the campaign id. + + `Args:` + id: string + The ID of the subscription event + member_id: string + The ID of the member in question + type: string + The type of event which lead to the subscription or unsubscription + created_at: string + When the event occurred + ref_id: string + ID of upload, status code, incoming message, or other relevant artifact of subscription event + supplemental: string + Supplemental information about the event + unsubscribe: string + Whether the member has been unsubscribed + campaign_id: string + The ID of the campaign associated with this event + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /p2ps endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "subscription_events") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + +def get_members(self, **kwargs): """ Sends a GET request to the /members endpoint with specified parameters, and returns the response in a Table object. From 7ac52388b9e0df9357c33cf099c18d470778169f Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 13:52:37 -0400 Subject: [PATCH 15/35] add a few more get requests --- parsons/strive/strive.py | 290 +++++++++++++++++++++++++++++++++------ 1 file changed, 250 insertions(+), 40 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 917f60670b..c2c4cde101 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -21,7 +21,6 @@ def __init__(self, api_key=None): } self.client = APIConnector(self.uri, headers=self.headers) - def build_url(self, params, endpoint): """ Takes a set of parameters and an API endpoint and builds a URL using horizontal @@ -45,7 +44,7 @@ def get_p2ps(self, **kwargs): horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows For example, if you want to filter on a specific `id`, you would pass `eq.12345` to the `id` param - where `12345` is the P2P id. + where `12345` is the P2P id. If you want to search on a key word in a message, you would pass `like*hello*` to the `message` param where `hello` is the keyword you want to search for in the message. The `*` is a wildcard operator @@ -98,7 +97,7 @@ def get_p2ps(self, **kwargs): # Process the response table = Table(response) return table - + def get_custom_fields(self, **kwargs): """ Sends a GET request to the /custom_fields endpoint with specified parameters, @@ -108,12 +107,12 @@ def get_custom_fields(self, **kwargs): horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows For example, if you want to filter on a specific `campaign_id`, you would pass `eq.12345` to the `campaign_id` param - where `12345` is the campaign id. + where `12345` is the campaign id. `Args:` campaign_id: int The ID of the campaign that the P2P message is associated with. - field: str + field: str The name of the field within the API label: str The name of the field within the product @@ -145,7 +144,7 @@ def get_custom_fields(self, **kwargs): # Process the response table = Table(response) return table - + def get_outgoing_messages(self, **kwargs): """ Sends a GET request to the /outgoing_messages endpoint with specified parameters, @@ -155,14 +154,14 @@ def get_outgoing_messages(self, **kwargs): horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows For example, if you want to filter on a specific `campaign_id`, you would pass `eq.12345` to the `campaign_id` param - where `12345` is the campaign id. + where `12345` is the campaign id. `Args:` id: string The ID of the outgoing message campaign_id: string The campaign associated with the outgoing message - member_id: string + member_id: string The member targeted by the outgoing message message: string The contents of the outgoing message @@ -195,9 +194,9 @@ def get_outgoing_messages(self, **kwargs): `Raises:` ValueError: If any of the filter parameters have an invalid data type. """ - + # Build URL - full_url = self.build_url(kwargs, "custom_fields") + full_url = self.build_url(kwargs, "outgoing_messages") # Send the GET request response = self.client.get_request(url=full_url) @@ -205,7 +204,7 @@ def get_outgoing_messages(self, **kwargs): # Process the response table = Table(response) return table - + def get_subscription_events(self, **kwargs): """ Sends a GET request to the /subscription_events endpoint with specified parameters, @@ -215,7 +214,7 @@ def get_subscription_events(self, **kwargs): horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows For example, if you want to filter on a specific `campaign_id`, you would pass `eq.12345` to the `campaign_id` param - where `12345` is the campaign id. + where `12345` is the campaign id. `Args:` id: string @@ -249,7 +248,7 @@ def get_subscription_events(self, **kwargs): `Raises:` ValueError: If any of the filter parameters have an invalid data type. """ - + # Build URL full_url = self.build_url(kwargs, "subscription_events") @@ -260,47 +259,47 @@ def get_subscription_events(self, **kwargs): table = Table(response) return table -def get_members(self, **kwargs): + def get_members(self, **kwargs): """ Sends a GET request to the /members endpoint with specified parameters, and returns the response in a Table object. `Args:` - id: int + id: string The ID of the member - campaign_id: int + campaign_id: string The campaign associated with the member - phone_number: str + phone_number: string The member's phone number - first_name: str + first_name: string The member's first name - last_name: str + last_name: string The member's last name - city: str + city: string The City associated with the member - state: str + state: string The State assoicated with the member - postal_code: str + postal_code: string The zip or postcal code assoicated with the member - email: str + email: string The member's email address - notes: str + notes: string The content of notes associated with the member - additional_notes: str + additional_notes: string The content of additional notes field associated with the member - opt_in: str + opt_in: string Whether or not the member is subscribed to recieve further messages - custom: str + custom: string The custom fields associated with the member - created_at: str + created_at: string When the member was either first imported or opted-in to recieve messages - updated_at: str + updated_at: string When the member was last updated with a change - group: str + group: string Groups this member belongs to (json) - carrier: str + carrier: string The mobile carrier this member uses - first_sub_id: int + first_sub_id: string The ID of the first subscription event retained for the member select: str The fields to include in the response. Use comma-separated values to include multiple fields. @@ -319,7 +318,7 @@ def get_members(self, **kwargs): """ - # Build URL + # Build URL full_url = self.build_url(kwargs, "members") # Send the GET request @@ -328,17 +327,97 @@ def get_members(self, **kwargs): # Convert the API response to a Parsons Table object table = Table(response) return table - + + def post_members(self, payload): + """ + Sends a POST request to the /members endpoint with a given payload. + To learn more about POST requests to Strive's member endpoint, go here: + https://developers.strivemessaging.org/#tag/members/paths/~1members/post + + """ + + # Send the POST request + response = self.client.post_request(data=json.dumps(payload)) + + # Convert the API response to a Parsons Table object + table = Table(response) + return table + + def get_incoming_messages(self, **kwargs): + """ + Sends a GET request to the /incoming_messages endpoint with specified parameters, + and returns the response in a Table object. + + The Strive connector uses horizontal filtering. You can learn more about + horizontal filtering here: https://postgrest.org/en/stable/references/api/tables_views.html#horizontal-filtering-rows + + For example, if you want to filter on a specific `campaign_id`, you would pass `eq.12345` to the `campaign_id` param + where `12345` is the campaign id. + + `Args:` + id: string + The ID of the incoming message + campaign_id: string + The campaign associated with the outgoing message + member_id: string + The member targeted by the outgoing message + from_number: string + The member's phone number + to_number: string + The phone number the member targeted + message: string + The contents of the outgoing message + attachments: string + The attachement, or MMS included in the incoming message + sent_at: string + When the outgoing message was sent + is_opt_out: string + Whether or not the message was registerted as a request to unsubscribe from further messages + updated_at: string + When the message was updated + conversation_id: string + The id of the conversation that this message belongs to + flow_id: string + The flow that the message belongs to + step_idx: string + The step in the flow this message corresponds to + response_to_id: string + The id of the broadcast the incoming message was a response to + select: str + Filtering Columns + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /p2ps endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "outgoing_messages") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table def get_broadcasts_groups(self, **kwargs): """ - Sends a GET request to the /broadcasts endpoint with specified parameters, + Sends a GET request to the /broadcasts_groups endpoint with specified parameters, and returns the response in a Table object. `Args:` broadcast_id: int The ID of the Broadcast - group_id: int + group_id: int The ID of the group of members targeted by the broadcast updated_at: str string @@ -370,6 +449,136 @@ def get_broadcasts_groups(self, **kwargs): table = Table(response) return table + def get_campaigns(): + """ + Sends a GET request to the /campaigns endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: string + The ID of the campaign + primary_text_in_number: string + The phone number new supporters can text to become a member + is_active: string + The status of the campaign's subscription + custom_fields: string + Custom fields added or active to the campaign + organization_id: string + The ID of the parent account, which the campaign is part of + name: string + The name of the campaign + updated_at: string + When the campaign was last updated + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "campaigns") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + + def get_flows(): + """ + Sends a GET request to the /campaigns endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: string + The ID of the flow + campaign_id: string + The campaign associated with the flow + name: string + The name of the flow + created_at: string + When the flow was first created + updated_at: string + When the flow was last updated with a change + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "flows") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + + def get_members_custom_fields(): + """ + Sends a GET request to the /members_custom_fields endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: string + The ID of the custom field associated with a member + field: string + The name of the field in the API + value: string + The value of the field + updated_at: string + When this custom value was updated + campaign_id: string + The campaign the value belongs to + select: str + The fields to include in the response. Use comma-separated values to include multiple fields. + order: str + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: int + The number of records to skip before returning results. + limit: int + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "members_custom_fields") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + def get_broadcasts(): """ Sends a GET request to the /broadcasts endpoint with specified parameters, @@ -378,7 +587,7 @@ def get_broadcasts(): `Args:` id: int The ID of the Broadcast - user_id: int + user_id: int The Strive user who sent the broadcast campaign_id: int The campaign that the broadcast belongs to @@ -390,7 +599,7 @@ def get_broadcasts(): The content of the first message sent in the broadcast attachment: str The attachment or MMS included in the broadcast - recipient_count: int + recipient_count: int How many members were targeted for the broadcast scheduled_at: str When the broadcast is scheduled to send @@ -428,9 +637,10 @@ def get_broadcasts(): table = Table(response) return table + # Testing # strive = Strive() # strive.get_members(first_name = 'eq.brittany') -#in the docs, youw ant to pass params like this, here is an example. -# then add link to their documentation \ No newline at end of file +# in the docs, youw ant to pass params like this, here is an example. +# then add link to their documentation From 5309113eae4f19f9ff02c4d21865bc29111270d7 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 13:59:46 -0400 Subject: [PATCH 16/35] add get members links endpoint --- parsons/strive/strive.py | 94 ++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index c2c4cde101..eefa91379f 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -585,39 +585,39 @@ def get_broadcasts(): and returns the response in a Table object. `Args:` - id: int + id: string The ID of the Broadcast - user_id: int + user_id: string The Strive user who sent the broadcast - campaign_id: int + campaign_id: string The campaign that the broadcast belongs to - flow_id: int + flow_id: string The flow that was broadcasted - name: str + name: string The name of the Broadcast - message: str + message: string The content of the first message sent in the broadcast - attachment: str + attachment: string The attachment or MMS included in the broadcast - recipient_count: int + recipient_count: string How many members were targeted for the broadcast - scheduled_at: str + scheduled_at: string When the broadcast is scheduled to send - cancelled_at: str + cancelled_at: string When the broadcast was cancelled - sent_at: str + sent_at: string When the broadcast began to deliver - created_at: str + created_at: string When the broadcast was first created - updated_at: str + updated_at: string When the broadcast was last updated - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -637,6 +637,66 @@ def get_broadcasts(): table = Table(response) return table + def get_members_links(): + """ + Sends a GET request to the /members_links endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: string + The ID of the member_link + link_id: string + The link this member_link references + member_id: string + The member the link was sent to + outgoing_message_id: string + The outgoing message in which this link was sent + broadcast_id: string + The broadcast in which this link was sent + url: string + The url that the trackable link directed to + was_visited: string + Whether or not the member visited the link + created_at: string + When the link was sent to the member + updated_at: string + When the link was last updated + visited_at: string + When the member visited the link + crawled_at: string + When an automated process visited the link + user_agent: string + The user agent string recorded when the link was visited + visitor_ip: string + The IP address recorded when the link was visited + campaign_id: string + The campaign this link belongs to + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "members_links") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() From 05479067539fa1334501200c8ea015b41823e45d Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:04:57 -0400 Subject: [PATCH 17/35] added groups endpoint --- parsons/strive/strive.py | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index eefa91379f..9984a50dfa 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -697,6 +697,58 @@ def get_members_links(): table = Table(response) return table + def get_groups(): + """ + Sends a GET request to the /groups endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: string + The ID of the group + name: string + The name of the group + campaign_id: string + The campaign associated with the group + created_at: string + The outgoing messagWhen the group was first created + updated_at: string + When the group was last updated with a change + keyword: string + The keyword that, when used by members, adds members to the group + synonyms: string + The synonyms of the keyword that, when used by members, adds members to the group + flow_id: string + The flow that is sent to members when they join the group + groupable_type: string + The type of attribute or relationship on which members are added to the group + groupable_id: string + The identifier of the attribute or relationship on which members are added to the group + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "groups") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() From db680b44574234c4ab4bfa6b6ad7a2c64532f7d0 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:06:42 -0400 Subject: [PATCH 18/35] add organizations endpoint --- parsons/strive/strive.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 9984a50dfa..f0c36448a2 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -749,6 +749,42 @@ def get_groups(): table = Table(response) return table + def get_organizations(): + """ + Sends a GET request to the /organizations endpoint with specified parameters, + and returns the response in a Table object. + + `Args:` + id: string + The ID of the organization + name: string + The name of the organization + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "organizations") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() From 60f1a69b618045563d88c4c6f71fc6e94c52adfa Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:09:54 -0400 Subject: [PATCH 19/35] add member delete log --- parsons/strive/strive.py | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index f0c36448a2..21dbb82a23 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -785,6 +785,56 @@ def get_organizations(): table = Table(response) return table + def get_member_group_delete_log(): + """ + Sends a GET request to the /member_group_delete_log endpoint with specified parameters, + and returns the response in a Table object. this endpoint represents an organization's records on when members are removed from groups + + `Args:` + group_id: string + The ID of the organization + campaign_id: string + The campaign associated with the group and member + member_id: string + The member that has been removed + member_added_on: string + Date that the member was added to the group + delete_source: string + The general source of the member being removed from the group + delete_source_id: string + The id of the source of the member group removal if there is one + removed_by: string + The admin/orgainzer that removed the member of the group if there was + member_removed_on: string + Date that the member was removed from the group + name: string + The name of the organization + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "member_group_delete_log") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() From 8bdbd0e3893067a36f2112cce17b2c9c56714c04 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:17:09 -0400 Subject: [PATCH 20/35] added call logs endpoint --- parsons/strive/strive.py | 83 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 21dbb82a23..c38b53e274 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -835,6 +835,89 @@ def get_member_group_delete_log(): table = Table(response) return table + def get_call_logs(): + """ + Sends a GET request to the /call_logs endpoint with specified parameters, + and returns the response in a Table object. This endpoint represents each call queued or connected through the campaign. + + `Args:` + id: string + The ID of the call log + campaign_id: string + The ID of the campaign for which the call was connected + member_id: string + The ID of the member for whom the call was connected + call_target_id: string + The ID of the call target + bot_conversation_id: string + The ID of the bot conversation from which the call, or call invitation, was dispatched + call_number_id: string + The ID of the call number + from_number: string + The number of the member for whom the call was connected + to_number: string + The number to which the call was connected + machine_detected: string + Whether an answering machine was detected after connecting to the target + successful_connection: string + Whether a successful connection was made to the member + created_at: string + When the target was first looked up and the call queued + connected_at: string + When the call connected to the member + redirected_at: string + When the call redirected to the target + ended_at: string + When the call ended + updated_at: string + flow_id: string + The flow of which this call was a part + step_idx: string + The step of the flow in which this call took place + office: string + The office of the target contacted + state: string + The state in which the target exists + party: string + The party of the target + name: string + The name of the target + member_voicemail_answered_at: string + The time at which the voicemail of the member picked up + member_call_failed_at: string + The time at which the call to the member failed + target_call_failed_at: string + The time at which the call to the target failed + last_event: string + The status of the call based on last event recorded + broadcast_id: string + The broadcast in which the call was made + call_number: string + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "call_logs") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table # Testing # strive = Strive() From 2d126c179b4486d93af7e2aa2f00ea2df2a82805 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:21:42 -0400 Subject: [PATCH 21/35] add member change log endpoint --- parsons/strive/strive.py | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index c38b53e274..fcf5329716 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -919,6 +919,54 @@ def get_call_logs(): table = Table(response) return table + def get_mmeber_change_log(self, **kwargs): + """ + Sends a GET request to the /member_change_log endpoint with specified parameters, + and returns the response in a Table object. This endpoint represents Organization's change data as it relates to member fields. + + `Args:` + member_id: string + The ID of the member + campaign_id: string + The campaign associated with the member + change_action: string + The action that changed the previous value to the new value + previous_value: string + The previous value for the field(s) denoted in the object + new_value: string + The new value for the field(s) denoted in the object + change_type: string + The source of the member change + change_value: string + The value of the source of the member change + updated_at: string + The date and time at which this member value was created + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "member_change_log") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() # strive.get_members(first_name = 'eq.brittany') From 0d9291ba0e8d19499d9004626dfcbf10d75d54ec Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:25:23 -0400 Subject: [PATCH 22/35] add enhanced_member_data endpoint --- parsons/strive/strive.py | 55 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index fcf5329716..122d7aff6d 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -919,7 +919,7 @@ def get_call_logs(): table = Table(response) return table - def get_mmeber_change_log(self, **kwargs): + def get_member_change_log(self, **kwargs): """ Sends a GET request to the /member_change_log endpoint with specified parameters, and returns the response in a Table object. This endpoint represents Organization's change data as it relates to member fields. @@ -967,6 +967,59 @@ def get_mmeber_change_log(self, **kwargs): table = Table(response) return table + def get_enhanced_member_data(self, **kwargs): + """ + Sends a GET request to the /enhanced_member_data endpoint with specified parameters, + and returns the response in a Table object. This endpoint represents organization's member data populated through Strive automations + + `Args:` + id: string + member_id: string + The ID of the member + campaign_id: string + The campaign associated with the member + federal_house_district: string + The federal district for the member + state_upper_chamber_district: string + The district of the upper state chamber + state_lower_chamber_district: string + The district of the lower state chamber + created_at: string + When this member's Strive data was first populated + updated_at: string + The last time we updated a member's automated data + federal_representative: string + The member's federal representative + federal_senator_one: string + One member's federal senator + federal_senator_two: string + The other federal senator for the member + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "enhanced_member_data") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() # strive.get_members(first_name = 'eq.brittany') From 587da89d95fa5076bdd922017a6228d3e7a4495a Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:31:31 -0400 Subject: [PATCH 23/35] add flow actions endpoint --- parsons/strive/strive.py | 51 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 122d7aff6d..0c528c856d 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -1020,6 +1020,57 @@ def get_enhanced_member_data(self, **kwargs): table = Table(response) return table + def get_flow_actions(self, **kwargs): + """ + Sends a GET request to the /flow_actions endpoint with specified parameters, + and returns the response in a Table object. This endpoint represents actions taken by members when interacting with flows + + `Args:` + id: string + flow_id: string + The flow associated with the action + member_id: string + The member who took the action + incoming_message_id: string + The message the member responded wtih + step_number: string + The position of the message within the flow sequence + is_response_valid: string + Whether or not the member's response was successfully qualified + collected_value: string + The data successfully parsed and mapped by the flow's "Collect" + created_at: string + When the flow action occurred + updated_at: string + When the flow action was updated, usually the same as created + campaign_id: string + The campaign the flow action belongs to + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "flow_actions") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() # strive.get_members(first_name = 'eq.brittany') From 92605046166586c45984800d2d93fb551b083f5e Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:35:05 -0400 Subject: [PATCH 24/35] add group members endpoint --- parsons/strive/strive.py | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 0c528c856d..55cf0d0a0d 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -1071,6 +1071,51 @@ def get_flow_actions(self, **kwargs): table = Table(response) return table + def get_group_members(self, **kwargs): + """ + Sends a GET request to the /groups_members endpoint with specified parameters, + and returns the response in a Table object. This endpoint represents members in a group. + + `Args:` + member_id: string + The ID of the member + group_id: string + The ID of ther group + created_at: string > + When the group membership was created + updated_at: string > + When the group membership was updated + organizer_ids: string + campaign_id: string + The campaign that the group and member belong to + user_id: string + The ID of the user that added the member to the group + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "groups_members") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table + # Testing # strive = Strive() # strive.get_members(first_name = 'eq.brittany') From d2919324331959aefd7ea593dd3ea8ad9d6fec1b Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:38:19 -0400 Subject: [PATCH 25/35] add flow steps endpoint --- parsons/strive/strive.py | 48 +++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 55cf0d0a0d..9387ac2558 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -1116,9 +1116,47 @@ def get_group_members(self, **kwargs): table = Table(response) return table -# Testing -# strive = Strive() -# strive.get_members(first_name = 'eq.brittany') + def get_flow_steps(self, **kwargs): + """ + Sends a GET request to the /flow_steps endpoint with specified parameters, + and returns the response in a Table object. This endpoint represents the steps within a flow sequence + + `Args:` + flow_id: string + The flow associated with the flow step + step_number: string + The position of the flow step within the larger flow sequence + type: string > + The type of the step, typically one of these three types: Simple, Collect Info, or Ask A Question type + message: string + The content of the message inlcuded in the flow step + updated_at: string + When this flow was last updated + campaign_id: string + The campaign the flow step belongs to + select: string + The fields to include in the response. Use comma-separated values to include multiple fields. + order: string + The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. + offset: string + The number of records to skip before returning results. + limit: string + The maximum number of records to return. + + `Returns:` + parsons.Table: A Parsons Table object containing the response data from the /broadcasts endpoint. + + `Raises:` + ValueError: If any of the filter parameters have an invalid data type. + """ + + # Build URL + full_url = self.build_url(kwargs, "flow_steps") + + # Send the GET request + response = self.client.get_request(url=full_url) + + # Process the response + table = Table(response) + return table -# in the docs, youw ant to pass params like this, here is an example. -# then add link to their documentation From c83acf65fbbe6fb7f8852c417fd7a813c53b0981 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 19 Jun 2023 14:44:33 -0400 Subject: [PATCH 26/35] fix some types --- parsons/strive/strive.py | 110 +++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 9387ac2558..ce809dafef 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -52,33 +52,33 @@ def get_p2ps(self, **kwargs): `Args:` - id: int + id: string The ID of the P2P message. - user_id: int + user_id: string The ID of the user who created the P2P message. - campaign_id: int + campaign_id: string The ID of the campaign that the P2P message is associated with. - message: str + message: string The text content of the P2P message. - attachment: str + attachment: string A URL to an attachment that was sent with the P2P message. - scheduled_at: str + scheduled_at: string The date and time that the P2P message is scheduled to be sent. - cancelled_at: str + cancelled_at: string The date and time that the P2P message was cancelled, if applicable. - sent_at: str + sent_at: string The date and time that the P2P message was sent, if applicable. - created_at: str + created_at: string The date and time that the P2P message was created. - updated_at: str + updated_at: string The date and time that the P2P message was last updated. - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -110,23 +110,23 @@ def get_custom_fields(self, **kwargs): where `12345` is the campaign id. `Args:` - campaign_id: int + campaign_id: string The ID of the campaign that the P2P message is associated with. - field: str + field: string The name of the field within the API - label: str + label: string The name of the field within the product - type: str + type: string The type of field the custom field is - updated_at: str + updated_at: string The date and time that the P2P message was last updated. - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -179,13 +179,13 @@ def get_outgoing_messages(self, **kwargs): When the outgoing message was sent queued_at: string When the outgoing message was added to our aggregators queue - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -233,13 +233,13 @@ def get_subscription_events(self, **kwargs): Whether the member has been unsubscribed campaign_id: string The ID of the campaign associated with this event - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -301,13 +301,13 @@ def get_members(self, **kwargs): The mobile carrier this member uses first_sub_id: string The ID of the first subscription event retained for the member - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -383,13 +383,13 @@ def get_incoming_messages(self, **kwargs): The step in the flow this message corresponds to response_to_id: string The id of the broadcast the incoming message was a response to - select: str + select: string Filtering Columns - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -423,13 +423,13 @@ def get_broadcasts_groups(self, **kwargs): string campaign_id: int The campaign that the broadcast belongs to - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -469,13 +469,13 @@ def get_campaigns(): The name of the campaign updated_at: string When the campaign was last updated - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -511,13 +511,13 @@ def get_flows(): When the flow was first created updated_at: string When the flow was last updated with a change - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` @@ -553,13 +553,13 @@ def get_members_custom_fields(): When this custom value was updated campaign_id: string The campaign the value belongs to - select: str + select: string The fields to include in the response. Use comma-separated values to include multiple fields. - order: str + order: string The field to use for sorting the response. Use a minus sign (-) prefix to sort in descending order. - offset: int + offset: string The number of records to skip before returning results. - limit: int + limit: string The maximum number of records to return. `Returns:` From 61a10e35d5843d472a0c80e537980461d30209c3 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Wed, 21 Jun 2023 10:11:23 -0400 Subject: [PATCH 27/35] add test file --- test/test_strive/test_strive.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index f70940e89c..5ce8034a61 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -15,7 +15,7 @@ def test_get_members_with_first_name(self): # Mock the GET request method to return the mock response with patch.object(self.strive, "get_members", return_value=mock_response): # Call the get_members method with the first_name parameter - result = self.strive.get_members(first_name="brittany") + result = self.strive.get_members(first_name="eq.brittany") # Verify that the result is a Table object assert isinstance(result, Table) # Verify that the result contains the expected data @@ -28,7 +28,7 @@ def test_get_members_with_last_name(self): # Mock the GET request method to return the mock response with patch.object(self.strive, "get_members", return_value=mock_response): # Call the get_members method with the first_name parameter - result = self.strive.get_members(first_name="bennett") + result = self.strive.get_members(first_name="eq.bennett") # Verify that the result is a Table object assert isinstance(result, Table) # Verify that the result contains the expected data From 07b5edda03b33f0716c7f753ce83fd306928c2e3 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Tue, 11 Jul 2023 11:23:07 -0400 Subject: [PATCH 28/35] outlined mock tests --- parsons/strive/strive.py | 2 +- test/test_strive/strive_test_data.py | 3 +- test/test_strive/test_strive.py | 63 ++++++++++++++-------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index ce809dafef..9e314890be 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -337,7 +337,7 @@ def post_members(self, payload): """ # Send the POST request - response = self.client.post_request(data=json.dumps(payload)) + response = self.client.post_request(data=payload) # Convert the API response to a Parsons Table object table = Table(response) diff --git a/test/test_strive/strive_test_data.py b/test/test_strive/strive_test_data.py index 8959d1b23a..967d9e66a5 100644 --- a/test/test_strive/strive_test_data.py +++ b/test/test_strive/strive_test_data.py @@ -1,5 +1,6 @@ from parsons import Table -get_members_expected_output = Table({ + +mock_member_data = Table({ "id": 252025504, "campaign_id": 558, "phone_number": "+1234567891", diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index 5ce8034a61..3a9c777656 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -1,37 +1,36 @@ -from parsons import Strive -import pytest import unittest -import strive_test_data -from parsons import Table -from unittest.mock import patch +from parsons import Table, Connector +import os +import requests_mock +from strive_test_data import mock_member_data +class TestConnector(unittest.TestCase): -class TestStrive(unittest.TestCase): - def setUp(self): - self.strive = Strive() + self.api_key = os.environ["STRIVE_KEY"] + self.connector = Connector(api_key=self.api_key) + + def tearDown(self): + pass - def test_get_members_with_first_name(self): - mock_response = strive_test_data.get_members_expected_output - # Mock the GET request method to return the mock response - with patch.object(self.strive, "get_members", return_value=mock_response): - # Call the get_members method with the first_name parameter - result = self.strive.get_members(first_name="eq.brittany") - # Verify that the result is a Table object - assert isinstance(result, Table) - # Verify that the result contains the expected data - expected_data = [{"id": 252025504, "first_name": "brittany", "last_name": "bennett", "phone_number": "+1234567891"}] - assert result.columns == ['id', 'first_name', 'last_name', 'phone_number'] - assert result.data == expected_data + @requests_mock.Mocker() + def test_get_members(self, m): + m.get(self.base_uri + '/members', json=mock_member_data) + result = self.connector.get_members(params={'first_name' : 'brittany'}) + + + # want to make sure that each of the functions being called is + # using the correct URL + + # Want to be sure that Auth is being sent in the header + + # PARAMS are being passed through correctly + # want to assert proper auth + # want to assert structure of request + + # What happens if you don't have the correct environment variables + # if you don't have an API key + + # have the same test per function -- fail if the URLs ont heir end change + - def test_get_members_with_last_name(self): - mock_response = strive_test_data.get_members_expected_output - # Mock the GET request method to return the mock response - with patch.object(self.strive, "get_members", return_value=mock_response): - # Call the get_members method with the first_name parameter - result = self.strive.get_members(first_name="eq.bennett") - # Verify that the result is a Table object - assert isinstance(result, Table) - # Verify that the result contains the expected data - expected_data = [{"id": 252025504, "first_name": "brittany", "last_name": "bennett", "phone_number": "+1234567891"}] - assert result.columns == ['id', 'first_name', 'last_name', 'phone_number'] - assert result.data == expected_data + \ No newline at end of file From 8ed78105eb35c32b139117317c27453d428a7bce Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Wed, 19 Jul 2023 09:58:37 -0400 Subject: [PATCH 29/35] first test --- test/test_strive/strive_test_data.py | 4 ++-- test/test_strive/test_strive.py | 36 +++++++++++++++------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/test/test_strive/strive_test_data.py b/test/test_strive/strive_test_data.py index 967d9e66a5..a5bee10db5 100644 --- a/test/test_strive/strive_test_data.py +++ b/test/test_strive/strive_test_data.py @@ -1,6 +1,6 @@ from parsons import Table -mock_member_data = Table({ +mock_member_data = [{ "id": 252025504, "campaign_id": 558, "phone_number": "+1234567891", @@ -21,4 +21,4 @@ {"id": 555505, "name": "Election 2022 Countdown"}, ], "carrier": "Verizon", -}) \ No newline at end of file +}] \ No newline at end of file diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index 3a9c777656..5b700f7b4f 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -1,36 +1,38 @@ import unittest -from parsons import Table, Connector +from parsons import Table, Strive import os import requests_mock from strive_test_data import mock_member_data +from test.utils import assert_matching_tables class TestConnector(unittest.TestCase): def setUp(self): - self.api_key = os.environ["STRIVE_KEY"] - self.connector = Connector(api_key=self.api_key) + self.api_key = os.environ["STRIVE_SANDBOX_KEY"] + self.connector = Strive(api_key=self.api_key) + self.base_uri = "https://api.strivedigital.org" def tearDown(self): pass - + @requests_mock.Mocker() def test_get_members(self, m): m.get(self.base_uri + '/members', json=mock_member_data) - result = self.connector.get_members(params={'first_name' : 'brittany'}) - - - # want to make sure that each of the functions being called is - # using the correct URL - - # Want to be sure that Auth is being sent in the header + response = self.connector.get_members() + assert m.called == True + assert_matching_tables(response, Table(mock_member_data)) + + # Want to be sure that Auth header is being passed correctly # PARAMS are being passed through correctly - # want to assert proper auth - # want to assert structure of request - - # What happens if you don't have the correct environment variables - # if you don't have an API key + # pass in params and assert that those were passed in correctly + # asserting response.params == params, check mock requests documentation + # + # Live tests + # Instead of asserting table values + # + # User validate_list to assert that live tests return right data + # - # have the same test per function -- fail if the URLs ont heir end change \ No newline at end of file From 2ea3e014ff7f518d2097a38f86e866416f8d3a61 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Wed, 19 Jul 2023 09:59:12 -0400 Subject: [PATCH 30/35] first test --- parsons/strive/strive.py | 122 +++++++-------------------------------- 1 file changed, 22 insertions(+), 100 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 9e314890be..6efe66646b 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -21,20 +21,6 @@ def __init__(self, api_key=None): } self.client = APIConnector(self.uri, headers=self.headers) - def build_url(self, params, endpoint): - """ - Takes a set of parameters and an API endpoint and builds a URL using horizontal - filter rules. - """ - # Build the query string for the URL - query_string = "&".join([f"{key}={value}" for key, value in params.items()]) - - # Build the full URL with the query string - url = endpoint - full_url = f"{url}?{query_string}" - - return full_url - def get_p2ps(self, **kwargs): """ Sends a GET request to the /p2ps endpoint with specified parameters, @@ -88,11 +74,8 @@ def get_p2ps(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "p2ps") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="p2ps", params=kwargs) # Process the response table = Table(response) @@ -135,11 +118,9 @@ def get_custom_fields(self, **kwargs): `Raises:` ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "custom_fields") # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request("custom_fields", params=kwargs) # Process the response table = Table(response) @@ -194,12 +175,8 @@ def get_outgoing_messages(self, **kwargs): `Raises:` ValueError: If any of the filter parameters have an invalid data type. """ - - # Build URL - full_url = self.build_url(kwargs, "outgoing_messages") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request("outgoing_messages", params=kwargs) # Process the response table = Table(response) @@ -249,11 +226,8 @@ def get_subscription_events(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "subscription_events") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request("subscription_events", params=kwargs) # Process the response table = Table(response) @@ -318,12 +292,9 @@ def get_members(self, **kwargs): """ - # Build URL - full_url = self.build_url(kwargs, "members") - # Send the GET request - response = self.client.get_request(url=full_url) - + response = self.client.get_request(url="members", params=kwargs) + # Convert the API response to a Parsons Table object table = Table(response) return table @@ -399,11 +370,8 @@ def get_incoming_messages(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "outgoing_messages") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="outgoing_messages", params=kwargs) # Process the response table = Table(response) @@ -439,11 +407,8 @@ def get_broadcasts_groups(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "broadcast_groups") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="broadcast_groups", params=kwargs) # Convert the API response to a Parsons Table object table = Table(response) @@ -485,11 +450,8 @@ def get_campaigns(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "campaigns") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="campaigns", params=kwargs) # Process the response table = Table(response) @@ -527,11 +489,8 @@ def get_flows(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "flows") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="flows", params=kwargs) # Process the response table = Table(response) @@ -569,11 +528,8 @@ def get_members_custom_fields(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "members_custom_fields") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="members_custom_fields", params=kwargs) # Process the response table = Table(response) @@ -627,11 +583,8 @@ def get_broadcasts(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "broadcasts") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="broadcasts", params=kwargs) # Process the response table = Table(response) @@ -687,11 +640,8 @@ def get_members_links(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "members_links") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="members_links", params=kwargs) # Process the response table = Table(response) @@ -739,11 +689,8 @@ def get_groups(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "groups") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="groups", params=kwargs) # Process the response table = Table(response) @@ -775,11 +722,8 @@ def get_organizations(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "organizations") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="organizations", params=kwargs) # Process the response table = Table(response) @@ -825,11 +769,8 @@ def get_member_group_delete_log(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "member_group_delete_log") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="member_group_delete_log", params=kwargs) # Process the response table = Table(response) @@ -909,11 +850,8 @@ def get_call_logs(): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "call_logs") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="call_logs", params=kwargs) # Process the response table = Table(response) @@ -957,11 +895,8 @@ def get_member_change_log(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "member_change_log") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="member_change_log", params=kwargs) # Process the response table = Table(response) @@ -1010,11 +945,8 @@ def get_enhanced_member_data(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "enhanced_member_data") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="enhanced_member_data", params=kwargs) # Process the response table = Table(response) @@ -1061,11 +993,8 @@ def get_flow_actions(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "flow_actions") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="flow_actions", params=kwargs) # Process the response table = Table(response) @@ -1106,11 +1035,8 @@ def get_group_members(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "groups_members") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="groups_members", params=kwargs) # Process the response table = Table(response) @@ -1150,13 +1076,9 @@ def get_flow_steps(self, **kwargs): ValueError: If any of the filter parameters have an invalid data type. """ - # Build URL - full_url = self.build_url(kwargs, "flow_steps") - # Send the GET request - response = self.client.get_request(url=full_url) + response = self.client.get_request(url="flow_steps", params=kwargs) # Process the response table = Table(response) return table - From 24e6279e2c625a714c8b90c7a9bb1adb05fc18b7 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Fri, 21 Jul 2023 15:21:18 -0400 Subject: [PATCH 31/35] stopping point --- test/test_strive/test_strive.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index 5b700f7b4f..48cc295785 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -16,10 +16,16 @@ def tearDown(self): @requests_mock.Mocker() def test_get_members(self, m): - m.get(self.base_uri + '/members', json=mock_member_data) + headers = {'Authorization': 'Bearer test'} + m.get(self.base_uri + '/members', json=mock_member_data, headers=headers) response = self.connector.get_members() + history = m.request_history[0] + import pytest; pytest.set_trace() + print(history) assert m.called == True assert_matching_tables(response, Table(mock_member_data)) + assert "Bearer test" == history.headers.get("Authorization") + # Want to be sure that Auth header is being passed correctly From 8169e87ba44d14c3b3b3022a89e446bd9c0efb60 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Sat, 22 Jul 2023 14:51:31 -0400 Subject: [PATCH 32/35] param test returning empty dictionary --- test/test_strive/test_strive.py | 40 ++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index 48cc295785..e338707f3e 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -1,4 +1,5 @@ import unittest +from parsons.utilities.api_connector import APIConnector from parsons import Table, Strive import os import requests_mock @@ -16,28 +17,35 @@ def tearDown(self): @requests_mock.Mocker() def test_get_members(self, m): - headers = {'Authorization': 'Bearer test'} - m.get(self.base_uri + '/members', json=mock_member_data, headers=headers) + m.get(self.base_uri + '/members', json=mock_member_data) response = self.connector.get_members() - history = m.request_history[0] - import pytest; pytest.set_trace() - print(history) + history = m.request_history[0] # Get the first (and only) request made + # Assert that a get request was made + self.assertEqual(history.method, 'GET') + # Assert mock object has been called assert m.called == True + # Assert mock data was successfully passed and retrieved assert_matching_tables(response, Table(mock_member_data)) - assert "Bearer test" == history.headers.get("Authorization") + # Assert headers passed correctly + assert f"Bearer {self.api_key}" == history.headers.get("Authorization") + + # Define the data to be returned by the mock request + m.get(self.base_uri + '/members', json=mock_member_data) + # Call the function that makes the HTTP request (replace get_members with the actual function name) + response = self.connector.get_members(first_name='eq.brittany', city='eq.Pittsburgh') + import pytest; pytest.set_trace() + history = m.request_history[0] + assert history.qs == {'first_name':'eq.brittany', 'city': 'eq.Pittsburgh'} + + + + + + - # Want to be sure that Auth header is being passed correctly - # PARAMS are being passed through correctly - # pass in params and assert that those were passed in correctly - # asserting response.params == params, check mock requests documentation - # - # Live tests - # Instead of asserting table values - # - # User validate_list to assert that live tests return right data - # + From 044d839e3b94b48f0f3f40ebbe5e8d286e74f74e Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Sat, 22 Jul 2023 15:20:47 -0400 Subject: [PATCH 33/35] one set of tests for a function --- test/test_strive/test_strive.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index e338707f3e..e6168d3a06 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -19,7 +19,7 @@ def tearDown(self): def test_get_members(self, m): m.get(self.base_uri + '/members', json=mock_member_data) response = self.connector.get_members() - history = m.request_history[0] # Get the first (and only) request made + history = m.request_history[0] # Get the first request made # Assert that a get request was made self.assertEqual(history.method, 'GET') # Assert mock object has been called @@ -28,16 +28,12 @@ def test_get_members(self, m): assert_matching_tables(response, Table(mock_member_data)) # Assert headers passed correctly assert f"Bearer {self.api_key}" == history.headers.get("Authorization") - - - # Define the data to be returned by the mock request - m.get(self.base_uri + '/members', json=mock_member_data) - # Call the function that makes the HTTP request (replace get_members with the actual function name) + # Mock a request with params, asser that params were passed successfully + m.get(self.base_uri + '/members?first_name=eq.brittany&city=eq.pittsburgh', json=mock_member_data) response = self.connector.get_members(first_name='eq.brittany', city='eq.Pittsburgh') - import pytest; pytest.set_trace() - history = m.request_history[0] - assert history.qs == {'first_name':'eq.brittany', 'city': 'eq.Pittsburgh'} + history = m.request_history[1] # Get the second request made + assert history.qs == {'first_name':['eq.brittany'], 'city': ['eq.pittsburgh']} From 26d5b193c654eb8a436de310089c8b620fae220a Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 24 Jul 2023 12:14:45 -0400 Subject: [PATCH 34/35] working post tests --- test/test_strive/test_strive.py | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/test_strive/test_strive.py b/test/test_strive/test_strive.py index e6168d3a06..3a74d15b74 100644 --- a/test/test_strive/test_strive.py +++ b/test/test_strive/test_strive.py @@ -5,6 +5,10 @@ import requests_mock from strive_test_data import mock_member_data from test.utils import assert_matching_tables +from test.utils import mark_live_test +import pandas as pd +import json + class TestConnector(unittest.TestCase): def setUp(self): @@ -35,6 +39,39 @@ def test_get_members(self, m): history = m.request_history[1] # Get the second request made assert history.qs == {'first_name':['eq.brittany'], 'city': ['eq.pittsburgh']} + @mark_live_test + def test_get_members_live_test(self): + # Test filtering on first name + response = self.connector.get_members(first_name='eq.Rudolph') + assert (response.to_dataframe()["first_name"] == 'Rudolph').all() + + # Test that selecting for opt_in=True returns only subscribed members + response = self.connector.get_members(opt_in='eq.True') + self.assertTrue(all(response.to_dataframe()["opt_in"])) + + # Test filtering on NULL values + response = self.connector.get_members(email='eq.') + assert (response.to_dataframe()["email"] == '').all() + + @requests_mock.Mocker() + def test_post_members(self, m): + mock_member_payload = { + "phone_number": "+15555555555", + "campaign_id": 273, + "first_name": "Lucy", + "last_name": "Parsons" + } + m.post(self.base_uri + '/members', json=mock_member_payload) + response = self.connector.post_members(data=mock_member_payload) + history = m.request_history[0] # Get the first request made + # Assert that a get request was made + self.assertEqual(history.method, 'POST') + # Assert mock object has been called + assert m.called == True + import pytest; pytest.set_trace() + + + From 3e841e7a4f31992c9d736cbf61f601f5623e1661 Mon Sep 17 00:00:00 2001 From: Brittany Bennett Date: Mon, 24 Jul 2023 12:15:13 -0400 Subject: [PATCH 35/35] working tests --- parsons/strive/strive.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parsons/strive/strive.py b/parsons/strive/strive.py index 6efe66646b..d023f2a395 100644 --- a/parsons/strive/strive.py +++ b/parsons/strive/strive.py @@ -293,13 +293,13 @@ def get_members(self, **kwargs): """ # Send the GET request - response = self.client.get_request(url="members", params=kwargs) + response = self.client.get_request(url="/members", params=kwargs) # Convert the API response to a Parsons Table object table = Table(response) return table - def post_members(self, payload): + def post_members(self, data): """ Sends a POST request to the /members endpoint with a given payload. To learn more about POST requests to Strive's member endpoint, go here: @@ -308,7 +308,7 @@ def post_members(self, payload): """ # Send the POST request - response = self.client.post_request(data=payload) + response = self.client.post_request(url="/members", data=data) # Convert the API response to a Parsons Table object table = Table(response)