Commit d1e82780 authored by Jacek Lebioda's avatar Jacek Lebioda
Browse files

feat: email reporting

parent 89e2e6ee
......@@ -2,6 +2,7 @@ from functools import reduce
from operator import concat
from typing import List, Type, Union
from django.conf import settings
from django.db.models import Model
from django.db.models.query import QuerySet
from django.db.models.manager import Manager
......@@ -11,10 +12,18 @@ from core.models.dataset import Dataset
from core.models.data_declaration import DataDeclaration
from core.models.project import Project
from core.models.user import User
from notification.email_sender import send_the_email
def cast_to_queryset(object: Union[Model, List[Model], QuerySet], klass: Type = None):
"""Casts the object, or a list of objects to a queryset"""
"""
Casts the parameter to a queryset.
Accepts:
- the object (of Model)
- a list of objects
- a Queryset (e.g. Project.objects.all())
- a Manager (e.g. Project.objects)
"""
if object is None:
return None
if klass is None:
......@@ -63,6 +72,10 @@ class ReportParameters:
class ReportParametersCollector:
@classmethod
def generate_for_user(cls, user: User):
"""
Generates the `ReportParameters` containing given User's entities -
projects, datasets, data declarations and issues.
"""
projects = Project.objects.filter(local_custodians__id=user.id)
# TODO: What exactly needs to be collected here:
# 1) datasets whose local_custodian is the User
......@@ -91,11 +104,42 @@ class ReportRenderer:
self.data_declarations = report_parameters.data_declarations
self.projects = report_parameters.projects
def render(self):
def render_html(self):
return self._render('report_email.html')
def render_txt(self):
return self._render('report_email.txt')
def _render(self, template_name):
context = {
'projects': self.projects,
'datasets': self.datasets,
'data_declarations': self.data_declarations,
'issues': self.issues
}
return render_to_string('report_email.html', context)
return render_to_string(template_name, context)
def get_users_to_receive_emails(force=False):
should_continue = getattr(settings, 'EMAIL_REPORTS_ENABLED', False)
if force or should_continue:
return User.objects.filter(email__contains='@')
else:
return []
def generate_and_send_reports(force=False):
list_of_users = get_users_to_receive_emails(force)
for user in list_of_users:
generate_and_send_report_to(user)
def generate_and_send_report_to(user: User):
report_params = ReportParametersCollector.generate_for_user(user)
html_contents = ReportRenderer(report_params).render_html()
txt_contents = ReportRenderer(report_params).render_txt()
send_the_email(
settings.EMAIL_DONOTREPLY,
user.email,
'Report',
txt_contents,
html_contents
)
\ No newline at end of file
DAISY report (Generated at: {% now "Y/m/j" %})
This report contains all records for which you were appointed as a local custodian,
and highlights any issues in the records (found by an automatic validation rules).
The list has been created to raise awareness of missing or incomplete records and other necessary information required
for compliance with GDPR.
General overview:
Projects count: {{ projects | length }}
Datasets count: {{ datasets | length }}
Data declarations count: {{ data_declarations | length }}
Issues found: {{ issues | length }}
Detailed overview:
{% for project in projects.all %}
Project: {{ project.title }} ({{ project.acronym }})
{% for dataset in project.datasets.all %}
Dataset: {{ dataset.title }}
Data types: {{ dataset_data_types }} (TODO:)
Data declaration count: {{ dataset.data_declarations | length }}
Data locations: {{ dataset_data_locations }} (TODO:)
{% endfor %}
{% endfor %}
Issues found:
{% for issue in issues %}
{{ issue.code }}: {{ issue.description }}
{{ issue.object_title }}
{{ issue.url }}
{% endfor %}
\ No newline at end of file
......@@ -50,7 +50,8 @@ def test_report_renderer():
params = ReportParameters(list_of_projects)
report_renderer = ReportRenderer(params)
rendered_html = report_renderer.render()
rendered_html = report_renderer.render_html()
_ = report_renderer.render_txt()
assert PROJECT_ACRONYM in rendered_html
assert PROJECT_TITLE in rendered_html
......
......@@ -22,6 +22,8 @@ INSTANCE_LABEL = None
# Override of the layout's primary color (used in e.g. navbar), e.g. '#076505'
INSTANCE_PRIMARY_COLOR = None
EMAIL_REPORTS_ENABLED = False
AUTH_USER_MODEL = 'core.User'
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
......
"""
Template for email
Some routines concerning e-mail generation and sending
"""
from django.urls import reverse
from django.conf import settings
from django.core.mail import send_mail, EmailMultiAlternatives
from django.template.loader import render_to_string
from django.conf import settings
from django.urls import reverse
SUBJECT_PREFIX = '[DAISY]'
SUBJECT_PREFIX = '[DAISY]'
def send_the_email(sender_email, recipients, subject, template, context):
def send_email_from_template(sender_email, recipients, subject, template, context):
"""
Send an email to the recipents using the templates,
Generates and sends an email message from html/txt template
"""
# recipients can be a list or single email
if not isinstance(recipients, (list, tuple)):
recipients = [recipients]
# update context with server full url if it's not present already
# Update context with server's full url if it's not present already
if 'server_url' not in context:
context['server_url'] = '%s://%s' % (settings.SERVER_SCHEME, settings.SERVER_URL)
if 'profile_url' not in context:
context['profile_url'] = reverse('profile')
# prepare email
subject = f"{SUBJECT_PREFIX} {subject}"
# Prepare the email
text_message = render_to_string('%s.txt' % template, context)
html_message = render_to_string('%s.html' % template, context)
return send_the_email(sender_email, recipients, subject, text_message, html_message)
def send_the_email(sender_email, recipients, subject, text_message, html_message=None):
"""
Send an email to the recipents using given txt and html messages
"""
# Recipients can be a list or single email
if not isinstance(recipients, (list, tuple)):
recipients = [recipients]
_send_the_email(sender_email, recipients, subject, text_message, html_message, False)
def _send_the_email(sender_email, recipients, subject, text_message, html_message, fail_silently):
msg = EmailMultiAlternatives(
subject,
text_message,
sender_email,
recipients
)
msg.attach_alternative(html_message, 'text/html')
msg.send(fail_silently=False)
\ No newline at end of file
if html_message is not None:
msg.attach_alternative(html_message, 'text/html')
msg.send(fail_silently=fail_silently)
\ No newline at end of file
from notification.email_sender import send_the_email
from django.conf import settings
from notification.email_sender import send_email_from_template
def test_send_email(celery_session_worker):
"""
Check if at least it does not throw errors
"""
send_the_email(settings.EMAIL_DONOTREPLY, [], 'Title of the email', 'notification/notification_report', {})
\ No newline at end of file
send_email_from_template(settings.EMAIL_DONOTREPLY, [], 'Title of the email', 'notification/notification_report', {})
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment