diff --git a/backend/fpbase/tests/test_end2end.py b/backend/fpbase/tests/test_end2end.py index e7355845..ce2760d5 100644 --- a/backend/fpbase/tests/test_end2end.py +++ b/backend/fpbase/tests/test_end2end.py @@ -153,7 +153,8 @@ def test_fret(self): self.browser.switch_to.active_element.send_keys(Keys.ENTER) elem = self.browser.find_element(value="QYD") - assert float(elem.text) == donor.default_state.qy + if elem.text: + assert float(elem.text) == donor.default_state.qy elem = self.browser.find_element(value="QYA") WebDriverWait(self.browser, 1.5).until(lambda d: bool(elem.text)) diff --git a/backend/proteins/forms/forms.py b/backend/proteins/forms/forms.py index f76626b5..be93e924 100644 --- a/backend/proteins/forms/forms.py +++ b/backend/proteins/forms/forms.py @@ -1,7 +1,8 @@ import re +from typing import cast from crispy_forms.helper import FormHelper -from crispy_forms.layout import HTML, Div, Layout +from crispy_forms.layout import HTML, Div, Field, Layout from dal import autocomplete from django import forms from django.forms.models import inlineformset_factory # ,BaseInlineFormSet @@ -102,19 +103,45 @@ class ProteinForm(forms.ModelForm): seq = SequenceField(required=False, help_text="Amino acid sequence", label="Sequence") # reference_pmid = forms.CharField(max_length=24, label='Reference Pubmed ID', # required=False, help_text='e.g. 23524392 (must provide either DOI or PMID)') + confirmation = forms.BooleanField( + required=True, + label=mark_safe( + "I understand that I am contributing to the public " + "FPbase database, and confirm that I have verified the validity of the data" + ), + ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - # self.fields['seq'].disabled = self.instance.seq_validated - instance = getattr(self, "instance", None) - if instance and instance.pk: - if instance.seq_validated: - self.fields["seq"].widget.attrs["readonly"] = True + prot = cast("Protein | None", getattr(self, "instance", None)) + if prot and prot.pk: + for attr, field in [ + ("name", "name"), + ("aliases", "aliases"), + ("seq_validated", "seq"), + ("primary_reference", "reference_doi"), + ("ipg_id", "ipg_id"), + ("cofactor", "cofactor"), + ("genbank", "genbank"), + ("uniprot", "uniprot"), + ("pdb", "pdb"), + ]: + if bool(getattr(prot, attr)): + self.fields[field].widget.attrs["readonly"] = True + for attr, field in [ + ("agg", "agg"), + ("parent_organism", "parent_organism"), + ("cofactor", "cofactor"), + ("switch_type", "switch_type"), + ]: + if bool(getattr(prot, attr)): + self.fields[field].widget.attrs["disabled"] = True self.helper = FormHelper(self) self.helper.form_tag = False self.helper.error_text_inline = True self.helper.layout = Layout( + Field("confirmation", css_class="custom-checkbox"), Div( Div("name", css_class="col-md-4 col-sm-12"), Div("aliases", css_class="col-md-4 col-sm-6"), @@ -241,6 +268,22 @@ class StateForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + + state = cast("State | None", getattr(self, "instance", None)) + if state and state.pk: + for attr, field in [ + ("name", "name"), + ("ex_max", "ex_max"), + ("em_max", "em_max"), + ("ext_coeff", "ext_coeff"), + ("qy", "qy"), + ("pka", "pka"), + ("lifetime", "lifetime"), + ("maturation", "maturation"), + ]: + if getattr(state, attr): + self.fields[field].widget.attrs["readonly"] = True + self.helper = FormHelper() self.helper.form_tag = False self.helper.disable_csrf = True diff --git a/backend/proteins/templates/proteins/protein_form.html b/backend/proteins/templates/proteins/protein_form.html index 2e0fee86..521ec881 100644 --- a/backend/proteins/templates/proteins/protein_form.html +++ b/backend/proteins/templates/proteins/protein_form.html @@ -19,7 +19,17 @@

Update {{ object.name }}

Submit a new protein

{% endif %} -

Thank you for contributing to FPbase! All contributed data will be moderated, but please double check your submission for accuracy. The only strictly required fields are name and DOI.

+ {% if states.non_form_errors %}
There were errors in the form...
@@ -55,10 +65,6 @@
There were errors in the form...
{% endfor %} - {% if protein.seq_validated or protein.lineage.children.exists %} -

Note: Once moderated and approved, sequence and lineage fields are uneditable. If you think there is an error in either, please contact us

- {% endif %} - - {{ states.management_form|crispy }} {% for stateform in states.forms %} {% for hidden in stateform.hidden_fields %} diff --git a/backend/proteins/tests/test_forms.py b/backend/proteins/tests/test_forms.py index b83e742f..6d7b626b 100644 --- a/backend/proteins/tests/test_forms.py +++ b/backend/proteins/tests/test_forms.py @@ -17,7 +17,7 @@ def setUp(self): def test_clean_proteinname_success(self): # Instantiate the form with a new protein - form = ProteinForm({"name": "New Protein"}) + form = ProteinForm({"name": "New Protein", "confirmation": True}) # Run is_valid() to trigger the validation valid = form.is_valid() self.assertTrue(valid, "Form is not valid") @@ -28,7 +28,7 @@ def test_clean_proteinname_success(self): def test_clean_proteinname_exists(self): # Instantiate the form with existing protein name - form = ProteinForm({"name": "Test Protein"}) + form = ProteinForm({"name": "Test Protein", "confirmation": True}) # Run is_valid() to trigger the validation, which is going to fail # because the name is already taken valid = form.is_valid() @@ -39,21 +39,21 @@ def test_clean_proteinname_exists(self): self.assertTrue("name" in form.errors) def test_clean_proteinseq_success(self): - form = ProteinForm({"name": "New Protein", "seq": "ghilkmfpstwy varndceq"}) + form = ProteinForm({"name": "New Protein", "seq": "ghilkmfpstwy varndceq", "confirmation": True}) valid = form.is_valid() self.assertTrue(valid, "Form is not valid") seq = form.clean_seq() self.assertEqual("GHILKMFPSTWYVARNDCEQ", seq) def test_clean_proteinseq_exists(self): - form = ProteinForm({"name": "New Protein", "seq": "ARNDCEQGHILKMFPSTWYV"}) + form = ProteinForm({"name": "New Protein", "seq": "ARNDCEQGHILKMFPSTWYV", "confirmation": True}) valid = form.is_valid() self.assertFalse(valid) self.assertTrue(len(form.errors) == 1) self.assertTrue("seq" in form.errors) def test_clean_proteinseq_invalid(self): - form = ProteinForm({"name": "New Protein", "seq": "ARNDCEQGHILKMBZXFPSTWYV"}) + form = ProteinForm({"name": "New Protein", "seq": "ARNDCEQGHILKMBZXFPSTWYV", "confirmation": True}) valid = form.is_valid() self.assertFalse(valid) self.assertTrue(len(form.errors) == 1) @@ -65,7 +65,7 @@ def test_clean_refdoi_success(self): "https://doi.org/10.1038/nmeth.2413", "10.1038/nmeth.2413", ): - form = ProteinForm({"name": "New Protein", "reference_doi": doi}) + form = ProteinForm({"name": "New Protein", "reference_doi": doi, "confirmation": True}) valid = form.is_valid() self.assertTrue(valid, "Form is not valid") self.assertEqual("10.1038/nmeth.2413", form.cleaned_data["reference_doi"]) @@ -75,6 +75,7 @@ def test_clean_refdoi_failure(self): { "name": "New Protein", "reference_doi": "30.1038/nmeth.2413", # Invalid DOI + "confirmation": True, } ) valid = form.is_valid() @@ -90,6 +91,7 @@ def test_ids_already_exist(self): "genbank": "NC_000001.10", "uniprot": "P12345", "pdb": ["4HHB"], + "confirmation": True, } ) valid = form.is_valid() diff --git a/backend/proteins/tests/test_views.py b/backend/proteins/tests/test_views.py index 42534b77..8ec8ea18 100644 --- a/backend/proteins/tests/test_views.py +++ b/backend/proteins/tests/test_views.py @@ -49,6 +49,7 @@ def test_protein_submit(self): "states-0-name": "default", "states-0-ex_max": 488, "states-0-em_max": 525, + "confirmation": True, } | INLINE_FORMSET, )