def put(self, dataset_uuid, study_id=None, user=None):
        """ Update a dataset for a given study """
        prop_id_to_name = get_property_map(key="id", value="name")
        prop_name_to_id = reverse_map(prop_id_to_name)

        # Used for helper route using only dataset_uuid
        if study_id is None:
            study_id = find_study_id_from_lvl1_uuid("dataset", dataset_uuid,
                                                    prop_name_to_id)
            if study_id is None:
                raise Exception(
                    f"Dataset not found in any study (uuid = {dataset_uuid})")

        payload = api.payload

        # 1. Split payload
        form_name = payload["form_name"]
        entries = payload["entries"]
        entry_format = payload.get("entry_format", "api")

        # 2. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 3. Get current dataset data
        datasets_entry = study_converter.get_entry_by_name("datasets")
        dataset_nested_entry = datasets_entry.value.find_nested_entry(
            "uuid", dataset_uuid)[0]
        dataset_converter = FormatConverter(mapper=prop_id_to_name)
        dataset_converter.entries = dataset_nested_entry.value

        # 4. Get new dataset data and get entries to remove
        new_dataset_converter, entries_to_remove = get_entity_converter(
            entries, entry_format, prop_id_to_name, prop_name_to_id)

        # 5. Update current dataset by adding, updating and deleting entries
        # Nested entries not present in the original form are ignored (example: dataset["samples"])
        # won't be deleted if not present in the new data), it needs to be None or "" to be deleted
        dataset_converter.add_or_update_entries(new_dataset_converter.entries)
        dataset_converter.remove_entries(entries=entries_to_remove)
        dataset_nested_entry.value = dataset_converter.entries

        # 6. Validate dataset data against form
        validate_form_format_against_form(form_name,
                                          dataset_converter.get_form_format())

        # 7. Update study state, data and ulpoad on DB
        message = "Updated dataset"
        update_study(study, study_converter, payload, message, user)
        return {"message": message}
Ejemplo n.º 2
0
    def get(self, user=None):
        """ Fetch a list with all entries """
        # Convert query parameters
        args = self._get_parser.parse_args()
        include_deprecate = args["deprecated"]

        res = Study.objects()

        if not include_deprecate:
            res = res.filter(meta_information__deprecated=False)

        study_ids = [
            u.strip()
            for u in re.split(r",|;", args["study_ids"])
            if u.strip().lower() not in ["", "0", "none", "false"]
        ]
        if len(study_ids) > 0:
            res = res.filter(id__in=study_ids)
            if res.count() < len(study_ids):
                found_ids = [str(s.id) for s in res.only("id")]
                return {
                    "message": f"Some study ids were not found",
                    "missing_study_ids": list(set(study_ids) - set(found_ids)),
                }, 404

        # Limits and Skipping applied after main filters
        res = res.all().skip(args["skip"])

        # Issue with limit(0) that returns 0 items instead of all of them
        if args["limit"] != 0:
            res = res.limit(args["limit"])

        if args["properties_id_only"] or args["entry_format"] == "form":
            marchal_model = study_model_prop_id
        else:
            marchal_model = study_model

        # Marshal studies
        study_json_list = marshal(list(res.select_related()), marchal_model)

        if args["entry_format"] == "api":
            return study_json_list

        elif args["entry_format"] == "form":
            prop_map = get_property_map(key="id", value="name")
            for study_json in study_json_list:
                study_converter = FormatConverter(prop_map).add_api_format(
                    study_json["entries"]
                )
                study_json["entries"] = study_converter.get_form_format()

            return study_json_list
Ejemplo n.º 3
0
    def test_clean_data(self):
        "Remove empty values and perform other cleaning (like stripping strings)"
        mapper = {
            "TO_KEEP": "0",
            "TO_KEEP_1": "1",
            "TO_KEEP_2": "2",
            "TO_KEEP_3": "3",
            "TO_KEEP_4": "4",
            "TO_REMOVE": "5",
            "TO_REMOVE_2": "6",
        }

        form_format = {
            "TO_KEEP_1":
            1,
            "TO_REMOVE":
            "",
            "TO_KEEP_2": [1, 2, ""],
            "TO_KEEP_3": {
                "TO_KEEP": 31,
                "TO_REMOVE": ""
            },
            "TO_KEEP_4": [
                {
                    "TO_KEEP": 441,
                    "TO_REMOVE": ""
                },
                {
                    "TO_REMOVE": "",
                    "TO_REMOVE_2": ""
                },
            ],
        }
        c = FormatConverter(mapper=mapper).add_form_format(form_format)
        c.clean_data()

        actual_output = c.get_form_format()
        expected_output = {
            "TO_KEEP_1": 1,
            "TO_KEEP_2": [1, 2],
            "TO_KEEP_3": {
                "TO_KEEP": 31
            },
            "TO_KEEP_4": [{
                "TO_KEEP": 441
            }, {}],
        }

        self.assertEqual(actual_output, expected_output)
Ejemplo n.º 4
0
    def get(self, id, user=None):
        """Fetch an entry given its unique identifier"""
        args = self._get_parser.parse_args()

        if args["properties_id_only"] or args["entry_format"] == "form":
            marchal_model = study_model_prop_id
        else:
            marchal_model = study_model

        study_json = marshal(Study.objects(id=id).get(), marchal_model)

        if args["entry_format"] == "api":
            return study_json

        elif args["entry_format"] == "form":
            prop_map = get_property_map(key="id", value="name")
            study_converter = FormatConverter(prop_map).add_api_format(
                study_json["entries"]
            )
            study_json["entries"] = study_converter.get_form_format()
            return study_json
Ejemplo n.º 5
0
    def put(self, sample_uuid, study_id=None, user=None):
        """ Update a sample for a given study """
        prop_id_to_name = get_property_map(key="id", value="name")
        prop_name_to_id = reverse_map(prop_id_to_name)

        # Used for helper route using only sample_uuid
        if study_id is None:
            study_id = find_study_id_from_lvl1_uuid("sample", sample_uuid,
                                                    prop_name_to_id)
            if study_id is None:
                raise Exception(
                    f"Sample not found in any study (uuid = {sample_uuid})")

        payload = api.payload

        # 1. Split payload
        validate_dict = payload.get("validate", None)
        form_names = payload.get("form_names", None)
        entries = payload["entries"]
        entry_format = payload.get("entry_format", "api")

        # 2. Get forms for validation
        forms = {}
        for key, validate in validate_dict.items():
            if validate:
                forms[key] = app.form_manager.get_form_by_name(
                    form_name=form_names[key])

        # 3. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 3. Get current sample data
        samples_entry = study_converter.get_entry_by_name("samples")
        sample_nested_entry = samples_entry.value.find_nested_entry(
            "uuid", sample_uuid)[0]
        sample_converter = FormatConverter(mapper=prop_id_to_name)
        sample_converter.entries = sample_nested_entry.value

        # 4. Unify UUIDs with existing entities (including nested ones)
        # Format and clean entity
        new_sample_converter, _ = get_entity_converter(entries, entry_format,
                                                       prop_id_to_name,
                                                       prop_name_to_id)

        new_sample_form_format = new_sample_converter.get_form_format()

        [new_sample_form_format] = unify_sample_entities_uuids(
            existing_samples=study_converter.get_form_format().get(
                "samples", []),
            new_samples=[new_sample_form_format],
        )

        # 5. Clean new data and get entries to remove
        # Format and clean entity
        new_sample_converter, entries_to_remove = get_entity_converter(
            entries=new_sample_form_format,
            entry_format="form",
            prop_id_to_name=None,
            prop_name_to_id=prop_name_to_id,
        )

        # 6. Update current sample by adding, updating and deleting entries
        # Nested entries not present in the original form are ignored
        # won't be deleted if not present in the new data), it needs to be None or "" to be deleted
        sample_converter.add_or_update_entries(new_sample_converter.entries)
        sample_converter.remove_entries(entries=entries_to_remove)
        sample_nested_entry.value = sample_converter.entries

        # 7. Validate data against form
        validate_sample_against_form(sample_converter.get_form_format(),
                                     validate_dict, forms)

        # 8. Update study state, data and ulpoad on DB
        message = "Updated sample"
        update_study(study, study_converter, payload, message, user)
        return {"message": message}
Ejemplo n.º 6
0
    def post(self, study_id, user=None):
        """ Add a new sample for a given study """
        payload = api.payload

        prop_id_to_name = get_property_map(key="id", value="name")
        prop_name_to_id = reverse_map(prop_id_to_name)

        # 1. Split payload
        validate_dict = payload.get("validate", None)
        form_names = payload.get("form_names", None)
        entries = payload["entries"]
        entry_format = payload.get("entry_format", "api")

        # 2. Get forms for validation
        forms = {}
        for key, validate in validate_dict.items():
            if validate:
                forms[key] = app.form_manager.get_form_by_name(
                    form_name=form_names[key])

        # 3. Get study data
        study = Study.objects().get(id=study_id)
        study_json = marshal(study, study_model)

        study_converter = FormatConverter(mapper=prop_id_to_name)
        study_converter.add_api_format(study_json["entries"])

        # 4. Unify UUIDs with existing entities (including nested ones)
        # Format and clean entity
        sample_converter, _ = get_entity_converter(entries, entry_format,
                                                   prop_id_to_name,
                                                   prop_name_to_id)
        new_sample_form_format = sample_converter.get_form_format()

        [new_sample_form_format] = unify_sample_entities_uuids(
            existing_samples=study_converter.get_form_format().get(
                "samples", []),
            new_samples=[new_sample_form_format],
        )

        # 5. Append new samples to "samples" in study
        # Format and clean entity
        sample_converter, _ = get_entity_converter(
            entries=new_sample_form_format,
            entry_format="form",
            prop_id_to_name=None,
            prop_name_to_id=prop_name_to_id,
        )

        # Generate UUID (redundant, UUIDs already generated by unify_sample_entities_uuids)
        sample_converter, sample_uuid = add_uuid_entry_if_missing(
            sample_converter, prop_name_to_id)

        study_converter = add_entity_to_study_nested_list(
            study_converter=study_converter,
            entity_converter=sample_converter,
            prop_name_to_id=prop_name_to_id,
            study_list_prop="samples",
        )

        # 6. Validate data against form
        validate_sample_against_form(sample_converter.get_form_format(),
                                     validate_dict, forms)

        # 7. Update study state, data and ulpoad on DB
        message = "Added sample"
        update_study(study, study_converter, payload, message, user)
        return {"message": message, "uuid": sample_uuid}, 201