Skip to content

Commit 8a45cbb

Browse files
committed
add oauth for v2
1 parent d1ff157 commit 8a45cbb

File tree

2 files changed

+141
-50
lines changed

2 files changed

+141
-50
lines changed

parsons/newmode/newmode.py

Lines changed: 140 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
from parsons.utilities.api_connector import APIConnector
2+
from parsons.utilities.oauth_api_connector import OAuth2APIConnector
23
from parsons.utilities import check_env
34
from parsons import Table
45
import logging
56
import time
67

78
logger = logging.getLogger(__name__)
89

9-
API_URL = "https://engage.newmode.net/api/"
10-
10+
API_URL_V1 = "https://engage.newmode.net/api/"
11+
API_URL_V2 = "https://base.newmode.net/api/"
12+
API_AUTH_URL = 'https://base.newmode.net/oauth/token'
1113

1214
class Newmode(object):
1315
"""
@@ -25,29 +27,34 @@ class Newmode(object):
2527
NewMode Class
2628
"""
2729

28-
def __init__(self, api_user=None, api_password=None, api_version="v1.0"):
29-
self.base_url = check_env.check("NEWMODE_API_URL", API_URL)
30-
self.api_user = check_env.check("NEWMODE_API_USER", api_user)
31-
self.api_password = check_env.check("NEWMODE_API_PASSWORD", api_password)
30+
def __init__(self, api_user=None, api_password=None, client_id=None, client_secret=None, api_version="v1.0"):
3231
self.api_version = check_env.check("NEWMODE_API_VERSION", api_version)
33-
self.headers = {"Content-Type": "application/json"}
34-
self.client = APIConnector(
35-
self.base_url,
36-
auth=(self.api_user, self.api_password),
37-
headers=self.headers,
38-
)
3932

40-
def check_api_version(self, documentation_url="TODO", v1_0=True, v2_1=True):
41-
exception_text = f"Endpoint not supported by API version {self.api_version}"
42-
if self.api_version == "v1.0":
33+
if "v1" in self.api_version:
4334
logger.warning(
44-
"Newmode API v1.0 will no longer be supported starting February 2025."
45-
f"Documentation for v2.1 here: {documentation_url}"
35+
"Newmode API v1 will no longer be supported starting Feburary 2025."
4636
)
47-
if not v1_0:
48-
raise Exception(exception_text)
49-
elif self.api_version == "v2.1" and not v2_1:
50-
raise Exception(exception_text)
37+
self.base_url = API_URL_V1
38+
self.api_user = check_env.check("NEWMODE_API_USER", api_user)
39+
self.api_password = check_env.check("NEWMODE_API_PASSWORD", api_password)
40+
self.headers = {"Content-Type": "application/json"}
41+
self.client = APIConnector(
42+
self.base_url,
43+
auth=(self.api_user, self.api_password),
44+
headers=self.headers,)
45+
else:
46+
self.base_url = API_URL_V2
47+
self.client_id = check_env.check("NEWMODE_API_CLIENT_ID", client_id)
48+
self.__client_secret = check_env.check("NEWMODE_API_CLIENT_SECRET", client_secret)
49+
self.headers = {"content-type": "application/x-www-form-urlencoded"}
50+
self.client = OAuth2APIConnector(
51+
uri=self.base_url,
52+
auto_refresh_url=API_AUTH_URL,
53+
client_id=self.client_id,
54+
client_secret=self.__client_secret,
55+
headers=self.headers,
56+
token_url=API_AUTH_URL,
57+
grant_type="client_credentials",)
5158

5259
def convert_to_table(self, data):
5360
"""Internal method to create a Parsons table from a data element."""
@@ -69,6 +76,8 @@ def base_request(self, method, url, requires_csrf=True, params={}):
6976
response = None
7077
if method == "GET":
7178
response = self.client.get_request(url=url, params=params)
79+
# if "targets" in url:
80+
# response = self.client.get_request(url=url, params=params)['_embedded']['hal:tool']
7281
elif method == "PATCH":
7382
response = self.client.patch_request(url=url, params=params)
7483
# response.get("_embedded", {}).get(f"osdi:{object_name}")
@@ -82,19 +91,18 @@ def converted_request(
8291
supports_version=True,
8392
params={},
8493
convert_to_table=True,
85-
v1_0=True,
86-
v2_1=True,
8794
):
88-
self.check_api_version(v1_0=v1_0, v2_1=v2_1)
8995
url = f"{self.api_version}/{endpoint}" if supports_version else endpoint
9096
response = self.base_request(
9197
method=method, url=url, requires_csrf=requires_csrf, params=params
9298
)
99+
if not response:
100+
logging.warning(f"Empty result returned from endpoint: {endpoint}")
93101
if convert_to_table:
94102
return self.convert_to_table(response)
95103
else:
96104
return response
97-
105+
98106
def get_csrf_token(self, max_retries=10):
99107
"""
100108
Retrieve a CSRF token for making API requests
@@ -104,11 +112,11 @@ def get_csrf_token(self, max_retries=10):
104112
`Returns:`
105113
The CSRF token.
106114
"""
107-
115+
endpoint = "session/token"
108116
for attempt in range(max_retries):
109117
try:
110118
response = self.converted_request(
111-
endpoint="session/token",
119+
endpoint=endpoint,
112120
method="GET",
113121
supports_version=False,
114122
requires_csrf=False,
@@ -128,6 +136,7 @@ def get_csrf_token(self, max_retries=10):
128136

129137
def get_tools(self, params={}):
130138
"""
139+
V1 only
131140
Retrieve all tools
132141
`Args:`
133142
params: dict
@@ -140,6 +149,7 @@ def get_tools(self, params={}):
140149

141150
def get_tool(self, tool_id, params={}):
142151
"""
152+
V1 only
143153
Retrieve a specific tool by ID
144154
`Args:`
145155
tool_id: str
@@ -154,8 +164,9 @@ def get_tool(self, tool_id, params={}):
154164
)
155165
return response
156166

157-
def lookup_targets(self, tool_id, search=None, params={}):
167+
def lookup_targets(self, target_id, search=None, location=None, params={}):
158168
"""
169+
V1 only
159170
Lookup targets for a given tool
160171
`Args:`
161172
tool_id: str
@@ -167,16 +178,19 @@ def lookup_targets(self, tool_id, search=None, params={}):
167178
`Returns:`
168179
Parsons Table containing target data.
169180
"""
170-
endpoint = f"lookup/{tool_id}"
181+
endpoint = f"lookup/{target_id}"
171182
if search:
172183
endpoint += f"/{search}"
184+
if location:
185+
endpoint += f"/{location}"
173186
response = self.converted_request(
174187
endpoint=endpoint, method="GET", params=params
175188
)
176189
return response
177190

178191
def get_action(self, tool_id, params={}):
179192
"""
193+
V1 only
180194
Get action information for a specific tool
181195
`Args:`
182196
tool_id: str
@@ -193,6 +207,7 @@ def get_action(self, tool_id, params={}):
193207

194208
def run_action(self, tool_id, payload, params={}):
195209
"""
210+
V1 only
196211
Run a specific action for a tool
197212
`Args:`
198213
tool_id: str
@@ -208,40 +223,34 @@ def run_action(self, tool_id, payload, params={}):
208223
endpoint=f"action/{tool_id}", method="PATCH", payload=payload, params=params
209224
)
210225
return response
211-
212-
def get_target(self, target_id, params={}):
213-
"""
214-
Retrieve a specific target by ID
215-
`Args:`
216-
target_id: str
217-
The ID of the target to retrieve.
218-
params: dict
219-
Query parameters to include in the request.
220-
`Returns:`
221-
Parsons Table containing target data.
222-
"""
223-
response = self.converted_request(
224-
endpoint=f"target/{target_id}", method="GET", params=params
225-
)
226-
return response
227-
226+
228227
def get_campaigns(self, params={}):
229228
"""
229+
V1 & V2
230230
Retrieve all campaigns
231+
In v2, a campaign is equivalent to Tools or Actions in V1.
231232
`Args:`
232233
params: dict
233234
Query parameters to include in the request.
234235
`Returns:`
235236
Parsons Table containing campaigns data.
236237
"""
238+
if "v1" in self.api_version:
239+
endpoint = "campaign"
240+
else:
241+
self.api_version = "jsonapi"
242+
endpoint = "action/action"
237243
response = self.converted_request(
238-
endpoint="campaign", method="GET", params=params
244+
endpoint=endpoint, method="GET", params=params
239245
)
240246
return response
241247

242248
def get_campaign(self, campaign_id, params={}):
243249
"""
244-
Retrieve a specific campaign by ID
250+
V1 & V2
251+
Retrieve a specific campaign by ID.
252+
253+
In v2, a campaign is equivalent to Tools or Actions in V1.
245254
`Args:`
246255
campaign_id: str
247256
The ID of the campaign to retrieve.
@@ -250,13 +259,16 @@ def get_campaign(self, campaign_id, params={}):
250259
`Returns:`
251260
Parsons Table containing campaign data.
252261
"""
262+
endpoint = f"campaign/{campaign_id}" if "v1" in self.api_version else f"/campaign/{campaign_id}/form"
263+
253264
response = self.converted_request(
254-
endpoint=f"campaign/{campaign_id}", method="GET", params=params
265+
endpoint=endpoint, method="GET", params=params
255266
)
256267
return response
257268

258269
def get_organizations(self, params={}):
259270
"""
271+
V1 only
260272
Retrieve all organizations
261273
`Args:`
262274
params: dict
@@ -271,6 +283,7 @@ def get_organizations(self, params={}):
271283

272284
def get_organization(self, organization_id, params={}):
273285
"""
286+
V1 only
274287
Retrieve a specific organization by ID
275288
`Args:`
276289
organization_id: str
@@ -287,6 +300,7 @@ def get_organization(self, organization_id, params={}):
287300

288301
def get_services(self, params={}):
289302
"""
303+
V1 only
290304
Retrieve all services
291305
`Args:`
292306
params: dict
@@ -301,6 +315,7 @@ def get_services(self, params={}):
301315

302316
def get_service(self, service_id, params={}):
303317
"""
318+
V1 only
304319
Retrieve a specific service by ID
305320
`Args:`
306321
service_id: str
@@ -315,8 +330,24 @@ def get_service(self, service_id, params={}):
315330
)
316331
return response
317332

333+
def get_target(self, target_id, params={}):
334+
"""
335+
V1 only
336+
Get specific target.
337+
`Args:`
338+
params: dict
339+
Query parameters to include in the request.
340+
`Returns:`
341+
Parsons Table containing targets data.
342+
"""
343+
response = self.converted_request(
344+
endpoint=f"target/{target_id}", method="GET", params=params
345+
)
346+
return response
347+
318348
def get_targets(self, params={}):
319349
"""
350+
V1 only
320351
Retrieve all targets
321352
`Args:`
322353
params: dict
@@ -331,6 +362,7 @@ def get_targets(self, params={}):
331362

332363
def get_outreaches(self, tool_id, params={}):
333364
"""
365+
V1 only
334366
Retrieve all outreaches for a specific tool
335367
`Args:`
336368
tool_id: str
@@ -348,6 +380,7 @@ def get_outreaches(self, tool_id, params={}):
348380

349381
def get_outreach(self, outreach_id, params={}):
350382
"""
383+
V1 only
351384
Retrieve a specific outreach by ID
352385
`Args:`
353386
outreach_id: str
@@ -361,3 +394,61 @@ def get_outreach(self, outreach_id, params={}):
361394
endpoint=f"outreach/{outreach_id}", method="GET", params=params
362395
)
363396
return response
397+
398+
def get_recipient(self, campaign_id, params={}):
399+
"""
400+
V2 only
401+
Retrieve a specific recipient by ID
402+
`Args:`
403+
campaign_id: str
404+
The ID of the campaign to retrieve.
405+
params: dict
406+
Query parameters to include in the request.
407+
`Returns:`
408+
Parsons Table containing recipient data.
409+
"""
410+
response = self.converted_request(
411+
endpoint=f"campaign/{campaign_id}/target", method="GET", params=params
412+
)
413+
return response
414+
415+
def run_submit(self, campaign_id, params={}):
416+
"""
417+
V2 only
418+
Pass a submission from a supporter to a campaign
419+
that ultimately fills in a petition,
420+
sends an email or triggers a phone call
421+
depending on your campaign type
422+
423+
`Args:`
424+
campaign_id: str
425+
The ID of the campaign to retrieve.
426+
params: dict
427+
Query parameters to include in the request.
428+
`Returns:`
429+
Parsons Table containing submit data.
430+
"""
431+
response = self.converted_request(
432+
endpoint=f"campaign/{campaign_id}/submit ", method="POST", params=params
433+
)
434+
return response
435+
436+
def get_submissions(self, params={}):
437+
"""
438+
V2 only
439+
Retrieve and sort submission and contact data
440+
for your organization using a range of filters
441+
that include campaign id, data range and submission status
442+
443+
`Args:`
444+
campaign_id: str
445+
The ID of the campaign to retrieve.
446+
params: dict
447+
Query parameters to include in the request.
448+
`Returns:`
449+
Parsons Table containing submit data.
450+
"""
451+
response = self.converted_request(
452+
endpoint="submission", method="POST", params=params
453+
)
454+
return response

parsons/utilities/oauth_api_connector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def __init__(
4141
client_id: str,
4242
client_secret: str,
4343
token_url: str,
44-
auto_refresh_url: Optional[str],
44+
auto_refresh_url: str,
4545
headers: Optional[Dict[str, str]] = None,
4646
pagination_key: Optional[str] = None,
4747
data_key: Optional[str] = None,

0 commit comments

Comments
 (0)