Skip to content

Commit d52c7dc

Browse files
committed
feat(radiation_protection): send document to risk advisor when completing the certification
- Added radiation protection app with models and logic for certification. - Implemented document generation and email notification for risk advisors. - Updated environment configuration to include new risk advisor email setting. - Refactored existing code to integrate radiation protection features into the application. - Added tests for certification logic and document handling.
1 parent c621236 commit d52c7dc

23 files changed

Lines changed: 838 additions & 167 deletions

File tree

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ MATOMO_SITE_ID=
2828
ORCID_USE_SANDBOX=false
2929
RADIATION_PROTECTION_CERTIFICATION_NAME="Radiation protection"
3030
RADIATION_PROTECTION_TALLY_SECRET_KEY=
31+
RADIATION_PROTECTION_RISK_ADVISOR_EMAIL=
3132
SITE_URL=http://localhost:8000
3233
S3_BUCKET_NAME=euphrosyne
3334
S3_BUCKET_REGION_NAME=fr-par

.github/workflows/test.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ env:
1818
EROS_HTTP_TOKEN: token
1919
RADIATION_PROTECTION_CERTIFICATION_NAME: quiz
2020
RADIATION_PROTECTION_TALLY_SECRET_KEY: secret
21+
RADIATION_PROTECTION_RISK_ADVISOR_EMAIL: test@test.com
2122

2223
jobs:
2324
python-checks:
Lines changed: 76 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,98 @@
11
from io import StringIO
2+
from pathlib import Path
3+
from tempfile import TemporaryDirectory
24
from unittest import mock
3-
5+
import pytest
46
from django.core import mail
57
from django.core.management import call_command
6-
from django.test import TestCase
78

89
from certification.certifications.models import Certification, QuizCertification
910
from lab.tests.factories import StaffUserFactory
1011

1112
from ..models import CertificationNotification, NotificationType
1213

13-
TEMPLATE = "certification/email/radioprotection_invitation.html"
1414

15+
@pytest.fixture(name="temp_template_path")
16+
def temp_template_path_fixture():
17+
"""Create a temporary directory with a template file for testing."""
18+
with TemporaryDirectory() as temp_dir:
19+
# Create the template directory structure
20+
template_dir = Path(temp_dir) / "certification" / "email"
21+
template_dir.mkdir(parents=True)
1522

16-
class ClosepollTest(TestCase):
17-
def test_command_send_notification(self):
18-
user = StaffUserFactory()
19-
notification = CertificationNotification.objects.create(
20-
user=user,
21-
certification=Certification.objects.create(
22-
name="certification",
23-
invitation_to_complete_email_template_path=TEMPLATE,
24-
),
25-
type_of=NotificationType.INVITATION_TO_COMPLETE,
26-
)
27-
QuizCertification.objects.create(
28-
certification=notification.certification, url="url", passing_score=1
29-
)
23+
# Create a simple template file
24+
template_path = template_dir / "radioprotection_invitation.html"
25+
template_path.write_text("<html><body>Test template</body></html>")
3026

31-
out = StringIO()
32-
call_command("send_notifications", stdout=out)
27+
# Add the temp directory to template dirs
28+
with mock.patch(
29+
"django.template.loaders.filesystem.Loader.get_dirs"
30+
) as mock_get_dirs:
31+
mock_get_dirs.return_value = [temp_dir]
32+
yield str(template_path)
3333

34-
notification.refresh_from_db()
35-
assert notification.is_sent
3634

37-
assert (
38-
f"Notification for certification certification sent to {user.email}."
39-
in out.getvalue()
40-
)
35+
@pytest.mark.django_db
36+
def test_command_send_notification(temp_template_path: str):
37+
user = StaffUserFactory()
38+
notification = CertificationNotification.objects.create(
39+
user=user,
40+
certification=Certification.objects.create(
41+
name="certification",
42+
invitation_to_complete_email_template_path=temp_template_path,
43+
),
44+
type_of=NotificationType.INVITATION_TO_COMPLETE,
45+
)
46+
QuizCertification.objects.create(
47+
certification=notification.certification, url="url", passing_score=1
48+
)
4149

42-
assert len(mail.outbox) == 1
43-
assert mail.outbox[0].recipients() == [user.email]
50+
out = StringIO()
51+
call_command("send_notifications", stdout=out)
4452

45-
def test_command_continue_if_error(self):
46-
certification = Certification.objects.create(
47-
name="certification",
48-
invitation_to_complete_email_template_path=TEMPLATE,
49-
)
50-
QuizCertification.objects.create(
51-
certification=certification, url="url", passing_score=1
52-
)
53+
notification.refresh_from_db()
54+
assert notification.is_sent
5355

54-
notifications = []
55-
with mock.patch(
56-
# pylint: disable=line-too-long
57-
"certification.management.commands.send_notifications.CertificationNotification.send_notification"
58-
) as mock_fn:
59-
mock_fn.side_effect = [Exception("Error"), None]
60-
users = [StaffUserFactory(), StaffUserFactory()]
61-
for user in users:
62-
notifications.append(
63-
CertificationNotification.objects.create(
64-
user=user,
65-
certification=certification,
66-
type_of=NotificationType.INVITATION_TO_COMPLETE,
67-
)
56+
assert (
57+
f"Notification for certification certification sent to {user.email}."
58+
in out.getvalue()
59+
)
60+
61+
assert len(mail.outbox) == 1
62+
assert mail.outbox[0].recipients() == [user.email]
63+
64+
65+
@pytest.mark.django_db
66+
def test_command_continue_if_error(temp_template_path: str):
67+
certification = Certification.objects.create(
68+
name="certification",
69+
invitation_to_complete_email_template_path=temp_template_path,
70+
)
71+
QuizCertification.objects.create(
72+
certification=certification, url="url", passing_score=1
73+
)
74+
75+
notifications = []
76+
with mock.patch(
77+
# pylint: disable=line-too-long
78+
"certification.management.commands.send_notifications.CertificationNotification.send_notification"
79+
) as mock_fn:
80+
mock_fn.side_effect = [Exception("Error"), None]
81+
users = [StaffUserFactory(), StaffUserFactory()]
82+
for user in users:
83+
notifications.append(
84+
CertificationNotification.objects.create(
85+
user=user,
86+
certification=certification,
87+
type_of=NotificationType.INVITATION_TO_COMPLETE,
6888
)
89+
)
6990

70-
out = StringIO()
71-
call_command("send_notifications", stdout=out)
91+
out = StringIO()
92+
call_command("send_notifications", stdout=out)
7293

73-
for notification in notifications:
74-
notification.refresh_from_db()
94+
for notification in notifications:
95+
notification.refresh_from_db()
7596

76-
assert not notifications[0].is_sent
77-
assert notifications[1].is_sent
97+
assert not notifications[0].is_sent
98+
assert notifications[1].is_sent

euphro_auth/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
from django.utils.translation import gettext
1515
from django.utils.translation import gettext_lazy as _
1616

17-
from certification import radiation_protection
1817
from lab.participations.models import Participation
1918
from lab.permissions import is_lab_admin
19+
from radiation_protection import certification as radiation_protection
2020

2121
from .emails import send_invitation_email
2222
from .forms import UserChangeForm, UserCreationForm

euphrosyne/settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
"static_pages",
8888
"standard",
8989
"certification",
90+
"radiation_protection",
9091
"drf_spectacular",
9192
] + (["debug_toolbar"] if DEBUG else [])
9293

@@ -397,3 +398,6 @@ def _get_nav_items(request: HttpRequest) -> list:
397398
RADIATION_PROTECTION_TALLY_SECRET_KEY = os.environ[
398399
"RADIATION_PROTECTION_TALLY_SECRET_KEY"
399400
]
401+
RADIATION_PROTECTION_RISK_ADVISOR_EMAIL = os.environ[
402+
"RADIATION_PROTECTION_RISK_ADVISOR_EMAIL"
403+
]

lab/projects/inlines.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
from django.http.request import HttpRequest
1010
from django.utils.translation import gettext_lazy as _
1111

12-
from certification import radiation_protection
1312
from lab.admin.mixins import LabPermission, LabPermissionMixin, LabRole
1413
from lab.models import Participation
14+
from radiation_protection import certification as radiation_protection
1515

1616
from .forms import (
1717
BaseParticipationForm,

lab/projects/tests/test_inlines.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
from django.test import RequestFactory
66
from django.urls import reverse
77

8-
from certification import radiation_protection
98
from euphro_auth.tests import factories as auth_factories
109
from euphrosyne.admin import AdminSite
1110
from lab.tests import factories
11+
from radiation_protection import certification as radiation_protection
1212

1313
from .. import inlines
1414
from ..models import Participation

locale/fr/LC_MESSAGES/django.mo

43 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)