Skip to content

Commit 64258f1

Browse files
committed
Merge branch 'Derek-Furst/retracted-status' of https://github.com/hubmapconsortium/entity-api into dev-integrate
2 parents 0b7e277 + 0313194 commit 64258f1

11 files changed

Lines changed: 50 additions & 204 deletions

File tree

entity-api-spec.yaml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,8 @@ components:
645645
- Submitted
646646
- Incomplete
647647
- Approval
648-
description: 'One of: New|Processing|Published|QA|Error|Hold|Invalid|Submitted|Incomplete|Approval'
648+
- Retracted
649+
description: 'One of: New|Processing|Published|QA|Error|Hold|Invalid|Submitted|Incomplete|Approval|Retracted'
649650
title:
650651
type: string
651652
description: 'The dataset title.'
@@ -792,9 +793,6 @@ components:
792793
type: string
793794
format: uuid
794795
description: 'The thumbnail image file previously uploaded to delete. Provide as a string of the file_uuid like: "c35002f9c3d49f8b77e1e2cd4a01803d"'
795-
sub_status:
796-
type: string
797-
description: 'A sub-status provided to further define the status. The only current allowable value is "Retracted"'
798796
retraction_reason:
799797
type: string
800798
description: 'Information recorded about why a the dataset was retracted.'
@@ -1101,7 +1099,8 @@ components:
11011099
- Submitted
11021100
- Incomplete
11031101
- Approval
1104-
description: 'One of: New|Processing|Published|QA|Error|Hold|Invalid|Submitted|Incomplete|Approval'
1102+
- Retracted
1103+
description: 'One of: New|Processing|Published|QA|Error|Hold|Invalid|Submitted|Incomplete|Approval|Retracted'
11051104
title:
11061105
type: string
11071106
description: 'The Publication title.'

src/app.py

Lines changed: 25 additions & 127 deletions
Large diffs are not rendered by default.

src/app_neo4j_queries.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ def get_sorted_revisions(neo4j_driver, uuid):
542542

543543
def get_sorted_multi_revisions(neo4j_driver, uuid, fetch_all=True, property_key=False):
544544
results = []
545-
match_case = '' if fetch_all is True else 'AND prev.status = "Published" AND next.status = "Published" '
545+
match_case = '' if fetch_all is True else 'AND prev.status IN ["Published", "Retracted"] AND next.status IN ["Published", "Retracted"] '
546546
collect_prop = f".{property_key}" if property_key else ''
547547

548548
query = (
@@ -1095,7 +1095,7 @@ def get_all_dataset_samples(neo4j_driver, dataset_uuid):
10951095
def get_sankey_info(neo4j_driver, public_only):
10961096
public_only_query = " "
10971097
if public_only:
1098-
public_only_query = f"AND toLower(ds.status) = 'published' "
1098+
public_only_query = f"AND toLower(ds.status) IN ['published', 'retracted'] "
10991099
query = (f"MATCH (donor:Donor)-[:ACTIVITY_INPUT]->(organ_activity:Activity)-[:ACTIVITY_OUTPUT]-> "
11001100
f"(organ:Sample {{sample_category:'organ'}})-[*]->(a:Activity)-[:ACTIVITY_OUTPUT]->(ds:Dataset) "
11011101
f"WHERE toLower(a.creation_action) = 'create dataset activity' "
@@ -1138,7 +1138,7 @@ def get_sankey_info(neo4j_driver, public_only):
11381138
def get_unpublished(neo4j_driver):
11391139
query = (
11401140
"MATCH (ds:Dataset)<-[*]-(d:Donor) "
1141-
"WHERE ds.status <> 'Published' and ds.status <> 'Hold' "
1141+
"WHERE NOT ds.status IN ['Published', 'Hold', 'Retracted'] "
11421142
# specimen_type -> sample_category 12/15/2022
11431143
"OPTIONAL MATCH (ds)<-[*]-(s:Sample {sample_category:'organ'}) "
11441144
"RETURN distinct ds.data_types as data_types, ds.group_name as organization, ds.uuid as uuid, "

src/schema/provenance_schema.yaml

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ ENTITIES:
408408
- validate_dataset_not_component
409409
generated: true
410410
indexed: true
411-
description: "One of: New|Processing|Published|QA|Error|Hold|Invalid|Submitted|Incomplete|Approval"
411+
description: "One of: New|Processing|Published|QA|Error|Hold|Invalid|Submitted|Incomplete|Approval|Retracted"
412412
before_create_trigger: set_dataset_status_new
413413
after_create_trigger: set_status_history
414414
after_update_trigger: update_status
@@ -640,18 +640,7 @@ ENTITIES:
640640
retraction_reason:
641641
type: string
642642
indexed: true
643-
before_property_update_validators:
644-
- validate_if_retraction_permitted
645-
- validate_sub_status_provided
646643
description: 'Information recorded about why a the dataset was retracted.'
647-
sub_status:
648-
type: string
649-
indexed: true
650-
before_property_update_validators:
651-
- validate_if_retraction_permitted
652-
- validate_retraction_reason_provided
653-
- validate_retracted_dataset_sub_status_value
654-
description: 'A sub-status provided to further define the status. The only current allowable value is "Retracted"'
655644
provider_info:
656645
type: string
657646
indexed: true

src/schema/schema_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,12 +1470,12 @@ def normalize_entity_type(entity_type):
14701470
Parameters
14711471
----------
14721472
status : str
1473-
One of the status types: New|Processing|QA|Published|Error|Hold|Invalid|Approval
1473+
One of the status types: New|Processing|QA|Published|Error|Hold|Invalid|Approval|Retracted
14741474
14751475
Returns
14761476
-------
14771477
string
1478-
One of the normalized status types: New|Processing|QA|Published|Error|Hold|Invalid|Approval
1478+
One of the normalized status types: New|Processing|QA|Published|Error|Hold|Invalid|Approval|Retracted
14791479
"""
14801480
def normalize_status(status):
14811481
if status.lower() == "qa":

src/schema/schema_neo4j_queries.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1692,7 +1692,7 @@ def get_component_dataset_uuids(neo4j_driver, uuid):
16921692
def count_attached_published_datasets(neo4j_driver, entity_type, uuid):
16931693
query = (f"MATCH (e:{entity_type})-[:ACTIVITY_INPUT|ACTIVITY_OUTPUT*]->(d:Dataset) "
16941694
# Use the string function toLower() to avoid case-sensetivity issue
1695-
f"WHERE e.uuid='{uuid}' AND toLower(d.status) = 'published' "
1695+
f"WHERE e.uuid='{uuid}' AND toLower(d.status) IN ['published', 'retracted'] "
16961696
# COLLECT() returns a list
16971697
# apoc.coll.toSet() reruns a set containing unique nodes
16981698
f"RETURN COUNT(d) AS {record_field_name}")

src/schema/schema_triggers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1766,7 +1766,7 @@ def update_status(property_key, normalized_type, request_args, user_token, exist
17661766
set_status_history(property_key, normalized_type, request_args, user_token, existing_data_dict, new_data_dict)
17671767

17681768
# Only apply to non-published parent datasets
1769-
if status.lower() != 'published':
1769+
if status.lower() not in ['published', 'retracted']:
17701770
# Only sync the child component datasets status for Multi-Assay Split
17711771
component_dataset_uuids = schema_neo4j_queries.get_component_dataset_uuids(schema_manager.get_neo4j_driver_instance(), uuid)
17721772

src/schema/schema_validators.py

Lines changed: 7 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,9 @@ def halt_DOI_if_unpublished_dataset(property_key, normalized_entity_type, reques
298298
# simply get the existing, distinct 'data_access_level' setting for all the Datasets in the Collection
299299
distinct_dataset_statuses = schema_neo4j_queries.get_collection_datasets_statuses(neo4j_driver_instance
300300
,existing_data_dict['uuid'])
301-
if len( distinct_dataset_statuses) != 1 or \
302-
distinct_dataset_statuses[0].lower() != SchemaConstants.DATASET_STATUS_PUBLISHED:
301+
PUBLIC_STATUSES = {SchemaConstants.DATASET_STATUS_PUBLISHED, 'retracted'}
302+
303+
if not all(status.lower() in PUBLIC_STATUSES for status in distinct_dataset_statuses):
303304
raise ValueError(f"Unable to modify existing {existing_data_dict['entity_type']}"
304305
f" {existing_data_dict['uuid']} for DOI since it contains unpublished Datasets.")
305306

@@ -416,6 +417,7 @@ def validate_dataset_status_value(property_key, normalized_entity_type, request,
416417
accepted_status_values = [
417418
'new', 'processing', 'published', 'qa', 'error', 'hold', 'invalid', 'submitted', 'incomplete', 'approval'
418419
]
420+
# Retracted intentionally omitted. Status will be set to retracted only on a manual basis
419421
new_status = new_data_dict[property_key].lower()
420422

421423
if new_status not in accepted_status_values:
@@ -426,7 +428,7 @@ def validate_dataset_status_value(property_key, normalized_entity_type, request,
426428

427429
# If status == 'Published' already in Neo4j, then fail for any changes at all
428430
# Because once published, the dataset should be read-only
429-
if existing_data_dict['status'].lower() == SchemaConstants.DATASET_STATUS_PUBLISHED:
431+
if existing_data_dict['status'].lower() in [SchemaConstants.DATASET_STATUS_PUBLISHED, 'retracted']:
430432
raise ValueError(f"The status of this {normalized_entity_type} is already 'Published', status change is not allowed")
431433

432434
# HTTP header names are case-insensitive
@@ -480,6 +482,7 @@ def validate_status_changed(property_key, normalized_entity_type, request, exist
480482
The json data in request body, already after the regular validations
481483
"""
482484
def validate_if_retraction_permitted(property_key, normalized_entity_type, request, existing_data_dict, new_data_dict):
485+
# This validator is currently unused. Keeping it in case we decide we want an api endpoint for retraction at some point.
483486
if 'status' not in existing_data_dict:
484487
raise KeyError("Missing 'status' key in 'existing_data_dict' during calling 'validate_if_retraction_permitted()' validator method.")
485488

@@ -506,27 +509,6 @@ def validate_if_retraction_permitted(property_key, normalized_entity_type, reque
506509
raise ValueError("Permission denied, retraction is not allowed")
507510

508511

509-
"""
510-
Validate the sub_status field is also provided when Dataset.retraction_reason is provided on update via PUT
511-
512-
Parameters
513-
----------
514-
property_key : str
515-
The target property key
516-
normalized_type : str
517-
Submission
518-
request: Flask request object
519-
The instance of Flask request passed in from application request
520-
existing_data_dict : dict
521-
A dictionary that contains all existing entity properties
522-
new_data_dict : dict
523-
The json data in request body, already after the regular validations
524-
"""
525-
def validate_sub_status_provided(property_key, normalized_entity_type, request, existing_data_dict, new_data_dict):
526-
if 'sub_status' not in new_data_dict:
527-
raise ValueError("Missing sub_status field when retraction_reason is provided")
528-
529-
530512
"""
531513
Validate the reaction_reason field is also provided when Dataset.sub_status is provided on update via PUT
532514
@@ -548,31 +530,6 @@ def validate_retraction_reason_provided(property_key, normalized_entity_type, re
548530
raise ValueError("Missing retraction_reason field when sub_status is provided")
549531

550532

551-
"""
552-
Validate the provided value of Dataset.sub_status on update via PUT
553-
554-
Parameters
555-
----------
556-
property_key : str
557-
The target property key
558-
normalized_type : str
559-
Submission
560-
request: Flask request object
561-
The instance of Flask request passed in from application request
562-
existing_data_dict : dict
563-
A dictionary that contains all existing entity properties
564-
new_data_dict : dict
565-
The json data in request body, already after the regular validations
566-
"""
567-
def validate_retracted_dataset_sub_status_value(property_key, normalized_entity_type, request, existing_data_dict, new_data_dict):
568-
# Use lowercase for comparison
569-
accepted_sub_status_values = ['retracted']
570-
sub_status = new_data_dict[property_key].lower()
571-
572-
if sub_status not in accepted_sub_status_values:
573-
raise ValueError("Invalid sub_status value of the Dataset to be retracted")
574-
575-
576533
"""
577534
Validate the provided value of Upload.status on update via PUT
578535
@@ -1019,7 +976,7 @@ def _validate_application_header(applications_allowed, request_headers):
1019976
def _is_entity_locked_against_update(existing_entity_dict):
1020977
entity_type = existing_entity_dict['entity_type']
1021978
if entity_type in ['Publication','Dataset']:
1022-
if 'status' in existing_entity_dict and existing_entity_dict['status'] == 'Published':
979+
if 'status' in existing_entity_dict and existing_entity_dict['status'] in ['Published', 'Retracted']:
1023980
raise schema_errors.LockedEntityUpdateException(f"Permission denied to change a published/public {entity_type}.")
1024981
elif entity_type in ['Donor','Sample']:
1025982
if 'data_access_level' in existing_entity_dict and existing_entity_dict['data_access_level'] == 'public':

src/schema_templating/example-yaml-templates/api-template-test/entity-Template.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,8 @@ x-ref-components:
601601
- Hold
602602
- Invalid
603603
- Approval
604-
description: "One of: New|Processing|QA|Published|Error|Hold|Invalid|Approval"
604+
- Retracted
605+
description: "One of: New|Processing|QA|Published|Error|Hold|Invalid|Approval|Retracted"
605606
title:
606607
type: string
607608
description: "The dataset title."

src/schema_templating/example-yaml-templates/dataset-schema.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ Dataset:
9292
- Hold
9393
- Invalid
9494
- Approval
95-
description: "One of: New|Processing|QA|Published|Error|Hold|Invalid|Approval"
95+
- Retracted
96+
description: "One of: New|Processing|QA|Published|Error|Hold|Invalid|Approval|Retracted"
9697
title:
9798
type: string
9899
description: "The dataset title."

0 commit comments

Comments
 (0)