Source code for parsons.actblue.actblue

import logging
import time

from parsons.etl import Table
from parsons.utilities import check_env
from parsons.utilities.api_connector import APIConnector

logger = logging.getLogger(__name__)

POLLING_DELAY = 1
ACTBLUE_API_ENDPOINT = "https://secure.actblue.com/api/v1"


[docs] class ActBlue(object): """ Instantiate class. `Args:` actblue_client_uuid: str The ActBlue provided Client UUID. Not required if ``ACTBLUE_CLIENT_UUID`` env variable set. actblue_client_secret: str The ActBlue provided Client Secret. Not required if ``ACTBLUE_CLIENT_SECRET`` env variable set. actblue_uri: str The URI to access the CSV API. Not required, default is https://secure.actblue.com/api/v1. You can set an ``ACTBLUE_URI`` env variable or use this URI parameter if a different endpoint is necessary - for example, when running this code in a test environment where you don't want to hit the actual API. max_retries: int The maximum number of times to poll the API for a download URL. Not required, default is None, which means it will poll indefinitely until a download URL is returned. ```ACTBLUE_MAX_RETRIES``` env variable can be set, which will override this parameter. For instructions on how to generate a Client UUID and Client Secret set, visit https://secure.actblue.com/docs/csv_api#authentication. """ def __init__( self, actblue_client_uuid=None, actblue_client_secret=None, actblue_uri=None, max_retries=None, ): self.actblue_client_uuid = check_env.check("ACTBLUE_CLIENT_UUID", actblue_client_uuid) self.actblue_client_secret = check_env.check("ACTBLUE_CLIENT_SECRET", actblue_client_secret) self.uri = ( check_env.check("ACTBLUE_URI", actblue_uri, optional=True) or ACTBLUE_API_ENDPOINT ) self.headers = { "accept": "application/json", } self.client = APIConnector( self.uri, auth=(self.actblue_client_uuid, self.actblue_client_secret), headers=self.headers, ) self.max_retries = check_env.check("ACTBLUE_MAX_RETRIES", max_retries, optional=True) self.max_retries = int(self.max_retries) if self.max_retries else None
[docs] def post_request(self, csv_type=None, date_range_start=None, date_range_end=None): """ POST request to ActBlue API to begin generating the CSV. `Args:` csv_type: str Type of CSV you are requesting. Options: 'paid_contributions': contains paid, non-refunded contributions to the entity (campaign or organization) you created the credential for, during the specified date range. 'refunded_contributions': contributions to your entity that were refunded, during the specified date range. 'managed_form_contributions': contributions made through any form that is managed by your entity, during the specified date range - including contributions to other entities via that form if it is a tandem form. date_range_start: str Start of date range to withdraw contribution data (inclusive). Ex: '2020-01-01' date_range_end: str End of date range to withdraw contribution data (exclusive). Ex: '2020-02-01' `Returns:` Response of POST request; a successful response includes 'id', a unique identifier for the CSV being generated. """ body = { "csv_type": csv_type, "date_range_start": date_range_start, "date_range_end": date_range_end, } logger.info(f"Requesting {csv_type} from {date_range_start} up to {date_range_end}.") response = self.client.post_request(url="csvs", json=body) return response
[docs] def get_download_url(self, csv_id=None): """ GET request to retrieve download_url for generated CSV. `Args:` csv_id: str Unique identifier of the CSV you requested. `Returns:` While CSV is being generated, 'None' is returned. When CSV is ready, the method returns the download_url. """ response = self.client.get_request(url=f"csvs/{csv_id}") if response.get("download_url") is None and response.get("status") != "in_progress": raise ValueError("CSV generation failed: %s", response) return response["download_url"]
[docs] def poll_for_download_url(self, csv_id): """ Poll the GET request method to check whether CSV generation has finished, signified by the presence of a download_url. `Args:` csv_id: str Unique identifier of the CSV you requested. `Returns:` Download URL from which you can download the generated CSV, valid for 10 minutes after retrieval. Null until CSV has finished generating. Keep this URL secure because until it expires, it could be used by anyone to download the CSV. """ logger.info("Request received. Please wait while ActBlue generates this data.") download_url = None tries = 0 while download_url is None and (self.max_retries is None or tries < self.max_retries): download_url = self.get_download_url(csv_id) time.sleep(POLLING_DELAY) tries += 1 if download_url is None: raise TimeoutError("CSV generation timed out. Increase max_retries and try again.") logger.info("Completed data generation.") logger.info("Beginning conversion to Parsons Table.") return download_url
[docs] def get_contributions(self, csv_type, date_range_start, date_range_end, **csvargs): """ Get specified contribution data from CSV API as Parsons table. `Args:` csv_type: str Type of CSV you are requesting. Options: 'paid_contributions': contains paid, non-refunded contributions to the entity (campaign or organization) you created the credential for, during the specified date range. 'refunded_contributions': contributions to your entity that were refunded, during the specified date range. 'managed_form_contributions': contributions made through any form that is managed by your entity, during the specified date range - including contributions to other entities via that form if it is a tandem form. date_range_start: str Start of date range to withdraw contribution data (inclusive). Ex: '2020-01-01' date_range_end: str End of date range to withdraw contribution data (exclusive). Ex: '2020-02-01' **csvargs: Any additional arguments will be passed to Table.from_csv as keyword arguments. `Returns:` Contents of the generated contribution CSV as a Parsons table. """ post_request_response = self.post_request(csv_type, date_range_start, date_range_end) csv_id = post_request_response["id"] download_url = self.poll_for_download_url(csv_id) table = Table.from_csv(download_url, **csvargs) logger.info("Completed conversion to Parsons Table.") return table