Repository: AlexsLemonade/refinebio

Issue:
Dataset validation seems to be broken.
### Context

I saw a couple slackbot messages about no smashable files.1

### Problem or idea

Dataset ids:
* a71c681e-7dab-4d99-93c7-c43382ef0c72
* 1fd5bca4-c322-4433-ac65-d5d8f616d679

I only looked into 1fd5bca4-c322-4433-ac65-d5d8f616d679 but it had no email address and one of the experiments didn't even exist in our database at all.

### Solution or next step

Figure out how these datasets were able to be created and prevent it from happening.


Discussion:

Resolving patch:
diff --git a/api/data_refinery_api/views/dataset.py b/api/data_refinery_api/views/dataset.py
--- a/api/data_refinery_api/views/dataset.py
+++ b/api/data_refinery_api/views/dataset.py
@@ -117,10 +117,19 @@ def validate_dataset(data):
     if len(accessions) == 0:
         return
 
+    samples = Sample.public_objects.filter(accession_code__in=accessions)
+    if samples.count() != len(accessions):
+        raise serializers.ValidationError(
+            {
+                "message": "Sample(s) in dataset do not exist on refine.bio. See `non_downloadable_samples` for a full list",
+                "non_downloadable_samples": list(
+                    set(accessions) - set(s.accession_code for s in samples)
+                ),
+            },
+        )
+
     if data.get("quant_sf_only", False):
-        samples_without_quant_sf = Sample.public_objects.filter(
-            accession_code__in=accessions
-        ).exclude(
+        samples_without_quant_sf = samples.exclude(
             # Exclude samples that have at least one uploaded quant.sf file associated with them
             results__computedfile__filename="quant.sf",
             results__computedfile__s3_key__isnull=False,
@@ -137,9 +146,7 @@ def validate_dataset(data):
             )
 
     else:
-        unprocessed_samples = Sample.public_objects.filter(
-            accession_code__in=accessions, is_processed=False
-        )
+        unprocessed_samples = samples.exclude(is_processed=True)
         if unprocessed_samples.count() > 0:
             raise serializers.ValidationError(
                 {
@@ -382,7 +389,7 @@ def convert_ALL_to_accessions(data):
     def validate_email_address_is_nonempty(self):
         """Check to make sure the email exists. We call this when getting ready to dispatch a dataset"""
         supplied_email_address = self.request.data.get("email_address", None)
-        if supplied_email_address is None:
+        if supplied_email_address is None or supplied_email_address == "":
             raise serializers.ValidationError("You must provide an email address.")
 
     def dispatch_job(self, serializer, obj):


Test patch:
diff --git a/api/data_refinery_api/tests.py b/api/data_refinery_api/tests.py
--- a/api/data_refinery_api/tests.py
+++ b/api/data_refinery_api/tests.py
@@ -511,6 +511,23 @@ def test_create_dataset_fails_without_email(self):
 
         self.assertEqual(response.status_code, 400)
 
+        # Good, except for empty email.
+        jdata = json.dumps(
+            {
+                "start": True,
+                "data": {"GSE123": ["789"]},
+                "token_id": activated_token["id"],
+                "email_address": "",
+            }
+        )
+        response = self.client.post(
+            reverse("create_dataset", kwargs={"version": API_VERSION}),
+            jdata,
+            content_type="application/json",
+        )
+
+        self.assertEqual(response.status_code, 400)
+
         # You should not have to provide an email until you set start=True
         jdata = json.dumps({"data": {"GSE123": ["789"]}})
         response = self.client.post(
@@ -647,6 +664,18 @@ def test_dataset_adding_non_downloadable_samples_fails(self):
         )
         self.assertEqual(response.json()["non_downloadable_samples"], ["456"])
 
+        # Bad, 567 does not exist
+        jdata = json.dumps({"email_address": "baz@gmail.com", "data": {"GSE123": ["567"]}})
+        response = self.client.post(
+            reverse("create_dataset", kwargs={"version": API_VERSION}),
+            jdata,
+            content_type="application/json",
+        )
+        self.assertIn(
+            "Sample(s) in dataset do not exist on refine", response.json()["message"][0],
+        )
+        self.assertEqual(response.status_code, 400)
+
         # Good, 789 is processed
         jdata = json.dumps({"email_address": "baz@gmail.com", "data": {"GSE123": ["789"]}})
         response = self.client.post(