Skip to content
This repository was archived by the owner on Nov 24, 2023. It is now read-only.
Draft

WIP #410

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
106 changes: 53 additions & 53 deletions interactive/emails.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,61 @@
import html2text
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string


def send_welcome_email(email, context):
subject = "Welcome to OpenSAFELY Interactive"
html_body = render_to_string("emails/welcome_email.html", context)
text_body = _convert_html(html_body)

msg = EmailMultiAlternatives(
subject=subject,
from_email="OpenSAFELY Interactive <no-reply@mg.interactive.opensafely.org>",
reply_to=("OpenSAFELY Team <team@opensafely.org>",),
to=[email],
body=text_body,
from django.conf import settings
from furl import furl
from incuna_mail import send


def send_welcome_email(email, user):
reset_url = furl(settings.BASE_URL) / user.get_password_reset_url()

context = {
"domain": settings.BASE_URL,
"name": user.name,
"url": reset_url,
}

send(
to=email,
subject="Welcome to OpenSAFELY Interactive",
sender="OpenSAFELY Interactive <no-reply@mg.interactive.opensafely.org>",
reply_to=["OpenSAFELY Team <team@opensafely.org>"],
template_name="emails/welcome_email.txt",
html_template_name="emails/welcome_email.html",
context=context,
)
msg.attach_alternative(html_body, "text/html")
msg.send()


def send_analysis_request_email(email, context):
subject = f"OpenSAFELY: {context.get('title')}"
html_body = render_to_string("emails/analysis_done.html", context)
text_body = _convert_html(html_body)
def send_analysis_request_email(email, analysis_request):
output_url = furl(settings.BASE_URL) / analysis_request.get_output_url()

msg = EmailMultiAlternatives(
subject=subject,
from_email="OpenSAFELY Interactive <no-reply@mg.interactive.opensafely.org>",
reply_to=("OpenSAFELY Team <team@opensafely.org>",),
to=[email],
body=text_body,
)
msg.attach_alternative(html_body, "text/html")
msg.send()
context = {
"name": analysis_request.user.name,
"title": analysis_request.title,
"url": output_url,
}

send(
to=email,
subject=f"OpenSAFELY: {context.get('title')}",
sender="OpenSAFELY Interactive <no-reply@mg.interactive.opensafely.org>",
reply_to=["OpenSAFELY Team <team@opensafely.org>"],
template_name="emails/analysis_done.txt",
html_template_name="emails/analysis_done.html",
context=context,
)

def send_analysis_request_confirmation_email(to, subject, context):
subject = f"OpenSAFELY: {subject} submitted"
html_body = render_to_string("emails/analysis_confirmation.html", context)
text_body = _convert_html(html_body)

msg = EmailMultiAlternatives(
subject=subject,
from_email="OpenSAFELY Interactive <no-reply@mg.interactive.opensafely.org>",
reply_to=("OpenSAFELY Team <team@opensafely.org>",),
to=[to],
body=text_body,
def send_analysis_request_confirmation_email(email, analysis_request):
context = {
"name": analysis_request.user.name,
"codelist": analysis_request.codelist_name,
"email": analysis_request.user.email,
}

send(
to=email,
subject=f"OpenSAFELY: {analysis_request.title} submitted",
sender="OpenSAFELY Interactive <no-reply@mg.interactive.opensafely.org>",
reply_to=["OpenSAFELY Team <team@opensafely.org>"],
template_name="emails/analysis_confirmation.txt",
html_template_name="emails/analysis_confirmation.html",
context=context,
)
msg.attach_alternative(html_body, "text/html")
msg.send()


def _convert_html(raw_html):
text_maker = html2text.HTML2Text()
text_maker.ignore_images = True
text_maker.ignore_emphasis = True
text_maker.ignore_links = True
text_maker.body_width = 0
raw_text = text_maker.handle(raw_html)
return raw_text
17 changes: 5 additions & 12 deletions interactive/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from django.utils import timezone
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode
from furl import furl
from timeflake.extensions.django import TimeflakePrimaryKeyBinary

from .emails import send_welcome_email
Expand Down Expand Up @@ -115,7 +114,10 @@ def get_full_name(self):
def __str__(self):
return self.email

def get_password_reset_url(self, uid, token):
def get_password_reset_url(self):
uid = urlsafe_base64_encode(force_bytes(self.pk))
token = PasswordResetTokenGenerator().make_token(self)

return reverse("password_reset_confirm", kwargs={"uidb64": uid, "token": token})


Expand Down Expand Up @@ -203,13 +205,4 @@ def send_email(sender, instance, created, **kwargs):
if not created:
return

uid = urlsafe_base64_encode(force_bytes(instance.pk))
token = PasswordResetTokenGenerator().make_token(instance)
reset_url = furl(settings.BASE_URL) / instance.get_password_reset_url(uid, token)

context = {
"name": instance.name,
"url": reset_url,
}

send_welcome_email(instance.email, context)
send_welcome_email(instance.email, instance)
16 changes: 12 additions & 4 deletions interactive/notifications.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.conf import settings
from django_slack import slack_message
from furl import furl

from services import slack
Expand Down Expand Up @@ -35,7 +36,14 @@ def notify_analysis_request_submitted(analysis_request, issue_url):
slack.post(text=message, channel="opensafely-outputs")


def notify_registration_request_submitted(full_name, job_title, organisation, email):
full_name_link = slack.link(email, full_name, is_email=True)
message = f"{full_name_link} ({job_title}) from {organisation} has registered their interest in using OpenSAFELY Interactive"
slack.post(text=message, channel="interactive-registration-requests")
def notify_registration_request_submitted(user):
context = {
"full_name_link": slack.link(user.email, user.full_name, is_email=True),
"user": user,
}

slack_message(
"slacks/registration_request_submitted.slack",
channel="interactive-registration-requests",
context=context,
)
11 changes: 8 additions & 3 deletions interactive/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"anymail",
"django.contrib.staticfiles",
"django_extensions",
"django_slack",
"django_vite",
"django.contrib.admin",
"django.contrib.auth",
Expand Down Expand Up @@ -214,9 +215,6 @@ def immutable_file_test(path, url):
CSRF_TRUSTED_ORIGINS = [BASE_URL]
SESSION_COOKIE_SECURE = not DEBUG

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = BASE_DIR / "sent_emails"

# THIRD PARTY SETTINGS

sentry.initialise_sentry()
Expand Down Expand Up @@ -294,3 +292,10 @@ def immutable_file_test(path, url):
PERMISSIONS_POLICY = {
"interest-cohort": [],
}


# Slack
# https://django-slack.readthedocs.io/
SLACK_BACKEND = env.str("SLACK_BACKEND", default="django_slack.backends.ConsoleBackend")
SLACK_CHANNEL = "interactive-requests"
SLACK_TOKEN = env.str("SLACK_BOT_TOKEN", default="")
8 changes: 1 addition & 7 deletions interactive/submit.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,7 @@ def submit_analysis(analysis_request, force=False):
notify_analysis_request_submitted(analysis_request, issue_url)

send_analysis_request_confirmation_email(
analysis_request.user.email,
subject=analysis_request.title,
context={
"name": analysis_request.user.name,
"codelist": analysis_request.codelist_name,
"email": analysis_request.user.email,
},
analysis_request.user.email, analysis_request
)


Expand Down
13 changes: 13 additions & 0 deletions interactive/templates/emails/analysis_confirmation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% extends "emails/base.txt" %}

{% block content %}
Hi {{ name }},

You submitted an analysis request for the {{ codelist }} codelist.

We will send an email to {{ email }} when your analysis is ready.

During the pilot phase results will be checked carefully by our team for privacy and security reasons.
We aim to process requests within half a working day, although it may take up to two working days.
We are working to improve and automate these processes in the future.
{% endblock %}
11 changes: 11 additions & 0 deletions interactive/templates/emails/analysis_done.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% extends "emails/base.txt" %}

{% block content %}
Hi {{ name }},

Your analysis titled "{{ title }}" using OpenSAFELY interactive has now finished running. You can view the results at:

{{ url }}

These results are not publicly accessible and are only viewable when logged into your OpenSAFELY Interactive account. Please do not share these results with anyone. If you would like to share the results, please send an email to us at team@opensafely.org
{% endblock %}
9 changes: 9 additions & 0 deletions interactive/templates/emails/base.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% block content %}{% endblock %}
Kind regards,
The OpenSAFELY Team

OpenSAFELY Interactive is a new tool in active development. Please let us know your thoughts on how we can improve the service by filling out our feedback form:

https://docs.google.com/forms/d/e/1FAIpQLScWikDx0UlqbEcnbzZhn5FiBTBHc2LtrfhqmmKwgOuKt4oFTQ/viewform

or by emailing us at: team@opensafely.org
17 changes: 17 additions & 0 deletions interactive/templates/emails/welcome_email.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% extends "emails/base.txt" %}

{% block content %}
Hi {{ name }},

Thank you for your interest in OpenSAFELY Interactive.

Please click on the link to finish setting up your account:

{{ url }}

Once you've setup your account, you'll be able to login to the website, {{ domain }}, and request an analysis by clicking on "Get started".

In the early development phase, you will be able to analyse the rate of recorded coding activity in primary care across a specified time period, using all SNOMED CT codelists that have been used in OpenSAFELY projects for covid-related purposes.

Once your analysis has been run, we will send you an email with instructions on how to view the results.
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends django_slack %}

{% block text %}
{{ full_name_link }} ({{ user.job_title }}) from {{ user.organisation }} has registered their interest in using OpenSAFELY Interactive
{% endblock %}
18 changes: 3 additions & 15 deletions interactive/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import LoginView as DjangoLoginView
Expand All @@ -8,7 +7,6 @@
from django.template.response import TemplateResponse
from django.utils import timezone
from django.views.generic import FormView
from furl import furl

from interactive.submit import submit_analysis
from services import jobserver, opencodelists
Expand All @@ -24,13 +22,8 @@ class RegisterInterest(FormView):
template_name = "interactive/register_interest.html"

def form_valid(self, form):
form.save()
notify_registration_request_submitted(
form.instance.full_name,
form.instance.job_title,
form.instance.organisation,
form.instance.email,
)
registration = form.save()
notify_registration_request_submitted(registration)
return redirect("register_interest_done")


Expand Down Expand Up @@ -100,12 +93,7 @@ def analysis_request_email(request, pk):
return permission_denied(request)

analysis_request = get_object_or_404(AnalysisRequest, pk=pk)
context = {
"name": analysis_request.user.name,
"title": analysis_request.title,
"url": furl(settings.BASE_URL) / analysis_request.get_output_url(),
}
send_analysis_request_email(analysis_request.user.email, context)
send_analysis_request_email(analysis_request.user.email, analysis_request)

analysis_request.complete_email_sent_at = timezone.now()
analysis_request.save()
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ known_third_party = ["debug_toolbar", "django", "environs", "furl", "lxml", "pyt
DJANGO_SETTINGS_MODULE = "interactive.settings"
env = [
"SECRET_KEY=12345",
"SLACK_BACKEND=django_slack.backends.TestBackend",
]
addopts = "--tb=native --ignore=node_modules --no-migrations"
filterwarnings = [
Expand Down
2 changes: 1 addition & 1 deletion requirements.prod.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ django-vite
environs[django]
furl
gunicorn
html2text
incuna-mail
psycopg2-binary
requests
sentry-sdk
Expand Down
9 changes: 5 additions & 4 deletions requirements.prod.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,14 @@ gunicorn==20.1.0 \
--hash=sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e \
--hash=sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8
# via -r requirements.prod.in
html2text==2020.1.16 \
--hash=sha256:c7c629882da0cf377d66f073329ccf34a12ed2adf0169b9285ae4e63ef54c82b \
--hash=sha256:e296318e16b059ddb97f7a8a1d6a5c1d7af4544049a01e261731d2d5cc277bbb
# via -r requirements.prod.in
idna==3.3 \
--hash=sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff \
--hash=sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d
# via requests
incuna-mail==4.1.1 \
--hash=sha256:4071949a7cc70f88c1acea5f06ac8ba439029f655ff5d8c98277bbc8cc8d4bd5 \
--hash=sha256:d8ef4979264fba729fa1478819d71f66af17a795e82d9607d8e7ccd7edaafe10
# via -r requirements.prod.in
marshmallow==3.15.0 \
--hash=sha256:2aaaab4f01ef4f5a011a21319af9fce17ab13bf28a026d1252adab0e035648d5 \
--hash=sha256:ff79885ed43b579782f48c251d262e062bce49c65c52412458769a4fb57ac30f
Expand Down Expand Up @@ -250,6 +250,7 @@ six==1.16.0 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
# via
# furl
# incuna-mail
# orderedmultidict
slack-sdk==3.19.3 \
--hash=sha256:316574ffaf0f5c55bd08476b0a34f3bd2caa9b90b814859bc22922f25934d3aa \
Expand Down
9 changes: 9 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from collections import namedtuple

import pytest
from django_slack.utils import get_backend
from hypothesis import settings

import services
Expand Down Expand Up @@ -54,3 +55,11 @@ def post(text, channel=None):

monkeypatch.setattr("services.slack.post", post)
return messages


@pytest.fixture
def get_slack_messages():
backend = get_backend()
backend.reset_messages()

yield backend.retrieve_messages
Loading