Skip to content

Commit

Permalink
First draft at #346
Browse files Browse the repository at this point in the history
  • Loading branch information
nutjob4life committed Mar 8, 2024
1 parent 398b5f1 commit bce4479
Show file tree
Hide file tree
Showing 16 changed files with 464 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# encoding: utf-8

'''😌 EDRN Site Content: metadata collection form.'''

from .base_forms import (
AbstractEDRNForm, pi_site_choices, discipline_choices, data_category_choices, ALL_USERS_DN,
protocol_choices, organ_choices
)
from .base_models import AbstractFormPage
from captcha.fields import ReCaptchaField
from django import forms
from .tasks import send_email
from django.conf import settings
from eke.knowledge.models import Person, Protocol, BodySystem, Site
from io import StringIO
from urllib.parse import urlparse
from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel
from wagtail.contrib.forms.models import EmailFormMixin
from django.core.exceptions import ValidationError


class BiomarkerSubmissionForm(AbstractEDRNForm):
'''Form to make biomarkers submit.'''

@staticmethod
def get_encoding_type() -> str:
return 'multipart/form-data'

template_name = 'edrnsite.content/biomarker-submission-form.html'
_file_help_text = "A file describing new biomarker(s); PDF preferred but Word is acceptable. If you use this option, there's no need to enter any text in the next box."
_text_help_text = "Describe the biomarker(s) being submitted. If you use this option, there's no need to upload a file."

submitter_name = forms.CharField(
label='Submitter Name', help_text='The name of the person submitting a biomarker.', max_length=100
)
submitter_email = forms.EmailField(label='Submitter Email', help_text="Submitter's email address.")

biomarker_file = forms.FileField(
label='Biomarker(s) File', help_text=_file_help_text, allow_empty_file=False, required=False
)
biomarker_text = forms.CharField(
label='Biomarker(s) Researched', help_text=_text_help_text, required=False, max_length=5000,
widget=forms.Textarea
)
pi_site = forms.ChoiceField(label='Lead PI and Institution', help_text='Select a primary investigator and the institution to which they belong.', choices=pi_site_choices)

protocol = forms.ChoiceField(
label='Protocol', help_text='Select the protocol that generated the data.', choices=protocol_choices
)
organs = forms.MultipleChoiceField(
label='Organs', help_text='Select the body systems. You can select more than one.', choices=organ_choices
)
biomarker_types = forms.MultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
required=True,
label='Biomarker Type',
help_text='Select the kinds of biomarker(s). You can select more than one, but check at least one.',
choices=(
('molecular', 'Molecular'),
('histologic', 'Histologic'),
('radiographic', 'Radiographic'),
('physiological', 'Physiological')
)
)
molecular_subtype = forms.ChoiceField(
widget=forms.RadioSelect,
required=False,
label='Molecular Subtype',
help_text='If you selected "Molecular" as a type, please indicate the subtype by checking a box here.',
choices=(
('chemical', 'Chemical'),
('protein', 'Protein'),
('dna', 'DNA (Genetics)'),
('karyotypic', 'Karyotypic'),
)
)

if not settings.DEBUG:
captcha = ReCaptchaField()

def clean(self):
cleaned_data = super().clean()

f, t = cleaned_data.get('biomarker_file'), cleaned_data.get('biomarker_text')
if not f and not t:
raise ValidationError('You must either provide a file or fill in the text box describing biomarkers.')
elif f and t:
raise ValidationError('Please provide only a file or fill in the text box describing biomarkers—not both.')

t, st = cleaned_data.get('biomarker_types'), cleaned_data.get('molecular_subtype')
if t and 'molecular' in t and not st:
raise ValidationError('If you select "molecular" as a type, you must also select a subtype.')

return cleaned_data


class BiomarkerSubmissionFormPage(AbstractFormPage, EmailFormMixin):
'''Page containing a form for making biomarkers submit.'''
page_description = 'Page containing a form for biomarker submission'

content_panels = AbstractFormPage.content_panels + [
MultiFieldPanel([
FieldRowPanel([
FieldPanel('from_address', classname='col6', help_text='From whom this email will originate'),
FieldPanel('to_address', classname='col6', help_text='Who should receive this email; commas in between multiple addresses')
]),
FieldPanel('subject')
], 'Email')
]

def get_form(self) -> type:
return BiomarkerSubmissionForm

def get_initial_values(self, request) -> dict:
initial = super().get_initial_values(request)
if request.user.is_authenticated:
try:
name = request.user.ldap_user.attrs['cn'][0]
except (AttributeError, KeyError, IndexError, TypeError):
name = f'{request.user.first_name} {request.user.last_name}'.strip()
initial['submitter_name'] = name
try:
email = request.user.ldap_user.attrs['mail'][0]
except (AttributeError, KeyError, IndexError, TypeError):
email = request.user.email
initial['submitter_email'] = email
return initial

def get_landing_page(self) -> str:
return 'edrnsite.content/biomarker-submission-landing.html'

def _code(self, identifier: str) -> str:
return urlparse(identifier).path.split('/')[-1]

def process_submission(self, form: forms.Form) -> dict:
# The ``EmailFormMixin`` nicely provides both the from/to/subject fields and also this handy function:
# self.send_mail(form)
# which we can't use since it doesn't handle attachments.
if not settings.DEBUG:
del form.cleaned_data['captcha']
data = form.cleaned_data
rendered = f'Submitter Name: {data["submitter_name"]}\nSubmitter Email: {data["submitter_email"]}'

site_id, pi_id = data['pi_site'].split('-')
pi = Person.objects.filter(personID=pi_id).first()
if pi:
rendered += f'\nPI ID: {pi_id}'
rendered += f'\nPI Name: {pi.title}'
site = Site.objects.filter(dmccSiteID=site_id).first()
if site:
rendered += f'\nInstitution ID: {site_id}'
rendered += f'\nInstitution Name: {site.title}'

protocol = Protocol.objects.filter(identifier=data['protocol']).first()
if protocol:
rendered += f'\nProtocol ID: {self._code(data["protocol"])}'
rendered += f'\nProtocol Name: {protocol.title}'

organ_identifiers = data.get('organs')
if organ_identifiers:
names = [i for i in BodySystem.objects.filter(
identifier__in=organ_identifiers
).order_by('title').values_list('title', flat=True)]
rendered += f'\nOrgans: {", ".join(names)}'

types = data.get('biomarker_types')
if types:
rendered += f'\nBiomarker Types: {", ".join(types)}'

subtype = data.get('molecular_subtype')
if subtype:
rendered += f'\nMolecular Subtype: {subtype}'

biomarker_file = form.cleaned_data['biomarker_file']
if biomarker_file:
rendered += '\nA biomarker file was uploaded; it is attached'
attachment_data = biomarker_file.read()
send_email(
self.from_address, self.to_address.split(','), self.subject, rendered,
{'name': biomarker_file.name, 'data': attachment_data, 'content_type': biomarker_file.content_type}, 10
)
else:
rendered += f'\nBiomarker(s) Researched:\n{data["biomarker_text"]}'
send_email(self.from_address, self.to_address.split(','), self.subject, rendered, None, 10)

# And we're done
return {'name': form.cleaned_data['submitter_name'], 'email': form.cleaned_data['submitter_email']}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
'''😌 EDRN Site Content: metadata collection form.'''

from .base_forms import (
AbstractEDRNForm, pi_site_choices, discipline_choices, data_category_choices, ALL_USERS_DN
AbstractEDRNForm, pi_site_choices, discipline_choices, data_category_choices, ALL_USERS_DN,
protocol_choices, organ_choices
)
from .base_models import AbstractFormPage
from captcha.fields import ReCaptchaField
Expand All @@ -17,14 +18,6 @@
from wagtail.contrib.forms.models import EmailFormMixin


def _protocols():
return [(i.identifier, f'{i.title} ({i.protocolID})') for i in Protocol.objects.all().order_by('title')]


def _organs():
return [(i.identifier, i.title) for i in BodySystem.objects.all().order_by('title')]


def _species():
species = (
'Homo sapiens',
Expand All @@ -47,7 +40,7 @@ class MetadataCollectionForm(AbstractEDRNForm):
custodian = forms.CharField(label='Data Custodian', help_text='Genrally, this is your name.')
custodian_email = forms.EmailField(label='Data Custodian Email', help_text='Email address for the data custodian.')
pi_site = forms.ChoiceField(label='Lead PI and Institution', help_text='Select a primary investigator and the institution to which they belong.', choices=pi_site_choices)
protocol = forms.ChoiceField(label='Protocol', help_text='Select the protocol that generated the data.', choices=_protocols)
protocol = forms.ChoiceField(label='Protocol', help_text='Select the protocol that generated the data.', choices=protocol_choices)
biomarkers_researched = forms.CharField(
required=False, label='Biomarkers Researched', widget=forms.Textarea, max_length=5000,
help_text='Describe the cancer biomarkers being researched by this data.'
Expand All @@ -68,7 +61,7 @@ class MetadataCollectionForm(AbstractEDRNForm):
label='Other Data Category', help_text='If you selected Other above ↑, enter the category here.',
max_length=100, required=False
)
organ = forms.ChoiceField(label='Organ', help_text='Select the body system.', choices=_organs)
organ = forms.ChoiceField(label='Organ', help_text='Select the body system.', choices=organ_choices)
species = forms.ChoiceField(label='Species', help_text='Enter the species.', choices=_species)
private = forms.BooleanField(required=False, label='Private Data', help_text='Check this box ↑ if this data collection is private.')
access_groups = forms.CharField(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel
from wagtail.contrib.forms.models import EmailFormMixin
from wagtail.fields import RichTextField
from django.utils.text import slugify


_preamble_default = (
Expand Down
11 changes: 9 additions & 2 deletions src/edrnsite.content/src/edrnsite/content/base_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@

from django import forms
from django.forms.utils import ErrorList
from eke.knowledge.models import Site, Person

from eke.knowledge.models import Site, Person, Protocol, BodySystem

ALL_USERS_DN = 'cn=All Users,dc=edrn,dc=jpl,dc=nasa,dc=gov'


def protocol_choices():
return [(i.identifier, f'{i.title} ({i.protocolID})') for i in Protocol.objects.all().order_by('title')]


def organ_choices():
return [(i.identifier, i.title) for i in BodySystem.objects.all().order_by('title')]


def institution_choices():
'''Vocabulary for choices of institution in choice fields.'''
return [(i.identifier, f'{i.title} ({i.dmccSiteID})') for i in Site.objects.all().order_by('title')]
Expand Down
1 change: 0 additions & 1 deletion src/edrnsite.content/src/edrnsite/content/base_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,3 @@ class BaseEmailForm(Page):
]
class Meta:
abstract = True

6 changes: 4 additions & 2 deletions src/edrnsite.content/src/edrnsite/content/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

'''😌 EDRN Site Content: Django forms.'''

from ._metadata_collection_form import MetadataCollectionForm # noqa
from ._spec_ref_set_form import SpecimenReferenceSetRequestForm # noqa
from ._metadata_collection_form import MetadataCollectionForm # noqa: F401
from ._spec_ref_set_form import SpecimenReferenceSetRequestForm # noqa: F401
from ._biomarker_submission_form import BiomarklerSubmissionForm # noqa: F401


__all__ = (
BiomarklerSubmissionForm,
MetadataCollectionForm,
SpecimenReferenceSetRequestForm,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Generated by Django 4.2.10 on 2024-03-08 20:22

from django.db import migrations, models
import django.db.models.deletion
import wagtail.contrib.forms.models
import wagtail.fields


class Migration(migrations.Migration):
dependencies = [
("wagtailcore", "0089_log_entry_data_json_null_to_object"),
("edrnsitecontent", "0033_alter_homepage_body"),
]

operations = [
migrations.CreateModel(
name="BiomarkerSubmissionFormPage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
(
"to_address",
models.CharField(
blank=True,
help_text="Optional - form submissions will be emailed to these addresses. Separate multiple addresses by comma.",
max_length=255,
validators=[wagtail.contrib.forms.models.validate_to_address],
verbose_name="to address",
),
),
(
"from_address",
models.EmailField(
blank=True, max_length=255, verbose_name="from address"
),
),
(
"subject",
models.CharField(
blank=True, max_length=255, verbose_name="subject"
),
),
(
"intro",
wagtail.fields.RichTextField(
blank=True,
help_text="Introductory text to appear above the form",
),
),
(
"outro",
wagtail.fields.RichTextField(
blank=True, help_text="Text to appear below the form"
),
),
],
options={
"abstract": False,
},
bases=("wagtailcore.page", models.Model),
),
]
1 change: 1 addition & 0 deletions src/edrnsite.content/src/edrnsite/content/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
'''😌 EDRN site content's models.'''


from ._biomarker_submission_form import BiomarkerSubmissionFormPage # noqa: F401
from ._dataset_metadata_form import DatasetMetadataFormPage # noqa: F401
from ._metadata_collection_form import MetadataCollectionFormPage # noqa: F401
from ._spec_ref_set_form import SpecimenReferenceSetRequestFormPage # noqa: F401
Expand Down
Loading

0 comments on commit bce4479

Please sign in to comment.