Skip to content

Commit

Permalink
feat: add email reminder sent every 3 months to organizations admins …
Browse files Browse the repository at this point in the history
…having multiple members
  • Loading branch information
leo-naeka committed Jun 27, 2024
1 parent ea7bd8c commit 223af45
Show file tree
Hide file tree
Showing 16 changed files with 705 additions and 3 deletions.
1 change: 1 addition & 0 deletions clevercloud/cron.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"30 1 * * * $ROOT/clevercloud/run_management_command.sh new_users_to_mailjet --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",
"0 12 * * * $ROOT/clevercloud/run_management_command.sh evaluation_campaign_notify",
"30 20 * * * $ROOT/clevercloud/crons/populate_metabase_emplois.sh --daily",
"5 23 * * * $ROOT/clevercloud/run_management_command.sh archive_employee_records --wet-run",
Expand Down
5 changes: 5 additions & 0 deletions itou/common_apps/organizations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ class OrganizationAbstract(models.Model):
# This enables us to keep our internal primary key opaque and independent from any external logic.
uid = models.UUIDField(db_index=True, default=uuid.uuid4, unique=True)

active_members_email_reminder_last_sent_at = models.DateTimeField(
null=True,
verbose_name="date d'envoi du dernier rappel pour vérifier les membres actifs",
)

# Child class should have a "members" attribute, for example:
# members = models.ManyToManyField(
# settings.AUTH_USER_MODEL,
Expand Down
1 change: 1 addition & 0 deletions itou/communications/dispatch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
JobSeekerNotification,
PrescriberNotification,
PrescriberOrEmployerNotification,
PrescriberOrEmployerOrLaborInspectorNotification,
WithStructureMixin,
)
7 changes: 7 additions & 0 deletions itou/communications/dispatch/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ def is_manageable_by_user(self):
return super().is_manageable_by_user() and (self.user.is_prescriber or self.user.is_employer)


class PrescriberOrEmployerOrLaborInspectorNotification:
def is_manageable_by_user(self):
return super().is_manageable_by_user() and (
self.user.is_prescriber or self.user.is_employer or self.user.is_labor_inspector
)


class WithStructureMixin:
def is_manageable_by_user(self):
return super().is_manageable_by_user() and self.structure is not None
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.6 on 2024-06-05 09:52

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("companies", "0002_fix_job_app_contract_type_enum"),
]

operations = [
migrations.AddField(
model_name="company",
name="active_members_email_reminder_last_sent_at",
field=models.DateTimeField(
null=True, verbose_name="date d'envoi du dernier rappel pour vérifier les membres actifs"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 5.0.6 on 2024-06-10 15:31

import datetime
import math
import time

from dateutil.relativedelta import relativedelta
from django.db import migrations


def set_active_members_email_reminder_last_sent_at(apps, schema_editor):
"""
Set active_members_email_reminder_last_sent_at for companies created more than 3 months ago.
Doing so to avoid processing a single and huge batch of most of the pre-existing companies during the first run of
the send_check_authorized_members_email management command.
"""
START_DATE = datetime.date.today() - relativedelta(months=3)
Company = apps.get_model("companies", "Company")

companies_qs = (
Company.objects.filter(
active_members_email_reminder_last_sent_at__isnull=True,
created_at__date__lt=START_DATE,
)
.only("active_members_email_reminder_last_sent_at", "created_at")
.order_by("created_at")
)
batch_size = max([math.ceil(companies_qs.count() / 90), 50])
batch_start_date = START_DATE

companies_processed = 0
start = time.perf_counter()
while companies_batch := companies_qs[:batch_size]:
companies = []
for company in companies_batch:
company.active_members_email_reminder_last_sent_at = datetime.datetime.combine(
batch_start_date,
company.created_at.timetz(),
)
companies.append(company)
companies_processed += Company.objects.bulk_update(companies, {"active_members_email_reminder_last_sent_at"})
batch_start_date += datetime.timedelta(days=1)
print(f"{companies_processed} companies migrated in {time.perf_counter() - start:.2f} sec")


class Migration(migrations.Migration):
dependencies = [
("companies", "0003_company_active_members_email_reminder_last_sent_at"),
]

operations = [
migrations.RunPython(set_active_members_email_reminder_last_sent_at, migrations.RunPython.noop, elidable=True),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.6 on 2024-06-05 09:52

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("institutions", "0003_institution_unique_ddets_per_department"),
]

operations = [
migrations.AddField(
model_name="institution",
name="active_members_email_reminder_last_sent_at",
field=models.DateTimeField(
null=True, verbose_name="date d'envoi du dernier rappel pour vérifier les membres actifs"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 5.0.6 on 2024-06-10 15:31

import datetime
import math
import time

from dateutil.relativedelta import relativedelta
from django.db import migrations


def set_active_members_email_reminder_last_sent_at(apps, schema_editor):
"""
Set active_members_email_reminder_last_sent_at for institutions created more than 3 months ago.
Doing so to avoid processing a single and huge batch of most of the pre-existing institutions during the first run
of the send_check_authorized_members_email management command.
"""
START_DATE = datetime.date.today() - relativedelta(months=3)
Institution = apps.get_model("institutions", "Institution")

institutions_qs = (
Institution.objects.filter(
active_members_email_reminder_last_sent_at__isnull=True,
created_at__date__lt=START_DATE,
)
.only("active_members_email_reminder_last_sent_at", "created_at")
.order_by("created_at")
)
batch_size = max([math.ceil(institutions_qs.count() / 90), 50])
batch_start_date = START_DATE

institutions_processed = 0
start = time.perf_counter()
while institutions_batch := institutions_qs[:batch_size]:
institutions = []
for institution in institutions_batch:
institution.active_members_email_reminder_last_sent_at = datetime.datetime.combine(
batch_start_date,
institution.created_at.timetz(),
)
institutions.append(institution)
institutions_processed += Institution.objects.bulk_update(
institutions, {"active_members_email_reminder_last_sent_at"}
)
batch_start_date += datetime.timedelta(days=1)
print(f"{institutions_processed} institutions migrated in {time.perf_counter() - start:.2f} sec")


class Migration(migrations.Migration):
dependencies = [
("institutions", "0004_institution_active_members_email_reminder_last_sent_at"),
]

operations = [
migrations.RunPython(set_active_members_email_reminder_last_sent_at, migrations.RunPython.noop, elidable=True),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.0.6 on 2024-06-05 09:52

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("prescribers", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="prescriberorganization",
name="active_members_email_reminder_last_sent_at",
field=models.DateTimeField(
null=True, verbose_name="date d'envoi du dernier rappel pour vérifier les membres actifs"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Generated by Django 5.0.6 on 2024-06-10 15:31

import datetime
import math
import time

from dateutil.relativedelta import relativedelta
from django.db import migrations


def set_active_members_email_reminder_last_sent_at(apps, schema_editor):
"""
Set active_members_email_reminder_last_sent_at for prescriber organizations created more than 3 months ago.
Doing so to avoid processing a single and huge batch of most of the pre-existing prescriber organizations during
the first run of the send_check_authorized_members_email management command.
"""
START_DATE = datetime.date.today() - relativedelta(months=3)
PrescriberOrganization = apps.get_model("prescribers", "PrescriberOrganization")

prescriber_organizations_qs = (
PrescriberOrganization.objects.filter(
active_members_email_reminder_last_sent_at__isnull=True,
created_at__date__lt=START_DATE,
)
.only("active_members_email_reminder_last_sent_at", "created_at")
.order_by("created_at")
)
batch_size = max([math.ceil(prescriber_organizations_qs.count() / 90), 50])
batch_start_date = START_DATE

prescriber_organizations_processed = 0
start = time.perf_counter()
while prescriber_organizations_batch := prescriber_organizations_qs[:batch_size]:
prescriber_organizations = []
for prescriber_organization in prescriber_organizations_batch:
prescriber_organization.active_members_email_reminder_last_sent_at = datetime.datetime.combine(
batch_start_date,
prescriber_organization.created_at.timetz(),
)
prescriber_organizations.append(prescriber_organization)
prescriber_organizations_processed += PrescriberOrganization.objects.bulk_update(
prescriber_organizations, {"active_members_email_reminder_last_sent_at"}
)
batch_start_date += datetime.timedelta(days=1)
print(
f"{prescriber_organizations_processed} prescriber organizations "
f"migrated in {time.perf_counter() - start:.2f} sec"
)


class Migration(migrations.Migration):
dependencies = [
("prescribers", "0002_prescriberorganization_active_members_email_reminder_last_sent_at"),
]

operations = [
migrations.RunPython(set_active_members_email_reminder_last_sent_at, migrations.RunPython.noop, elidable=True),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% extends "layout/base_email_text_body.txt" %}
{% load format_filters %}
{% block body %}
Bonjour,

En tant qu’administrateur de l’organisation {{ structure.name }}, nous vous invitons à vérifier la liste des membres afin de vous assurer que seuls les collaborateurs qui travaillent au sein de cette organisation puissent accéder à votre espace de travail.

RDV sur votre espace des emplois de l’inclusion à la rubrique “Gérer les collaborateurs” : {{ itou_protocol }}://{{ itou_fqdn }}{{ members_url }}

Si un collaborateur a quitté votre organisation, vous devez le retirer des membres en cliquant sur le bouton d’action situé à droite, puis sur l’option “retirer de la structure”.

{% if active_admins_count == 1 %}Pour des raisons de sécurité et si la configuration de votre organisation vous le permet, nous vous invitons à nommer plusieurs administrateurs.

{% endif %}Ce rappel automatique vous sera transmis tous les 3 mois, mais il est vivement recommandé d’effectuer cette action dès qu’un collaborateur quitte votre organisation.

Cordialement,
{% endblock body %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{% extends "layout/base_email_text_subject.txt" %}
{% block subject %}
Rappel sécurité : vérifiez la liste des membres de l’organisation {{ structure.name }}
{% endblock %}
Loading

0 comments on commit 223af45

Please sign in to comment.