def send_expiration_sms_reminder(sp_subscription_pk):
    try:
        sp_subscription = SystemPaySubscription.objects.select_related(
            "subscription__person", "alias"
        ).get(pk=sp_subscription_pk)
    except SystemPaySubscription.DoesNotExist:
        return

    recipient = sp_subscription.subscription.person

    if (
        not recipient.contact_phone
        or not is_french_number(recipient.contact_phone)
        or not is_mobile_number(recipient.contact_phone)
    ):
        return

    connection_params = generate_token_params(recipient)

    url = shorten_url(
        add_params_to_urls(front_url("view_payments"), connection_params), secret=True
    )

    send_sms(
        f"Votre carte bleue arrive à expiration. Pour continuer votre don régulier à la France insoumise, "
        f"mettez là à jour : {url}\n"
        f"Merci encore de votre soutien !",
        recipient.contact_phone,
    )
    def get_subscriber_data(self):
        data = super().get_subscriber_data()

        return {
            **data,
            "login_query":
            mark_safe(urlencode(generate_token_params(self))),
            "greeting":
            self.formule_adresse,
            "full_name":
            self.get_full_name(),
            "short_name":
            self.get_short_name(),
            "ancienne_region":
            self.ancienne_region,
            "region":
            self.region,
            "departement":
            self.departement,
            "city":
            self.location_city,
            "short_address":
            self.short_address,
            "short_location":
            self.short_location(),
            "full_address":
            self.html_full_address(),
        }
Exemple #3
0
    def send_emails(self, config, status):
        sending = status._active & ~status._email_envoye

        if self.verbosity >= 1 and sending.sum():
            self.stdout.write(f"{sending.sum()} emails à envoyer.\n")

        persons = {
            str(p.id): p
            for p in Person.objects.filter(id__in=status.loc[sending, "id"])
        }

        with open(config["email_html_file"]) as f:
            html_template = Template(f.read())
        with open(config["email_text_file"]) as f:
            text_template = Template(f.read())

        locale.setlocale(locale.LC_TIME, "fr_FR.UTF-8")

        with open(config["email_sent_file"], mode="a") as f:
            for g in grouper(
                    tqdm(status.loc[sending].itertuples(),
                         total=sending.sum(),
                         disable=None),
                    EMAILS_BY_CONNECTION,
            ):
                connection = get_connection()
                with connection:
                    for i, row in enumerate(g):
                        person = persons[row.id]

                        context = Context({
                            "email":
                            person.email,
                            "login_query":
                            urlencode(generate_token_params(person)),
                            "limit_time":
                            row.subscribe_limit.strftime("%A %d %B avant %Hh"),
                        })

                        html_message = html_template.render(context)
                        text_message = text_template.render(context)

                        msg = EmailMultiAlternatives(
                            subject=config["email_subject"],
                            body=text_message,
                            from_email=config.get(
                                "email_from",
                                "La France insoumise <*****@*****.**>",
                            ),
                            to=[person.email],
                            connection=connection,
                        )
                        msg.attach_alternative(html_message, "text/html")

                        msg.send(fail_silently=False)
                        f.write(f"{row.id}\n")
                        f.flush()
 def connection_params(self, obj):
     if obj.pk:
         return format_html(
             '{params} <a class="button" href="{invalidate_link}">Invalider les liens</a>',
             params=urlencode(generate_token_params(obj)),
             invalidate_link=reverse("admin:people_person_invalidate_link",
                                     args=(obj.pk, )),
         )
     else:
         return "-"
 def test_can_retrieve_person_information_with_login_link(self):
     self.client.logout()
     params = generate_token_params(self.person)
     url = add_query_params_to_url(
         reverse("api_people_retrieve"),
         {
             "id": str(self.person.id),
             "no_session": "o",
             **params
         },
     )
     res = self.client.get(url)
     self.assertEqual(res.status_code, status.HTTP_200_OK)
Exemple #6
0
def data_from_person(person, tmp_tags=None):
    data = {}

    is_animateur = Q(is_referent=True) | Q(is_manager=True)
    inscriptions = [
        ("evenements_yes"
         if person.events.upcoming().count() > 0 else "evenements_no"),
        ("groupe_yes"
         if person.supportgroups.active().count() > 0 else "groupe_no"),
        ("groupe_certifié_yes"
         if person.supportgroups.active().certified().count() > 0 else
         "groupe_certifié_no"),
        ("groupe_anim_yes"
         if person.memberships.active().filter(is_animateur).count() > 0 else
         "groupe_anim_no"),
        ("groupe_certifié_anim_yes" if person.memberships.active().filter(
            is_animateur
            & Q(supportgroup__subtypes__label__in=settings.
                CERTIFIED_GROUP_SUBTYPES)).count() > 0 else
         "groupe_certifié_anim_no"),
        ("country-{}".format(
            person.location_country if person.location_country else "FR")),
    ]

    data["FIRST_NAME"] = person.first_name
    data["LAST_NAME"] = person.last_name
    data["MERGE_GENDER"] = person.gender
    data["MERGE_ZIPCODE"] = (person.location_zip if
                             (person.location_country == "FR"
                              or not person.location_country) else str(
                                  person.location_country))
    data["MERGE_INSCRIPTIONS"] = ",".join(inscriptions)
    data["MERGE_LOGIN_QUERY"] = urlencode(generate_token_params(person))
    data["MERGE_TAGS"] = (
        "," + ",".join(t.label
                       for t in person.tags.filter(exported=True)) + ",")

    data["MERGE_REGION"] = " ".join([person.region, person.ancienne_region])
    data["MERGE_ANNEE_DE_NAISSANCE"] = (person.date_of_birth.year
                                        if person.date_of_birth else None)

    if tmp_tags:
        data["MERGE_TAGS"] = "," + ",".join(tmp_tags) + data["MERGE_TAGS"]

    if len(data["MERGE_TAGS"]) > 255:
        warnings.warn("Tag string is longer than 255 characters for " +
                      person.email)

    return data
Exemple #7
0
    def update_and_draw(self, config, do_it=False, **options):
        status = get_current_status(config)
        stats = get_stats(status, config)

        new_draws = status.id.isin([
            id for name, g in status[status._available].groupby(["college"])
            for id in g["id"].iloc[:stats.loc[name, "to_draw"]]
        ])

        if new_draws.sum() == 0:
            return

        # obligé de passer par UTC sinon Pandas fait chier :(
        limit = (pd.Timestamp(timezone.now() + timezone.timedelta(
            hours=config["subscribe_period"])).astimezone(
                status.subscribe_limit.dt.tz).replace(minute=0,
                                                      second=0,
                                                      microsecond=0))

        status.loc[new_draws, "subscribe_limit"] = limit

        if self.verbosity >= 1:
            drawn_counts = Counter(status.loc[new_draws, "college"])
            print("Tirage :")
            for g, c in drawn_counts.items():
                print(f"{g}: {c} personnes")

        if do_it:
            status[[c for c in status.columns
                    if not c.startswith("_")]].to_csv(config["status_file"])

        tag_current = PersonTag.objects.get(
            label=f"{config['tag_prefix']} - ouvert")

        active_persons = {
            str(p.id): p
            for p in Person.objects.filter(id__in=status.loc[status._active
                                                             | new_draws,
                                                             "id"])
        }

        if do_it:
            with transaction.atomic():
                # on retire la possibilité de s'inscrire aux précédents
                tag_current.people.remove(*tag_current.people.all())

                # on ajoute les nouveaux aux deux tags
                tag_current.people.add(*status.loc[status._active | new_draws,
                                                   "id"].map(active_persons))

        with open(config["email_html_file"]) as f:
            html_template = Template(f.read())
        with open(config["email_text_file"]) as f:
            text_template = Template(f.read())

        connection = get_connection()

        locale.setlocale(locale.LC_TIME, "fr_FR.UTF-8")

        with connection:
            for i, row in enumerate(status.loc[new_draws].itertuples()):
                person = active_persons[row.id]

                context = Context({
                    "email":
                    person.email,
                    "login_query":
                    urlencode(generate_token_params(person)),
                    "limit_time":
                    row.subscribe_limit.strftime("%A %d %B avant %Hh"),
                })

                html_message = html_template.render(context)
                text_message = text_template.render(context)

                msg = EmailMultiAlternatives(
                    subject=config["email_subject"],
                    body=text_message,
                    from_email=config.get(
                        "email_from",
                        "La France insoumise <*****@*****.**>",
                    ),
                    to=[person.email],
                    connection=connection,
                )
                msg.attach_alternative(html_message, "text/html")

                print(row.college,
                      end="\n" if i % 80 == 79 else "",
                      flush=True)

                if do_it:
                    msg.send(fail_silently=False)

        print()  # newline
def send_mosaico_email(
    code,
    subject,
    from_email,
    recipients,
    recipient_type="to",
    bindings=None,
    connection=None,
    backend=None,
    fail_silently=False,
    preferences_link=True,
    reply_to=None,
    attachments=None,
):
    """Send an email from a Mosaico template

    :param code: the code identifying the Mosaico template
    :param subject: the subject line of the email
    :param from_email: the address from which the email is to be sent
    :param recipients: a list of recipients to which the email will be send; alternatively, a single address
    :param bindings: a dictionary of replacements variables and their target values in the Mosaico template
    :param connection: an optional email server connection to use to send the emails
    :param backend: if no connection is given, an optional mail backend to use to send the emails
    :param fail_silently: whether any error should be raised, or just be ignored; by default it will raise
    :param gen_connection_params_function: a function that takes a recipient and generates connection params
    """
    try:
        iter(recipients)
    except TypeError:
        recipients = [recipients]

    if recipient_type not in ["to", "cc", "bcc"]:
        raise ValueError("`recipient_type` must be to, cc or bcc")

    if bindings is None:
        bindings = {}

    if connection is None:
        connection = get_connection(backend, fail_silently)

    if preferences_link:
        bindings["preferences_link"] = bindings["PREFERENCES_LINK"] = front_url(
            "contact"
        )
        bindings["unsubscribe_link"] = bindings["UNSUBSCRIBE_LINK"] = front_url(
            "unsubscribe"
        )

    link_bindings = {
        key: value for key, value in bindings.items() if is_front_url(value)
    }

    html_template = loader.get_template(f"mail_templates/{code}.html")
    try:
        text_template = loader.get_template(f"mail_templates/{code}.txt")
    except TemplateDoesNotExist:
        text_template = None

    with connection:
        for recipient in recipients:
            # recipient can be either a Person or an email address
            if isinstance(recipient, Person):
                if recipient.role is not None and not recipient.role.is_active:
                    continue
                connection_params = generate_token_params(recipient)
                for key, value in link_bindings.items():
                    if isinstance(value, AutoLoginUrl):
                        bindings[key] = add_params_to_urls(value, connection_params)
                bindings["MERGE_LOGIN"] = urlencode(connection_params)

            context = get_context_from_bindings(code, recipient, bindings)
            html_message = html_template.render(context=context)
            text_message = (
                text_template.render(
                    context={k: conditional_html_to_text(v) for k, v in context.items()}
                )
                if text_template
                else generate_plain_text(html_message)
            )

            email = EmailMultiAlternatives(
                subject=subject,
                body=text_message,
                from_email=from_email,
                reply_to=reply_to,
                connection=connection,
                **{
                    recipient_type: [
                        recipient.email if isinstance(recipient, Person) else recipient
                    ]
                },
            )
            email.attach_alternative(html_message, "text/html")
            if attachments is not None:
                for attachment in attachments:
                    if isinstance(attachment, MIMEBase):
                        email.attach(attachment)
                    elif isinstance(attachment, dict):
                        email.attach(**attachment)
                    else:
                        email.attach(*attachment)
            email.send(fail_silently=fail_silently)
Exemple #9
0
    def get_subscriber_data(self):
        data = super().get_subscriber_data()

        return {**data, "login_query": urlencode(generate_token_params(self))}