5454 SequenceSubtype ,
5555 SequenceType ,
5656)
57- from pydantic import Field
57+ from pydantic import Field , ValidationError
5858from tqdm .auto import tqdm
5959
6060from ... import get_versions
@@ -698,20 +698,20 @@ def populate( # noqa: C901, PLR0913
698698 "or use 'grzctl db submission modify' directly."
699699 ) from e
700700
701- submission_finished_date = (
702- submission_date .date () if submission_date is not None else submission .submission_finished_date
701+ submission_uploaded_date = (
702+ submission_date .date () if submission_date is not None else submission .submission_uploaded_date
703703 )
704704 if submission_date is None :
705705 log .warning (
706706 "No submission date provided and submission date is missing in the database. "
707707 "Will use submission date from metadata.json..."
708708 )
709- submission_finished_date = metadata .submission .submission_date
709+ submission_uploaded_date = metadata .submission .submission_date
710710
711711 submission_diff , donors_diff = db_service .diff (
712712 submission_id ,
713713 metadata ,
714- submission_finished_date = submission_finished_date ,
714+ submission_uploaded_date = submission_uploaded_date ,
715715 ignore_fields = set (ignore_field ),
716716 )
717717
@@ -941,6 +941,69 @@ def change_request(ctx: click.Context, submission_id: str, change_str: str, data
941941 raise click .ClickException (f"Failed to update submission state: { e } " ) from e
942942
943943
944+ def _research_consented_today (submission : Submission ) -> bool | None :
945+ """Research consent for the submission re-evaluated as of today.
946+
947+ Unlike the persisted ``consented`` field (evaluated at the submission date),
948+ this recomputes consent from the stored redacted metadata using today's date.
949+
950+ :param submission: Submission whose stored metadata to evaluate.
951+ :returns: ``True``/``False`` for the consent decision today, or ``None`` when
952+ no metadata is stored (e.g. rows migrated without backpopulated metadata)
953+ or when the stored metadata cannot be parsed.
954+ """
955+ if not submission .submission_metadata :
956+ return None
957+ try :
958+ metadata = GrzSubmissionMetadata .model_validate (submission .submission_metadata )
959+ except ValidationError :
960+ log .debug ("Could not parse stored metadata for submission %s to evaluate consent today." , submission .id )
961+ return None
962+ return metadata .consents_to_research (date = date .today ())
963+
964+
965+ def _build_attribute_table (submission : Submission , research_consented_today : bool | None ) -> rich .table .Table :
966+ """Build the attribute table shown by ``submission show``.
967+
968+ :param submission: Submission to render.
969+ :param research_consented_today: Research consent re-evaluated as of today
970+ (see :func:`_research_consented_today`), or ``None`` when unavailable.
971+ :returns: A populated rich table of submission attributes.
972+ """
973+ attribute_table = rich .table .Table (box = None )
974+ attribute_table .add_column ("Attribute" , justify = "right" )
975+ attribute_table .add_column ("Value" )
976+ for label , attr_name in (
977+ ("tanG" , "tan_g" ),
978+ ("Pseudonym" , "pseudonym" ),
979+ ("Submission Uploaded Date" , "submission_uploaded_date" ),
980+ ("Submission Size" , "submission_size" ),
981+ ("Submission Type" , "submission_type" ),
982+ ("Submitter ID" , "submitter_id" ),
983+ ("Data Node ID" , "data_node_id" ),
984+ ("Disease Type" , "disease_type" ),
985+ ("Genomic Study Type" , "genomic_study_type" ),
986+ ("Genomic Study Subtype" , "genomic_study_subtype" ),
987+ ("Basic QC Passed" , "basic_qc_passed" ),
988+ ("Research consent (at submission)" , "consented" ),
989+ ("Selected For QC" , "selected_for_qc" ),
990+ ("Detailed QC Passed" , "detailed_qc_passed" ),
991+ ):
992+ attr = getattr (submission , attr_name )
993+ attribute_table .add_row (
994+ rich .text .Text (f"{ label } " , style = "cyan" ), rich .text .Text (str (attr )) if attr is not None else _TEXT_MISSING
995+ )
996+ if attr_name == "consented" :
997+ # Adjacent row: research consent re-evaluated as of today (recomputed from stored metadata).
998+ attribute_table .add_row (
999+ rich .text .Text ("Research consent (today)" , style = "cyan" ),
1000+ rich .text .Text (str (research_consented_today ))
1001+ if research_consented_today is not None
1002+ else _TEXT_MISSING ,
1003+ )
1004+ return attribute_table
1005+
1006+
9441007@submission .command ("show" )
9451008@click .argument ("submission_id" , type = str )
9461009@output_json
@@ -956,8 +1019,11 @@ def show(ctx: click.Context, submission_id: str, output_json: bool):
9561019 console_err .print (f"[red]Error: Submission with ID '{ submission_id } ' not found.[/red]" )
9571020 raise click .Abort ()
9581021
1022+ research_consented_today = _research_consented_today (submission )
1023+
9591024 if output_json :
9601025 submission_dict = submission .model_dump (mode = "json" )
1026+ submission_dict ["research_consented_today" ] = research_consented_today
9611027 submission_dict ["states" ] = []
9621028
9631029 for state_log in sorted (submission .states , key = lambda s : s .timestamp ):
@@ -977,29 +1043,7 @@ def show(ctx: click.Context, submission_id: str, output_json: bool):
9771043 sys .stdout .write ("\n " )
9781044 return
9791045
980- attribute_table = rich .table .Table (box = None )
981- attribute_table .add_column ("Attribute" , justify = "right" )
982- attribute_table .add_column ("Value" )
983- for label , attr_name in (
984- ("tanG" , "tan_g" ),
985- ("Pseudonym" , "pseudonym" ),
986- ("Submission Date" , "submission_finished_date" ),
987- ("Submission Size" , "submission_size" ),
988- ("Submission Type" , "submission_type" ),
989- ("Submitter ID" , "submitter_id" ),
990- ("Data Node ID" , "data_node_id" ),
991- ("Disease Type" , "disease_type" ),
992- ("Genomic Study Type" , "genomic_study_type" ),
993- ("Genomic Study Subtype" , "genomic_study_subtype" ),
994- ("Basic QC Passed" , "basic_qc_passed" ),
995- ("Consented" , "consented" ),
996- ("Selected For QC" , "selected_for_qc" ),
997- ("Detailed QC Passed" , "detailed_qc_passed" ),
998- ):
999- attr = getattr (submission , attr_name )
1000- attribute_table .add_row (
1001- rich .text .Text (f"{ label } " , style = "cyan" ), rich .text .Text (str (attr )) if attr is not None else _TEXT_MISSING
1002- )
1046+ attribute_table = _build_attribute_table (submission , research_consented_today )
10031047
10041048 renderables : list [rich .console .RenderableType ] = [rich .padding .Padding (attribute_table , (1 , 0 ))]
10051049 if submission .states :
@@ -1110,18 +1154,18 @@ def _backfill_submission( # noqa: PLR0911, PLR0913
11101154 return _BackfillResult .ERROR
11111155
11121156 try :
1113- # If submission_finished_date is not set in the DB, replace it with the one from metadata.json.
1157+ # If submission_uploaded_date is not set in the DB, replace it with the one from metadata.json.
11141158 # This case is expected for submissions that were created before the submission_date field was added.
1115- submission_finished_date = (
1116- current_submission .submission_finished_date
1117- if current_submission .submission_finished_date
1159+ submission_uploaded_date = (
1160+ current_submission .submission_uploaded_date
1161+ if current_submission .submission_uploaded_date
11181162 else metadata .submission .submission_date
11191163 )
11201164
11211165 submission_diff , donors_diff = db_service .diff (
11221166 submission_id ,
11231167 metadata ,
1124- submission_finished_date = submission_finished_date ,
1168+ submission_uploaded_date = submission_uploaded_date ,
11251169 ignore_fields = ignore_fields or None ,
11261170 )
11271171 except Exception as exc :
@@ -1223,7 +1267,7 @@ def backfill( # noqa: PLR0913
12231267 raise click .UsageError ("--submission-id and --start-date/--end-date are mutually exclusive." )
12241268
12251269 ignore_fields = set (ignore_field ) | {
1226- "submission_finished_date " ,
1270+ "submission_uploaded_date " ,
12271271 "tan_g" ,
12281272 "local_case_id" ,
12291273 }
0 commit comments