diff --git a/sefaria/helper/crm/crm_mediator.py b/sefaria/helper/crm/crm_mediator.py index 87980f1175..d07d1619d7 100644 --- a/sefaria/helper/crm/crm_mediator.py +++ b/sefaria/helper/crm/crm_mediator.py @@ -20,8 +20,8 @@ def create_crm_user(self, email, first_name, last_name, lang="en", educator=Fals except: return False - def subscribe_to_lists(self, email, first_name, last_name, educator=False, lang="en"): - return self._crm_connection.subscribe_to_lists(email, first_name, last_name, educator, lang) + def subscribe_to_lists(self, email, first_name, last_name, educator=False, lang="en", mailing_lists=None): + return self._crm_connection.subscribe_to_lists(email, first_name, last_name, educator, lang, mailing_lists) def sync_sustainers(self): current_sustainers = CrmInfoStore.get_current_sustainers() @@ -71,3 +71,6 @@ def get_and_save_crm_id(self, email=None): CrmInfoStore.save_crm_id(crm_id, email) else: return False + + def get_available_lists(self): + return self._crm_connection.get_available_lists() diff --git a/sefaria/helper/crm/salesforce.py b/sefaria/helper/crm/salesforce.py index 8f850d803f..8f040993f3 100644 --- a/sefaria/helper/crm/salesforce.py +++ b/sefaria/helper/crm/salesforce.py @@ -6,6 +6,11 @@ from sefaria.helper.crm.crm_connection_manager import CrmConnectionManager from sefaria import settings as sls +from typing import Any, Optional + +class SalesforceNewsletterListRetrievalError(Exception): + pass + class SalesforceConnectionManager(CrmConnectionManager): def __init__(self): CrmConnectionManager.__init__(self, sls.SALESFORCE_BASE_URL) @@ -25,7 +30,7 @@ def make_request(self, request, **kwargs): def get(self, endpoint): headers = {'Content-type': 'application/json', 'Accept': 'application/json'} - return self.session.get(endpoint, headers) + return self.session.get(endpoint, headers=headers) def post(self, endpoint, **kwargs): headers = {'Content-type': 'application/json', 'Accept': 'application/json'} @@ -120,8 +125,17 @@ def find_crm_id(self, email=None): except: return False - def subscribe_to_lists(self, email, first_name=None, last_name=None, lang="en", educator=False): - # TODO: Implement once endpoint exists + def subscribe_to_lists( + self, + email: str, + first_name: Optional[str] = None, + last_name: Optional[str] = None, + lang: str = "en", + educator: bool = False, + mailing_lists: Optional[list[str]] = None) -> Any: + + mailing_lists = mailing_lists or [] + CrmConnectionManager.subscribe_to_lists(self, email, first_name, last_name, lang, educator) if lang == "he": language = "Hebrew" @@ -134,7 +148,8 @@ def subscribe_to_lists(self, email, first_name=None, last_name=None, lang="en", "Last_Name__c": last_name, "Sefaria_App_Email__c": email, "Hebrew_English__c": language, - "Educator__c": educator + "Educator__c": educator, + "Newsletter_Names__c": mailing_lists }) res = self.post(self.create_endpoint("Sefaria_App_Data__c"), json={ @@ -145,3 +160,13 @@ def subscribe_to_lists(self, email, first_name=None, last_name=None, lang="en", except: return False return res + + def get_available_lists(self) -> list[str]: + try: + resource_prefix = f"services/data/v{self.version}/query" + endpoint = f"{sls.SALESFORCE_BASE_URL}/{resource_prefix}/" + response = self.get(endpoint + "?q=SELECT+Subscriptions__c+FROM+AC_to_SF_List_Mapping__mdt") + records = response.json()["records"] + return [record["Subscriptions__c"] for record in records] + except (requests.RequestException, KeyError, json.JSONDecodeError, AttributeError): + raise SalesforceNewsletterListRetrievalError("Unable to retrieve newsletter mailing lists from Salesforce CRM") diff --git a/sefaria/urls.py b/sefaria/urls.py index e03302f937..1e357159f7 100644 --- a/sefaria/urls.py +++ b/sefaria/urls.py @@ -398,10 +398,11 @@ url(r'^api/send_feedback$', sefaria_views.generate_feedback), ] -# Email Subscribe +# Email Newsletter Subscriptions urlpatterns += [ url(r'^api/subscribe/(?P.+)/(?P.+)$', sefaria_views.generic_subscribe_to_newsletter_api), url(r'^api/subscribe/(?P.+)$', sefaria_views.subscribe_sefaria_newsletter_view), + url(r'^api/newsletter_mailing_lists/?$', sefaria_views.get_available_newsletter_mailing_lists), ] # Admin diff --git a/sefaria/views.py b/sefaria/views.py index 71bf51d404..c7c3ba3d92 100644 --- a/sefaria/views.py +++ b/sefaria/views.py @@ -36,6 +36,7 @@ import sefaria.model as model import sefaria.system.cache as scache from sefaria.helper.crm.crm_mediator import CrmMediator +from sefaria.helper.crm.salesforce import SalesforceNewsletterListRetrievalError from sefaria.system.cache import in_memory_cache from sefaria.client.util import jsonResponse, send_email, read_webpack_bundle from sefaria.forms import SefariaNewUserForm, SefariaNewUserFormAPI, SefariaDeleteUserForm, SefariaDeleteSheet @@ -204,16 +205,27 @@ def subscribe_sefaria_newsletter_view(request, email): def subscribe_sefaria_newsletter(request, email, first_name, last_name): """ - API for subscribing to mailing lists, in `lists` url param. - Currently active lists are: - "Announcements_General", "Announcements_General_Hebrew", "Announcements_Edu", "Announcements_Edu_Hebrew" + API for subscribing to mailing lists + * By default, the user's email address is subscribed to the default lists: "Master," "General Updates" (or the one for Hebrew), and "Educator Updates" (if the user is an educator). + * If the user's email address already exists, the email address to those lists is not resubscribed to those lists + * When you provide additional newsletter mailing lists, the email address will be subscribed to those lists, along with the default ones, if the email address does not already exist. + * However, if we pass the email address with any of those default newsletter lists as additional ones, Salesforce will resubscribe the email address to those lists. """ body = json.loads(request.body) language = body.get("language", "") educator = body.get("educator", False) + mailing_lists = body.get("lists", []) crm_mediator = CrmMediator() - return crm_mediator.subscribe_to_lists(email, first_name, last_name, educator=educator, lang=language) + return crm_mediator.subscribe_to_lists(email, first_name, last_name, educator=educator, lang=language, mailing_lists=mailing_lists) +@csrf_exempt +def get_available_newsletter_mailing_lists(request): + try: + return jsonResponse({"newsletter_mailing_lists": CrmMediator().get_available_lists()}) + except SalesforceNewsletterListRetrievalError as e: + return jsonResponse({"error": str(e)}, status=502) + except: + return jsonResponse({"error": "Unknown error occurred"}, status=500) def subscribe_steinsaltz(request, email, first_name, last_name): """