Skip to content

Commit

Permalink
Refactored Wizard tests and view; added docstrings and type hints.
Browse files Browse the repository at this point in the history
  • Loading branch information
moustaphacheikh committed Aug 8, 2023
1 parent 7afc37e commit e35ae89
Show file tree
Hide file tree
Showing 16 changed files with 187 additions and 105 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ You are encouraged to try Daisy for yourself using our [DEMO deployment](https:/
1. Create initial data in the database

```bash
docker-compose exec web bash -c "apt update && apt install -y wget"
docker-compose exec web bash -c "cd core/fixtures/ && wget https://git-r3lab.uni.lu/pinar.alper/metadata-tools/raw/master/metadata_tools/resources/edda.json && wget https://git-r3lab.uni.lu/pinar.alper/metadata-tools/raw/master/metadata_tools/resources/hpo.json && wget https://git-r3lab.uni.lu/pinar.alper/metadata-tools/raw/master/metadata_tools/resources/hdo.json && wget https://git-r3lab.uni.lu/pinar.alper/metadata-tools/raw/master/metadata_tools/resources/hgnc.json"
docker-compose exec web python manage.py load_initial_data
```
Expand All @@ -69,7 +70,7 @@ You are encouraged to try Daisy for yourself using our [DEMO deployment](https:/
```bash
docker-compose exec web python manage.py load_demo_data
```
This will create mock datasets, projects and create an demo admin account.
This will create mock datasets, projects and create a demo admin account.

1. Optional - import users from an active directory instance

Expand Down Expand Up @@ -170,7 +171,7 @@ where ${JSON_FILE} is the path to a json file that will be produced. In additio

```bash
docker-compose exec web python manage.py rebuild_index -u default
```
```
1. Reimport the users (optional).

If LDAP was used during initial setup to import users, they have to be imported again:
Expand Down
10 changes: 5 additions & 5 deletions core/forms/access.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ class Meta:
"access_notes": Textarea(attrs={"rows": 2, "cols": 40}),
}
heading = "Access"
heading_help = "Please provide a help text for Access form"
heading_help = "Specify who can access the data, the duration, and any relevant notes. Ensure accuracy for data security."

def __init__(self, *args, **kwargs):
dataset = kwargs.pop("dataset", None)
super().__init__(*args, **kwargs)
# we don't allow editing dataset
self.fields.pop("dataset")
if dataset:
self.fields["defined_on_locations"].choices = [
(d.id, d) for d in dataset.data_locations.all()
]
self.fields["defined_on_locations"].choices = [
(d.id, d) for d in dataset.data_locations.all()
]

field_order = [
"contact",
Expand Down
57 changes: 27 additions & 30 deletions core/forms/data_declaration.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,40 @@
from django import forms
from django.forms import ValidationError
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy

from core.forms import SkipFieldValidationMixin
from core.forms import UseRestrictionForm
from core.forms import UseRestrictionForm, SkipFieldValidationMixin
from core.models import DataDeclaration, Partner, Contract, GDPRRole
from core.models.contract import PartnerRole


class DataDeclarationEditForm(forms.ModelForm):

class Meta:
model = DataDeclaration
fields = [
'title',
'cohorts',
'partner',
'contract',
'data_declarations_parents',
'comments',
'data_types_generated',
'data_types_received',
'deidentification_method',
'has_special_subjects',
'subjects_category',
'consent_status',
'special_subjects_description',
'end_of_storage_duration',
'storage_duration_criteria',
'embargo_date',
'data_types_notes'
]
widgets = {
# Date pickers
'end_of_storage_duration': forms.DateInput(attrs={'class': 'datepicker'}),
'embargo_date': forms.DateInput(attrs={'class': 'datepicker'}),
}
model = DataDeclaration
fields = [
'title',
'cohorts',
'partner',
'contract',
'data_declarations_parents',
'comments',
'data_types_generated',
'data_types_received',
'deidentification_method',
'has_special_subjects',
'subjects_category',
'consent_status',
'special_subjects_description',
'end_of_storage_duration',
'storage_duration_criteria',
'embargo_date',
'data_types_notes'
]
widgets = {
# Date pickers
'end_of_storage_duration': forms.DateInput(attrs={'class': 'datepicker'}),
'embargo_date': forms.DateInput(attrs={'class': 'datepicker'}),
}

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand All @@ -46,7 +44,6 @@ def __init__(self, *args, **kwargs):
self.fields['data_declarations_parents'].widget.attrs['class'] = 'ontocomplete'+ ' '+ self.fields['data_declarations_parents'].widget.attrs.get('class','')
self.fields['data_declarations_parents'].widget.attrs['data-url'] = reverse_lazy('data_dec_paginated_search')


def clean(self):
"""
Override to check selected Partner and Contract match
Expand Down Expand Up @@ -175,7 +172,7 @@ class Meta:
model = DataDeclaration
fields = ['title']
heading = "Data declaration"
heading_help = "Please provide a help text for the Data declaration form"
heading_help = "Detail your data's origin for clarity. Knowing its provenance enhances its value and trust."

def __init__(self, *args, **kwargs):
self.dataset = kwargs.pop('dataset')
Expand Down
22 changes: 19 additions & 3 deletions core/forms/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,29 @@
from core.models import Dataset, User, Project
from core.models.contract import Contract

from typing import Any


class SkipFieldValidationMixin:
def __init__(self, *args, **kwargs):
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""
Initialize the mixin. Adds a hidden Boolean field named `skip_wizard`
to the form which determines if validation should be skipped.
Args:
*args: Variable arguments to pass to the superclass.
**kwargs: Keyword arguments to pass to the superclass.
"""
super().__init__(*args, **kwargs)
self.fields['skip_wizard'] = forms.BooleanField(initial=False, required=False, widget=forms.HiddenInput())

def is_valid(self):
def is_valid(self) -> bool:
"""
Check if the form is valid. Validation is skipped if `skip_wizard` is True.
Returns:
bool: True if the form is valid or if `skip_wizard` is True, otherwise False.
"""
if self.data.get(f'{self.prefix}-skip_wizard') == 'True':
return True
return super().is_valid()
Expand All @@ -25,7 +41,7 @@ class Meta:
'comments': forms.Textarea(attrs={'rows': 2, 'cols': 40}),
}
heading = "Dataset"
heading_help = "Please provide a help text for the dataset form"
heading_help = "Complete the form to enhance dataset quality. Your careful input benefits our community!"

def __init__(self, *args, **kwargs):
dataset = None
Expand Down
5 changes: 2 additions & 3 deletions core/forms/legal_basis.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ class Meta:
fields = '__all__'
exclude = []
heading = "Data Legal Basis"
heading_help = "Please provide a title for this data declaration"
heading_help = "Define the legal grounds for processing. Ensure your data complies with relevant regulations."

def __init__(self, *args, **kwargs):
dataset = kwargs.pop('dataset', None)
super().__init__(*args, **kwargs)
# we don't allow editing dataset
self.fields.pop('dataset')
if dataset:
self.fields['data_declarations'].choices = [(d.id, d.title) for d in dataset.data_declarations.all()]
self.fields['data_declarations'].choices = [(d.id, d.title) for d in dataset.data_declarations.all()]

field_order = [
'data_declarations',
Expand Down
2 changes: 1 addition & 1 deletion core/forms/storage_location.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Meta:
fields = '__all__'
exclude = []
heading = "Add a new storage location"
heading_help = "Please provide a title for this storage location"
heading_help = "Specify your data's home. Clear storage details ensure easy retrieval and management."

def __init__(self, *args, **kwargs):
dataset = kwargs.pop('dataset', None)
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ services:
- solrdata:/solr
- .:/code
ports:
- "5000:5000"
- "5001:5000"
depends_on:
- db
- node
Expand Down
2 changes: 1 addition & 1 deletion docker/node/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:11.10.1-alpine
FROM node:14
COPY web/static/css /static/css
COPY web/static/js /static/js
COPY web/static/vendor/bootstrap-material-datetimepicker /static/vendor/bootstrap-material-datetimepicker
Expand Down
2 changes: 1 addition & 1 deletion web/static/css/dataset_wizard.css
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,5 @@
}

.skipped:after {
background: #e9ecef;
background: #6c757d;
}
45 changes: 28 additions & 17 deletions web/static/js/data_declaration.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
const skipInput = document.getElementById(skipInputID)
const skipButton = document.getElementById('skipButton')
if (!skipInput) {
skipButton.remove();
}

if (skipButton) {
skipButton.addEventListener('click', function () {
if (skipInput) {
Expand All @@ -11,19 +9,32 @@ if (skipButton) {
}
});
}

/*
* On page load, this script checks if the current step is `data_declaration`.
* If true, it listens for changes on any radio button input. When a radio button
* input changes, the script dynamically loads and inserts a sub-form based on
* the selected declaration type and the dataset ID. This sub-form is placed
* before the form footer. Additionally, after loading the sub-form, it initializes
* select2 on any select fields and applies Bootstrap Material Design styles.
*/

$(document).ready(function () {
$('input[type=radio]').change(function () {
const submit_button = $("#buttons")
$("#sub-form").remove();
const sub_form = $("<div id='sub-form'>");
submit_button.before(sub_form);
const declaration_type = this.value;
const forms_url = dataDeclarationsAddSubFormUrl + '?declaration_type=' + declaration_type + '&dataset_id=' + dataset_id;
sub_form.load(forms_url, function () {
sub_form.find('select').select2();
sub_form.bootstrapMaterialDesign();
}
)
;
});
if (stepName === 'data_declaration') {
$('input[type=radio]').change(function () {
const form_footer = $("#form_footer")
$("#sub-form").remove();
const sub_form = $("<div id='sub-form'>");
form_footer.before(sub_form);
const declaration_type = this.value;
const forms_url = dataDeclarationsAddSubFormUrl + '?declaration_type=' + declaration_type + '&dataset_id=' + dataset_id;
sub_form.load(forms_url, function () {
sub_form.find('select').select2();
sub_form.bootstrapMaterialDesign();
}
)
;
});
}

});
2 changes: 1 addition & 1 deletion web/templates/_includes/forms.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
{% endfor %}
{% if not hide_submit %}
{% if wizard %}
<div class="row" id="buttons">
<div class="row" id="form_footer">
<div class="col">
<button {% if submit_disabled %}disabled="disabled"{% endif %} type="submit"
class="btn btn-primary btn-raised float-right">{{ submit_label | default:"Submit" }}</button>
Expand Down
4 changes: 3 additions & 1 deletion web/templates/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
</div>
<div class="row mt-4">
<div class="col">
{% url 'wizard' as dataset_add_url %}
{% url 'wizard' as base_url %}
{% with dataset_add_url=base_url|add:"?reset=true" %}
{% include '_includes/card_list.html' with list=last_datasets list_title='My datasets' url_name='dataset' add_new_link=dataset_add_url %}
{% endwith %}
</div>
<div class="col">
{% url 'project_add' as project_add_url %}
Expand Down
20 changes: 9 additions & 11 deletions web/templates/datasets/dataset_wizard_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@
</div>

<div class="col-md-12 card">
<div class="d-flex justify-content-between mt-3">
<a href="{% url 'wizard' %}?reset=true"
class="btn btn-outline-secondary btn-raised float-right">
<i class="material-icons" style="line-height:1.5;">refresh</i>
</a>
<a type="button" id="skipButton" class="btn btn-outline-secondary btn-raised float-left">
<i class="material-icons" style="line-height:1.5;">skip_next</i>
</a>
<div class="d-flex justify-content-end mt-3">
{% if wizard.steps.step0 != 0 %}
<a type="button" id="skipButton" class="btn btn-outline-secondary btn-raised float-left">
<i class="material-icons" style="line-height:1.5;">skip_next</i>
</a>
{% endif %}
</div>
<form action="" method="post" class="form col-md-12 nice-selects" id="wizard-form">
{% csrf_token %}
Expand All @@ -37,7 +35,7 @@
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
<!-- Display form information -->
<div class="jumbotron mt-5 p-4">
<div class="jumbotron mt-2 p-4">
<h1 class="display-4">{{ form.Meta.heading }}</h1>
<p class="text-muted">{{ form.Meta.heading_help }}</p>
</div>
Expand All @@ -46,7 +44,7 @@ <h1 class="display-4">{{ form.Meta.heading }}</h1>
{% else %}
<!-- If wizard.form.forms is empty or evaluates to False -->
<!-- Display form information -->
<div class="jumbotron mt-5 p-4">
<div class="jumbotron mt-2 p-4">
<h1 class="display-4">{{ form.Meta.heading }}</h1>
<p class="text-muted">{{ form.Meta.heading_help }}</p>
</div>
Expand All @@ -61,7 +59,7 @@ <h1 class="display-4">{{ form.Meta.heading }}</h1>
{% block js %}
<script>
const dataDeclarationsAddSubFormUrl = "{% url 'data_declarations_add_sub_form' %}";
const dataset_id = '{{ dataset_id }}';
const dataset_id = '{{ dataset_id|safe }}';
const stepName = '{{ step_name|safe }}';
const skipInputID = 'id_' + '{{ step_name|safe }}' + '-skip_wizard';
</script>
Expand Down
2 changes: 1 addition & 1 deletion web/templates/search/search_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h1 class="display-4">Filter the results</h1>


{% block floating-buttons %}
<a class="btn btn-primary bmd-btn-fab float-right" href="{% url 'wizard' %}{% if reset %}?reset=true{% endif %}">
<a class="btn btn-primary bmd-btn-fab float-right" href="{% url 'wizard' %}?reset=true">
<i class="material-icons">add</i>
</a>
<a class="btn btn-secondary bmd-btn-fab d-md-none float-right" href="#sidebar-responsive-left">
Expand Down
Loading

0 comments on commit e35ae89

Please sign in to comment.