Skip to content

Commit

Permalink
users: Sendemails to Brevo instead of Mailjet
Browse files Browse the repository at this point in the history
  • Loading branch information
tonial committed Oct 3, 2024
1 parent 5ef6fc6 commit 22dfb9f
Show file tree
Hide file tree
Showing 6 changed files with 415 additions and 602 deletions.
2 changes: 1 addition & 1 deletion clevercloud/cron.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

"1 0 * * * $ROOT/clevercloud/run_management_command.sh update_prescriber_organization_with_api_entreprise --verbosity 2",
"30 0 * * * $ROOT/clevercloud/run_management_command.sh collect_analytics_data --save",
"30 1 * * * $ROOT/clevercloud/run_management_command.sh new_users_to_mailjet --wet-run",
"30 1 * * * $ROOT/clevercloud/run_management_command.sh new_users_to_brevo --wet-run",
"0 3 * * * $ROOT/clevercloud/run_management_command.sh clearsessions",
"15 5 * * * $ROOT/clevercloud/run_management_command.sh prolongation_requests_chores email_reminder --wet-run",
"0 9 * * * $ROOT/clevercloud/run_management_command.sh send_check_authorized_members_email",
Expand Down
8 changes: 5 additions & 3 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,9 +477,6 @@
"immediate": ITOU_ENVIRONMENT == ItouEnvironment.FAST_MACHINE,
}

MAILJET_API_KEY_PRINCIPAL = os.getenv("API_MAILJET_KEY_PRINCIPAL")
MAILJET_SECRET_KEY_PRINCIPAL = os.getenv("API_MAILJET_SECRET_PRINCIPAL")

# Email https://anymail.readthedocs.io/en/stable/esps/mailjet/
ANYMAIL = {
# it's the default but our probes need this at import time.
Expand Down Expand Up @@ -694,5 +691,10 @@
RDV_INSERTION_WEBHOOK_SECRET = os.getenv("RDV_INSERTION_WEBHOOK_SECRET")

# API Particuliers
# ------------------------------------------------------------------------------
API_PARTICULIER_BASE_URL = os.getenv("API_PARTICULIER_BASE_URL", "https://particulier.api.gouv.fr/api/")
API_PARTICULIER_TOKEN = os.getenv("API_PARTICULIER_TOKEN")

# Brevo
# ------------------------------------------------------------------------------
BREVO_API_KEY = os.getenv("BREVO_API_KEY")
3 changes: 0 additions & 3 deletions config/settings/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@

HUEY["immediate"] = True # noqa: F405

MAILJET_API_KEY_PRINCIPAL = "API_MAILJET_KEY_PRINCIPAL"
MAILJET_SECRET_KEY_PRINCIPAL = "API_MAILJET_SECRET_PRINCIPAL"

AWS_S3_ENDPOINT_URL = f"http://{os.getenv('CELLAR_ADDON_HOST', 'localhost:9000')}/"
AWS_S3_ACCESS_KEY_ID = "minioadmin"
AWS_S3_SECRET_ACCESS_KEY = "minioadmin"
Expand Down
159 changes: 159 additions & 0 deletions itou/users/management/commands/new_users_to_brevo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import enum
import logging

import httpx
from allauth.account.models import EmailAddress
from django.conf import settings
from django.db.models import Exists, OuterRef, Q
from sentry_sdk.crons import monitor

from itou.companies.enums import SIAE_WITH_CONVENTION_KINDS
from itou.companies.models import CompanyMembership
from itou.prescribers.models import PrescriberMembership
from itou.users.enums import IdentityProvider, UserKind
from itou.users.models import User
from itou.utils.command import BaseCommand
from itou.utils.iterators import chunks


logger = logging.getLogger(__name__)

# https://app.brevo.com/contact/list-listing
BREVO_LIST_ID = 31
BREVO_API_URL = "https://api.brevo.com/v3"


class UserCategory(enum.Enum):
PRESCRIBER = "prescripteur habilité"
ORIENTEUR = "orienteur"
EMPLOYEUR = "employeur"


class BrevoClient:
IMPORT_BATCH_SIZE = 1000

def __init__(self):
self.client = httpx.Client(
headers={
"accept": "application/json",
"api-key": settings.BREVO_API_KEY,
}
)

def _import_contacts(self, users_data, category):
data = [
{
"email": user["email"],
"attributes": {
"prenom": user["first_name"].title(),
"nom": user["last_name"].upper(),
"date_inscription": user["date_joined"].strftime("%Y-%m-%d"),
"type": category.value,
},
}
for user in users_data
]

response = self.client.post(
f"{BREVO_API_URL}/contacts/import",
headers={"Content-Type": "application/json"},
json={
"listIds": [BREVO_LIST_ID],
"emailBlacklist": False,
"smsBlacklist": False,
"updateExistingContacts": False, # Don't update because we don't want to update emailBlacklist
"emptyContactsAttributes": False,
"jsonBody": data,
},
)
if response.status_code != 202:
logger.error(
"Brevo API: Some emails were not imported, status_code=%d, content=%s",
response.status_code,
response.content.decode(),
)

def import_users(self, users, category):
for chunk in chunks(users, self.IMPORT_BATCH_SIZE):
if chunk:
self._import_contacts(chunk, category)


class Command(BaseCommand):
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
"--wet-run",
action="store_true",
help="Enroll new users to a mailing list in Brevo",
)

@monitor(
monitor_slug="new-users-to-brevo",
monitor_config={
"schedule": {"type": "crontab", "value": "30 1 * * *"},
"checkin_margin": 30,
"max_runtime": 30,
"failure_issue_threshold": 1,
"recovery_threshold": 1,
"timezone": "UTC",
},
)
def handle(self, *args, wet_run, **options):
client = BrevoClient()

users = (
User.objects.filter(kind__in=[UserKind.PRESCRIBER, UserKind.EMPLOYER])
.filter(
# Someday only filter on identity_provider ?
Exists(
EmailAddress.objects.filter(
user_id=OuterRef("pk"),
email=OuterRef("email"),
primary=True,
verified=True,
)
)
| Q(identity_provider=IdentityProvider.INCLUSION_CONNECT), # IC verifies emails on its own
is_active=True,
)
.order_by("email")
)
employers = list(
users.filter(kind=UserKind.EMPLOYER)
.filter(
Exists(
CompanyMembership.objects.filter(
user_id=OuterRef("pk"),
is_active=True,
company__kind__in=SIAE_WITH_CONVENTION_KINDS,
)
)
)
.values("email", "first_name", "last_name", "date_joined")
)

all_prescribers = users.filter(kind=UserKind.PRESCRIBER)
prescriber_membership_qs = PrescriberMembership.objects.filter(user_id=OuterRef("pk"), is_active=True)
prescribers = list(
all_prescribers.filter(Exists(prescriber_membership_qs.filter(organization__is_authorized=True))).values(
"email", "first_name", "last_name", "date_joined"
)
)
orienteurs = list(
all_prescribers.exclude(Exists(prescriber_membership_qs.filter(organization__is_authorized=True))).values(
"email", "first_name", "last_name", "date_joined"
)
)

logger.info("SIAE users count: %d", len(employers))
logger.info("Prescribers count: %d", len(prescribers))
logger.info("Orienteurs count: %d", len(orienteurs))

if wet_run:
for category, users in [
(UserCategory.EMPLOYEUR, employers),
(UserCategory.PRESCRIBER, prescribers),
(UserCategory.ORIENTEUR, orienteurs),
]:
client.import_users(users, category)
163 changes: 0 additions & 163 deletions itou/users/management/commands/new_users_to_mailjet.py

This file was deleted.

Loading

0 comments on commit 22dfb9f

Please sign in to comment.