Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Send mails contributions (managers and senders) #196

Merged
merged 6 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ CHANGELOG
* Add contributions type / category filters
* Add contributions manager
* Add contribution status

* Send mail to managers when contribution is created
* Send mail to contributor when contribution is created

1.1.0 (2023-13-06)
-------------------------
Expand Down
30 changes: 29 additions & 1 deletion docs/usage/configuration.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
=============
Configuration
=============

Expand Down Expand Up @@ -63,4 +64,31 @@ To customize lists for each module, go to django administration page.
* Cities
* Districts
* Restricted area types
* Restricted areas
* Restricted areas


Email settings
--------------

Georiviere-admin will send emails:

* to administrators when internal errors occur
* to managers when a contribution is created
* to contributors when a contribution is created

Email configuration takes place in ``var/conf/custom.py``, where you control
recipients emails (``ADMINS``, ``MANAGERS``) and email server configuration.

You can test your configuration with the following command. A fake email will
be sent to the managers:

::

docker-compose run --rm web ./manage.py sendtestemail --managers

If you don't want to send an email to contributors when they create a contribution on portal website,
change this setting in ``var/conf/custom.py``:

::

SEND_REPORT_ACK = False
22 changes: 22 additions & 0 deletions georiviere/contribution/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import logging

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.gis.db import models
from django.core.mail import mail_managers
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _

from mapentity.models import MapEntityMixin
Expand All @@ -19,6 +23,8 @@
from georiviere.studies.models import Study
from georiviere.watershed.mixins import WatershedPropertiesMixin

logger = logging.getLogger(__name__)


class SeverityType(models.Model):
label = models.CharField(max_length=128, verbose_name=_("Label"), unique=True)
Expand Down Expand Up @@ -144,6 +150,22 @@ def category_display(self):
s = '<span class="badge badge-success" title="%s">&#x2606;</span> ' % _("Published") + s
return s

def send_report_to_managers(self, template_name="contribution/report_email.txt"):
subject = _("Feedback from {email}").format(email=self.email_author)
message = render_to_string(template_name, {"contribution": self})
mail_managers(subject, message, fail_silently=False)

def try_send_report_to_managers(self):
try:
self.send_report_to_managers()
except Exception as e:
logger.error("Email could not be sent to managers.")
logger.exception(e) # This sends an email to admins :)

def save(self, *args, **kwargs):
super().save(*args, **kwargs) # Contribution updates should do nothing more
self.try_send_report_to_managers()


class LandingType(models.Model):
label = models.CharField(max_length=128, verbose_name=_("Label"), unique=True)
Expand Down
16 changes: 16 additions & 0 deletions georiviere/contribution/templates/contribution/report_email.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% load i18n l10n %}
{% autoescape off %}
{% blocktrans with email=contribution.email_author %}{{email}} has sent a contribution.{% endblocktrans %}

{% if contribution.severity %}{% blocktrans with severity=report.severity %}Severity : {{severity}}{% endblocktrans %}{% endif %}
{% trans "Category" %} : {{contribution.category}}
{% trans "Description" %} : {{contribution.description}}

{% trans "Portal" %} : {{contribution.portal}}

{% if report.geom %}{% blocktrans with lat=report.geom_wgs84.y|stringformat:".6f" lng=report.geom_wgs84.x|stringformat:".6f" %}
Lat : {{lat}} / Lon : {{lng}}
http://www.openstreetmap.org/?mlat={{lat}}&mlon={{lng}}
{% endblocktrans %}{% endif %}

{% endautoescape %}
27 changes: 24 additions & 3 deletions georiviere/contribution/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.test import TestCase
from django.core import mail
from django.test import override_settings, TestCase

from .factories import (ContributionFactory, ContributionPotentialDamageFactory, ContributionQualityFactory,
ContributionQuantityFactory, ContributionFaunaFloraFactory,
Expand All @@ -8,59 +9,79 @@
TypePollutionFactory, ContributionStatusFactory)


class ContributionCategoriesTest(TestCase):
"""Test for Category Contribution model"""
@override_settings(MANAGERS=[("Fake", "fake@fake.fake"), ])
class ContributionMetaTest(TestCase):
"""Test for Contribution model"""

@override_settings(MANAGERS=["fake@fake.fake"])
def test_contribution_try_send_report_fail(self):
self.assertEqual(len(mail.outbox), 0)
contribution = ContributionFactory(email_author='mail.mail@mail')
self.assertEqual(str(contribution), "mail.mail@mail")
self.assertEqual(len(mail.outbox), 0)

def test_contribution_str(self):
ContributionStatusFactory(label="Informé")
self.assertEqual(len(mail.outbox), 0)
contribution = ContributionFactory(email_author='mail.mail@mail')
self.assertEqual(str(contribution), "mail.mail@mail")
self.assertEqual(contribution.category, "No category")
self.assertEqual(len(mail.outbox), 1)

def test_potentialdamage_str(self):
self.assertEqual(len(mail.outbox), 0)
potential_damage = ContributionPotentialDamageFactory(type=2)
self.assertEqual(str(potential_damage), "Contribution Potential Damage Excessive cutting of riparian forest")
contribution = potential_damage.contribution
self.assertEqual(str(contribution),
f"{contribution.email_author} "
f"Contribution Potential Damage Excessive cutting of riparian forest")
self.assertEqual(contribution.category, potential_damage)
self.assertEqual(len(mail.outbox), 1)

def test_quality_str(self):
self.assertEqual(len(mail.outbox), 0)
quality = ContributionQualityFactory(type=2)
self.assertEqual(str(quality), "Contribution Quality Pollution")
contribution = quality.contribution
self.assertEqual(str(contribution),
f"{contribution.email_author} "
f"Contribution Quality Pollution")
self.assertEqual(contribution.category, quality)
self.assertEqual(len(mail.outbox), 1)

def test_quantity_str(self):
self.assertEqual(len(mail.outbox), 0)
quantity = ContributionQuantityFactory(type=2)
self.assertEqual(str(quantity), "Contribution Quantity In the process of drying out")
contribution = quantity.contribution
self.assertEqual(str(contribution),
f"{contribution.email_author} "
f"Contribution Quantity In the process of drying out")
self.assertEqual(contribution.category, quantity)
self.assertEqual(len(mail.outbox), 1)

def test_fauna_flora_str(self):
self.assertEqual(len(mail.outbox), 0)
fauna_flora = ContributionFaunaFloraFactory(type=2)
self.assertEqual(str(fauna_flora), "Contribution Fauna-Flora Heritage species")
contribution = fauna_flora.contribution
self.assertEqual(str(contribution),
f"{contribution.email_author} "
f"Contribution Fauna-Flora Heritage species")
self.assertEqual(contribution.category, fauna_flora)
self.assertEqual(len(mail.outbox), 1)

def test_landscape_elements_str(self):
self.assertEqual(len(mail.outbox), 0)
landscape_elements = ContributionLandscapeElementsFactory(type=2)
self.assertEqual(str(landscape_elements), "Contribution Landscape Element Fountain")
contribution = landscape_elements.contribution
self.assertEqual(str(contribution),
f"{contribution.email_author} "
f"Contribution Landscape Element Fountain")
self.assertEqual(contribution.category, landscape_elements)
self.assertEqual(len(mail.outbox), 1)

def test_severitytype_str(self):
severity_type = SeverityTypeTypeFactory(label="Severity type 1")
Expand Down
22 changes: 20 additions & 2 deletions georiviere/portal/locale/en/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-15 20:17+0000\n"
"POT-Creation-Date: 2023-07-24 14:23+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -27,7 +27,7 @@ msgstr ""
msgid "Map group layer"
msgstr ""

msgid "Map group layers"
msgid "Map groups layer"
msgstr ""

msgid "Map base layer"
Expand Down Expand Up @@ -86,3 +86,21 @@ msgstr ""

msgid "Category is not valid"
msgstr ""

msgid "An error occured"
msgstr ""

msgid "Georiviere : Contribution"
msgstr ""

msgid ""
"Hello,\n"
"\n"
" We acknowledge receipt of your contribution, thank you for "
"your interest in Georiviere.\n"
"\n"
" Best regards,\n"
"\n"
" The Georiviere Team\n"
" http://georiviere.fr"
msgstr ""
33 changes: 30 additions & 3 deletions georiviere/portal/locale/fr/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-15 20:17+0000\n"
"POT-Creation-Date: 2023-07-24 14:23+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
Expand All @@ -27,8 +27,8 @@ msgstr "Couches de carte"
msgid "Map group layer"
msgstr "Groupe de couche de carte"

msgid "Map group layers"
msgstr "Groupes de couche de carte"
msgid "Map groups layer"
msgstr "Groupe de couche de carte"

msgid "Map base layer"
msgstr "Fond de carte"
Expand Down Expand Up @@ -86,3 +86,30 @@ msgstr "Portails"

msgid "Category is not valid"
msgstr "La catégorie n'est pas valide"

msgid "An error occured"
msgstr "Une erreur s'es produite"

msgid "Georiviere : Contribution"
msgstr "Georiviere : Contribution"

msgid ""
"Hello,\n"
"\n"
" We acknowledge receipt of your contribution, thank you for "
"your interest in Georiviere.\n"
"\n"
" Best regards,\n"
"\n"
" The Georiviere Team\n"
" http://georiviere.fr"
msgstr ""
"Bonjour,\n"
"\n"
"Nous accusons réception de votre contribution, merci de votre intérêt pour "
"Georiviere.\n"
"\n"
"Cordialement,\n"
"\n"
"L'équipe Georiviere\n"
"http://georiviere.fr"
24 changes: 23 additions & 1 deletion georiviere/portal/tests/test_views/test_contribution.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.core import mail
from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.test import TestCase, override_settings
from django.urls import reverse
from unittest import mock
from geotrek.common.utils.testdata import get_dummy_uploaded_image, get_dummy_uploaded_file
Expand Down Expand Up @@ -32,6 +33,7 @@ def test_contribution_structure(self):
self.assertSetEqual(set(response.json().keys()), {'type', 'required', 'properties', 'allOf'})

def test_contribution_landscape_element(self):
self.assertEqual(len(mail.outbox), 0)
url = reverse('api_portal:contributions-list',
kwargs={'portal_pk': self.portal.pk, 'lang': 'fr'})
response = self.client.post(url, data={"geom": "POINT(0 0)",
Expand All @@ -44,8 +46,21 @@ def test_contribution_landscape_element(self):
landscape_element = contribution.landscape_element
self.assertEqual(contribution.email_author, 'x@x.x')
self.assertEqual(landscape_element.get_type_display(), 'Doline')
self.assertEqual(len(mail.outbox), 1)

@override_settings(MANAGERS=[("Fake", "fake@fake.fake"), ])
def test_contribution_create_send_manager_contributor(self):
self.assertEqual(len(mail.outbox), 0)
url = reverse('api_portal:contributions-list',
kwargs={'portal_pk': self.portal.pk, 'lang': 'fr'})
self.client.post(url, data={"geom": "POINT(0 0)",
"properties": '{"email_author": "x@x.x", "date_observation": "2022-08-16", '
'"category": "Contribution Élément Paysagers",'
'"type": "Doline"}'})
self.assertEqual(len(mail.outbox), 2)

def test_contribution_quality(self):
self.assertEqual(len(mail.outbox), 0)
url = reverse('api_portal:contributions-list',
kwargs={'portal_pk': self.portal.pk, 'lang': 'fr'})
response = self.client.post(url, data={"geom": "POINT(0 0)",
Expand All @@ -60,8 +75,10 @@ def test_contribution_quality(self):
self.assertEqual(quality.nature_pollution.label, 'Baz')
self.assertEqual(contribution.email_author, 'x@x.x')
self.assertEqual(quality.get_type_display(), 'Pollution')
self.assertEqual(len(mail.outbox), 1)

def test_contribution_quantity(self):
self.assertEqual(len(mail.outbox), 0)
url = reverse('api_portal:contributions-list',
kwargs={'portal_pk': self.portal.pk, 'lang': 'fr', 'format': 'json'})
response = self.client.post(url, data={"geom": "POINT(0 0)",
Expand All @@ -74,8 +91,10 @@ def test_contribution_quantity(self):
quantity = contribution.quantity
self.assertEqual(contribution.email_author, 'x@x.x')
self.assertEqual(quantity.get_type_display(), 'A sec')
self.assertEqual(len(mail.outbox), 1)

def test_contribution_faunaflora(self):
self.assertEqual(len(mail.outbox), 0)
url = reverse('api_portal:contributions-list',
kwargs={'portal_pk': self.portal.pk, 'lang': 'fr', 'format': 'json'})
response = self.client.post(url, data={"geom": "POINT(4 43.5)",
Expand All @@ -90,8 +109,10 @@ def test_contribution_faunaflora(self):
fauna_flora = contribution.fauna_flora
self.assertEqual(contribution.email_author, 'x@x.x')
self.assertEqual(fauna_flora.get_type_display(), 'Espèce invasive')
self.assertEqual(len(mail.outbox), 1)

def test_contribution_potential_damages(self):
self.assertEqual(len(mail.outbox), 0)
url = reverse('api_portal:contributions-list',
kwargs={'portal_pk': self.portal.pk, 'lang': 'fr', 'format': 'json'})
response = self.client.post(url, data={"geom": "POINT(4 42.5)",
Expand All @@ -104,6 +125,7 @@ def test_contribution_potential_damages(self):
potential_damage = contribution.potential_damage
self.assertEqual(contribution.email_author, 'x@x.x')
self.assertEqual(potential_damage.get_type_display(), 'Éboulements')
self.assertEqual(len(mail.outbox), 1)

def test_contribution_category_does_not_exist(self):
url = reverse('api_portal:contributions-list',
Expand Down
Loading
Loading