11from parsons .utilities .api_connector import APIConnector
2+ from parsons .utilities .oauth_api_connector import OAuth2APIConnector
23from parsons .utilities import check_env
34from parsons import Table
45import logging
56import time
67
78logger = 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
1214class 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
0 commit comments