Skip to content

Commit

Permalink
Enhance EveryAction activist code handling with caching and improved …
Browse files Browse the repository at this point in the history
…lookup
  • Loading branch information
butkeraites-hotglue committed Jan 29, 2025
1 parent 0221abc commit d6b1cbf
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 11 deletions.
3 changes: 2 additions & 1 deletion target_everyaction/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,14 @@ def validate_response(self, response: requests.Response) -> None:
msg = self.response_error_message(response)
raise FatalAPIError(msg)

def request_api(self, method, request_data, endpoint):
def request_api(self, method, endpoint, request_data=None, params=None):
url = f"{self.base_url}{endpoint}"
LOGGER.info(self.__auth)
response = requests.request(
method,
url,
json=request_data,
params=params,
auth=self.__auth,
headers={"Content-Type": "application/json", "Accept": "application/json"},
)
Expand Down
102 changes: 92 additions & 10 deletions target_everyaction/sinks.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,90 @@ def _get_or_create_code(self, code_payload: dict) -> Optional[str]:
request_data=code_payload)
return response.json() if response.ok else None

def _get_activist_code_id(self, code_name: str) -> Optional[int]:
"""Get existing activist code ID."""
params = {
"statuses": "Active,Archived",
"$top": 200,
"name": code_name
}

response = self.request_api("GET", endpoint="activistCodes", params=params)
while True:
if response.ok:
data = response.json()
# Look for exact match (case-insensitive)
for item in data["items"]:
if item["name"].lower() == code_name.lower():
return item["activistCodeId"]

# Check if there are more pages
if "nextPageLink" not in data:
break
# Extract next page URL and make request
next_page = data["nextPageLink"].split("?")[1]
response = self.request_api("GET", endpoint=f"activistCodes?{next_page}")
else:
break

LOGGER.warning(f"Activist code '{code_name}' not found")
return None

def _get_all_activist_codes(self) -> dict:
"""Get all activist codes and cache them in memory."""
all_codes = {}
params = {
"statuses": "Active,Archived",
"$top": 200
}

response = self.request_api("GET", endpoint="activistCodes", params=params)
while True:
if response.ok:
data = response.json()
# Store codes with lowercase names for case-insensitive lookup
for item in data["items"]:
all_codes[item["name"].lower()] = item["activistCodeId"]

if "nextPageLink" not in data:
break

next_page = data["nextPageLink"].split("?")[1]
response = self.request_api("GET", endpoint=f"activistCodes?{next_page}")
else:
break

return all_codes

def _process_activist_codes(self, person_id: int, code_names: list, cached_codes: dict):
"""Process activist codes for a person."""
missing_codes = []

# Build payload for existing codes
responses = []
for code_name in code_names:
code_id = cached_codes.get(code_name.lower())
if code_id:
responses.append({
"activistCodeId": code_id,
"action": "Apply",
"type": "ActivistCode"
})
else:
missing_codes.append(code_name)
LOGGER.warning(f"Activist code '{code_name}' not found")

# Apply existing codes in a single request if any exist
if responses:
payload = {"responses": responses}
self.request_api(
"POST",
endpoint=f"people/{person_id}/canvassResponses",
request_data=payload
)

return missing_codes

def upsert_record(self, record: dict, context: dict):
method = "POST"
state_dict = dict()
Expand All @@ -113,16 +197,14 @@ def upsert_record(self, record: dict, context: dict):
if hasattr(self, "pending_codes"):
# Activist codes
if self.pending_codes.get("activist"):
for code in self.pending_codes["activist"]:
payload = {
"responses": [{
"activistCodeId": code,
"action": "Apply",
"type": "ActivistCode"
}]
}
self.request_api("POST", endpoint=f"people/{id}/canvassResponses",
request_data=payload)
# Get all activist codes once
cached_codes = self._get_all_activist_codes()
# Process all codes for this person
missing_codes = self._process_activist_codes(
id,
self.pending_codes["activist"],
cached_codes
)

# Handle both Source Codes and Tags
for code_type, codes in self.pending_codes.items():
Expand Down

0 comments on commit d6b1cbf

Please sign in to comment.